UNPKG

@agentica/core

Version:

Agentic AI Library specialized in LLM Function Calling

372 lines 17.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.call = call; const openapi_1 = require("@samchon/openapi"); const AgenticaConstant_1 = require("../constants/AgenticaConstant"); const AgenticaDefaultPrompt_1 = require("../constants/AgenticaDefaultPrompt"); const AgenticaSystemPrompt_1 = require("../constants/AgenticaSystemPrompt"); const isAgenticaContext_1 = require("../context/internal/isAgenticaContext"); const events_1 = require("../factory/events"); const histories_1 = require("../factory/histories"); const ChatGptCompletionMessageUtil_1 = require("../utils/ChatGptCompletionMessageUtil"); const StreamUtil_1 = require("../utils/StreamUtil"); const cancelFunctionFromContext_1 = require("./internal/cancelFunctionFromContext"); function call(ctx, operations) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g, _h, _j; const stream = yield ctx.request("call", { messages: [ // COMMON SYSTEM PROMPT { role: "system", content: AgenticaDefaultPrompt_1.AgenticaDefaultPrompt.write(ctx.config), }, // PREVIOUS HISTORIES ...ctx.histories.map(histories_1.decodeHistory).flat(), // USER INPUT { role: "user", content: ctx.prompt.contents.map(histories_1.decodeUserMessageContent), }, // SYSTEM PROMPT ...(((_b = (_a = ctx.config) === null || _a === void 0 ? void 0 : _a.systemPrompt) === null || _b === void 0 ? void 0 : _b.execute) === null ? [] : [{ role: "system", content: (_f = (_e = (_d = (_c = ctx.config) === null || _c === void 0 ? void 0 : _c.systemPrompt) === null || _d === void 0 ? void 0 : _d.execute) === null || _e === void 0 ? void 0 : _e.call(_d, ctx.histories)) !== null && _f !== void 0 ? _f : AgenticaSystemPrompt_1.AgenticaSystemPrompt.EXECUTE, }]), ], // STACKED FUNCTIONS tools: operations.map(s => { var _a; return ({ type: "function", function: { name: s.name, description: s.function.description, parameters: (("separated" in s.function && s.function.separated !== undefined) ? ((_a = s.function.separated.llm) !== null && _a !== void 0 ? _a : { type: "object", properties: {}, required: [], additionalProperties: false, $defs: {}, }) : s.function.parameters), }, }); }), tool_choice: "auto", // parallel_tool_calls: false, }); const chunks = yield StreamUtil_1.StreamUtil.readAll(stream); const completion = ChatGptCompletionMessageUtil_1.ChatGptCompletionMessageUtil.merge(chunks); const executes = []; const retry = (_h = (_g = ctx.config) === null || _g === void 0 ? void 0 : _g.retry) !== null && _h !== void 0 ? _h : AgenticaConstant_1.AgenticaConstant.RETRY; for (const choice of completion.choices) { for (const tc of (_j = choice.message.tool_calls) !== null && _j !== void 0 ? _j : []) { if (tc.type === "function") { const operation = operations.find(s => s.name === tc.function.name); if (operation === undefined) { continue; // Ignore unknown tool calls } const event = yield predicate(ctx, operation, tc, [], retry); ctx.dispatch(event); executes.push(event); if ((0, isAgenticaContext_1.isAgenticaContext)(ctx)) { (0, cancelFunctionFromContext_1.cancelFunctionFromContext)(ctx, { name: event.operation.name, reason: "completed", }); } } } if (choice.message.role === "assistant" && choice.message.content != null && choice.message.content.length !== 0) { const text = choice.message.content; const event = (0, events_1.createAssistantMessageEvent)({ get: () => text, done: () => true, stream: (0, StreamUtil_1.toAsyncGenerator)(text), join: () => __awaiter(this, void 0, void 0, function* () { return Promise.resolve(text); }), }); ctx.dispatch(event); } } return executes; }); } function predicate(ctx, operation, toolCall, previousValidationErrors, life) { return __awaiter(this, void 0, void 0, function* () { // CHECK INPUT ARGUMENT const call = parseArguments(operation, toolCall); ctx.dispatch(call); if (call.type === "jsonParseError") { return correctJsonError(ctx, call, previousValidationErrors, life - 1); } // CHECK TYPE VALIDATION const check = operation.function.validate(call.arguments); if (check.success === false) { const event = (0, events_1.createValidateEvent)({ id: toolCall.id, operation, result: check, }); ctx.dispatch(event); return correctTypeError(ctx, call, event, [...previousValidationErrors, event], life - 1); } // EXECUTE OPERATION return executeFunction(call, operation); }); } /* ----------------------------------------------------------- ERROR CORRECTORS ----------------------------------------------------------- */ function correctTypeError(ctx, callEvent, validateEvent, previousValidationErrors, life) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d; return correctError(ctx, { giveUp: () => (0, events_1.createExecuteEvent)({ operation: callEvent.operation, arguments: callEvent.arguments, value: { name: "ValidationError", message: `Invalid arguments. The validation failed after ${AgenticaConstant_1.AgenticaConstant.RETRY} retries.`, errors: validateEvent.result.errors, }, }), operation: callEvent.operation, toolCall: { id: callEvent.id, arguments: JSON.stringify(callEvent.arguments), result: JSON.stringify(validateEvent.result.errors), }, systemPrompt: (_d = (_c = (_b = (_a = ctx.config) === null || _a === void 0 ? void 0 : _a.systemPrompt) === null || _b === void 0 ? void 0 : _b.validate) === null || _c === void 0 ? void 0 : _c.call(_b, previousValidationErrors.slice(0, -1))) !== null && _d !== void 0 ? _d : [ AgenticaSystemPrompt_1.AgenticaSystemPrompt.VALIDATE, ...(previousValidationErrors.length > 1 ? [ "", AgenticaSystemPrompt_1.AgenticaSystemPrompt.VALIDATE_REPEATED.replace("${{HISTORICAL_ERRORS}}", JSON.stringify(previousValidationErrors.slice(0, -1).map(e => e.result.errors))), ] : []), ].join("\n"), life, previousValidationErrors, }); }); } function correctJsonError(ctx, parseErrorEvent, previousValidationErrors, life) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d; return correctError(ctx, { giveUp: () => (0, events_1.createExecuteEvent)({ operation: parseErrorEvent.operation, arguments: {}, value: { name: "JsonParseError", message: `Invalid JSON format. The parsing failed after ${AgenticaConstant_1.AgenticaConstant.RETRY} retries.`, arguments: parseErrorEvent.arguments, errorMessage: parseErrorEvent.errorMessage, }, }), operation: parseErrorEvent.operation, toolCall: { id: parseErrorEvent.id, arguments: parseErrorEvent.arguments, result: parseErrorEvent.errorMessage, }, systemPrompt: (_d = (_c = (_b = (_a = ctx.config) === null || _a === void 0 ? void 0 : _a.systemPrompt) === null || _b === void 0 ? void 0 : _b.jsonParseError) === null || _c === void 0 ? void 0 : _c.call(_b, parseErrorEvent)) !== null && _d !== void 0 ? _d : AgenticaSystemPrompt_1.AgenticaSystemPrompt.JSON_PARSE_ERROR.replace("${{ERROR_MESSAGE}}", parseErrorEvent.errorMessage), life, previousValidationErrors, }); }); } function parseArguments(operation, toolCall) { try { const data = JSON.parse(toolCall.function.arguments); return (0, events_1.createCallEvent)({ id: toolCall.id, operation, arguments: data, }); } catch (error) { return (0, events_1.createJsonParseErrorEvent)({ id: toolCall.id, operation, arguments: toolCall.function.arguments, errorMessage: error instanceof Error ? error.message : String(error), }); } } function correctError(ctx, props) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g, _h; if (props.life <= 0) { return props.giveUp(); } const stream = yield ctx.request("call", { messages: [ // COMMON SYSTEM PROMPT { role: "system", content: AgenticaDefaultPrompt_1.AgenticaDefaultPrompt.write(ctx.config), }, // PREVIOUS HISTORIES ...ctx.histories.map(histories_1.decodeHistory).flat(), // USER INPUT { role: "user", content: ctx.prompt.contents.map(histories_1.decodeUserMessageContent), }, // TYPE CORRECTION { role: "system", content: (_d = (_c = (_b = (_a = ctx.config) === null || _a === void 0 ? void 0 : _a.systemPrompt) === null || _b === void 0 ? void 0 : _b.execute) === null || _c === void 0 ? void 0 : _c.call(_b, ctx.histories)) !== null && _d !== void 0 ? _d : AgenticaSystemPrompt_1.AgenticaSystemPrompt.EXECUTE, }, { role: "assistant", tool_calls: [ { type: "function", id: props.toolCall.id, function: { name: props.operation.name, arguments: props.toolCall.arguments, }, }, ], }, { role: "tool", content: props.toolCall.result, tool_call_id: props.toolCall.id, }, { role: "system", content: props.systemPrompt, }, ], // STACK FUNCTIONS tools: [ { type: "function", function: { name: props.operation.name, description: props.operation.function.description, /** * @TODO fix it * The property and value have a type mismatch, but it works. */ parameters: (("separated" in props.operation.function && props.operation.function.separated !== undefined) ? ((_f = (_e = props.operation.function.separated) === null || _e === void 0 ? void 0 : _e.llm) !== null && _f !== void 0 ? _f : { $defs: {}, type: "object", properties: {}, additionalProperties: false, required: [], }) : props.operation.function.parameters), }, }, ], tool_choice: "required", // parallel_tool_calls: false, }); const chunks = yield StreamUtil_1.StreamUtil.readAll(stream); const completion = ChatGptCompletionMessageUtil_1.ChatGptCompletionMessageUtil.merge(chunks); const toolCall = (_h = (_g = completion.choices[0]) === null || _g === void 0 ? void 0 : _g.message.tool_calls) === null || _h === void 0 ? void 0 : _h.find(s => s.function.name === props.operation.name); return toolCall === undefined ? props.giveUp() : predicate(ctx, props.operation, toolCall, props.previousValidationErrors, props.life); }); } /* ----------------------------------------------------------- FUNCTION EXECUTORS ----------------------------------------------------------- */ function executeFunction(call, operation) { return __awaiter(this, void 0, void 0, function* () { try { const value = yield (() => __awaiter(this, void 0, void 0, function* () { switch (operation.protocol) { case "class": return executeClassFunction(call, operation); case "http": return executeHttpOperation(call, operation); case "mcp": return executeMcpOperation(call, operation); default: operation; // Ensure all cases are handled throw new Error("Unknown protocol"); // never be happen } }))(); return (0, events_1.createExecuteEvent)({ operation: call.operation, arguments: call.arguments, value, }); } catch (error) { return (0, events_1.createExecuteEvent)({ operation: call.operation, arguments: call.arguments, value: error instanceof Error ? Object.assign(Object.assign({}, error), { name: error.name, message: error.message }) : error, }); } }); } function executeClassFunction(call, operation) { return __awaiter(this, void 0, void 0, function* () { const execute = operation.controller.execute; const value = typeof execute === "function" ? yield execute({ application: operation.controller.application, function: operation.function, arguments: call.arguments, }) : yield execute[operation.function.name](call.arguments); return value; }); } function executeHttpOperation(call, operation) { return __awaiter(this, void 0, void 0, function* () { const execute = operation.controller.execute; const value = typeof execute === "function" ? yield execute({ connection: operation.controller.connection, application: operation.controller.application, function: operation.function, arguments: call.arguments, }) : yield openapi_1.HttpLlm.propagate({ connection: operation.controller.connection, application: operation.controller.application, function: operation.function, input: call.arguments, }); return value; }); } function executeMcpOperation(call, operation) { return __awaiter(this, void 0, void 0, function* () { return operation.controller.client.callTool({ method: operation.function.name, name: operation.function.name, arguments: call.arguments, }).then(v => v.content); }); } //# sourceMappingURL=call.js.map