@agentica/core 0.44.0-dev.20260313-2 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +218 -218
- package/lib/context/internal/__IChatInitialApplication.d.ts +1 -2
- package/lib/errors/AgenticaJsonParseError.js +6 -6
- package/lib/index.mjs +47 -1
- package/lib/index.mjs.map +1 -1
- package/lib/orchestrate/call.js +16 -16
- package/lib/orchestrate/initialize.js +43 -1
- package/lib/orchestrate/initialize.js.map +1 -1
- package/lib/structures/IAgenticaController.d.ts +143 -143
- package/lib/utils/ChatGptCompletionMessageUtil.js +6 -6
- package/package.json +6 -6
- package/prompts/cancel.md +5 -5
- package/prompts/common.md +3 -3
- package/prompts/describe.md +7 -7
- package/prompts/execute.md +122 -122
- package/prompts/initialize.md +3 -3
- package/prompts/json_parse_error.md +35 -35
- package/prompts/select.md +7 -7
- package/prompts/validate.md +123 -123
- package/prompts/validate_repeated.md +31 -31
- package/src/Agentica.ts +367 -367
- package/src/MicroAgentica.ts +357 -357
- package/src/constants/AgenticaConstant.ts +4 -4
- package/src/constants/AgenticaDefaultPrompt.ts +44 -44
- package/src/constants/index.ts +2 -2
- package/src/context/AgenticaContext.ts +136 -136
- package/src/context/AgenticaContextRequestResult.ts +14 -14
- package/src/context/AgenticaOperation.ts +73 -73
- package/src/context/AgenticaOperationCollection.ts +49 -49
- package/src/context/AgenticaOperationSelection.ts +9 -9
- package/src/context/AgenticaTokenUsage.ts +186 -186
- package/src/context/MicroAgenticaContext.ts +99 -99
- package/src/context/index.ts +5 -5
- package/src/context/internal/AgenticaOperationComposer.ts +177 -177
- package/src/context/internal/AgenticaTokenUsageAggregator.ts +66 -66
- package/src/context/internal/__IChatCancelFunctionsApplication.ts +23 -23
- package/src/context/internal/__IChatFunctionReference.ts +21 -21
- package/src/context/internal/__IChatInitialApplication.ts +13 -15
- package/src/context/internal/__IChatSelectFunctionsApplication.ts +24 -24
- package/src/context/internal/isAgenticaContext.ts +11 -11
- package/src/errors/AgenticaJsonParseError.ts +52 -52
- package/src/errors/AgenticaValidationError.ts +49 -49
- package/src/errors/index.ts +2 -2
- package/src/events/AgenticaAssistantMessageEvent.ts +12 -12
- package/src/events/AgenticaCallEvent.ts +27 -27
- package/src/events/AgenticaCancelEvent.ts +9 -9
- package/src/events/AgenticaDescribeEvent.ts +14 -14
- package/src/events/AgenticaEvent.ts +59 -59
- package/src/events/AgenticaEvent.type.ts +19 -19
- package/src/events/AgenticaEventBase.ts +18 -18
- package/src/events/AgenticaEventSource.ts +6 -6
- package/src/events/AgenticaExecuteEvent.ts +45 -45
- package/src/events/AgenticaInitializeEvent.ts +7 -7
- package/src/events/AgenticaJsonParseErrorEvent.ts +16 -16
- package/src/events/AgenticaRequestEvent.ts +27 -27
- package/src/events/AgenticaResponseEvent.ts +32 -32
- package/src/events/AgenticaSelectEvent.ts +11 -11
- package/src/events/AgenticaUserMessageEvent.ts +12 -12
- package/src/events/AgenticaValidateEvent.ts +32 -32
- package/src/events/MicroAgenticaEvent.ts +45 -45
- package/src/events/index.ts +15 -15
- package/src/factory/events.ts +357 -357
- package/src/factory/histories.ts +348 -348
- package/src/factory/index.ts +3 -3
- package/src/factory/operations.ts +16 -16
- package/src/functional/assertHttpController.ts +106 -106
- package/src/functional/assertHttpLlmApplication.ts +52 -52
- package/src/functional/assertMcpController.ts +47 -47
- package/src/functional/createMcpLlmApplication.ts +72 -72
- package/src/functional/index.ts +7 -7
- package/src/functional/validateHttpController.ts +113 -113
- package/src/functional/validateHttpLlmApplication.ts +65 -65
- package/src/functional/validateMcpController.ts +53 -53
- package/src/histories/AgenticaAssistantMessageHistory.ts +10 -10
- package/src/histories/AgenticaCancelHistory.ts +8 -8
- package/src/histories/AgenticaDescribeHistory.ts +18 -18
- package/src/histories/AgenticaExecuteHistory.ts +64 -64
- package/src/histories/AgenticaHistory.ts +28 -28
- package/src/histories/AgenticaHistoryBase.ts +35 -35
- package/src/histories/AgenticaSelectHistory.ts +8 -8
- package/src/histories/AgenticaSystemMessageHistory.ts +10 -10
- package/src/histories/AgenticaUserMessageHistory.ts +11 -11
- package/src/histories/MicroAgenticaHistory.ts +19 -19
- package/src/histories/contents/AgenticaUserMessageAudioContent.ts +21 -21
- package/src/histories/contents/AgenticaUserMessageContent.ts +19 -19
- package/src/histories/contents/AgenticaUserMessageContentBase.ts +6 -6
- package/src/histories/contents/AgenticaUserMessageFileContent.ts +25 -25
- package/src/histories/contents/AgenticaUserMessageImageContent.ts +33 -33
- package/src/histories/contents/AgenticaUserMessageTextContent.ts +15 -15
- package/src/histories/contents/index.ts +5 -5
- package/src/histories/index.ts +10 -10
- package/src/index.ts +15 -15
- package/src/json/IAgenticaEventJson.ts +265 -265
- package/src/json/IAgenticaEventJson.type.ts +19 -19
- package/src/json/IAgenticaHistoryJson.ts +165 -165
- package/src/json/IAgenticaHistoryJson.type.ts +19 -19
- package/src/json/IAgenticaOperationJson.ts +36 -36
- package/src/json/IAgenticaOperationSelectionJson.ts +26 -26
- package/src/json/IAgenticaTokenUsageJson.ts +107 -107
- package/src/json/IMicroAgenticaEventJson.ts +22 -22
- package/src/json/IMicroAgenticaHistoryJson.ts +25 -25
- package/src/json/index.ts +7 -7
- package/src/orchestrate/call.ts +542 -542
- package/src/orchestrate/cancel.ts +265 -265
- package/src/orchestrate/describe.ts +66 -66
- package/src/orchestrate/execute.ts +61 -61
- package/src/orchestrate/index.ts +6 -6
- package/src/orchestrate/initialize.ts +102 -102
- package/src/orchestrate/internal/cancelFunctionFromContext.ts +33 -33
- package/src/orchestrate/internal/selectFunctionFromContext.ts +34 -34
- package/src/orchestrate/select.ts +320 -320
- package/src/structures/IAgenticaConfig.ts +83 -83
- package/src/structures/IAgenticaConfigBase.ts +87 -87
- package/src/structures/IAgenticaController.ts +143 -143
- package/src/structures/IAgenticaExecutor.ts +167 -167
- package/src/structures/IAgenticaProps.ts +78 -78
- package/src/structures/IAgenticaSystemPrompt.ts +236 -236
- package/src/structures/IAgenticaVendor.ts +54 -54
- package/src/structures/IMcpTool.ts +60 -60
- package/src/structures/IMicroAgenticaConfig.ts +56 -56
- package/src/structures/IMicroAgenticaExecutor.ts +67 -67
- package/src/structures/IMicroAgenticaProps.ts +77 -77
- package/src/structures/IMicroAgenticaSystemPrompt.ts +169 -169
- package/src/structures/index.ts +10 -10
- package/src/transformers/transformHistory.ts +172 -172
- package/src/utils/AssistantMessageEmptyError.ts +20 -20
- package/src/utils/AsyncQueue.spec.ts +355 -355
- package/src/utils/AsyncQueue.ts +95 -95
- package/src/utils/ByteArrayUtil.ts +5 -5
- package/src/utils/ChatGptCompletionMessageUtil.spec.ts +314 -314
- package/src/utils/ChatGptCompletionMessageUtil.ts +210 -210
- package/src/utils/ChatGptCompletionStreamingUtil.spec.ts +909 -909
- package/src/utils/ChatGptCompletionStreamingUtil.ts +91 -91
- package/src/utils/ChatGptTokenUsageAggregator.spec.ts +226 -226
- package/src/utils/ChatGptTokenUsageAggregator.ts +57 -57
- package/src/utils/MPSC.spec.ts +276 -276
- package/src/utils/MPSC.ts +42 -42
- package/src/utils/Singleton.spec.ts +138 -138
- package/src/utils/Singleton.ts +42 -42
- package/src/utils/StreamUtil.spec.ts +512 -512
- package/src/utils/StreamUtil.ts +87 -87
- package/src/utils/__map_take.spec.ts +140 -140
- package/src/utils/__map_take.ts +13 -13
- package/src/utils/__retry.spec.ts +198 -198
- package/src/utils/__retry.ts +18 -18
- package/src/utils/assertExecuteFailure.ts +16 -16
- package/src/utils/index.ts +4 -4
- package/src/utils/request.ts +140 -140
- package/src/utils/types.ts +50 -50
package/src/orchestrate/call.ts
CHANGED
|
@@ -1,542 +1,542 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
IHttpResponse,
|
|
3
|
-
IJsonParseResult,
|
|
4
|
-
IValidation,
|
|
5
|
-
} from "@typia/interface";
|
|
6
|
-
import type OpenAI from "openai";
|
|
7
|
-
|
|
8
|
-
import { dedent, HttpLlm, LlmJson } from "@typia/utils";
|
|
9
|
-
|
|
10
|
-
import type { AgenticaContext } from "../context/AgenticaContext";
|
|
11
|
-
import type { AgenticaOperation } from "../context/AgenticaOperation";
|
|
12
|
-
import type { MicroAgenticaContext } from "../context/MicroAgenticaContext";
|
|
13
|
-
import type { AgenticaAssistantMessageEvent, AgenticaValidateEvent } from "../events";
|
|
14
|
-
import type { AgenticaCallEvent } from "../events/AgenticaCallEvent";
|
|
15
|
-
import type { AgenticaExecuteEvent } from "../events/AgenticaExecuteEvent";
|
|
16
|
-
import type { AgenticaJsonParseErrorEvent } from "../events/AgenticaJsonParseErrorEvent";
|
|
17
|
-
import type { MicroAgenticaHistory } from "../histories/MicroAgenticaHistory";
|
|
18
|
-
|
|
19
|
-
import { AgenticaConstant } from "../constants/AgenticaConstant";
|
|
20
|
-
import { AgenticaDefaultPrompt } from "../constants/AgenticaDefaultPrompt";
|
|
21
|
-
import { AgenticaSystemPrompt } from "../constants/AgenticaSystemPrompt";
|
|
22
|
-
import { isAgenticaContext } from "../context/internal/isAgenticaContext";
|
|
23
|
-
import { AgenticaJsonParseError } from "../errors/AgenticaJsonParseError";
|
|
24
|
-
import { AgenticaValidationError } from "../errors/AgenticaValidationError";
|
|
25
|
-
import { createAssistantMessageEvent, createCallEvent, createExecuteEvent, createJsonParseErrorEvent, createValidateEvent } from "../factory/events";
|
|
26
|
-
import { decodeHistory, decodeUserMessageContent } from "../factory/histories";
|
|
27
|
-
import { __get_retry } from "../utils/__retry";
|
|
28
|
-
import { AssistantMessageEmptyError, AssistantMessageEmptyWithReasoningError } from "../utils/AssistantMessageEmptyError";
|
|
29
|
-
import { ChatGptCompletionMessageUtil } from "../utils/ChatGptCompletionMessageUtil";
|
|
30
|
-
import { reduceStreamingWithDispatch } from "../utils/ChatGptCompletionStreamingUtil";
|
|
31
|
-
import { StreamUtil, toAsyncGenerator } from "../utils/StreamUtil";
|
|
32
|
-
|
|
33
|
-
import { cancelFunctionFromContext } from "./internal/cancelFunctionFromContext";
|
|
34
|
-
|
|
35
|
-
export async function call(
|
|
36
|
-
ctx: AgenticaContext | MicroAgenticaContext,
|
|
37
|
-
operations: AgenticaOperation[],
|
|
38
|
-
): Promise<AgenticaExecuteEvent[]> {
|
|
39
|
-
const _retryFn = __get_retry(1);
|
|
40
|
-
const retryFn = async (fn: (prevError?: unknown) => Promise<OpenAI.ChatCompletion>) => {
|
|
41
|
-
return _retryFn(fn).catch((e) => {
|
|
42
|
-
if (e instanceof AssistantMessageEmptyError) {
|
|
43
|
-
return Symbol("emptyAssistantMessage");
|
|
44
|
-
}
|
|
45
|
-
throw e;
|
|
46
|
-
});
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const completion = await retryFn(async (prevError) => {
|
|
50
|
-
const result = await ctx.request("call", {
|
|
51
|
-
messages: [
|
|
52
|
-
// PREVIOUS HISTORIES
|
|
53
|
-
...ctx.histories.map(decodeHistory).flat(),
|
|
54
|
-
// USER INPUT
|
|
55
|
-
{
|
|
56
|
-
role: "user",
|
|
57
|
-
content: ctx.prompt.contents.map(decodeUserMessageContent),
|
|
58
|
-
},
|
|
59
|
-
...(prevError instanceof AssistantMessageEmptyWithReasoningError
|
|
60
|
-
? [
|
|
61
|
-
{
|
|
62
|
-
role: "assistant",
|
|
63
|
-
content: prevError.reasoning,
|
|
64
|
-
} satisfies OpenAI.ChatCompletionMessageParam,
|
|
65
|
-
]
|
|
66
|
-
: []),
|
|
67
|
-
// SYSTEM PROMPT
|
|
68
|
-
...(ctx.config?.systemPrompt?.execute === null
|
|
69
|
-
? []
|
|
70
|
-
: [{
|
|
71
|
-
role: "system",
|
|
72
|
-
content: ctx.config?.systemPrompt?.execute?.(ctx.histories as MicroAgenticaHistory[])
|
|
73
|
-
?? AgenticaSystemPrompt.EXECUTE,
|
|
74
|
-
} satisfies OpenAI.ChatCompletionSystemMessageParam]),
|
|
75
|
-
// COMMON SYSTEM PROMPT
|
|
76
|
-
{
|
|
77
|
-
role: "system",
|
|
78
|
-
content: AgenticaDefaultPrompt.write(ctx.config),
|
|
79
|
-
} satisfies OpenAI.ChatCompletionSystemMessageParam,
|
|
80
|
-
],
|
|
81
|
-
// STACKED FUNCTIONS
|
|
82
|
-
tools: operations.map(
|
|
83
|
-
s =>
|
|
84
|
-
({
|
|
85
|
-
type: "function",
|
|
86
|
-
function: {
|
|
87
|
-
name: s.name,
|
|
88
|
-
description: s.function.description,
|
|
89
|
-
parameters: s.function.parameters as Record<string, any>,
|
|
90
|
-
},
|
|
91
|
-
}) as OpenAI.ChatCompletionTool,
|
|
92
|
-
),
|
|
93
|
-
tool_choice: "auto",
|
|
94
|
-
// parallel_tool_calls: false,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
if (result.type === "none-stream") {
|
|
98
|
-
return result.value;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const completion = await reduceStreamingWithDispatch(result.value, (props) => {
|
|
102
|
-
const event: AgenticaAssistantMessageEvent = createAssistantMessageEvent(props);
|
|
103
|
-
void ctx.dispatch(event).catch(() => {});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
const allAssistantMessagesEmpty: boolean = (completion.choices ?? []).every(
|
|
107
|
-
v => v.message.tool_calls == null && v.message.content === "",
|
|
108
|
-
);
|
|
109
|
-
if (allAssistantMessagesEmpty) {
|
|
110
|
-
const firstChoice: OpenAI.ChatCompletion.Choice | undefined = completion.choices?.[0];
|
|
111
|
-
if ((firstChoice?.message as { reasoning?: string })?.reasoning != null) {
|
|
112
|
-
throw new AssistantMessageEmptyWithReasoningError((firstChoice?.message as { reasoning?: string })?.reasoning ?? "");
|
|
113
|
-
}
|
|
114
|
-
throw new AssistantMessageEmptyError();
|
|
115
|
-
}
|
|
116
|
-
return completion;
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
if (typeof completion === "symbol") {
|
|
120
|
-
const event: AgenticaAssistantMessageEvent = createAssistantMessageEvent({
|
|
121
|
-
stream: toAsyncGenerator(""),
|
|
122
|
-
done: () => true,
|
|
123
|
-
get: () => "",
|
|
124
|
-
join: async () => {
|
|
125
|
-
return "";
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
void ctx.dispatch(event).catch(() => {});
|
|
129
|
-
return [];
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const executes: AgenticaExecuteEvent[] = [];
|
|
133
|
-
|
|
134
|
-
const retry: number = ctx.config?.retry ?? AgenticaConstant.RETRY;
|
|
135
|
-
for (const choice of (completion.choices ?? [])) {
|
|
136
|
-
for (const tc of choice.message.tool_calls ?? []) {
|
|
137
|
-
if (tc.type === "function") {
|
|
138
|
-
const operation: AgenticaOperation | undefined = operations.find(
|
|
139
|
-
s => s.name === tc.function.name,
|
|
140
|
-
);
|
|
141
|
-
if (operation === undefined) {
|
|
142
|
-
continue; // Ignore unknown tool calls
|
|
143
|
-
}
|
|
144
|
-
const event: AgenticaExecuteEvent = await predicate(
|
|
145
|
-
ctx,
|
|
146
|
-
operation,
|
|
147
|
-
tc,
|
|
148
|
-
[],
|
|
149
|
-
retry,
|
|
150
|
-
);
|
|
151
|
-
await ctx.dispatch(event);
|
|
152
|
-
executes.push(event);
|
|
153
|
-
if (isAgenticaContext(ctx)) {
|
|
154
|
-
cancelFunctionFromContext(ctx as unknown as AgenticaContext, {
|
|
155
|
-
name: event.operation.name,
|
|
156
|
-
reason: "completed",
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return executes;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
async function predicate(
|
|
166
|
-
ctx: AgenticaContext | MicroAgenticaContext,
|
|
167
|
-
operation: AgenticaOperation,
|
|
168
|
-
toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
169
|
-
previousValidationErrors: AgenticaValidateEvent[],
|
|
170
|
-
life: number,
|
|
171
|
-
): Promise<AgenticaExecuteEvent> {
|
|
172
|
-
// CHECK INPUT ARGUMENT
|
|
173
|
-
const call: AgenticaCallEvent | AgenticaJsonParseErrorEvent
|
|
174
|
-
= parseArguments(
|
|
175
|
-
operation,
|
|
176
|
-
toolCall,
|
|
177
|
-
life,
|
|
178
|
-
);
|
|
179
|
-
await ctx.dispatch(call);
|
|
180
|
-
if (call.type === "jsonParseError") {
|
|
181
|
-
return correctJsonError(ctx, toolCall, call, previousValidationErrors, life - 1);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// CHECK TYPE VALIDATION
|
|
185
|
-
const check: IValidation<unknown> = operation.function.validate(call.arguments);
|
|
186
|
-
if (check.success === false) {
|
|
187
|
-
const event: AgenticaValidateEvent = createValidateEvent({
|
|
188
|
-
call_id: toolCall.id,
|
|
189
|
-
operation,
|
|
190
|
-
result: check,
|
|
191
|
-
life,
|
|
192
|
-
});
|
|
193
|
-
await ctx.dispatch(event);
|
|
194
|
-
return correctTypeError(
|
|
195
|
-
ctx,
|
|
196
|
-
call,
|
|
197
|
-
event,
|
|
198
|
-
[...previousValidationErrors, event],
|
|
199
|
-
life - 1,
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// EXECUTE OPERATION
|
|
204
|
-
return executeFunction(call, operation);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/* -----------------------------------------------------------
|
|
208
|
-
ERROR CORRECTORS
|
|
209
|
-
----------------------------------------------------------- */
|
|
210
|
-
async function correctTypeError(
|
|
211
|
-
ctx: AgenticaContext | MicroAgenticaContext,
|
|
212
|
-
callEvent: AgenticaCallEvent,
|
|
213
|
-
validateEvent: AgenticaValidateEvent,
|
|
214
|
-
previousValidationErrors: AgenticaValidateEvent[],
|
|
215
|
-
life: number,
|
|
216
|
-
): Promise<AgenticaExecuteEvent> {
|
|
217
|
-
return correctError(ctx, {
|
|
218
|
-
giveUp: () => createExecuteEvent({
|
|
219
|
-
call_id: callEvent.id,
|
|
220
|
-
operation: callEvent.operation,
|
|
221
|
-
arguments: callEvent.arguments,
|
|
222
|
-
value: new AgenticaValidationError({
|
|
223
|
-
arguments: callEvent.arguments,
|
|
224
|
-
errors: validateEvent.result.errors,
|
|
225
|
-
}),
|
|
226
|
-
success: false,
|
|
227
|
-
}),
|
|
228
|
-
operation: callEvent.operation,
|
|
229
|
-
toolCall: {
|
|
230
|
-
id: callEvent.id,
|
|
231
|
-
arguments: JSON.stringify(callEvent.arguments),
|
|
232
|
-
result: [
|
|
233
|
-
"🚨 VALIDATION FAILURE: Your function arguments do not conform to the required schema.",
|
|
234
|
-
"",
|
|
235
|
-
"The validation errors below represent computed absolute truth from rigorous type validation.",
|
|
236
|
-
"Each error is marked with ❌ comments showing the exact location, expected type, and actual value.",
|
|
237
|
-
"",
|
|
238
|
-
"You must fix ALL errors to achieve 100% schema compliance.",
|
|
239
|
-
"",
|
|
240
|
-
LlmJson.stringify(validateEvent.result),
|
|
241
|
-
].join("\n"),
|
|
242
|
-
},
|
|
243
|
-
systemPrompt: ctx.config?.systemPrompt?.validate?.(previousValidationErrors.slice(0, -1))
|
|
244
|
-
?? [
|
|
245
|
-
AgenticaSystemPrompt.VALIDATE,
|
|
246
|
-
...(previousValidationErrors.length > 1
|
|
247
|
-
? [
|
|
248
|
-
"",
|
|
249
|
-
AgenticaSystemPrompt.VALIDATE_REPEATED.replace(
|
|
250
|
-
"${{HISTORICAL_ERRORS}}",
|
|
251
|
-
previousValidationErrors
|
|
252
|
-
.slice(0, -1)
|
|
253
|
-
.map((ve, i) => [
|
|
254
|
-
`### ${i + 1}. Previous Validation Error`,
|
|
255
|
-
"",
|
|
256
|
-
LlmJson.stringify(ve.result),
|
|
257
|
-
].join("\n"))
|
|
258
|
-
.join("\n\n"),
|
|
259
|
-
// JSON.stringify(previousValidationErrors.slice(0, -1).map(e => e.result.errors)),
|
|
260
|
-
),
|
|
261
|
-
]
|
|
262
|
-
: []),
|
|
263
|
-
].join("\n"),
|
|
264
|
-
life,
|
|
265
|
-
previousValidationErrors,
|
|
266
|
-
});
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
async function correctJsonError(
|
|
270
|
-
ctx: AgenticaContext | MicroAgenticaContext,
|
|
271
|
-
toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
272
|
-
parseErrorEvent: AgenticaJsonParseErrorEvent,
|
|
273
|
-
previousValidationErrors: AgenticaValidateEvent[],
|
|
274
|
-
life: number,
|
|
275
|
-
): Promise<AgenticaExecuteEvent> {
|
|
276
|
-
return correctError(ctx, {
|
|
277
|
-
giveUp: () => createExecuteEvent({
|
|
278
|
-
call_id: toolCall.id,
|
|
279
|
-
operation: parseErrorEvent.operation,
|
|
280
|
-
arguments: {},
|
|
281
|
-
value: new AgenticaJsonParseError(parseErrorEvent.failure),
|
|
282
|
-
success: false,
|
|
283
|
-
}),
|
|
284
|
-
operation: parseErrorEvent.operation,
|
|
285
|
-
toolCall: {
|
|
286
|
-
id: parseErrorEvent.id,
|
|
287
|
-
arguments: parseErrorEvent.failure.input,
|
|
288
|
-
result: dedent`
|
|
289
|
-
Invalid JSON format.
|
|
290
|
-
|
|
291
|
-
Here is the detailed parsing failure information,
|
|
292
|
-
including error messages and their locations within the input:
|
|
293
|
-
|
|
294
|
-
\`\`\`json
|
|
295
|
-
${JSON.stringify(parseErrorEvent.failure.errors)}
|
|
296
|
-
\`\`\`
|
|
297
|
-
|
|
298
|
-
And here is the partially parsed data that was successfully
|
|
299
|
-
extracted before the error occurred:
|
|
300
|
-
|
|
301
|
-
\`\`\`json
|
|
302
|
-
${JSON.stringify(parseErrorEvent.failure.data)}
|
|
303
|
-
\`\`\`
|
|
304
|
-
`,
|
|
305
|
-
},
|
|
306
|
-
systemPrompt: ctx.config?.systemPrompt?.jsonParseError?.(parseErrorEvent)
|
|
307
|
-
?? AgenticaSystemPrompt.JSON_PARSE_ERROR.replace(
|
|
308
|
-
"${{FAILURE}}",
|
|
309
|
-
JSON.stringify(parseErrorEvent.failure),
|
|
310
|
-
),
|
|
311
|
-
life,
|
|
312
|
-
previousValidationErrors,
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function parseArguments(
|
|
317
|
-
operation: AgenticaOperation,
|
|
318
|
-
toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
319
|
-
life: number,
|
|
320
|
-
): AgenticaCallEvent | AgenticaJsonParseErrorEvent {
|
|
321
|
-
const result: IJsonParseResult<Record<string, unknown>> = operation.function.parse(
|
|
322
|
-
toolCall.function.arguments,
|
|
323
|
-
) satisfies IJsonParseResult<unknown> as IJsonParseResult<Record<string, unknown>>;
|
|
324
|
-
if (result.success === false) {
|
|
325
|
-
return createJsonParseErrorEvent({
|
|
326
|
-
call_id: toolCall.id,
|
|
327
|
-
operation,
|
|
328
|
-
failure: result,
|
|
329
|
-
life,
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
return createCallEvent({
|
|
333
|
-
id: toolCall.id,
|
|
334
|
-
operation,
|
|
335
|
-
arguments: result.data,
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
async function correctError(
|
|
340
|
-
ctx: AgenticaContext | MicroAgenticaContext,
|
|
341
|
-
props: {
|
|
342
|
-
giveUp: () => AgenticaExecuteEvent;
|
|
343
|
-
operation: AgenticaOperation;
|
|
344
|
-
toolCall: {
|
|
345
|
-
id: string;
|
|
346
|
-
arguments: string;
|
|
347
|
-
result: string;
|
|
348
|
-
};
|
|
349
|
-
systemPrompt: string;
|
|
350
|
-
life: number;
|
|
351
|
-
previousValidationErrors: AgenticaValidateEvent[];
|
|
352
|
-
},
|
|
353
|
-
): Promise<AgenticaExecuteEvent> {
|
|
354
|
-
if (props.life <= 0) {
|
|
355
|
-
return props.giveUp();
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const result = await ctx.request("call", {
|
|
359
|
-
messages: [
|
|
360
|
-
// PREVIOUS HISTORIES
|
|
361
|
-
...ctx.histories.map(decodeHistory).flat(),
|
|
362
|
-
// USER INPUT
|
|
363
|
-
{
|
|
364
|
-
role: "user",
|
|
365
|
-
content: ctx.prompt.contents.map(decodeUserMessageContent),
|
|
366
|
-
},
|
|
367
|
-
// TYPE CORRECTION
|
|
368
|
-
{
|
|
369
|
-
role: "system",
|
|
370
|
-
content:
|
|
371
|
-
ctx.config?.systemPrompt?.execute?.(ctx.histories as MicroAgenticaHistory[])
|
|
372
|
-
?? AgenticaSystemPrompt.EXECUTE,
|
|
373
|
-
},
|
|
374
|
-
{
|
|
375
|
-
role: "assistant",
|
|
376
|
-
tool_calls: [
|
|
377
|
-
{
|
|
378
|
-
type: "function",
|
|
379
|
-
id: props.toolCall.id,
|
|
380
|
-
function: {
|
|
381
|
-
name: props.operation.name,
|
|
382
|
-
arguments: props.toolCall.arguments,
|
|
383
|
-
},
|
|
384
|
-
} satisfies OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
385
|
-
],
|
|
386
|
-
} satisfies OpenAI.ChatCompletionAssistantMessageParam,
|
|
387
|
-
{
|
|
388
|
-
role: "tool",
|
|
389
|
-
content: props.toolCall.result,
|
|
390
|
-
tool_call_id: props.toolCall.id,
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
role: "system",
|
|
394
|
-
content: props.systemPrompt,
|
|
395
|
-
},
|
|
396
|
-
// COMMON SYSTEM PROMPT
|
|
397
|
-
{
|
|
398
|
-
role: "system",
|
|
399
|
-
content: AgenticaDefaultPrompt.write(ctx.config),
|
|
400
|
-
} satisfies OpenAI.ChatCompletionSystemMessageParam,
|
|
401
|
-
],
|
|
402
|
-
// STACK FUNCTIONS
|
|
403
|
-
tools: [
|
|
404
|
-
{
|
|
405
|
-
type: "function",
|
|
406
|
-
function: {
|
|
407
|
-
name: props.operation.name,
|
|
408
|
-
description: props.operation.function.description,
|
|
409
|
-
/**
|
|
410
|
-
* @TODO fix it
|
|
411
|
-
* The property and value have a type mismatch, but it works.
|
|
412
|
-
*/
|
|
413
|
-
parameters: props.operation.function.parameters as unknown as Record<string, unknown>,
|
|
414
|
-
},
|
|
415
|
-
},
|
|
416
|
-
],
|
|
417
|
-
tool_choice: "required",
|
|
418
|
-
// parallel_tool_calls: false,
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
const completion = await (async () => {
|
|
422
|
-
if (result.type === "none-stream") {
|
|
423
|
-
return result.value;
|
|
424
|
-
}
|
|
425
|
-
return ChatGptCompletionMessageUtil.merge(await StreamUtil.readAll(result.value));
|
|
426
|
-
})();
|
|
427
|
-
|
|
428
|
-
const toolCall: OpenAI.ChatCompletionMessageFunctionToolCall | undefined = completion.choices?.[0]?.message.tool_calls?.filter(
|
|
429
|
-
tc => tc.type === "function",
|
|
430
|
-
).find(
|
|
431
|
-
s => s.function.name === props.operation.name,
|
|
432
|
-
);
|
|
433
|
-
if (toolCall === undefined) {
|
|
434
|
-
// LLM did not return a valid tool call - retry if life remains
|
|
435
|
-
return correctError(ctx, {
|
|
436
|
-
...props,
|
|
437
|
-
life: props.life - 1,
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
return predicate(
|
|
441
|
-
ctx,
|
|
442
|
-
props.operation,
|
|
443
|
-
toolCall,
|
|
444
|
-
props.previousValidationErrors,
|
|
445
|
-
props.life,
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/* -----------------------------------------------------------
|
|
450
|
-
FUNCTION EXECUTORS
|
|
451
|
-
----------------------------------------------------------- */
|
|
452
|
-
async function executeFunction(
|
|
453
|
-
call: AgenticaCallEvent,
|
|
454
|
-
operation: AgenticaOperation,
|
|
455
|
-
): Promise<AgenticaExecuteEvent> {
|
|
456
|
-
try {
|
|
457
|
-
const value: unknown = await (async () => {
|
|
458
|
-
switch (operation.protocol) {
|
|
459
|
-
case "class":
|
|
460
|
-
return executeClassFunction(call, operation);
|
|
461
|
-
case "http":
|
|
462
|
-
return executeHttpOperation(call, operation);
|
|
463
|
-
case "mcp":
|
|
464
|
-
return executeMcpOperation(call, operation);
|
|
465
|
-
default:
|
|
466
|
-
operation satisfies never; // Ensure all cases are handled
|
|
467
|
-
throw new Error("Unknown protocol"); // never be happen
|
|
468
|
-
}
|
|
469
|
-
})();
|
|
470
|
-
return createExecuteEvent({
|
|
471
|
-
call_id: call.id,
|
|
472
|
-
operation: call.operation,
|
|
473
|
-
arguments: call.arguments,
|
|
474
|
-
value,
|
|
475
|
-
success: true,
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
catch (error) {
|
|
479
|
-
return createExecuteEvent({
|
|
480
|
-
call_id: call.id,
|
|
481
|
-
operation: call.operation,
|
|
482
|
-
arguments: call.arguments,
|
|
483
|
-
value: error instanceof Error
|
|
484
|
-
? {
|
|
485
|
-
...error,
|
|
486
|
-
name: error.name,
|
|
487
|
-
message: error.message,
|
|
488
|
-
stack: error.stack,
|
|
489
|
-
}
|
|
490
|
-
: error,
|
|
491
|
-
success: false,
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
async function executeClassFunction(
|
|
497
|
-
call: AgenticaCallEvent,
|
|
498
|
-
operation: AgenticaOperation.Class,
|
|
499
|
-
): Promise<unknown> {
|
|
500
|
-
const execute = operation.controller.execute;
|
|
501
|
-
const value: unknown = typeof execute === "function"
|
|
502
|
-
? await execute({
|
|
503
|
-
application: operation.controller.application,
|
|
504
|
-
function: operation.function,
|
|
505
|
-
arguments: call.arguments,
|
|
506
|
-
})
|
|
507
|
-
: await (execute as Record<string, any>)[operation.function.name](
|
|
508
|
-
call.arguments,
|
|
509
|
-
);
|
|
510
|
-
return value;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
async function executeHttpOperation(
|
|
514
|
-
call: AgenticaCallEvent,
|
|
515
|
-
operation: AgenticaOperation.Http,
|
|
516
|
-
): Promise<unknown> {
|
|
517
|
-
const execute = operation.controller.execute;
|
|
518
|
-
const value: IHttpResponse = typeof execute === "function"
|
|
519
|
-
? await execute({
|
|
520
|
-
connection: operation.controller.connection,
|
|
521
|
-
application: operation.controller.application,
|
|
522
|
-
function: operation.function,
|
|
523
|
-
arguments: call.arguments,
|
|
524
|
-
})
|
|
525
|
-
: await HttpLlm.propagate({
|
|
526
|
-
connection: operation.controller.connection,
|
|
527
|
-
application: operation.controller.application,
|
|
528
|
-
function: operation.function,
|
|
529
|
-
input: call.arguments,
|
|
530
|
-
});
|
|
531
|
-
return value;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
async function executeMcpOperation(
|
|
535
|
-
call: AgenticaCallEvent,
|
|
536
|
-
operation: AgenticaOperation.Mcp,
|
|
537
|
-
): Promise<unknown> {
|
|
538
|
-
return operation.controller.client.callTool({
|
|
539
|
-
name: operation.function.name,
|
|
540
|
-
arguments: call.arguments,
|
|
541
|
-
}).then(v => v.content);
|
|
542
|
-
}
|
|
1
|
+
import type {
|
|
2
|
+
IHttpResponse,
|
|
3
|
+
IJsonParseResult,
|
|
4
|
+
IValidation,
|
|
5
|
+
} from "@typia/interface";
|
|
6
|
+
import type OpenAI from "openai";
|
|
7
|
+
|
|
8
|
+
import { dedent, HttpLlm, LlmJson } from "@typia/utils";
|
|
9
|
+
|
|
10
|
+
import type { AgenticaContext } from "../context/AgenticaContext";
|
|
11
|
+
import type { AgenticaOperation } from "../context/AgenticaOperation";
|
|
12
|
+
import type { MicroAgenticaContext } from "../context/MicroAgenticaContext";
|
|
13
|
+
import type { AgenticaAssistantMessageEvent, AgenticaValidateEvent } from "../events";
|
|
14
|
+
import type { AgenticaCallEvent } from "../events/AgenticaCallEvent";
|
|
15
|
+
import type { AgenticaExecuteEvent } from "../events/AgenticaExecuteEvent";
|
|
16
|
+
import type { AgenticaJsonParseErrorEvent } from "../events/AgenticaJsonParseErrorEvent";
|
|
17
|
+
import type { MicroAgenticaHistory } from "../histories/MicroAgenticaHistory";
|
|
18
|
+
|
|
19
|
+
import { AgenticaConstant } from "../constants/AgenticaConstant";
|
|
20
|
+
import { AgenticaDefaultPrompt } from "../constants/AgenticaDefaultPrompt";
|
|
21
|
+
import { AgenticaSystemPrompt } from "../constants/AgenticaSystemPrompt";
|
|
22
|
+
import { isAgenticaContext } from "../context/internal/isAgenticaContext";
|
|
23
|
+
import { AgenticaJsonParseError } from "../errors/AgenticaJsonParseError";
|
|
24
|
+
import { AgenticaValidationError } from "../errors/AgenticaValidationError";
|
|
25
|
+
import { createAssistantMessageEvent, createCallEvent, createExecuteEvent, createJsonParseErrorEvent, createValidateEvent } from "../factory/events";
|
|
26
|
+
import { decodeHistory, decodeUserMessageContent } from "../factory/histories";
|
|
27
|
+
import { __get_retry } from "../utils/__retry";
|
|
28
|
+
import { AssistantMessageEmptyError, AssistantMessageEmptyWithReasoningError } from "../utils/AssistantMessageEmptyError";
|
|
29
|
+
import { ChatGptCompletionMessageUtil } from "../utils/ChatGptCompletionMessageUtil";
|
|
30
|
+
import { reduceStreamingWithDispatch } from "../utils/ChatGptCompletionStreamingUtil";
|
|
31
|
+
import { StreamUtil, toAsyncGenerator } from "../utils/StreamUtil";
|
|
32
|
+
|
|
33
|
+
import { cancelFunctionFromContext } from "./internal/cancelFunctionFromContext";
|
|
34
|
+
|
|
35
|
+
export async function call(
|
|
36
|
+
ctx: AgenticaContext | MicroAgenticaContext,
|
|
37
|
+
operations: AgenticaOperation[],
|
|
38
|
+
): Promise<AgenticaExecuteEvent[]> {
|
|
39
|
+
const _retryFn = __get_retry(1);
|
|
40
|
+
const retryFn = async (fn: (prevError?: unknown) => Promise<OpenAI.ChatCompletion>) => {
|
|
41
|
+
return _retryFn(fn).catch((e) => {
|
|
42
|
+
if (e instanceof AssistantMessageEmptyError) {
|
|
43
|
+
return Symbol("emptyAssistantMessage");
|
|
44
|
+
}
|
|
45
|
+
throw e;
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const completion = await retryFn(async (prevError) => {
|
|
50
|
+
const result = await ctx.request("call", {
|
|
51
|
+
messages: [
|
|
52
|
+
// PREVIOUS HISTORIES
|
|
53
|
+
...ctx.histories.map(decodeHistory).flat(),
|
|
54
|
+
// USER INPUT
|
|
55
|
+
{
|
|
56
|
+
role: "user",
|
|
57
|
+
content: ctx.prompt.contents.map(decodeUserMessageContent),
|
|
58
|
+
},
|
|
59
|
+
...(prevError instanceof AssistantMessageEmptyWithReasoningError
|
|
60
|
+
? [
|
|
61
|
+
{
|
|
62
|
+
role: "assistant",
|
|
63
|
+
content: prevError.reasoning,
|
|
64
|
+
} satisfies OpenAI.ChatCompletionMessageParam,
|
|
65
|
+
]
|
|
66
|
+
: []),
|
|
67
|
+
// SYSTEM PROMPT
|
|
68
|
+
...(ctx.config?.systemPrompt?.execute === null
|
|
69
|
+
? []
|
|
70
|
+
: [{
|
|
71
|
+
role: "system",
|
|
72
|
+
content: ctx.config?.systemPrompt?.execute?.(ctx.histories as MicroAgenticaHistory[])
|
|
73
|
+
?? AgenticaSystemPrompt.EXECUTE,
|
|
74
|
+
} satisfies OpenAI.ChatCompletionSystemMessageParam]),
|
|
75
|
+
// COMMON SYSTEM PROMPT
|
|
76
|
+
{
|
|
77
|
+
role: "system",
|
|
78
|
+
content: AgenticaDefaultPrompt.write(ctx.config),
|
|
79
|
+
} satisfies OpenAI.ChatCompletionSystemMessageParam,
|
|
80
|
+
],
|
|
81
|
+
// STACKED FUNCTIONS
|
|
82
|
+
tools: operations.map(
|
|
83
|
+
s =>
|
|
84
|
+
({
|
|
85
|
+
type: "function",
|
|
86
|
+
function: {
|
|
87
|
+
name: s.name,
|
|
88
|
+
description: s.function.description,
|
|
89
|
+
parameters: s.function.parameters as Record<string, any>,
|
|
90
|
+
},
|
|
91
|
+
}) as OpenAI.ChatCompletionTool,
|
|
92
|
+
),
|
|
93
|
+
tool_choice: "auto",
|
|
94
|
+
// parallel_tool_calls: false,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (result.type === "none-stream") {
|
|
98
|
+
return result.value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const completion = await reduceStreamingWithDispatch(result.value, (props) => {
|
|
102
|
+
const event: AgenticaAssistantMessageEvent = createAssistantMessageEvent(props);
|
|
103
|
+
void ctx.dispatch(event).catch(() => {});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const allAssistantMessagesEmpty: boolean = (completion.choices ?? []).every(
|
|
107
|
+
v => v.message.tool_calls == null && v.message.content === "",
|
|
108
|
+
);
|
|
109
|
+
if (allAssistantMessagesEmpty) {
|
|
110
|
+
const firstChoice: OpenAI.ChatCompletion.Choice | undefined = completion.choices?.[0];
|
|
111
|
+
if ((firstChoice?.message as { reasoning?: string })?.reasoning != null) {
|
|
112
|
+
throw new AssistantMessageEmptyWithReasoningError((firstChoice?.message as { reasoning?: string })?.reasoning ?? "");
|
|
113
|
+
}
|
|
114
|
+
throw new AssistantMessageEmptyError();
|
|
115
|
+
}
|
|
116
|
+
return completion;
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
if (typeof completion === "symbol") {
|
|
120
|
+
const event: AgenticaAssistantMessageEvent = createAssistantMessageEvent({
|
|
121
|
+
stream: toAsyncGenerator(""),
|
|
122
|
+
done: () => true,
|
|
123
|
+
get: () => "",
|
|
124
|
+
join: async () => {
|
|
125
|
+
return "";
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
void ctx.dispatch(event).catch(() => {});
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const executes: AgenticaExecuteEvent[] = [];
|
|
133
|
+
|
|
134
|
+
const retry: number = ctx.config?.retry ?? AgenticaConstant.RETRY;
|
|
135
|
+
for (const choice of (completion.choices ?? [])) {
|
|
136
|
+
for (const tc of choice.message.tool_calls ?? []) {
|
|
137
|
+
if (tc.type === "function") {
|
|
138
|
+
const operation: AgenticaOperation | undefined = operations.find(
|
|
139
|
+
s => s.name === tc.function.name,
|
|
140
|
+
);
|
|
141
|
+
if (operation === undefined) {
|
|
142
|
+
continue; // Ignore unknown tool calls
|
|
143
|
+
}
|
|
144
|
+
const event: AgenticaExecuteEvent = await predicate(
|
|
145
|
+
ctx,
|
|
146
|
+
operation,
|
|
147
|
+
tc,
|
|
148
|
+
[],
|
|
149
|
+
retry,
|
|
150
|
+
);
|
|
151
|
+
await ctx.dispatch(event);
|
|
152
|
+
executes.push(event);
|
|
153
|
+
if (isAgenticaContext(ctx)) {
|
|
154
|
+
cancelFunctionFromContext(ctx as unknown as AgenticaContext, {
|
|
155
|
+
name: event.operation.name,
|
|
156
|
+
reason: "completed",
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return executes;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function predicate(
|
|
166
|
+
ctx: AgenticaContext | MicroAgenticaContext,
|
|
167
|
+
operation: AgenticaOperation,
|
|
168
|
+
toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
169
|
+
previousValidationErrors: AgenticaValidateEvent[],
|
|
170
|
+
life: number,
|
|
171
|
+
): Promise<AgenticaExecuteEvent> {
|
|
172
|
+
// CHECK INPUT ARGUMENT
|
|
173
|
+
const call: AgenticaCallEvent | AgenticaJsonParseErrorEvent
|
|
174
|
+
= parseArguments(
|
|
175
|
+
operation,
|
|
176
|
+
toolCall,
|
|
177
|
+
life,
|
|
178
|
+
);
|
|
179
|
+
await ctx.dispatch(call);
|
|
180
|
+
if (call.type === "jsonParseError") {
|
|
181
|
+
return correctJsonError(ctx, toolCall, call, previousValidationErrors, life - 1);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// CHECK TYPE VALIDATION
|
|
185
|
+
const check: IValidation<unknown> = operation.function.validate(call.arguments);
|
|
186
|
+
if (check.success === false) {
|
|
187
|
+
const event: AgenticaValidateEvent = createValidateEvent({
|
|
188
|
+
call_id: toolCall.id,
|
|
189
|
+
operation,
|
|
190
|
+
result: check,
|
|
191
|
+
life,
|
|
192
|
+
});
|
|
193
|
+
await ctx.dispatch(event);
|
|
194
|
+
return correctTypeError(
|
|
195
|
+
ctx,
|
|
196
|
+
call,
|
|
197
|
+
event,
|
|
198
|
+
[...previousValidationErrors, event],
|
|
199
|
+
life - 1,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// EXECUTE OPERATION
|
|
204
|
+
return executeFunction(call, operation);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* -----------------------------------------------------------
|
|
208
|
+
ERROR CORRECTORS
|
|
209
|
+
----------------------------------------------------------- */
|
|
210
|
+
async function correctTypeError(
|
|
211
|
+
ctx: AgenticaContext | MicroAgenticaContext,
|
|
212
|
+
callEvent: AgenticaCallEvent,
|
|
213
|
+
validateEvent: AgenticaValidateEvent,
|
|
214
|
+
previousValidationErrors: AgenticaValidateEvent[],
|
|
215
|
+
life: number,
|
|
216
|
+
): Promise<AgenticaExecuteEvent> {
|
|
217
|
+
return correctError(ctx, {
|
|
218
|
+
giveUp: () => createExecuteEvent({
|
|
219
|
+
call_id: callEvent.id,
|
|
220
|
+
operation: callEvent.operation,
|
|
221
|
+
arguments: callEvent.arguments,
|
|
222
|
+
value: new AgenticaValidationError({
|
|
223
|
+
arguments: callEvent.arguments,
|
|
224
|
+
errors: validateEvent.result.errors,
|
|
225
|
+
}),
|
|
226
|
+
success: false,
|
|
227
|
+
}),
|
|
228
|
+
operation: callEvent.operation,
|
|
229
|
+
toolCall: {
|
|
230
|
+
id: callEvent.id,
|
|
231
|
+
arguments: JSON.stringify(callEvent.arguments),
|
|
232
|
+
result: [
|
|
233
|
+
"🚨 VALIDATION FAILURE: Your function arguments do not conform to the required schema.",
|
|
234
|
+
"",
|
|
235
|
+
"The validation errors below represent computed absolute truth from rigorous type validation.",
|
|
236
|
+
"Each error is marked with ❌ comments showing the exact location, expected type, and actual value.",
|
|
237
|
+
"",
|
|
238
|
+
"You must fix ALL errors to achieve 100% schema compliance.",
|
|
239
|
+
"",
|
|
240
|
+
LlmJson.stringify(validateEvent.result),
|
|
241
|
+
].join("\n"),
|
|
242
|
+
},
|
|
243
|
+
systemPrompt: ctx.config?.systemPrompt?.validate?.(previousValidationErrors.slice(0, -1))
|
|
244
|
+
?? [
|
|
245
|
+
AgenticaSystemPrompt.VALIDATE,
|
|
246
|
+
...(previousValidationErrors.length > 1
|
|
247
|
+
? [
|
|
248
|
+
"",
|
|
249
|
+
AgenticaSystemPrompt.VALIDATE_REPEATED.replace(
|
|
250
|
+
"${{HISTORICAL_ERRORS}}",
|
|
251
|
+
previousValidationErrors
|
|
252
|
+
.slice(0, -1)
|
|
253
|
+
.map((ve, i) => [
|
|
254
|
+
`### ${i + 1}. Previous Validation Error`,
|
|
255
|
+
"",
|
|
256
|
+
LlmJson.stringify(ve.result),
|
|
257
|
+
].join("\n"))
|
|
258
|
+
.join("\n\n"),
|
|
259
|
+
// JSON.stringify(previousValidationErrors.slice(0, -1).map(e => e.result.errors)),
|
|
260
|
+
),
|
|
261
|
+
]
|
|
262
|
+
: []),
|
|
263
|
+
].join("\n"),
|
|
264
|
+
life,
|
|
265
|
+
previousValidationErrors,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function correctJsonError(
|
|
270
|
+
ctx: AgenticaContext | MicroAgenticaContext,
|
|
271
|
+
toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
272
|
+
parseErrorEvent: AgenticaJsonParseErrorEvent,
|
|
273
|
+
previousValidationErrors: AgenticaValidateEvent[],
|
|
274
|
+
life: number,
|
|
275
|
+
): Promise<AgenticaExecuteEvent> {
|
|
276
|
+
return correctError(ctx, {
|
|
277
|
+
giveUp: () => createExecuteEvent({
|
|
278
|
+
call_id: toolCall.id,
|
|
279
|
+
operation: parseErrorEvent.operation,
|
|
280
|
+
arguments: {},
|
|
281
|
+
value: new AgenticaJsonParseError(parseErrorEvent.failure),
|
|
282
|
+
success: false,
|
|
283
|
+
}),
|
|
284
|
+
operation: parseErrorEvent.operation,
|
|
285
|
+
toolCall: {
|
|
286
|
+
id: parseErrorEvent.id,
|
|
287
|
+
arguments: parseErrorEvent.failure.input,
|
|
288
|
+
result: dedent`
|
|
289
|
+
Invalid JSON format.
|
|
290
|
+
|
|
291
|
+
Here is the detailed parsing failure information,
|
|
292
|
+
including error messages and their locations within the input:
|
|
293
|
+
|
|
294
|
+
\`\`\`json
|
|
295
|
+
${JSON.stringify(parseErrorEvent.failure.errors)}
|
|
296
|
+
\`\`\`
|
|
297
|
+
|
|
298
|
+
And here is the partially parsed data that was successfully
|
|
299
|
+
extracted before the error occurred:
|
|
300
|
+
|
|
301
|
+
\`\`\`json
|
|
302
|
+
${JSON.stringify(parseErrorEvent.failure.data)}
|
|
303
|
+
\`\`\`
|
|
304
|
+
`,
|
|
305
|
+
},
|
|
306
|
+
systemPrompt: ctx.config?.systemPrompt?.jsonParseError?.(parseErrorEvent)
|
|
307
|
+
?? AgenticaSystemPrompt.JSON_PARSE_ERROR.replace(
|
|
308
|
+
"${{FAILURE}}",
|
|
309
|
+
JSON.stringify(parseErrorEvent.failure),
|
|
310
|
+
),
|
|
311
|
+
life,
|
|
312
|
+
previousValidationErrors,
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function parseArguments(
|
|
317
|
+
operation: AgenticaOperation,
|
|
318
|
+
toolCall: OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
319
|
+
life: number,
|
|
320
|
+
): AgenticaCallEvent | AgenticaJsonParseErrorEvent {
|
|
321
|
+
const result: IJsonParseResult<Record<string, unknown>> = operation.function.parse(
|
|
322
|
+
toolCall.function.arguments,
|
|
323
|
+
) satisfies IJsonParseResult<unknown> as IJsonParseResult<Record<string, unknown>>;
|
|
324
|
+
if (result.success === false) {
|
|
325
|
+
return createJsonParseErrorEvent({
|
|
326
|
+
call_id: toolCall.id,
|
|
327
|
+
operation,
|
|
328
|
+
failure: result,
|
|
329
|
+
life,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
return createCallEvent({
|
|
333
|
+
id: toolCall.id,
|
|
334
|
+
operation,
|
|
335
|
+
arguments: result.data,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
async function correctError(
|
|
340
|
+
ctx: AgenticaContext | MicroAgenticaContext,
|
|
341
|
+
props: {
|
|
342
|
+
giveUp: () => AgenticaExecuteEvent;
|
|
343
|
+
operation: AgenticaOperation;
|
|
344
|
+
toolCall: {
|
|
345
|
+
id: string;
|
|
346
|
+
arguments: string;
|
|
347
|
+
result: string;
|
|
348
|
+
};
|
|
349
|
+
systemPrompt: string;
|
|
350
|
+
life: number;
|
|
351
|
+
previousValidationErrors: AgenticaValidateEvent[];
|
|
352
|
+
},
|
|
353
|
+
): Promise<AgenticaExecuteEvent> {
|
|
354
|
+
if (props.life <= 0) {
|
|
355
|
+
return props.giveUp();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const result = await ctx.request("call", {
|
|
359
|
+
messages: [
|
|
360
|
+
// PREVIOUS HISTORIES
|
|
361
|
+
...ctx.histories.map(decodeHistory).flat(),
|
|
362
|
+
// USER INPUT
|
|
363
|
+
{
|
|
364
|
+
role: "user",
|
|
365
|
+
content: ctx.prompt.contents.map(decodeUserMessageContent),
|
|
366
|
+
},
|
|
367
|
+
// TYPE CORRECTION
|
|
368
|
+
{
|
|
369
|
+
role: "system",
|
|
370
|
+
content:
|
|
371
|
+
ctx.config?.systemPrompt?.execute?.(ctx.histories as MicroAgenticaHistory[])
|
|
372
|
+
?? AgenticaSystemPrompt.EXECUTE,
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
role: "assistant",
|
|
376
|
+
tool_calls: [
|
|
377
|
+
{
|
|
378
|
+
type: "function",
|
|
379
|
+
id: props.toolCall.id,
|
|
380
|
+
function: {
|
|
381
|
+
name: props.operation.name,
|
|
382
|
+
arguments: props.toolCall.arguments,
|
|
383
|
+
},
|
|
384
|
+
} satisfies OpenAI.ChatCompletionMessageFunctionToolCall,
|
|
385
|
+
],
|
|
386
|
+
} satisfies OpenAI.ChatCompletionAssistantMessageParam,
|
|
387
|
+
{
|
|
388
|
+
role: "tool",
|
|
389
|
+
content: props.toolCall.result,
|
|
390
|
+
tool_call_id: props.toolCall.id,
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
role: "system",
|
|
394
|
+
content: props.systemPrompt,
|
|
395
|
+
},
|
|
396
|
+
// COMMON SYSTEM PROMPT
|
|
397
|
+
{
|
|
398
|
+
role: "system",
|
|
399
|
+
content: AgenticaDefaultPrompt.write(ctx.config),
|
|
400
|
+
} satisfies OpenAI.ChatCompletionSystemMessageParam,
|
|
401
|
+
],
|
|
402
|
+
// STACK FUNCTIONS
|
|
403
|
+
tools: [
|
|
404
|
+
{
|
|
405
|
+
type: "function",
|
|
406
|
+
function: {
|
|
407
|
+
name: props.operation.name,
|
|
408
|
+
description: props.operation.function.description,
|
|
409
|
+
/**
|
|
410
|
+
* @TODO fix it
|
|
411
|
+
* The property and value have a type mismatch, but it works.
|
|
412
|
+
*/
|
|
413
|
+
parameters: props.operation.function.parameters as unknown as Record<string, unknown>,
|
|
414
|
+
},
|
|
415
|
+
},
|
|
416
|
+
],
|
|
417
|
+
tool_choice: "required",
|
|
418
|
+
// parallel_tool_calls: false,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const completion = await (async () => {
|
|
422
|
+
if (result.type === "none-stream") {
|
|
423
|
+
return result.value;
|
|
424
|
+
}
|
|
425
|
+
return ChatGptCompletionMessageUtil.merge(await StreamUtil.readAll(result.value));
|
|
426
|
+
})();
|
|
427
|
+
|
|
428
|
+
const toolCall: OpenAI.ChatCompletionMessageFunctionToolCall | undefined = completion.choices?.[0]?.message.tool_calls?.filter(
|
|
429
|
+
tc => tc.type === "function",
|
|
430
|
+
).find(
|
|
431
|
+
s => s.function.name === props.operation.name,
|
|
432
|
+
);
|
|
433
|
+
if (toolCall === undefined) {
|
|
434
|
+
// LLM did not return a valid tool call - retry if life remains
|
|
435
|
+
return correctError(ctx, {
|
|
436
|
+
...props,
|
|
437
|
+
life: props.life - 1,
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return predicate(
|
|
441
|
+
ctx,
|
|
442
|
+
props.operation,
|
|
443
|
+
toolCall,
|
|
444
|
+
props.previousValidationErrors,
|
|
445
|
+
props.life,
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/* -----------------------------------------------------------
|
|
450
|
+
FUNCTION EXECUTORS
|
|
451
|
+
----------------------------------------------------------- */
|
|
452
|
+
async function executeFunction(
|
|
453
|
+
call: AgenticaCallEvent,
|
|
454
|
+
operation: AgenticaOperation,
|
|
455
|
+
): Promise<AgenticaExecuteEvent> {
|
|
456
|
+
try {
|
|
457
|
+
const value: unknown = await (async () => {
|
|
458
|
+
switch (operation.protocol) {
|
|
459
|
+
case "class":
|
|
460
|
+
return executeClassFunction(call, operation);
|
|
461
|
+
case "http":
|
|
462
|
+
return executeHttpOperation(call, operation);
|
|
463
|
+
case "mcp":
|
|
464
|
+
return executeMcpOperation(call, operation);
|
|
465
|
+
default:
|
|
466
|
+
operation satisfies never; // Ensure all cases are handled
|
|
467
|
+
throw new Error("Unknown protocol"); // never be happen
|
|
468
|
+
}
|
|
469
|
+
})();
|
|
470
|
+
return createExecuteEvent({
|
|
471
|
+
call_id: call.id,
|
|
472
|
+
operation: call.operation,
|
|
473
|
+
arguments: call.arguments,
|
|
474
|
+
value,
|
|
475
|
+
success: true,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
return createExecuteEvent({
|
|
480
|
+
call_id: call.id,
|
|
481
|
+
operation: call.operation,
|
|
482
|
+
arguments: call.arguments,
|
|
483
|
+
value: error instanceof Error
|
|
484
|
+
? {
|
|
485
|
+
...error,
|
|
486
|
+
name: error.name,
|
|
487
|
+
message: error.message,
|
|
488
|
+
stack: error.stack,
|
|
489
|
+
}
|
|
490
|
+
: error,
|
|
491
|
+
success: false,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async function executeClassFunction(
|
|
497
|
+
call: AgenticaCallEvent,
|
|
498
|
+
operation: AgenticaOperation.Class,
|
|
499
|
+
): Promise<unknown> {
|
|
500
|
+
const execute = operation.controller.execute;
|
|
501
|
+
const value: unknown = typeof execute === "function"
|
|
502
|
+
? await execute({
|
|
503
|
+
application: operation.controller.application,
|
|
504
|
+
function: operation.function,
|
|
505
|
+
arguments: call.arguments,
|
|
506
|
+
})
|
|
507
|
+
: await (execute as Record<string, any>)[operation.function.name](
|
|
508
|
+
call.arguments,
|
|
509
|
+
);
|
|
510
|
+
return value;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
async function executeHttpOperation(
|
|
514
|
+
call: AgenticaCallEvent,
|
|
515
|
+
operation: AgenticaOperation.Http,
|
|
516
|
+
): Promise<unknown> {
|
|
517
|
+
const execute = operation.controller.execute;
|
|
518
|
+
const value: IHttpResponse = typeof execute === "function"
|
|
519
|
+
? await execute({
|
|
520
|
+
connection: operation.controller.connection,
|
|
521
|
+
application: operation.controller.application,
|
|
522
|
+
function: operation.function,
|
|
523
|
+
arguments: call.arguments,
|
|
524
|
+
})
|
|
525
|
+
: await HttpLlm.propagate({
|
|
526
|
+
connection: operation.controller.connection,
|
|
527
|
+
application: operation.controller.application,
|
|
528
|
+
function: operation.function,
|
|
529
|
+
input: call.arguments,
|
|
530
|
+
});
|
|
531
|
+
return value;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
async function executeMcpOperation(
|
|
535
|
+
call: AgenticaCallEvent,
|
|
536
|
+
operation: AgenticaOperation.Mcp,
|
|
537
|
+
): Promise<unknown> {
|
|
538
|
+
return operation.controller.client.callTool({
|
|
539
|
+
name: operation.function.name,
|
|
540
|
+
arguments: call.arguments,
|
|
541
|
+
}).then(v => v.content);
|
|
542
|
+
}
|