@falai/agent 1.1.3 → 1.2.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/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 -0
- package/dist/cjs/core/ResponseEngine.d.ts.map +1 -1
- package/dist/cjs/core/ResponseEngine.js +10 -6
- 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 +75 -16
- package/dist/cjs/core/ResponseModal.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 +3 -2
- 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.map +1 -1
- package/dist/cjs/providers/AnthropicProvider.js +8 -7
- package/dist/cjs/providers/AnthropicProvider.js.map +1 -1
- package/dist/cjs/providers/GeminiProvider.d.ts +25 -0
- package/dist/cjs/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/cjs/providers/GeminiProvider.js +79 -51
- package/dist/cjs/providers/GeminiProvider.js.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenAIProvider.js +14 -6
- package/dist/cjs/providers/OpenAIProvider.js.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/cjs/providers/OpenRouterProvider.js +7 -6
- 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/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 -0
- package/dist/core/ResponseEngine.d.ts.map +1 -1
- package/dist/core/ResponseEngine.js +10 -6
- package/dist/core/ResponseEngine.js.map +1 -1
- package/dist/core/ResponseModal.d.ts.map +1 -1
- package/dist/core/ResponseModal.js +75 -16
- package/dist/core/ResponseModal.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 +3 -2
- 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.map +1 -1
- package/dist/providers/AnthropicProvider.js +8 -7
- package/dist/providers/AnthropicProvider.js.map +1 -1
- package/dist/providers/GeminiProvider.d.ts +25 -0
- package/dist/providers/GeminiProvider.d.ts.map +1 -1
- package/dist/providers/GeminiProvider.js +79 -51
- package/dist/providers/GeminiProvider.js.map +1 -1
- package/dist/providers/OpenAIProvider.d.ts.map +1 -1
- package/dist/providers/OpenAIProvider.js +14 -6
- package/dist/providers/OpenAIProvider.js.map +1 -1
- package/dist/providers/OpenRouterProvider.d.ts.map +1 -1
- package/dist/providers/OpenRouterProvider.js +7 -6
- 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/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 +9 -6
- package/src/core/ResponseModal.ts +77 -16
- package/src/core/RoutingEngine.ts +13 -2
- 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 +11 -12
- package/src/providers/GeminiProvider.ts +83 -52
- package/src/providers/OpenAIProvider.ts +21 -13
- package/src/providers/OpenRouterProvider.ts +13 -13
- package/src/types/agent.ts +45 -0
- package/src/types/compaction.ts +52 -0
- package/src/types/index.ts +35 -14
- package/src/types/tool.ts +108 -0
package/src/core/ToolManager.ts
CHANGED
|
@@ -12,6 +12,9 @@ import type {
|
|
|
12
12
|
ApiCallConfig,
|
|
13
13
|
ComputationConfig,
|
|
14
14
|
ToolContext,
|
|
15
|
+
ToolCallRequest,
|
|
16
|
+
ToolExecutionUpdate,
|
|
17
|
+
EnhancedTool,
|
|
15
18
|
Event,
|
|
16
19
|
} from "../types";
|
|
17
20
|
import { ToolScope } from "../types";
|
|
@@ -19,6 +22,7 @@ import { logger } from "../utils";
|
|
|
19
22
|
import { Agent } from "./Agent";
|
|
20
23
|
import { Route } from "./Route";
|
|
21
24
|
import { Step } from "./Step";
|
|
25
|
+
import { StreamingToolExecutor } from "./StreamingToolExecutor";
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
28
|
* Error thrown when tool creation fails
|
|
@@ -283,13 +287,13 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
283
287
|
|
|
284
288
|
this.toolRegistry.set(tool.id, tool);
|
|
285
289
|
logger.debug(`[ToolManager] Registered tool: ${tool.id} (${tool.name || 'unnamed'})`);
|
|
286
|
-
|
|
290
|
+
|
|
287
291
|
return tool;
|
|
288
292
|
} catch (error) {
|
|
289
293
|
if (error instanceof ToolCreationError) {
|
|
290
294
|
throw error;
|
|
291
295
|
}
|
|
292
|
-
|
|
296
|
+
|
|
293
297
|
const toolId = tool?.id || 'unknown';
|
|
294
298
|
throw new ToolCreationError(
|
|
295
299
|
`Failed to register tool '${toolId}': ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -387,14 +391,14 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
387
391
|
if (!tool || !tool.id || !tool.handler) {
|
|
388
392
|
throw new ToolCreationError('Invalid tool: must have id and handler properties', tool?.id || 'unknown');
|
|
389
393
|
}
|
|
390
|
-
|
|
394
|
+
|
|
391
395
|
// Add to agent's tools array using the unified interface
|
|
392
396
|
if (this.agent) {
|
|
393
397
|
this.agent.addTool(tool);
|
|
394
398
|
} else {
|
|
395
399
|
logger.warn(`[ToolManager] No agent available, tool not added to agent scope: ${tool.id}`);
|
|
396
400
|
}
|
|
397
|
-
|
|
401
|
+
|
|
398
402
|
logger.debug(`[ToolManager] Added tool to agent scope: ${tool.id}`);
|
|
399
403
|
return tool;
|
|
400
404
|
}
|
|
@@ -403,7 +407,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
403
407
|
* Add a tool to a specific route scope (creates and adds in one operation)
|
|
404
408
|
*/
|
|
405
409
|
addToRoute(
|
|
406
|
-
route: Route<TContext, TData>,
|
|
410
|
+
route: Route<TContext, TData>,
|
|
407
411
|
tool: Tool<TContext, TData>
|
|
408
412
|
): Tool<TContext, TData> {
|
|
409
413
|
// Add to route's tools array using the existing createTool method
|
|
@@ -412,7 +416,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
412
416
|
} else {
|
|
413
417
|
logger.warn(`[ToolManager] Route does not support createTool method, tool not added to route scope: ${tool.id}`);
|
|
414
418
|
}
|
|
415
|
-
|
|
419
|
+
|
|
416
420
|
logger.debug(`[ToolManager] Added tool to route scope: ${tool.id}`);
|
|
417
421
|
return tool;
|
|
418
422
|
}
|
|
@@ -479,7 +483,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
479
483
|
logger.debug(`[ToolManager] Found tool in registry: ${toolId}`);
|
|
480
484
|
return registeredTool;
|
|
481
485
|
}
|
|
482
|
-
|
|
486
|
+
|
|
483
487
|
// Also check by name in registry
|
|
484
488
|
for (const [id, tool] of Array.from(this.toolRegistry.entries())) {
|
|
485
489
|
if (tool.name === toolId) {
|
|
@@ -557,7 +561,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
557
561
|
|
|
558
562
|
// Convert map to array, preserving priority order
|
|
559
563
|
const allTools = Array.from(toolMap.values());
|
|
560
|
-
|
|
564
|
+
|
|
561
565
|
// If we have step-specific tools, prioritize them
|
|
562
566
|
if (resolvedTools.length > 0) {
|
|
563
567
|
// Add resolved step tools first, then other tools not already included
|
|
@@ -575,7 +579,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
575
579
|
* Consolidates tool execution logic from ToolExecutor and ResponseModal
|
|
576
580
|
*/
|
|
577
581
|
async execute(
|
|
578
|
-
toolId: string,
|
|
582
|
+
toolId: string,
|
|
579
583
|
args?: Record<string, unknown>,
|
|
580
584
|
context?: {
|
|
581
585
|
step?: Step<TContext, TData>;
|
|
@@ -610,14 +614,14 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
610
614
|
// Tool not found - try fallback tools if available
|
|
611
615
|
if (fallbackTools.length > 0) {
|
|
612
616
|
logger.warn(`[ToolManager] Primary tool '${toolId}' not found, trying fallback tools: ${fallbackTools.join(', ')}`);
|
|
613
|
-
|
|
617
|
+
|
|
614
618
|
for (const fallbackId of fallbackTools) {
|
|
615
619
|
const fallbackResult = await this.execute(fallbackId, args, {
|
|
616
620
|
...context,
|
|
617
621
|
fallbackTools: [], // Prevent infinite recursion
|
|
618
622
|
retryCount: 0 // Don't retry fallback tools
|
|
619
623
|
});
|
|
620
|
-
|
|
624
|
+
|
|
621
625
|
if (fallbackResult.success) {
|
|
622
626
|
logger.info(`[ToolManager] Fallback tool '${fallbackId}' succeeded for primary tool '${toolId}'`);
|
|
623
627
|
return {
|
|
@@ -676,13 +680,13 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
676
680
|
} catch (error) {
|
|
677
681
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
678
682
|
const errorMessage = lastError.message;
|
|
679
|
-
|
|
683
|
+
|
|
680
684
|
// Check if this is a transient error that should be retried
|
|
681
685
|
const isTransientError = this.isTransientError(lastError);
|
|
682
|
-
|
|
686
|
+
|
|
683
687
|
if (attempt < maxRetries && isTransientError) {
|
|
684
688
|
logger.warn(`[ToolManager] Tool execution attempt ${attempt + 1} failed for ${toolId}, retrying: ${errorMessage}`);
|
|
685
|
-
|
|
689
|
+
|
|
686
690
|
// Exponential backoff for retries
|
|
687
691
|
const delay = Math.min(1000 * Math.pow(2, attempt), 5000);
|
|
688
692
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
@@ -697,7 +701,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
697
701
|
// All retries failed - try fallback tools
|
|
698
702
|
if (fallbackTools.length > 0) {
|
|
699
703
|
logger.warn(`[ToolManager] Primary tool '${toolId}' failed after retries, trying fallback tools: ${fallbackTools.join(', ')}`);
|
|
700
|
-
|
|
704
|
+
|
|
701
705
|
for (const fallbackId of fallbackTools) {
|
|
702
706
|
try {
|
|
703
707
|
const fallbackResult = await this.execute(fallbackId, args, {
|
|
@@ -705,7 +709,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
705
709
|
fallbackTools: [], // Prevent infinite recursion
|
|
706
710
|
retryCount: 0 // Don't retry fallback tools
|
|
707
711
|
});
|
|
708
|
-
|
|
712
|
+
|
|
709
713
|
if (fallbackResult.success) {
|
|
710
714
|
logger.info(`[ToolManager] Fallback tool '${fallbackId}' succeeded for failed primary tool '${toolId}'`);
|
|
711
715
|
return {
|
|
@@ -769,7 +773,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
769
773
|
}): Promise<ToolExecutionResult> {
|
|
770
774
|
const { tool, context, updateContext, updateData, history, data, toolArguments } = params;
|
|
771
775
|
const startTime = Date.now();
|
|
772
|
-
|
|
776
|
+
|
|
773
777
|
try {
|
|
774
778
|
// Validate tool before execution
|
|
775
779
|
if (!tool || !tool.handler || typeof tool.handler !== 'function') {
|
|
@@ -802,6 +806,40 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
802
806
|
|
|
803
807
|
logger.debug(`[ToolManager] Executing tool: ${tool.id} with args:`, toolArguments);
|
|
804
808
|
|
|
809
|
+
// EnhancedTool validation gate (Req 9.2, 10.6)
|
|
810
|
+
const enhanced = tool as EnhancedTool<TContext, TData>;
|
|
811
|
+
if (typeof enhanced.validateInput === 'function' && toolArguments) {
|
|
812
|
+
const validation = await enhanced.validateInput(toolArguments, toolContext);
|
|
813
|
+
if (!validation.valid) {
|
|
814
|
+
const executionTime = Date.now() - startTime;
|
|
815
|
+
logger.warn(`[ToolManager] Tool ${tool.id} input validation failed: ${validation.error}`);
|
|
816
|
+
return {
|
|
817
|
+
success: false,
|
|
818
|
+
error: `Validation failed: ${validation.error || 'Invalid input'}`,
|
|
819
|
+
metadata: { toolId: tool.id, executionTime, gate: 'validateInput' }
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// EnhancedTool permission gate (Req 9.3, 10.6)
|
|
825
|
+
if (typeof enhanced.checkPermissions === 'function' && toolArguments) {
|
|
826
|
+
const permission = await enhanced.checkPermissions(toolArguments, toolContext);
|
|
827
|
+
if (!permission.allowed) {
|
|
828
|
+
const executionTime = Date.now() - startTime;
|
|
829
|
+
logger.warn(`[ToolManager] Tool ${tool.id} permission denied: ${permission.reason}`);
|
|
830
|
+
return {
|
|
831
|
+
success: false,
|
|
832
|
+
error: `Permission denied: ${permission.reason || 'Not allowed'}`,
|
|
833
|
+
metadata: {
|
|
834
|
+
toolId: tool.id,
|
|
835
|
+
executionTime,
|
|
836
|
+
gate: 'checkPermissions',
|
|
837
|
+
canOverride: permission.canOverride
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
805
843
|
// Execute tool with timeout protection
|
|
806
844
|
const executionTimeout = 30000; // 30 seconds default timeout
|
|
807
845
|
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
@@ -818,7 +856,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
818
856
|
|
|
819
857
|
// Handle different result types
|
|
820
858
|
let toolResult: ToolResult<unknown, TContext, TData>;
|
|
821
|
-
|
|
859
|
+
|
|
822
860
|
if (result && typeof result === 'object' && ('data' in result || 'success' in result || 'error' in result)) {
|
|
823
861
|
// It's already a ToolResult-like object
|
|
824
862
|
toolResult = result as ToolResult<unknown, TContext, TData>;
|
|
@@ -882,9 +920,9 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
882
920
|
};
|
|
883
921
|
} catch (error) {
|
|
884
922
|
const executionTime = Date.now() - startTime;
|
|
885
|
-
|
|
923
|
+
|
|
886
924
|
logger.error(`[ToolManager] Tool execution error for ${tool.id} after ${executionTime}ms:`, error);
|
|
887
|
-
|
|
925
|
+
|
|
888
926
|
// Re-throw the error so the execute method can handle retries
|
|
889
927
|
throw error;
|
|
890
928
|
}
|
|
@@ -936,6 +974,78 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
936
974
|
return results;
|
|
937
975
|
}
|
|
938
976
|
|
|
977
|
+
/**
|
|
978
|
+
* Execute tool calls with concurrency control using StreamingToolExecutor.
|
|
979
|
+
* Creates a StreamingToolExecutor, resolves tools, queues them, and yields
|
|
980
|
+
* ToolExecutionUpdate results in original request order.
|
|
981
|
+
*
|
|
982
|
+
* Concurrency-safe tools run in parallel; non-safe tools run serially.
|
|
983
|
+
* Progress messages are yielded immediately.
|
|
984
|
+
*/
|
|
985
|
+
async *executeWithConcurrency(params: {
|
|
986
|
+
toolCalls: ToolCallRequest[];
|
|
987
|
+
context: TContext;
|
|
988
|
+
data?: Partial<TData>;
|
|
989
|
+
history?: Event[];
|
|
990
|
+
signal?: AbortSignal;
|
|
991
|
+
route?: Route<TContext, TData>;
|
|
992
|
+
step?: Step<TContext, TData>;
|
|
993
|
+
}): AsyncGenerator<ToolExecutionUpdate<TData>> {
|
|
994
|
+
const { toolCalls, context, data, history, signal, route, step } = params;
|
|
995
|
+
|
|
996
|
+
if (toolCalls.length === 0) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// Build a ToolContext for the executor
|
|
1001
|
+
const toolContext: ToolContext<TContext, TData> = {
|
|
1002
|
+
context,
|
|
1003
|
+
data: data || {} as Partial<TData>,
|
|
1004
|
+
history: history || [],
|
|
1005
|
+
step: step ? { id: step.id, routeId: route?.id || '' } : undefined,
|
|
1006
|
+
updateContext: (updates: Partial<TContext>): Promise<void> => {
|
|
1007
|
+
Object.assign(context as Record<string, unknown>, updates);
|
|
1008
|
+
return Promise.resolve();
|
|
1009
|
+
},
|
|
1010
|
+
updateData: (updates: Partial<TData>): Promise<void> => {
|
|
1011
|
+
if (data) {
|
|
1012
|
+
Object.assign(data as Record<string, unknown>, updates);
|
|
1013
|
+
}
|
|
1014
|
+
return Promise.resolve();
|
|
1015
|
+
},
|
|
1016
|
+
getField: <K extends keyof TData>(key: K): TData[K] | undefined => {
|
|
1017
|
+
return data?.[key];
|
|
1018
|
+
},
|
|
1019
|
+
setField: <K extends keyof TData>(key: K, value: TData[K]): Promise<void> => {
|
|
1020
|
+
if (data) {
|
|
1021
|
+
(data as TData)[key] = value;
|
|
1022
|
+
}
|
|
1023
|
+
return Promise.resolve();
|
|
1024
|
+
},
|
|
1025
|
+
hasField: <K extends keyof TData>(key: K): boolean => {
|
|
1026
|
+
return data != null && key in (data as Record<string, unknown>);
|
|
1027
|
+
},
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
const executor = new StreamingToolExecutor<TContext, TData>(toolContext, {
|
|
1031
|
+
signal,
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
// Resolve and queue each tool call
|
|
1035
|
+
for (const toolCall of toolCalls) {
|
|
1036
|
+
const tool = this.find(toolCall.toolName, undefined, step, route);
|
|
1037
|
+
if (!tool) {
|
|
1038
|
+
logger.warn(`[ToolManager] Tool not found for concurrent execution: ${toolCall.toolName}`);
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
// Cast to EnhancedTool — plain Tools are compatible (defaults apply)
|
|
1042
|
+
executor.addTool(toolCall, tool as EnhancedTool<TContext, TData>);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// Yield all results in order
|
|
1046
|
+
yield* executor.getRemainingResults();
|
|
1047
|
+
}
|
|
1048
|
+
|
|
939
1049
|
/**
|
|
940
1050
|
* Create a data enrichment tool that modifies collected data
|
|
941
1051
|
* Returns a tool instance that can be registered or added to scope
|
|
@@ -945,7 +1055,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
945
1055
|
): Tool<TContext, TData, void> {
|
|
946
1056
|
// Validate configuration first
|
|
947
1057
|
this.validateDataEnrichmentConfig(config);
|
|
948
|
-
|
|
1058
|
+
|
|
949
1059
|
const tool: Tool<TContext, TData, void> = {
|
|
950
1060
|
id: config.id,
|
|
951
1061
|
name: config.name || `Data Enrichment: ${config.id}`,
|
|
@@ -982,7 +1092,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
982
1092
|
}
|
|
983
1093
|
|
|
984
1094
|
logger.debug(`[ToolManager] Data enrichment completed for tool: ${config.id}`);
|
|
985
|
-
|
|
1095
|
+
|
|
986
1096
|
return {
|
|
987
1097
|
success: true,
|
|
988
1098
|
dataUpdate: enrichedData
|
|
@@ -1012,7 +1122,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1012
1122
|
): Tool<TContext, TData, ValidationResult> {
|
|
1013
1123
|
// Validate configuration first
|
|
1014
1124
|
this.validateValidationConfig(config);
|
|
1015
|
-
|
|
1125
|
+
|
|
1016
1126
|
const tool: Tool<TContext, TData, ValidationResult> = {
|
|
1017
1127
|
id: config.id,
|
|
1018
1128
|
name: config.name || `Validation: ${config.id}`,
|
|
@@ -1048,7 +1158,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1048
1158
|
} catch (error) {
|
|
1049
1159
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1050
1160
|
logger.error(`[ToolManager] Validation failed for ${config.id}: ${errorMessage}`);
|
|
1051
|
-
|
|
1161
|
+
|
|
1052
1162
|
// Return validation failure result instead of throwing
|
|
1053
1163
|
return {
|
|
1054
1164
|
valid: false,
|
|
@@ -1076,7 +1186,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1076
1186
|
): Tool<TContext, TData, TResult> {
|
|
1077
1187
|
// Validate configuration first
|
|
1078
1188
|
this.validateApiCallConfig(config);
|
|
1079
|
-
|
|
1189
|
+
|
|
1080
1190
|
const tool: Tool<TContext, TData, TResult> = {
|
|
1081
1191
|
id: config.id,
|
|
1082
1192
|
name: config.name || `API Call: ${config.id}`,
|
|
@@ -1098,7 +1208,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1098
1208
|
handler: async (context: ToolContext<TContext, TData>, args?: Record<string, unknown>): Promise<TResult> => {
|
|
1099
1209
|
try {
|
|
1100
1210
|
// Resolve endpoint URL
|
|
1101
|
-
const endpoint = typeof config.endpoint === 'function'
|
|
1211
|
+
const endpoint = typeof config.endpoint === 'function'
|
|
1102
1212
|
? config.endpoint(context.context, context.data)
|
|
1103
1213
|
: config.endpoint;
|
|
1104
1214
|
|
|
@@ -1124,7 +1234,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1124
1234
|
|
|
1125
1235
|
// Make the API call
|
|
1126
1236
|
const response = await fetch(endpoint, requestOptions);
|
|
1127
|
-
|
|
1237
|
+
|
|
1128
1238
|
if (!response.ok) {
|
|
1129
1239
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1130
1240
|
}
|
|
@@ -1146,7 +1256,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1146
1256
|
} catch (error) {
|
|
1147
1257
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1148
1258
|
logger.error(`[ToolManager] API call failed for ${config.id}: ${errorMessage}`);
|
|
1149
|
-
|
|
1259
|
+
|
|
1150
1260
|
throw new ToolExecutionError(
|
|
1151
1261
|
`API call failed: ${errorMessage}`,
|
|
1152
1262
|
config.id,
|
|
@@ -1169,7 +1279,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1169
1279
|
): Tool<TContext, TData, TResult> {
|
|
1170
1280
|
// Validate configuration first
|
|
1171
1281
|
this.validateComputationConfig(config);
|
|
1172
|
-
|
|
1282
|
+
|
|
1173
1283
|
const tool: Tool<TContext, TData, TResult> = {
|
|
1174
1284
|
id: config.id,
|
|
1175
1285
|
name: config.name || `Computation: ${config.id}`,
|
|
@@ -1205,7 +1315,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1205
1315
|
} catch (error) {
|
|
1206
1316
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1207
1317
|
logger.error(`[ToolManager] Computation failed for ${config.id}: ${errorMessage}`);
|
|
1208
|
-
|
|
1318
|
+
|
|
1209
1319
|
throw new ToolExecutionError(
|
|
1210
1320
|
`Computation failed: ${errorMessage}`,
|
|
1211
1321
|
config.id,
|
|
@@ -1229,36 +1339,36 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1229
1339
|
metadata?: Record<string, unknown>;
|
|
1230
1340
|
} {
|
|
1231
1341
|
const tool = this.find(toolId, scope, step, route);
|
|
1232
|
-
|
|
1342
|
+
|
|
1233
1343
|
if (!tool) {
|
|
1234
1344
|
return { found: false };
|
|
1235
1345
|
}
|
|
1236
1346
|
|
|
1237
1347
|
// Determine which scope the tool was found in
|
|
1238
1348
|
let foundScope = 'unknown';
|
|
1239
|
-
|
|
1349
|
+
|
|
1240
1350
|
// Check step scope
|
|
1241
1351
|
if (step?.tools) {
|
|
1242
|
-
const stepTool = step.tools.find((t) =>
|
|
1243
|
-
(typeof t === 'string' && t === toolId) ||
|
|
1352
|
+
const stepTool = step.tools.find((t) =>
|
|
1353
|
+
(typeof t === 'string' && t === toolId) ||
|
|
1244
1354
|
(typeof t === 'object' && (t.id === toolId || t.name === toolId))
|
|
1245
1355
|
);
|
|
1246
1356
|
if (stepTool) foundScope = 'step';
|
|
1247
1357
|
}
|
|
1248
|
-
|
|
1358
|
+
|
|
1249
1359
|
// Check route scope
|
|
1250
1360
|
if (foundScope === 'unknown' && route?.tools) {
|
|
1251
1361
|
const routeTool = route.tools.find((t) => t.id === toolId || t.name === toolId);
|
|
1252
1362
|
if (routeTool) foundScope = 'route';
|
|
1253
1363
|
}
|
|
1254
|
-
|
|
1364
|
+
|
|
1255
1365
|
// Check agent scope
|
|
1256
1366
|
if (foundScope === 'unknown' && this.agent) {
|
|
1257
1367
|
const agentTools = this.agent.getTools();
|
|
1258
1368
|
const agentTool = agentTools.find((t) => t.id === toolId || t.name === toolId);
|
|
1259
1369
|
if (agentTool) foundScope = 'agent';
|
|
1260
1370
|
}
|
|
1261
|
-
|
|
1371
|
+
|
|
1262
1372
|
// Check registry
|
|
1263
1373
|
if (foundScope === 'unknown' && this.toolRegistry.has(toolId)) {
|
|
1264
1374
|
foundScope = 'registry';
|
|
@@ -1293,7 +1403,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1293
1403
|
|
|
1294
1404
|
for (const toolId of toolIds) {
|
|
1295
1405
|
const info = this.getToolInfo(toolId, ToolScope.ALL, step, route);
|
|
1296
|
-
|
|
1406
|
+
|
|
1297
1407
|
if (info.found) {
|
|
1298
1408
|
found.push(toolId);
|
|
1299
1409
|
details.push({ id: toolId, found: true, scope: info.scope });
|
|
@@ -1324,10 +1434,10 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1324
1434
|
const registeredToolIds = Array.from(this.toolRegistry.keys());
|
|
1325
1435
|
const agentTools = this.agent ? this.agent.getTools() : [];
|
|
1326
1436
|
const agentToolIds = agentTools.map((t) => t.id);
|
|
1327
|
-
|
|
1437
|
+
|
|
1328
1438
|
// Find duplicate IDs between registry and agent
|
|
1329
1439
|
const duplicateIds = registeredToolIds.filter(id => agentToolIds.includes(id));
|
|
1330
|
-
|
|
1440
|
+
|
|
1331
1441
|
const allAvailable = this.getAvailable();
|
|
1332
1442
|
|
|
1333
1443
|
return {
|
|
@@ -1368,7 +1478,7 @@ export class ToolManager<TContext = unknown, TData = unknown> {
|
|
|
1368
1478
|
if (!tool.handler || typeof tool.handler !== 'function') {
|
|
1369
1479
|
issues.push(`Tool '${id}' has invalid or missing handler`);
|
|
1370
1480
|
}
|
|
1371
|
-
|
|
1481
|
+
|
|
1372
1482
|
if (!tool.id || tool.id.trim() === '') {
|
|
1373
1483
|
issues.push(`Tool has empty or invalid ID: ${JSON.stringify(tool)}`);
|
|
1374
1484
|
}
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,10 @@ export { SessionManager } from "./core/SessionManager";
|
|
|
21
21
|
export { ToolManager, ToolCreationError, ToolExecutionError } from "./core/ToolManager";
|
|
22
22
|
export { BatchExecutor, needsInput, type NeedsInputStep, type DetermineBatchParams } from "./core/BatchExecutor";
|
|
23
23
|
export { BatchPromptBuilder, type BuildBatchPromptParams, type BatchPromptResult } from "./core/BatchPromptBuilder";
|
|
24
|
+
export { CompactionEngine } from "./core/CompactionEngine";
|
|
25
|
+
export { StreamingToolExecutor } from "./core/StreamingToolExecutor";
|
|
26
|
+
export { PromptSectionCache } from "./core/PromptSectionCache";
|
|
27
|
+
export type { PromptSectionType, PromptCacheConfig, SectionCompute } from "./core/PromptSectionCache";
|
|
24
28
|
|
|
25
29
|
// Providers
|
|
26
30
|
export { GeminiProvider } from "./providers/GeminiProvider";
|
|
@@ -94,6 +98,7 @@ export {
|
|
|
94
98
|
// Types
|
|
95
99
|
export type {
|
|
96
100
|
AgentOptions,
|
|
101
|
+
AgentCompactionConfig,
|
|
97
102
|
AgentResponse,
|
|
98
103
|
Term,
|
|
99
104
|
Guideline,
|
|
@@ -119,6 +124,15 @@ export type {
|
|
|
119
124
|
ToolHandler,
|
|
120
125
|
Tool,
|
|
121
126
|
|
|
127
|
+
EnhancedTool,
|
|
128
|
+
ToolValidationResult,
|
|
129
|
+
ToolPermissionResult,
|
|
130
|
+
ToolCallRequest,
|
|
131
|
+
ToolExecutionUpdate,
|
|
132
|
+
|
|
133
|
+
CompactionOptions,
|
|
134
|
+
CompactionResult,
|
|
135
|
+
|
|
122
136
|
DataEnrichmentConfig,
|
|
123
137
|
ValidationConfig,
|
|
124
138
|
ValidationError,
|
|
@@ -199,8 +199,7 @@ export class AnthropicProvider implements AiProvider {
|
|
|
199
199
|
for (let i = 0; i < this.backupModels.length; i++) {
|
|
200
200
|
const backupModel = this.backupModels[i];
|
|
201
201
|
logger.debug(
|
|
202
|
-
`[ANTHROPIC] Trying backup model ${i + 1}/${
|
|
203
|
-
this.backupModels.length
|
|
202
|
+
`[ANTHROPIC] Trying backup model ${i + 1}/${this.backupModels.length
|
|
204
203
|
}: ${backupModel}`
|
|
205
204
|
);
|
|
206
205
|
|
|
@@ -299,10 +298,6 @@ export class AnthropicProvider implements AiProvider {
|
|
|
299
298
|
);
|
|
300
299
|
const message = textContent?.type === "text" ? textContent.text : "";
|
|
301
300
|
|
|
302
|
-
if (!message) {
|
|
303
|
-
throw new Error("No response from Anthropic");
|
|
304
|
-
}
|
|
305
|
-
|
|
306
301
|
// Extract tool calls from response
|
|
307
302
|
const toolCalls: Array<{
|
|
308
303
|
toolName: string;
|
|
@@ -319,6 +314,11 @@ export class AnthropicProvider implements AiProvider {
|
|
|
319
314
|
}
|
|
320
315
|
}
|
|
321
316
|
|
|
317
|
+
// Only throw error if we have no text AND no function calls
|
|
318
|
+
if (!message && toolCalls.length === 0) {
|
|
319
|
+
throw new Error("No response from Anthropic");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
322
|
// Parse JSON response if schema was provided
|
|
323
323
|
let structured: AgentStructuredResponse | undefined;
|
|
324
324
|
if (input.parameters?.jsonSchema) {
|
|
@@ -333,9 +333,9 @@ export class AnthropicProvider implements AiProvider {
|
|
|
333
333
|
// If tools were used, include them in structured response
|
|
334
334
|
if (toolCalls.length > 0) {
|
|
335
335
|
structured = {
|
|
336
|
-
|
|
336
|
+
...(structured || {}),
|
|
337
|
+
message: structured?.message || message,
|
|
337
338
|
toolCalls,
|
|
338
|
-
...structured,
|
|
339
339
|
} as AgentStructuredResponse;
|
|
340
340
|
}
|
|
341
341
|
|
|
@@ -390,8 +390,7 @@ export class AnthropicProvider implements AiProvider {
|
|
|
390
390
|
for (let i = 0; i < this.backupModels.length; i++) {
|
|
391
391
|
const backupModel = this.backupModels[i];
|
|
392
392
|
logger.debug(
|
|
393
|
-
`[ANTHROPIC] Trying backup model ${i + 1}/${
|
|
394
|
-
this.backupModels.length
|
|
393
|
+
`[ANTHROPIC] Trying backup model ${i + 1}/${this.backupModels.length
|
|
395
394
|
}: ${backupModel}`
|
|
396
395
|
);
|
|
397
396
|
|
|
@@ -536,9 +535,9 @@ export class AnthropicProvider implements AiProvider {
|
|
|
536
535
|
// If tools were used, include them in structured response
|
|
537
536
|
if (toolCalls.length > 0) {
|
|
538
537
|
structured = {
|
|
539
|
-
|
|
538
|
+
...(structured || {}),
|
|
539
|
+
message: structured?.message || accumulated,
|
|
540
540
|
toolCalls,
|
|
541
|
-
...structured,
|
|
542
541
|
} as AgentStructuredResponse;
|
|
543
542
|
}
|
|
544
543
|
|