@falai/agent 1.1.3 → 1.2.1
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/README.md +9 -0
- package/dist/cjs/core/Agent.d.ts +17 -1
- package/dist/cjs/core/Agent.d.ts.map +1 -1
- package/dist/cjs/core/Agent.js +47 -0
- package/dist/cjs/core/Agent.js.map +1 -1
- package/dist/cjs/core/BatchPromptBuilder.d.ts +3 -0
- package/dist/cjs/core/BatchPromptBuilder.d.ts.map +1 -1
- package/dist/cjs/core/BatchPromptBuilder.js +4 -1
- package/dist/cjs/core/BatchPromptBuilder.js.map +1 -1
- package/dist/cjs/core/CompactionEngine.d.ts +65 -0
- package/dist/cjs/core/CompactionEngine.d.ts.map +1 -0
- package/dist/cjs/core/CompactionEngine.js +251 -0
- package/dist/cjs/core/CompactionEngine.js.map +1 -0
- package/dist/cjs/core/PromptComposer.d.ts +8 -1
- package/dist/cjs/core/PromptComposer.d.ts.map +1 -1
- package/dist/cjs/core/PromptComposer.js +238 -126
- package/dist/cjs/core/PromptComposer.js.map +1 -1
- package/dist/cjs/core/PromptSectionCache.d.ts +57 -0
- package/dist/cjs/core/PromptSectionCache.d.ts.map +1 -0
- package/dist/cjs/core/PromptSectionCache.js +108 -0
- package/dist/cjs/core/PromptSectionCache.js.map +1 -0
- package/dist/cjs/core/ResponseEngine.d.ts +3 -2
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +8 -8
- package/dist/cjs/core/ResponseEngine.js.map +1 -1
- package/dist/cjs/core/ResponseModal.d.ts.map +1 -1
- package/dist/cjs/core/ResponseModal.js +120 -70
- package/dist/cjs/core/ResponseModal.js.map +1 -1
- package/dist/cjs/core/ResponsePipeline.d.ts +2 -1
- package/dist/cjs/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/cjs/core/ResponsePipeline.js +17 -19
- package/dist/cjs/core/ResponsePipeline.js.map +1 -1
- package/dist/cjs/core/RoutingEngine.d.ts +10 -0
- package/dist/cjs/core/RoutingEngine.d.ts.map +1 -1
- package/dist/cjs/core/RoutingEngine.js +5 -4
- package/dist/cjs/core/RoutingEngine.js.map +1 -1
- package/dist/cjs/core/SessionManager.d.ts.map +1 -1
- package/dist/cjs/core/SessionManager.js +20 -0
- package/dist/cjs/core/SessionManager.js.map +1 -1
- package/dist/cjs/core/StreamingToolExecutor.d.ts +142 -0
- package/dist/cjs/core/StreamingToolExecutor.d.ts.map +1 -0
- package/dist/cjs/core/StreamingToolExecutor.js +455 -0
- package/dist/cjs/core/StreamingToolExecutor.js.map +1 -0
- package/dist/cjs/core/ToolManager.d.ts +18 -1
- package/dist/cjs/core/ToolManager.d.ts.map +1 -1
- package/dist/cjs/core/ToolManager.js +91 -0
- package/dist/cjs/core/ToolManager.js.map +1 -1
- package/dist/cjs/index.d.ts +5 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +8 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.d.ts +7 -0
- package/dist/cjs/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +109 -19
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts +32 -0
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +160 -53
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts +5 -0
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +65 -18
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts +5 -0
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +57 -18
- package/dist/cjs/providers/OpenRouterProvider.js.map +1 -1
- package/dist/cjs/types/agent.d.ts +44 -0
- package/dist/cjs/types/agent.d.ts.map +1 -1
- package/dist/cjs/types/agent.js.map +1 -1
- package/dist/cjs/types/ai.d.ts +2 -2
- package/dist/cjs/types/ai.d.ts.map +1 -1
- package/dist/cjs/types/compaction.d.ts +50 -0
- package/dist/cjs/types/compaction.d.ts.map +1 -0
- package/dist/cjs/types/compaction.js +6 -0
- package/dist/cjs/types/compaction.js.map +1 -0
- package/dist/cjs/types/index.d.ts +4 -2
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/tool.d.ts +84 -0
- package/dist/cjs/types/tool.d.ts.map +1 -1
- package/dist/core/Agent.d.ts +17 -1
- package/dist/core/Agent.d.ts.map +1 -1
- package/dist/core/Agent.js +47 -0
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/BatchPromptBuilder.d.ts +3 -0
- package/dist/core/BatchPromptBuilder.d.ts.map +1 -1
- package/dist/core/BatchPromptBuilder.js +4 -1
- package/dist/core/BatchPromptBuilder.js.map +1 -1
- package/dist/core/CompactionEngine.d.ts +65 -0
- package/dist/core/CompactionEngine.d.ts.map +1 -0
- package/dist/core/CompactionEngine.js +244 -0
- package/dist/core/CompactionEngine.js.map +1 -0
- package/dist/core/PromptComposer.d.ts +8 -1
- package/dist/core/PromptComposer.d.ts.map +1 -1
- package/dist/core/PromptComposer.js +238 -126
- package/dist/core/PromptComposer.js.map +1 -1
- package/dist/core/PromptSectionCache.d.ts +57 -0
- package/dist/core/PromptSectionCache.d.ts.map +1 -0
- package/dist/core/PromptSectionCache.js +104 -0
- package/dist/core/PromptSectionCache.js.map +1 -0
- package/dist/core/ResponseEngine.d.ts +3 -2
- package/dist/core/ResponseEngine.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +8 -8
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/ResponseModal.d.ts.map +1 -1
- package/dist/core/ResponseModal.js +121 -71
- package/dist/core/ResponseModal.js.map +1 -1
- package/dist/core/ResponsePipeline.d.ts +2 -1
- package/dist/core/ResponsePipeline.d.ts.map +1 -1
- package/dist/core/ResponsePipeline.js +18 -20
- package/dist/core/ResponsePipeline.js.map +1 -1
- package/dist/core/RoutingEngine.d.ts +10 -0
- package/dist/core/RoutingEngine.d.ts.map +1 -1
- package/dist/core/RoutingEngine.js +6 -5
- package/dist/core/RoutingEngine.js.map +1 -1
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +17 -0
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/StreamingToolExecutor.d.ts +142 -0
- package/dist/core/StreamingToolExecutor.d.ts.map +1 -0
- package/dist/core/StreamingToolExecutor.js +448 -0
- package/dist/core/StreamingToolExecutor.js.map +1 -0
- package/dist/core/ToolManager.d.ts +18 -1
- package/dist/core/ToolManager.d.ts.map +1 -1
- package/dist/core/ToolManager.js +91 -0
- package/dist/core/ToolManager.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/AnthropicProvider.d.ts +7 -0
- package/dist/providers/AnthropicProvider.d.ts.map +1 -1
- package/dist/providers/AnthropicProvider.js +109 -19
- package/dist/providers/AnthropicProvider.js.map +1 -1
- package/dist/providers/GeminiProvider.d.ts +32 -0
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +160 -53
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts +5 -0
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +65 -18
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts +5 -0
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +57 -18
- package/dist/providers/OpenRouterProvider.js.map +1 -1
- package/dist/types/agent.d.ts +44 -0
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/agent.js.map +1 -1
- package/dist/types/ai.d.ts +2 -2
- package/dist/types/ai.d.ts.map +1 -1
- package/dist/types/compaction.d.ts +50 -0
- package/dist/types/compaction.d.ts.map +1 -0
- package/dist/types/compaction.js +5 -0
- package/dist/types/compaction.js.map +1 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/tool.d.ts +84 -0
- package/dist/types/tool.d.ts.map +1 -1
- package/docs/api/overview.md +140 -0
- package/docs/core/tools/enhanced-tool.md +186 -0
- package/docs/core/tools/streaming-execution.md +161 -0
- package/docs/guides/context-compaction.md +96 -0
- package/docs/guides/prompt-optimization.md +164 -0
- package/examples/advanced-patterns/context-compaction.ts +223 -0
- package/examples/advanced-patterns/streaming-responses.ts +85 -7
- package/examples/tools/enhanced-tool-metadata.ts +268 -0
- package/examples/tools/streaming-tool-execution.ts +283 -0
- package/package.json +1 -1
- package/src/core/Agent.ts +58 -2
- package/src/core/BatchPromptBuilder.ts +4 -1
- package/src/core/CompactionEngine.ts +318 -0
- package/src/core/PromptComposer.ts +259 -156
- package/src/core/PromptSectionCache.ts +136 -0
- package/src/core/ResponseEngine.ts +7 -11
- package/src/core/ResponseModal.ts +133 -83
- package/src/core/ResponsePipeline.ts +22 -22
- package/src/core/RoutingEngine.ts +16 -5
- package/src/core/SessionManager.ts +19 -0
- package/src/core/StreamingToolExecutor.ts +572 -0
- package/src/core/ToolManager.ts +151 -41
- package/src/index.ts +14 -0
- package/src/providers/AnthropicProvider.ts +121 -24
- package/src/providers/GeminiProvider.ts +174 -54
- package/src/providers/OpenAIProvider.ts +77 -25
- package/src/providers/OpenRouterProvider.ts +68 -25
- package/src/types/agent.ts +45 -0
- package/src/types/ai.ts +2 -2
- package/src/types/compaction.ts +52 -0
- package/src/types/index.ts +35 -14
- package/src/types/tool.ts +108 -0
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
AgentStructuredResponse,
|
|
14
14
|
StructuredSchema,
|
|
15
15
|
} from "../types";
|
|
16
|
+
import type { HistoryItem } from "../types/history";
|
|
16
17
|
import { withTimeoutAndRetry, logger } from "../utils";
|
|
17
18
|
import { FunctionParameters } from "openai/resources/shared.mjs";
|
|
18
19
|
|
|
@@ -161,6 +162,52 @@ export class OpenAIProvider implements AiProvider {
|
|
|
161
162
|
};
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Build OpenAI-formatted messages from HistoryItem[] array.
|
|
167
|
+
* Maps directly to ChatCompletionMessageParam format.
|
|
168
|
+
*/
|
|
169
|
+
private buildOpenAIMessages(history: HistoryItem[]): Array<unknown> {
|
|
170
|
+
const messages: Array<unknown> = [];
|
|
171
|
+
|
|
172
|
+
for (const item of history) {
|
|
173
|
+
switch (item.role) {
|
|
174
|
+
case "system":
|
|
175
|
+
messages.push({ role: "system", content: item.content });
|
|
176
|
+
break;
|
|
177
|
+
case "user":
|
|
178
|
+
messages.push({ role: "user", content: item.content });
|
|
179
|
+
break;
|
|
180
|
+
case "assistant":
|
|
181
|
+
if (item.tool_calls && item.tool_calls.length > 0) {
|
|
182
|
+
messages.push({
|
|
183
|
+
role: "assistant",
|
|
184
|
+
content: item.content || null,
|
|
185
|
+
tool_calls: item.tool_calls.map(tc => ({
|
|
186
|
+
id: tc.id,
|
|
187
|
+
type: "function",
|
|
188
|
+
function: {
|
|
189
|
+
name: tc.name,
|
|
190
|
+
arguments: JSON.stringify(tc.arguments),
|
|
191
|
+
},
|
|
192
|
+
})),
|
|
193
|
+
});
|
|
194
|
+
} else {
|
|
195
|
+
messages.push({ role: "assistant", content: item.content || "" });
|
|
196
|
+
}
|
|
197
|
+
break;
|
|
198
|
+
case "tool":
|
|
199
|
+
messages.push({
|
|
200
|
+
role: "tool",
|
|
201
|
+
tool_call_id: item.tool_call_id,
|
|
202
|
+
content: typeof item.content === "string" ? item.content : JSON.stringify(item.content),
|
|
203
|
+
});
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return messages;
|
|
209
|
+
}
|
|
210
|
+
|
|
164
211
|
/**
|
|
165
212
|
* Adapt common schema format to OpenAI's format.
|
|
166
213
|
* OpenAI uses standard JSON Schema, so this is mostly a passthrough.
|
|
@@ -222,8 +269,7 @@ export class OpenAIProvider implements AiProvider {
|
|
|
222
269
|
for (let i = 0; i < this.backupModels.length; i++) {
|
|
223
270
|
const backupModel = this.backupModels[i];
|
|
224
271
|
logger.debug(
|
|
225
|
-
`[OPENAI] Trying backup model ${i + 1}/${
|
|
226
|
-
this.backupModels.length
|
|
272
|
+
`[OPENAI] Trying backup model ${i + 1}/${this.backupModels.length
|
|
227
273
|
}: ${backupModel}`
|
|
228
274
|
);
|
|
229
275
|
|
|
@@ -266,14 +312,12 @@ export class OpenAIProvider implements AiProvider {
|
|
|
266
312
|
input: GenerateMessageInput<TContext>
|
|
267
313
|
): Promise<GenerateMessageOutput<TStructured>> {
|
|
268
314
|
const operation = async (): Promise<GenerateMessageOutput> => {
|
|
315
|
+
const historyMessages = this.buildOpenAIMessages(input.history);
|
|
316
|
+
historyMessages.push({ role: "user", content: input.prompt });
|
|
317
|
+
|
|
269
318
|
const params: ChatCompletionCreateParamsNonStreaming = {
|
|
270
319
|
model,
|
|
271
|
-
messages: [
|
|
272
|
-
{
|
|
273
|
-
role: "user",
|
|
274
|
-
content: input.prompt,
|
|
275
|
-
},
|
|
276
|
-
],
|
|
320
|
+
messages: historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
|
|
277
321
|
...this.config,
|
|
278
322
|
};
|
|
279
323
|
|
|
@@ -336,10 +380,7 @@ export class OpenAIProvider implements AiProvider {
|
|
|
336
380
|
// Fall back to regular chat completions API if no schema provided
|
|
337
381
|
const response = await this.client.chat.completions.create(params);
|
|
338
382
|
|
|
339
|
-
const message = response.choices[0]?.message?.content;
|
|
340
|
-
if (!message) {
|
|
341
|
-
throw new Error("No response from OpenAI");
|
|
342
|
-
}
|
|
383
|
+
const message = response.choices[0]?.message?.content || "";
|
|
343
384
|
|
|
344
385
|
let toolCalls: Array<{
|
|
345
386
|
toolName: string;
|
|
@@ -368,7 +409,11 @@ export class OpenAIProvider implements AiProvider {
|
|
|
368
409
|
};
|
|
369
410
|
});
|
|
370
411
|
}
|
|
371
|
-
|
|
412
|
+
|
|
413
|
+
// Only throw error if we have no text AND no function calls
|
|
414
|
+
if (!message && toolCalls.length === 0) {
|
|
415
|
+
throw new Error("No response from OpenAI");
|
|
416
|
+
}
|
|
372
417
|
|
|
373
418
|
return {
|
|
374
419
|
message,
|
|
@@ -423,8 +468,7 @@ export class OpenAIProvider implements AiProvider {
|
|
|
423
468
|
for (let i = 0; i < this.backupModels.length; i++) {
|
|
424
469
|
const backupModel = this.backupModels[i];
|
|
425
470
|
logger.debug(
|
|
426
|
-
`[OPENAI] Trying backup model ${i + 1}/${
|
|
427
|
-
this.backupModels.length
|
|
471
|
+
`[OPENAI] Trying backup model ${i + 1}/${this.backupModels.length
|
|
428
472
|
}: ${backupModel}`
|
|
429
473
|
);
|
|
430
474
|
|
|
@@ -469,15 +513,14 @@ export class OpenAIProvider implements AiProvider {
|
|
|
469
513
|
model: string,
|
|
470
514
|
input: GenerateMessageInput<TContext>
|
|
471
515
|
): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
|
|
516
|
+
// Build messages from history and append prompt as final user message
|
|
517
|
+
const historyMessages = this.buildOpenAIMessages(input.history);
|
|
518
|
+
historyMessages.push({ role: "user" as const, content: input.prompt });
|
|
519
|
+
|
|
472
520
|
const params = {
|
|
473
521
|
...this.config,
|
|
474
522
|
model,
|
|
475
|
-
messages: [
|
|
476
|
-
{
|
|
477
|
-
role: "user" as const,
|
|
478
|
-
content: input.prompt,
|
|
479
|
-
},
|
|
480
|
-
],
|
|
523
|
+
messages: historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
|
|
481
524
|
stream: true as const,
|
|
482
525
|
};
|
|
483
526
|
|
|
@@ -530,9 +573,9 @@ export class OpenAIProvider implements AiProvider {
|
|
|
530
573
|
try {
|
|
531
574
|
toolCallArguments = toolCall.function.arguments
|
|
532
575
|
? (JSON.parse(toolCall.function.arguments) as Record<
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
576
|
+
string,
|
|
577
|
+
unknown
|
|
578
|
+
>)
|
|
536
579
|
: {};
|
|
537
580
|
} catch (error) {
|
|
538
581
|
logger.warn(
|
|
@@ -584,6 +627,15 @@ export class OpenAIProvider implements AiProvider {
|
|
|
584
627
|
}
|
|
585
628
|
}
|
|
586
629
|
|
|
630
|
+
// Include tool calls in structured response (even without JSON schema)
|
|
631
|
+
if (toolCalls.length > 0) {
|
|
632
|
+
structured = {
|
|
633
|
+
...(structured || {}),
|
|
634
|
+
message: (structured as AgentStructuredResponse | undefined)?.message || accumulated,
|
|
635
|
+
toolCalls,
|
|
636
|
+
} as TStructured;
|
|
637
|
+
}
|
|
638
|
+
|
|
587
639
|
// Yield final chunk
|
|
588
640
|
yield {
|
|
589
641
|
delta: "",
|
|
@@ -596,7 +648,7 @@ export class OpenAIProvider implements AiProvider {
|
|
|
596
648
|
promptTokens,
|
|
597
649
|
completionTokens,
|
|
598
650
|
},
|
|
599
|
-
structured
|
|
651
|
+
structured,
|
|
600
652
|
};
|
|
601
653
|
}
|
|
602
654
|
}
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
GenerateMessageStreamChunk,
|
|
16
16
|
StructuredSchema,
|
|
17
17
|
} from "../types";
|
|
18
|
+
import type { HistoryItem } from "../types/history";
|
|
18
19
|
import { withTimeoutAndRetry, logger } from "../utils";
|
|
19
20
|
|
|
20
21
|
const DEFAULT_RETRY_CONFIG = {
|
|
@@ -171,6 +172,52 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
171
172
|
};
|
|
172
173
|
}
|
|
173
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Build OpenRouter-formatted messages from HistoryItem[] array.
|
|
177
|
+
* OpenRouter uses OpenAI-compatible format.
|
|
178
|
+
*/
|
|
179
|
+
private buildOpenRouterMessages(history: HistoryItem[]): Array<unknown> {
|
|
180
|
+
const messages: Array<unknown> = [];
|
|
181
|
+
|
|
182
|
+
for (const item of history) {
|
|
183
|
+
switch (item.role) {
|
|
184
|
+
case "system":
|
|
185
|
+
messages.push({ role: "system", content: item.content });
|
|
186
|
+
break;
|
|
187
|
+
case "user":
|
|
188
|
+
messages.push({ role: "user", content: item.content });
|
|
189
|
+
break;
|
|
190
|
+
case "assistant":
|
|
191
|
+
if (item.tool_calls && item.tool_calls.length > 0) {
|
|
192
|
+
messages.push({
|
|
193
|
+
role: "assistant",
|
|
194
|
+
content: item.content || null,
|
|
195
|
+
tool_calls: item.tool_calls.map(tc => ({
|
|
196
|
+
id: tc.id,
|
|
197
|
+
type: "function",
|
|
198
|
+
function: {
|
|
199
|
+
name: tc.name,
|
|
200
|
+
arguments: JSON.stringify(tc.arguments),
|
|
201
|
+
},
|
|
202
|
+
})),
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
messages.push({ role: "assistant", content: item.content || "" });
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
208
|
+
case "tool":
|
|
209
|
+
messages.push({
|
|
210
|
+
role: "tool",
|
|
211
|
+
tool_call_id: item.tool_call_id,
|
|
212
|
+
content: typeof item.content === "string" ? item.content : JSON.stringify(item.content),
|
|
213
|
+
});
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return messages;
|
|
219
|
+
}
|
|
220
|
+
|
|
174
221
|
/**
|
|
175
222
|
* Adapt common schema format to OpenRouter's format.
|
|
176
223
|
* OpenRouter is OpenAI-compatible and uses standard JSON Schema.
|
|
@@ -229,8 +276,7 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
229
276
|
for (let i = 0; i < this.backupModels.length; i++) {
|
|
230
277
|
const backupModel = this.backupModels[i];
|
|
231
278
|
logger.debug(
|
|
232
|
-
`[OPENROUTER] Trying backup model ${i + 1}/${
|
|
233
|
-
this.backupModels.length
|
|
279
|
+
`[OPENROUTER] Trying backup model ${i + 1}/${this.backupModels.length
|
|
234
280
|
}: ${backupModel}`
|
|
235
281
|
);
|
|
236
282
|
|
|
@@ -273,14 +319,12 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
273
319
|
input: GenerateMessageInput<TContext>
|
|
274
320
|
): Promise<GenerateMessageOutput<TStructured>> {
|
|
275
321
|
const operation = async (): Promise<GenerateMessageOutput> => {
|
|
322
|
+
const historyMessages = this.buildOpenRouterMessages(input.history);
|
|
323
|
+
historyMessages.push({ role: "user", content: input.prompt });
|
|
324
|
+
|
|
276
325
|
const params: ChatCompletionCreateParamsNonStreaming = {
|
|
277
326
|
model,
|
|
278
|
-
messages: [
|
|
279
|
-
{
|
|
280
|
-
role: "user",
|
|
281
|
-
content: input.prompt,
|
|
282
|
-
},
|
|
283
|
-
],
|
|
327
|
+
messages: historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
|
|
284
328
|
...this.config,
|
|
285
329
|
};
|
|
286
330
|
|
|
@@ -345,10 +389,7 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
345
389
|
// Fall back to regular chat completions API if no schema provided
|
|
346
390
|
const response = await this.client.chat.completions.create(params);
|
|
347
391
|
|
|
348
|
-
const message = response.choices[0]?.message?.content;
|
|
349
|
-
if (!message) {
|
|
350
|
-
throw new Error("No response from OpenRouter");
|
|
351
|
-
}
|
|
392
|
+
const message = response.choices[0]?.message?.content || "";
|
|
352
393
|
|
|
353
394
|
let toolCalls: Array<{
|
|
354
395
|
toolName: string;
|
|
@@ -378,6 +419,11 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
378
419
|
});
|
|
379
420
|
}
|
|
380
421
|
|
|
422
|
+
// Only throw error if we have no text AND no function calls
|
|
423
|
+
if (!message && toolCalls.length === 0) {
|
|
424
|
+
throw new Error("No response from OpenRouter");
|
|
425
|
+
}
|
|
426
|
+
|
|
381
427
|
return {
|
|
382
428
|
message,
|
|
383
429
|
metadata: {
|
|
@@ -428,8 +474,7 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
428
474
|
for (let i = 0; i < this.backupModels.length; i++) {
|
|
429
475
|
const backupModel = this.backupModels[i];
|
|
430
476
|
logger.debug(
|
|
431
|
-
`[OPENROUTER] Trying backup model ${i + 1}/${
|
|
432
|
-
this.backupModels.length
|
|
477
|
+
`[OPENROUTER] Trying backup model ${i + 1}/${this.backupModels.length
|
|
433
478
|
}: ${backupModel}`
|
|
434
479
|
);
|
|
435
480
|
|
|
@@ -471,15 +516,13 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
471
516
|
model: string,
|
|
472
517
|
input: GenerateMessageInput<TContext>
|
|
473
518
|
): AsyncGenerator<GenerateMessageStreamChunk<TStructured>> {
|
|
519
|
+
const historyMessages = this.buildOpenRouterMessages(input.history);
|
|
520
|
+
historyMessages.push({ role: "user" as const, content: input.prompt });
|
|
521
|
+
|
|
474
522
|
const params = {
|
|
475
523
|
...this.config,
|
|
476
524
|
model,
|
|
477
|
-
messages: [
|
|
478
|
-
{
|
|
479
|
-
role: "user" as const,
|
|
480
|
-
content: input.prompt,
|
|
481
|
-
},
|
|
482
|
-
],
|
|
525
|
+
messages: historyMessages as ChatCompletionCreateParamsNonStreaming["messages"],
|
|
483
526
|
stream: true as const,
|
|
484
527
|
};
|
|
485
528
|
|
|
@@ -532,9 +575,9 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
532
575
|
try {
|
|
533
576
|
toolCallArguments = toolCall.function.arguments
|
|
534
577
|
? (JSON.parse(toolCall.function.arguments) as Record<
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
578
|
+
string,
|
|
579
|
+
unknown
|
|
580
|
+
>)
|
|
538
581
|
: {};
|
|
539
582
|
} catch (error) {
|
|
540
583
|
logger.warn(
|
|
@@ -589,9 +632,9 @@ export class OpenRouterProvider implements AiProvider {
|
|
|
589
632
|
// If tools were used, include them in structured response
|
|
590
633
|
if (toolCalls.length > 0) {
|
|
591
634
|
structured = {
|
|
592
|
-
|
|
635
|
+
...(structured || {}),
|
|
636
|
+
message: (structured as AgentStructuredResponse | undefined)?.message || accumulated,
|
|
593
637
|
toolCalls,
|
|
594
|
-
...structured,
|
|
595
638
|
} as TStructured;
|
|
596
639
|
}
|
|
597
640
|
|
package/src/types/agent.ts
CHANGED
|
@@ -9,6 +9,39 @@ import type { PersistenceConfig } from "./persistence";
|
|
|
9
9
|
import type { SessionState } from "./session";
|
|
10
10
|
import type { StructuredSchema } from "./schema";
|
|
11
11
|
import { Template, ConditionTemplate } from "./template";
|
|
12
|
+
import type { PromptCacheConfig } from "../core/PromptSectionCache";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Agent-level compaction configuration.
|
|
16
|
+
* Unlike CompactionOptions, this does not require a `provider` since the agent already has one.
|
|
17
|
+
*/
|
|
18
|
+
export interface AgentCompactionConfig {
|
|
19
|
+
/** Maximum token budget for the conversation */
|
|
20
|
+
maxTokens: number;
|
|
21
|
+
/**
|
|
22
|
+
* Threshold ratio (0–1) at which to trigger compaction.
|
|
23
|
+
* Must be between 0.5 and 0.95.
|
|
24
|
+
* @default 0.8
|
|
25
|
+
*/
|
|
26
|
+
compactionThreshold?: number;
|
|
27
|
+
/**
|
|
28
|
+
* Number of recent messages to always preserve unchanged.
|
|
29
|
+
* Must be >= 2.
|
|
30
|
+
* @default 4
|
|
31
|
+
*/
|
|
32
|
+
preserveRecentCount?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Maximum characters per tool result before truncation.
|
|
35
|
+
* Must be > 0.
|
|
36
|
+
* @default 5000
|
|
37
|
+
*/
|
|
38
|
+
maxToolResultChars?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Whether compaction is enabled.
|
|
41
|
+
* @default true when config is provided
|
|
42
|
+
*/
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
}
|
|
12
45
|
|
|
13
46
|
/**
|
|
14
47
|
* Composition mode determines how the agent processes and structures responses
|
|
@@ -132,6 +165,18 @@ export interface AgentOptions<TContext = unknown, TData = unknown> {
|
|
|
132
165
|
* @default 1
|
|
133
166
|
*/
|
|
134
167
|
maxStepsPerBatch?: number;
|
|
168
|
+
/**
|
|
169
|
+
* Optional compaction configuration for managing conversation history size.
|
|
170
|
+
* When provided, the agent will validate the options and make them available
|
|
171
|
+
* for use by the SessionManager/CompactionEngine.
|
|
172
|
+
*/
|
|
173
|
+
compaction?: AgentCompactionConfig;
|
|
174
|
+
/**
|
|
175
|
+
* Optional prompt cache configuration for controlling section memoization behavior.
|
|
176
|
+
* When provided, controls whether prompt sections are cached across turns.
|
|
177
|
+
* @default { enabled: true }
|
|
178
|
+
*/
|
|
179
|
+
promptCache?: PromptCacheConfig;
|
|
135
180
|
}
|
|
136
181
|
|
|
137
182
|
/**
|
package/src/types/ai.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* AI provider strategy types
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { HistoryItem } from "./history";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Reasoning/thinking configuration for AI models
|
|
@@ -36,7 +36,7 @@ export interface GenerateMessageInput<TContext = unknown> {
|
|
|
36
36
|
/** The constructed prompt */
|
|
37
37
|
prompt: string;
|
|
38
38
|
/** Interaction history */
|
|
39
|
-
history:
|
|
39
|
+
history: HistoryItem[];
|
|
40
40
|
/** Context data */
|
|
41
41
|
context: TContext;
|
|
42
42
|
/** Tools available for AI to call during this interaction */
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context compaction types for managing conversation history size
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { AiProvider } from "./ai";
|
|
6
|
+
import type { HistoryItem } from "./history";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for the compaction engine.
|
|
10
|
+
*
|
|
11
|
+
* Validation constraints:
|
|
12
|
+
* - `compactionThreshold` must be between 0.5 and 0.95
|
|
13
|
+
* - `preserveRecentCount` must be >= 2
|
|
14
|
+
* - `maxToolResultChars` must be > 0
|
|
15
|
+
*/
|
|
16
|
+
export interface CompactionOptions {
|
|
17
|
+
/** Maximum token budget for the conversation */
|
|
18
|
+
maxTokens: number;
|
|
19
|
+
/**
|
|
20
|
+
* Threshold ratio (0–1) at which to trigger compaction.
|
|
21
|
+
* Must be between 0.5 and 0.95.
|
|
22
|
+
*/
|
|
23
|
+
compactionThreshold: number;
|
|
24
|
+
/**
|
|
25
|
+
* Number of recent messages to always preserve unchanged.
|
|
26
|
+
* Must be >= 2.
|
|
27
|
+
*/
|
|
28
|
+
preserveRecentCount: number;
|
|
29
|
+
/**
|
|
30
|
+
* Maximum characters per tool result before truncation.
|
|
31
|
+
* Must be > 0.
|
|
32
|
+
*/
|
|
33
|
+
maxToolResultChars: number;
|
|
34
|
+
/** Provider to use for LLM summarization during auto-compact */
|
|
35
|
+
provider: AiProvider;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Result of a compaction operation
|
|
40
|
+
*/
|
|
41
|
+
export interface CompactionResult {
|
|
42
|
+
/** The compacted history */
|
|
43
|
+
history: HistoryItem[];
|
|
44
|
+
/** Strategy that was applied */
|
|
45
|
+
strategy: 'none' | 'tool_result_budget' | 'micro_compact' | 'auto_compact';
|
|
46
|
+
/** Estimated tokens after compaction */
|
|
47
|
+
estimatedTokens: number;
|
|
48
|
+
/** Number of messages removed/compacted */
|
|
49
|
+
messagesCompacted: number;
|
|
50
|
+
/** Summary text (if auto-compact was used) */
|
|
51
|
+
summary?: string;
|
|
52
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// Agent types
|
|
6
6
|
export type {
|
|
7
7
|
AgentOptions,
|
|
8
|
+
AgentCompactionConfig,
|
|
8
9
|
Term,
|
|
9
10
|
Guideline,
|
|
10
11
|
GuidelineMatch,
|
|
@@ -58,12 +59,19 @@ export * from "./route";
|
|
|
58
59
|
export type { SessionState, PendingTransition } from "./session";
|
|
59
60
|
|
|
60
61
|
// Tool types
|
|
61
|
-
export type {
|
|
62
|
-
Tool,
|
|
63
|
-
ToolContext,
|
|
64
|
-
ToolResult,
|
|
62
|
+
export type {
|
|
63
|
+
Tool,
|
|
64
|
+
ToolContext,
|
|
65
|
+
ToolResult,
|
|
65
66
|
ToolHandler,
|
|
66
67
|
ToolExecutionResult,
|
|
68
|
+
EnhancedTool,
|
|
69
|
+
ToolValidationResult,
|
|
70
|
+
ToolPermissionResult,
|
|
71
|
+
ToolCallRequest,
|
|
72
|
+
ToolExecutionUpdate,
|
|
73
|
+
TrackedTool,
|
|
74
|
+
ToolStatus,
|
|
67
75
|
DataEnrichmentConfig,
|
|
68
76
|
ValidationConfig,
|
|
69
77
|
ApiCallConfig,
|
|
@@ -71,6 +79,19 @@ export type {
|
|
|
71
79
|
} from "./tool";
|
|
72
80
|
export { ToolScope } from "./tool";
|
|
73
81
|
|
|
82
|
+
// Compaction types
|
|
83
|
+
export type {
|
|
84
|
+
CompactionOptions,
|
|
85
|
+
CompactionResult,
|
|
86
|
+
} from "./compaction";
|
|
87
|
+
|
|
88
|
+
// Prompt cache types (re-exported from core)
|
|
89
|
+
export type {
|
|
90
|
+
PromptSectionType,
|
|
91
|
+
PromptCacheConfig,
|
|
92
|
+
SectionCompute,
|
|
93
|
+
} from "../core/PromptSectionCache";
|
|
94
|
+
|
|
74
95
|
// AI provider types
|
|
75
96
|
export type {
|
|
76
97
|
AiProvider,
|
|
@@ -105,15 +126,15 @@ export type {
|
|
|
105
126
|
export * from "./persistence";
|
|
106
127
|
|
|
107
128
|
// Template types
|
|
108
|
-
export type {
|
|
109
|
-
Template,
|
|
110
|
-
TemplateContext,
|
|
111
|
-
ConditionTemplate,
|
|
112
|
-
ConditionEvaluationResult
|
|
129
|
+
export type {
|
|
130
|
+
Template,
|
|
131
|
+
TemplateContext,
|
|
132
|
+
ConditionTemplate,
|
|
133
|
+
ConditionEvaluationResult
|
|
113
134
|
} from "./template";
|
|
114
|
-
export {
|
|
115
|
-
ConditionEvaluator,
|
|
116
|
-
createConditionEvaluator,
|
|
117
|
-
extractAIContextStrings,
|
|
118
|
-
hasProgrammaticConditions
|
|
135
|
+
export {
|
|
136
|
+
ConditionEvaluator,
|
|
137
|
+
createConditionEvaluator,
|
|
138
|
+
extractAIContextStrings,
|
|
139
|
+
hasProgrammaticConditions
|
|
119
140
|
} from "../utils/condition";
|
package/src/types/tool.ts
CHANGED
|
@@ -116,6 +116,114 @@ export enum ToolScope {
|
|
|
116
116
|
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
// --- EnhancedTool and supporting types ---
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Result of input validation on a tool call
|
|
123
|
+
*/
|
|
124
|
+
export interface ToolValidationResult {
|
|
125
|
+
valid: boolean;
|
|
126
|
+
error?: string;
|
|
127
|
+
/** Suggested corrected input */
|
|
128
|
+
correctedInput?: Record<string, unknown>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Result of a permission check on a tool call
|
|
133
|
+
*/
|
|
134
|
+
export interface ToolPermissionResult {
|
|
135
|
+
allowed: boolean;
|
|
136
|
+
reason?: string;
|
|
137
|
+
/** If not allowed, can the user override? */
|
|
138
|
+
canOverride?: boolean;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A single tool invocation request from the LLM
|
|
143
|
+
*/
|
|
144
|
+
export interface ToolCallRequest {
|
|
145
|
+
/** Unique ID for this tool call instance */
|
|
146
|
+
id: string;
|
|
147
|
+
/** Tool name/ID to execute */
|
|
148
|
+
toolName: string;
|
|
149
|
+
/** Arguments passed to the tool */
|
|
150
|
+
arguments: Record<string, unknown>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Result or progress update from a tool execution
|
|
155
|
+
*/
|
|
156
|
+
export interface ToolExecutionUpdate<TData = unknown> {
|
|
157
|
+
/** The tool call this update relates to */
|
|
158
|
+
toolCallId: string;
|
|
159
|
+
/** Result message (undefined for progress updates) */
|
|
160
|
+
result?: ToolExecutionResult;
|
|
161
|
+
/** Progress message for long-running tools */
|
|
162
|
+
progress?: string;
|
|
163
|
+
/** Updated context after tool execution */
|
|
164
|
+
contextUpdate?: Record<string, unknown>;
|
|
165
|
+
/** Updated data after tool execution */
|
|
166
|
+
dataUpdate?: Partial<TData>;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Internal status of a tracked tool in the executor queue
|
|
171
|
+
*/
|
|
172
|
+
export type ToolStatus = 'queued' | 'executing' | 'completed' | 'yielded';
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Internal type tracking the state of a queued or executing tool
|
|
176
|
+
*/
|
|
177
|
+
export interface TrackedTool<TContext = unknown, TData = unknown> {
|
|
178
|
+
id: string;
|
|
179
|
+
toolCall: ToolCallRequest;
|
|
180
|
+
tool: EnhancedTool<TContext, TData>;
|
|
181
|
+
status: ToolStatus;
|
|
182
|
+
isConcurrencySafe: boolean;
|
|
183
|
+
promise?: Promise<void>;
|
|
184
|
+
results: ToolExecutionResult[];
|
|
185
|
+
pendingProgress: string[];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Extended tool interface with rich metadata for concurrency control,
|
|
190
|
+
* permission gating, input validation, and result size management.
|
|
191
|
+
*
|
|
192
|
+
* All additional methods/properties are optional — plain `Tool` objects
|
|
193
|
+
* remain fully compatible.
|
|
194
|
+
*/
|
|
195
|
+
export interface EnhancedTool<
|
|
196
|
+
TContext = any,
|
|
197
|
+
TData = any,
|
|
198
|
+
TResult = any
|
|
199
|
+
> extends Tool<TContext, TData, TResult> {
|
|
200
|
+
/** Whether this tool is safe to run concurrently with other concurrent-safe tools */
|
|
201
|
+
isConcurrencySafe?(input?: Record<string, unknown>): boolean;
|
|
202
|
+
/** Whether this tool only reads data without side effects */
|
|
203
|
+
isReadOnly?(input?: Record<string, unknown>): boolean;
|
|
204
|
+
/** Whether this tool performs destructive/irreversible operations */
|
|
205
|
+
isDestructive?(input?: Record<string, unknown>): boolean;
|
|
206
|
+
|
|
207
|
+
/** How the tool responds to abort signals: 'cancel' = immediate abort, 'block' = allow completion */
|
|
208
|
+
interruptBehavior?(): 'cancel' | 'block';
|
|
209
|
+
/** Maximum characters for the tool result before truncation */
|
|
210
|
+
maxResultSizeChars?: number;
|
|
211
|
+
|
|
212
|
+
/** Validate input before execution */
|
|
213
|
+
validateInput?(
|
|
214
|
+
input: Record<string, unknown>,
|
|
215
|
+
context: ToolContext<TContext, TData>
|
|
216
|
+
): Promise<ToolValidationResult> | ToolValidationResult;
|
|
217
|
+
|
|
218
|
+
/** Check permissions before execution */
|
|
219
|
+
checkPermissions?(
|
|
220
|
+
input: Record<string, unknown>,
|
|
221
|
+
context: ToolContext<TContext, TData>
|
|
222
|
+
): Promise<ToolPermissionResult> | ToolPermissionResult;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// --- Existing tool configuration types ---
|
|
226
|
+
|
|
119
227
|
/**
|
|
120
228
|
* Configuration for data enrichment tools
|
|
121
229
|
*/
|