@agentfield/sdk 0.1.45 → 0.1.46-rc.2
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/dist/index.d.ts +104 -2
- package/dist/index.js +352 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import http from 'node:http';
|
|
3
|
+
import * as _ai_sdk_provider from '@ai-sdk/provider';
|
|
3
4
|
import { z } from 'zod';
|
|
5
|
+
import { ToolSet } from 'ai';
|
|
4
6
|
|
|
5
7
|
type ZodSchema<T> = z.Schema<T, z.ZodTypeDef, any>;
|
|
6
8
|
interface AIRequestOptions {
|
|
@@ -34,6 +36,11 @@ declare class AIClient {
|
|
|
34
36
|
stream(prompt: string, options?: AIRequestOptions): Promise<AIStream>;
|
|
35
37
|
embed(value: string, options?: AIEmbeddingOptions): Promise<number[]>;
|
|
36
38
|
embedMany(values: string[], options?: AIEmbeddingOptions): Promise<number[][]>;
|
|
39
|
+
/**
|
|
40
|
+
* Build and return the AI model instance for a given set of options.
|
|
41
|
+
* Exposed for use by the tool-calling loop.
|
|
42
|
+
*/
|
|
43
|
+
getModel(options?: AIRequestOptions): _ai_sdk_provider.LanguageModelV2;
|
|
37
44
|
private buildModel;
|
|
38
45
|
private buildEmbeddingModel;
|
|
39
46
|
private getRateLimiter;
|
|
@@ -415,6 +422,89 @@ declare class DidInterface {
|
|
|
415
422
|
exportAuditTrail(filters?: AuditTrailFilters): Promise<AuditTrailExport>;
|
|
416
423
|
}
|
|
417
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Tool calling support for AgentField agents.
|
|
427
|
+
*
|
|
428
|
+
* Converts discovered capabilities into Vercel AI SDK tool definitions and provides
|
|
429
|
+
* an automatic tool-call execution loop that dispatches calls via agent.call().
|
|
430
|
+
*/
|
|
431
|
+
|
|
432
|
+
interface ToolCallConfig {
|
|
433
|
+
/** Maximum number of LLM turns in the tool-call loop (default: 10). */
|
|
434
|
+
maxTurns?: number;
|
|
435
|
+
/** Maximum total tool calls allowed (default: 25). */
|
|
436
|
+
maxToolCalls?: number;
|
|
437
|
+
/** Maximum candidate tools to present to the LLM. */
|
|
438
|
+
maxCandidateTools?: number;
|
|
439
|
+
/** Maximum tools to hydrate with full schemas (lazy mode). */
|
|
440
|
+
maxHydratedTools?: number;
|
|
441
|
+
/** Schema hydration mode: "eager" includes full schemas, "lazy" sends metadata first. */
|
|
442
|
+
schemaHydration?: 'eager' | 'lazy';
|
|
443
|
+
/** Whether to broaden discovery if no tools match (default: false). */
|
|
444
|
+
fallbackBroadening?: boolean;
|
|
445
|
+
/** Filter by tags during discovery. */
|
|
446
|
+
tags?: string[];
|
|
447
|
+
/** Filter by agent IDs during discovery. */
|
|
448
|
+
agentIds?: string[];
|
|
449
|
+
/** Filter by health status (default: "healthy"). */
|
|
450
|
+
healthStatus?: string;
|
|
451
|
+
}
|
|
452
|
+
interface ToolCallRecord {
|
|
453
|
+
toolName: string;
|
|
454
|
+
arguments: Record<string, any>;
|
|
455
|
+
result?: any;
|
|
456
|
+
error?: string;
|
|
457
|
+
latencyMs: number;
|
|
458
|
+
turn: number;
|
|
459
|
+
}
|
|
460
|
+
interface ToolCallTrace {
|
|
461
|
+
calls: ToolCallRecord[];
|
|
462
|
+
totalTurns: number;
|
|
463
|
+
totalToolCalls: number;
|
|
464
|
+
finalResponse?: string;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Options for tool-calling in ctx.ai().
|
|
468
|
+
*
|
|
469
|
+
* Accepts multiple forms:
|
|
470
|
+
* - "discover": auto-discover all tools from control plane
|
|
471
|
+
* - ToolCallConfig: discover with filtering/progressive options
|
|
472
|
+
* - DiscoveryResult: use pre-fetched discovery results
|
|
473
|
+
* - AgentCapability[]: convert capability list directly
|
|
474
|
+
* - ToolSet: raw Vercel AI SDK tool map
|
|
475
|
+
*/
|
|
476
|
+
type ToolsOption = 'discover' | ToolCallConfig | DiscoveryResult | AgentCapability[] | (ReasonerCapability | SkillCapability)[] | ToolSet;
|
|
477
|
+
interface AIToolRequestOptions extends AIRequestOptions {
|
|
478
|
+
/** Tool definitions for LLM tool calling. */
|
|
479
|
+
tools?: ToolsOption;
|
|
480
|
+
/** Maximum LLM turns in the tool-call loop. */
|
|
481
|
+
maxTurns?: number;
|
|
482
|
+
/** Maximum total tool calls allowed. */
|
|
483
|
+
maxToolCalls?: number;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Convert a single ReasonerCapability or SkillCapability to a Vercel AI SDK tool.
|
|
487
|
+
*/
|
|
488
|
+
declare function capabilityToTool(cap: ReasonerCapability | SkillCapability, agent: Agent): ToolSet[string];
|
|
489
|
+
/**
|
|
490
|
+
* Convert a single capability to a metadata-only tool (no full schema).
|
|
491
|
+
* Used for progressive/lazy discovery.
|
|
492
|
+
*/
|
|
493
|
+
declare function capabilityToMetadataTool(cap: ReasonerCapability | SkillCapability, agent: Agent): ToolSet[string];
|
|
494
|
+
/**
|
|
495
|
+
* Convert a list of capabilities into a Vercel AI SDK tool map.
|
|
496
|
+
*/
|
|
497
|
+
declare function capabilitiesToTools(capabilities: (AgentCapability | ReasonerCapability | SkillCapability)[], agent: Agent, metadataOnly?: boolean): ToolSet;
|
|
498
|
+
declare function buildToolConfig(toolsParam: ToolsOption, agent: Agent): Promise<{
|
|
499
|
+
tools: ToolSet;
|
|
500
|
+
config: ToolCallConfig;
|
|
501
|
+
needsLazyHydration: boolean;
|
|
502
|
+
}>;
|
|
503
|
+
declare function executeToolCallLoop(agent: Agent, prompt: string, toolMap: ToolSet, config: ToolCallConfig, needsLazyHydration: boolean, buildModel: () => any, options?: AIRequestOptions): Promise<{
|
|
504
|
+
text: string;
|
|
505
|
+
trace: ToolCallTrace;
|
|
506
|
+
}>;
|
|
507
|
+
|
|
418
508
|
declare class ReasonerContext<TInput = any> {
|
|
419
509
|
readonly input: TInput;
|
|
420
510
|
readonly executionId: string;
|
|
@@ -455,7 +545,19 @@ declare class ReasonerContext<TInput = any> {
|
|
|
455
545
|
ai<T>(prompt: string, options: AIRequestOptions & {
|
|
456
546
|
schema: ZodSchema<T>;
|
|
457
547
|
}): Promise<T>;
|
|
458
|
-
ai(prompt: string, options?:
|
|
548
|
+
ai(prompt: string, options?: AIToolRequestOptions): Promise<string>;
|
|
549
|
+
/**
|
|
550
|
+
* AI call with automatic tool calling via discover -> ai -> call loop.
|
|
551
|
+
*
|
|
552
|
+
* Discovers available capabilities, presents them as tools to the LLM,
|
|
553
|
+
* dispatches tool calls via agent.call(), and iterates until a final response.
|
|
554
|
+
*
|
|
555
|
+
* @returns Object with `text` (final response) and `trace` (observability data).
|
|
556
|
+
*/
|
|
557
|
+
aiWithTools(prompt: string, options?: AIToolRequestOptions): Promise<{
|
|
558
|
+
text: string;
|
|
559
|
+
trace: ToolCallTrace;
|
|
560
|
+
}>;
|
|
459
561
|
aiStream(prompt: string, options?: AIRequestOptions): Promise<AIStream>;
|
|
460
562
|
call(target: string, input: any): Promise<any>;
|
|
461
563
|
discover(options?: DiscoveryOptions): Promise<DiscoveryResult>;
|
|
@@ -1186,4 +1288,4 @@ declare class ApprovalClient {
|
|
|
1186
1288
|
waitForApproval(executionId: string, opts?: WaitForApprovalOptions): Promise<ApprovalStatusResponse>;
|
|
1187
1289
|
}
|
|
1188
1290
|
|
|
1189
|
-
export { ACTIVE_STATUSES, AIClient, type AIConfig, type AIEmbeddingOptions, type AIRequestOptions, type AIStream, Agent, type AgentCapability, type AgentConfig, type AgentHandler, AgentRouter, type AgentRouterOptions, type AgentState, ApprovalClient, type ApprovalRequestResponse, type ApprovalStatusResponse, type AuditTrailExport, type AuditTrailFilters, type Awaitable, CANONICAL_STATUSES, type CompactCapability, type CompactDiscoveryResponse, DIDAuthenticator, type DIDIdentity, type DIDIdentityPackage, type DIDRegistrationRequest, type DIDRegistrationResponse, type DeploymentType, DidClient, DidInterface, DidManager, type DiscoveryFormat, type DiscoveryOptions, type DiscoveryPagination, type DiscoveryResponse, type DiscoveryResult, ExecutionContext, type ExecutionCredential, type ExecutionMetadata, ExecutionStatus, type ExecutionStatusValue, type GenerateCredentialOptions, type GenerateCredentialParams, HEADER_CALLER_DID, HEADER_DID_NONCE, HEADER_DID_SIGNATURE, HEADER_DID_TIMESTAMP, type HarnessConfig, type HarnessOptions, type HarnessProvider, type HarnessResult, HarnessRunner, type HealthStatus, MCPClient, MCPClientRegistry, type MCPConfig, type MCPHealthSummary, type MCPServerConfig, type MCPTool, MCPToolRegistrar, type MCPToolRegistrarOptions, type MCPToolRegistration, type MemoryChangeEvent, MemoryClient, type MemoryConfig, MemoryEventClient, type MemoryEventHandler, MemoryInterface, type MemoryRequestMetadata, type MemoryRequestOptions, type MemoryScope, type MemoryWatchHandler, type Metrics, RateLimitError, type RateLimiterOptions, type RawResult, type ReasonerCapability, ReasonerContext, type ReasonerDefinition, type ReasonerHandler, type ReasonerOptions, type RequestApprovalPayload, SUPPORTED_PROVIDERS, type ServerlessAdapter, type ServerlessEvent, type ServerlessResponse, type SkillCapability, SkillContext, type SkillDefinition, type SkillHandler, type SkillOptions, StatelessRateLimiter, TERMINAL_STATUSES, type VectorSearchOptions, type VectorSearchResult, type WaitForApprovalOptions, type WorkflowCredential, type WorkflowMetadata, type WorkflowProgressOptions, WorkflowReporter, type ZodSchema, buildProvider, createHarnessResult, createMetrics, createRawResult, getCurrentContext, getCurrentSkillContext, isActive, isTerminal, normalizeStatus };
|
|
1291
|
+
export { ACTIVE_STATUSES, AIClient, type AIConfig, type AIEmbeddingOptions, type AIRequestOptions, type AIStream, type AIToolRequestOptions, Agent, type AgentCapability, type AgentConfig, type AgentHandler, AgentRouter, type AgentRouterOptions, type AgentState, ApprovalClient, type ApprovalRequestResponse, type ApprovalStatusResponse, type AuditTrailExport, type AuditTrailFilters, type Awaitable, CANONICAL_STATUSES, type CompactCapability, type CompactDiscoveryResponse, DIDAuthenticator, type DIDIdentity, type DIDIdentityPackage, type DIDRegistrationRequest, type DIDRegistrationResponse, type DeploymentType, DidClient, DidInterface, DidManager, type DiscoveryFormat, type DiscoveryOptions, type DiscoveryPagination, type DiscoveryResponse, type DiscoveryResult, ExecutionContext, type ExecutionCredential, type ExecutionMetadata, ExecutionStatus, type ExecutionStatusValue, type GenerateCredentialOptions, type GenerateCredentialParams, HEADER_CALLER_DID, HEADER_DID_NONCE, HEADER_DID_SIGNATURE, HEADER_DID_TIMESTAMP, type HarnessConfig, type HarnessOptions, type HarnessProvider, type HarnessResult, HarnessRunner, type HealthStatus, MCPClient, MCPClientRegistry, type MCPConfig, type MCPHealthSummary, type MCPServerConfig, type MCPTool, MCPToolRegistrar, type MCPToolRegistrarOptions, type MCPToolRegistration, type MemoryChangeEvent, MemoryClient, type MemoryConfig, MemoryEventClient, type MemoryEventHandler, MemoryInterface, type MemoryRequestMetadata, type MemoryRequestOptions, type MemoryScope, type MemoryWatchHandler, type Metrics, RateLimitError, type RateLimiterOptions, type RawResult, type ReasonerCapability, ReasonerContext, type ReasonerDefinition, type ReasonerHandler, type ReasonerOptions, type RequestApprovalPayload, SUPPORTED_PROVIDERS, type ServerlessAdapter, type ServerlessEvent, type ServerlessResponse, type SkillCapability, SkillContext, type SkillDefinition, type SkillHandler, type SkillOptions, StatelessRateLimiter, TERMINAL_STATUSES, type ToolCallConfig, type ToolCallRecord, type ToolCallTrace, type ToolsOption, type VectorSearchOptions, type VectorSearchResult, type WaitForApprovalOptions, type WorkflowCredential, type WorkflowMetadata, type WorkflowProgressOptions, WorkflowReporter, type ZodSchema, buildProvider, buildToolConfig, capabilitiesToTools, capabilityToMetadataTool, capabilityToTool, createHarnessResult, createMetrics, createRawResult, executeToolCallLoop, getCurrentContext, getCurrentSkillContext, isActive, isTerminal, normalizeStatus };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import express from 'express';
|
|
|
6
6
|
import rateLimit from 'express-rate-limit';
|
|
7
7
|
import crypto2, { randomUUID, createHash } from 'crypto';
|
|
8
8
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
9
|
-
import {
|
|
9
|
+
import { tool, jsonSchema, generateText, stepCountIs, generateObject, streamText, embed, embedMany } from 'ai';
|
|
10
10
|
import { createOpenAI } from '@ai-sdk/openai';
|
|
11
11
|
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
12
12
|
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
@@ -99,8 +99,8 @@ function isLargeSchema(schemaJson) {
|
|
|
99
99
|
return estimateTokens(schemaJson) > LARGE_SCHEMA_TOKEN_THRESHOLD;
|
|
100
100
|
}
|
|
101
101
|
function buildPromptSuffix(schema, cwd) {
|
|
102
|
-
const
|
|
103
|
-
const schemaJson = JSON.stringify(
|
|
102
|
+
const jsonSchema2 = schemaToJsonSchema(schema);
|
|
103
|
+
const schemaJson = JSON.stringify(jsonSchema2, null, 2);
|
|
104
104
|
const outputPath = getOutputPath(cwd);
|
|
105
105
|
if (isLargeSchema(schemaJson)) {
|
|
106
106
|
const schemaPath = writeSchemaFile(schemaJson, cwd);
|
|
@@ -883,6 +883,299 @@ var ExecutionContext = class {
|
|
|
883
883
|
return store.getStore();
|
|
884
884
|
}
|
|
885
885
|
};
|
|
886
|
+
var DEFAULT_MAX_TURNS = 10;
|
|
887
|
+
var DEFAULT_MAX_TOOL_CALLS = 25;
|
|
888
|
+
var DEFAULT_HEALTH_STATUS = void 0;
|
|
889
|
+
function invocationTargetToCallTarget(invocationTarget) {
|
|
890
|
+
if (invocationTarget.includes(":skill:")) {
|
|
891
|
+
const parts = invocationTarget.split(":skill:");
|
|
892
|
+
return `${parts[0]}.${parts[1]}`;
|
|
893
|
+
}
|
|
894
|
+
if (invocationTarget.includes(":")) {
|
|
895
|
+
const idx = invocationTarget.indexOf(":");
|
|
896
|
+
return `${invocationTarget.substring(0, idx)}.${invocationTarget.substring(idx + 1)}`;
|
|
897
|
+
}
|
|
898
|
+
return invocationTarget;
|
|
899
|
+
}
|
|
900
|
+
function makeExecute(agent, invocationTarget) {
|
|
901
|
+
const callTarget = invocationTargetToCallTarget(invocationTarget);
|
|
902
|
+
return async (args) => agent.call(callTarget, args);
|
|
903
|
+
}
|
|
904
|
+
function sanitizeToolName(invocationTarget) {
|
|
905
|
+
return invocationTarget.replace(/:/g, "__");
|
|
906
|
+
}
|
|
907
|
+
function unsanitizeToolName(sanitizedName) {
|
|
908
|
+
return sanitizedName.replace(/__/g, ":");
|
|
909
|
+
}
|
|
910
|
+
function capabilityToTool(cap, agent) {
|
|
911
|
+
const rawSchema = cap.inputSchema ?? { type: "object", properties: {} };
|
|
912
|
+
const schema = rawSchema.type ? rawSchema : { type: "object", properties: rawSchema };
|
|
913
|
+
return tool({
|
|
914
|
+
description: cap.description ?? `Call ${cap.invocationTarget}`,
|
|
915
|
+
inputSchema: jsonSchema(schema),
|
|
916
|
+
execute: makeExecute(agent, cap.invocationTarget)
|
|
917
|
+
});
|
|
918
|
+
}
|
|
919
|
+
function capabilityToMetadataTool(cap, agent) {
|
|
920
|
+
return tool({
|
|
921
|
+
description: cap.description ?? `Call ${cap.invocationTarget}`,
|
|
922
|
+
inputSchema: jsonSchema({ type: "object", properties: {} }),
|
|
923
|
+
execute: makeExecute(agent, cap.invocationTarget)
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
function capabilitiesToTools(capabilities, agent, metadataOnly = false) {
|
|
927
|
+
const tools = {};
|
|
928
|
+
const convert = metadataOnly ? capabilityToMetadataTool : capabilityToTool;
|
|
929
|
+
for (const cap of capabilities) {
|
|
930
|
+
if ("reasoners" in cap && "skills" in cap) {
|
|
931
|
+
const agentCap = cap;
|
|
932
|
+
for (const r of agentCap.reasoners) {
|
|
933
|
+
tools[sanitizeToolName(r.invocationTarget)] = convert(r, agent);
|
|
934
|
+
}
|
|
935
|
+
for (const s of agentCap.skills) {
|
|
936
|
+
tools[sanitizeToolName(s.invocationTarget)] = convert(s, agent);
|
|
937
|
+
}
|
|
938
|
+
} else {
|
|
939
|
+
const c = cap;
|
|
940
|
+
tools[sanitizeToolName(c.invocationTarget)] = convert(c, agent);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
return tools;
|
|
944
|
+
}
|
|
945
|
+
function limitToolSet(tools, max) {
|
|
946
|
+
const entries = Object.entries(tools);
|
|
947
|
+
if (entries.length <= max) return tools;
|
|
948
|
+
const limited = {};
|
|
949
|
+
for (let i = 0; i < max; i++) {
|
|
950
|
+
limited[entries[i][0]] = entries[i][1];
|
|
951
|
+
}
|
|
952
|
+
return limited;
|
|
953
|
+
}
|
|
954
|
+
async function discoverTools(agent, config, hydrateSchemas = true) {
|
|
955
|
+
const discoveryOpts = {
|
|
956
|
+
tags: config.tags,
|
|
957
|
+
agentIds: config.agentIds,
|
|
958
|
+
includeInputSchema: hydrateSchemas,
|
|
959
|
+
includeOutputSchema: false,
|
|
960
|
+
includeDescriptions: true,
|
|
961
|
+
healthStatus: config.healthStatus ?? DEFAULT_HEALTH_STATUS
|
|
962
|
+
};
|
|
963
|
+
const result = await agent.discover(discoveryOpts);
|
|
964
|
+
if (!result.json) return { tools: {}, capabilities: [] };
|
|
965
|
+
const caps = result.json.capabilities;
|
|
966
|
+
let tools = capabilitiesToTools(caps, agent, !hydrateSchemas);
|
|
967
|
+
if (config.maxCandidateTools) {
|
|
968
|
+
tools = limitToolSet(tools, config.maxCandidateTools);
|
|
969
|
+
}
|
|
970
|
+
return { tools, capabilities: caps };
|
|
971
|
+
}
|
|
972
|
+
async function hydrateSelectedTools(agent, config, selectedNames) {
|
|
973
|
+
const discoveryOpts = {
|
|
974
|
+
tags: config.tags,
|
|
975
|
+
agentIds: config.agentIds,
|
|
976
|
+
includeInputSchema: true,
|
|
977
|
+
includeOutputSchema: false,
|
|
978
|
+
includeDescriptions: true,
|
|
979
|
+
healthStatus: config.healthStatus ?? DEFAULT_HEALTH_STATUS
|
|
980
|
+
};
|
|
981
|
+
const result = await agent.discover(discoveryOpts);
|
|
982
|
+
if (!result.json) return {};
|
|
983
|
+
const selectedSet = new Set(selectedNames.map(unsanitizeToolName));
|
|
984
|
+
const tools = {};
|
|
985
|
+
for (const cap of result.json.capabilities) {
|
|
986
|
+
for (const r of cap.reasoners) {
|
|
987
|
+
if (selectedSet.has(r.invocationTarget)) {
|
|
988
|
+
tools[sanitizeToolName(r.invocationTarget)] = capabilityToTool(r, agent);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
for (const s of cap.skills) {
|
|
992
|
+
if (selectedSet.has(s.invocationTarget)) {
|
|
993
|
+
tools[sanitizeToolName(s.invocationTarget)] = capabilityToTool(s, agent);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
if (config.maxHydratedTools) {
|
|
998
|
+
return limitToolSet(tools, config.maxHydratedTools);
|
|
999
|
+
}
|
|
1000
|
+
return tools;
|
|
1001
|
+
}
|
|
1002
|
+
function isToolCallConfig(obj) {
|
|
1003
|
+
const keys = [
|
|
1004
|
+
"maxTurns",
|
|
1005
|
+
"maxToolCalls",
|
|
1006
|
+
"tags",
|
|
1007
|
+
"schemaHydration",
|
|
1008
|
+
"agentIds",
|
|
1009
|
+
"healthStatus",
|
|
1010
|
+
"fallbackBroadening",
|
|
1011
|
+
"maxCandidateTools",
|
|
1012
|
+
"maxHydratedTools"
|
|
1013
|
+
];
|
|
1014
|
+
return typeof obj === "object" && !Array.isArray(obj) && keys.some((k) => k in obj);
|
|
1015
|
+
}
|
|
1016
|
+
function isDiscoveryResult(obj) {
|
|
1017
|
+
return typeof obj === "object" && !Array.isArray(obj) && "raw" in obj && "format" in obj;
|
|
1018
|
+
}
|
|
1019
|
+
async function buildToolConfig(toolsParam, agent) {
|
|
1020
|
+
const baseConfig = {
|
|
1021
|
+
maxTurns: DEFAULT_MAX_TURNS,
|
|
1022
|
+
maxToolCalls: DEFAULT_MAX_TOOL_CALLS,
|
|
1023
|
+
schemaHydration: "eager",
|
|
1024
|
+
fallbackBroadening: false,
|
|
1025
|
+
healthStatus: DEFAULT_HEALTH_STATUS
|
|
1026
|
+
};
|
|
1027
|
+
if (toolsParam === "discover") {
|
|
1028
|
+
const { tools } = await discoverTools(agent, baseConfig);
|
|
1029
|
+
return { tools, config: baseConfig, needsLazyHydration: false };
|
|
1030
|
+
}
|
|
1031
|
+
if (isToolCallConfig(toolsParam)) {
|
|
1032
|
+
const config = { ...baseConfig, ...toolsParam };
|
|
1033
|
+
const isLazy = config.schemaHydration === "lazy";
|
|
1034
|
+
const { tools } = await discoverTools(agent, config, !isLazy);
|
|
1035
|
+
return { tools, config, needsLazyHydration: isLazy };
|
|
1036
|
+
}
|
|
1037
|
+
if (isDiscoveryResult(toolsParam)) {
|
|
1038
|
+
if (toolsParam.json) {
|
|
1039
|
+
const tools = capabilitiesToTools(toolsParam.json.capabilities, agent);
|
|
1040
|
+
return { tools, config: baseConfig, needsLazyHydration: false };
|
|
1041
|
+
}
|
|
1042
|
+
return { tools: {}, config: baseConfig, needsLazyHydration: false };
|
|
1043
|
+
}
|
|
1044
|
+
if (Array.isArray(toolsParam)) {
|
|
1045
|
+
const tools = capabilitiesToTools(toolsParam, agent);
|
|
1046
|
+
return { tools, config: baseConfig, needsLazyHydration: false };
|
|
1047
|
+
}
|
|
1048
|
+
if (typeof toolsParam === "object") {
|
|
1049
|
+
return { tools: toolsParam, config: baseConfig, needsLazyHydration: false };
|
|
1050
|
+
}
|
|
1051
|
+
throw new Error(
|
|
1052
|
+
`Invalid tools parameter: expected "discover", ToolCallConfig, DiscoveryResult, capability array, or tool map, got ${typeof toolsParam}`
|
|
1053
|
+
);
|
|
1054
|
+
}
|
|
1055
|
+
function wrapToolsWithObservability(toolMap, agent, trace, maxToolCalls, getCurrentTurn) {
|
|
1056
|
+
let totalCalls = 0;
|
|
1057
|
+
const observableTools = {};
|
|
1058
|
+
for (const [name, t] of Object.entries(toolMap)) {
|
|
1059
|
+
const originalTool = t;
|
|
1060
|
+
observableTools[name] = tool({
|
|
1061
|
+
description: originalTool.description ?? "",
|
|
1062
|
+
inputSchema: originalTool.inputSchema,
|
|
1063
|
+
execute: async (args) => {
|
|
1064
|
+
totalCalls++;
|
|
1065
|
+
trace.totalToolCalls = totalCalls;
|
|
1066
|
+
if (totalCalls > maxToolCalls) {
|
|
1067
|
+
const record2 = {
|
|
1068
|
+
toolName: name,
|
|
1069
|
+
arguments: args,
|
|
1070
|
+
error: "Tool call limit reached",
|
|
1071
|
+
latencyMs: 0,
|
|
1072
|
+
turn: getCurrentTurn()
|
|
1073
|
+
};
|
|
1074
|
+
trace.calls.push(record2);
|
|
1075
|
+
return { error: "Tool call limit reached. Please provide a final response." };
|
|
1076
|
+
}
|
|
1077
|
+
const record = {
|
|
1078
|
+
toolName: name,
|
|
1079
|
+
arguments: args,
|
|
1080
|
+
latencyMs: 0,
|
|
1081
|
+
turn: getCurrentTurn()
|
|
1082
|
+
};
|
|
1083
|
+
const invocationTarget = unsanitizeToolName(name);
|
|
1084
|
+
const callTarget = invocationTargetToCallTarget(invocationTarget);
|
|
1085
|
+
const start = Date.now();
|
|
1086
|
+
try {
|
|
1087
|
+
const result = await agent.call(callTarget, args);
|
|
1088
|
+
record.result = result;
|
|
1089
|
+
record.latencyMs = Date.now() - start;
|
|
1090
|
+
trace.calls.push(record);
|
|
1091
|
+
return result;
|
|
1092
|
+
} catch (err) {
|
|
1093
|
+
record.error = err.message ?? String(err);
|
|
1094
|
+
record.latencyMs = Date.now() - start;
|
|
1095
|
+
trace.calls.push(record);
|
|
1096
|
+
return { error: record.error, tool: name };
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
return { tools: observableTools, getTotalCalls: () => totalCalls };
|
|
1102
|
+
}
|
|
1103
|
+
async function executeToolCallLoop(agent, prompt, toolMap, config, needsLazyHydration, buildModel, options = {}) {
|
|
1104
|
+
const maxTurns = config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
1105
|
+
const maxToolCalls = config.maxToolCalls ?? DEFAULT_MAX_TOOL_CALLS;
|
|
1106
|
+
const trace = {
|
|
1107
|
+
calls: [],
|
|
1108
|
+
totalTurns: 0,
|
|
1109
|
+
totalToolCalls: 0
|
|
1110
|
+
};
|
|
1111
|
+
let activeTools = toolMap;
|
|
1112
|
+
if (needsLazyHydration) {
|
|
1113
|
+
const selectionTools = {};
|
|
1114
|
+
for (const [name, t] of Object.entries(toolMap)) {
|
|
1115
|
+
const orig = t;
|
|
1116
|
+
selectionTools[name] = tool({
|
|
1117
|
+
description: orig.description ?? "",
|
|
1118
|
+
inputSchema: orig.inputSchema
|
|
1119
|
+
// No execute — AI SDK will stop after LLM selects tools
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
const selectionResult = await generateText({
|
|
1123
|
+
model: buildModel(),
|
|
1124
|
+
prompt,
|
|
1125
|
+
system: options.system,
|
|
1126
|
+
temperature: options.temperature,
|
|
1127
|
+
maxOutputTokens: options.maxTokens,
|
|
1128
|
+
tools: selectionTools,
|
|
1129
|
+
stopWhen: stepCountIs(1)
|
|
1130
|
+
// Stop after LLM's first response (tool selection)
|
|
1131
|
+
});
|
|
1132
|
+
const selectedNames = /* @__PURE__ */ new Set();
|
|
1133
|
+
for (const step of selectionResult.steps) {
|
|
1134
|
+
for (const tc of step.toolCalls) {
|
|
1135
|
+
selectedNames.add(tc.toolName);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
if (selectedNames.size > 0) {
|
|
1139
|
+
const hydratedTools = await hydrateSelectedTools(
|
|
1140
|
+
agent,
|
|
1141
|
+
config,
|
|
1142
|
+
Array.from(selectedNames)
|
|
1143
|
+
);
|
|
1144
|
+
if (Object.keys(hydratedTools).length > 0) {
|
|
1145
|
+
activeTools = hydratedTools;
|
|
1146
|
+
}
|
|
1147
|
+
} else {
|
|
1148
|
+
trace.totalTurns = selectionResult.steps.length;
|
|
1149
|
+
trace.finalResponse = selectionResult.text;
|
|
1150
|
+
return { text: selectionResult.text, trace };
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
let currentTurn = 0;
|
|
1154
|
+
const { tools: observableTools } = wrapToolsWithObservability(
|
|
1155
|
+
activeTools,
|
|
1156
|
+
agent,
|
|
1157
|
+
trace,
|
|
1158
|
+
maxToolCalls,
|
|
1159
|
+
() => currentTurn
|
|
1160
|
+
);
|
|
1161
|
+
const model = buildModel();
|
|
1162
|
+
const result = await generateText({
|
|
1163
|
+
model,
|
|
1164
|
+
prompt,
|
|
1165
|
+
system: options.system,
|
|
1166
|
+
temperature: options.temperature,
|
|
1167
|
+
maxOutputTokens: options.maxTokens,
|
|
1168
|
+
tools: observableTools,
|
|
1169
|
+
stopWhen: stepCountIs(maxTurns),
|
|
1170
|
+
onStepFinish: () => {
|
|
1171
|
+
currentTurn++;
|
|
1172
|
+
trace.totalTurns = currentTurn;
|
|
1173
|
+
}
|
|
1174
|
+
});
|
|
1175
|
+
trace.finalResponse = result.text;
|
|
1176
|
+
trace.totalTurns = result.steps.length;
|
|
1177
|
+
return { text: result.text, trace };
|
|
1178
|
+
}
|
|
886
1179
|
|
|
887
1180
|
// src/context/ReasonerContext.ts
|
|
888
1181
|
var ReasonerContext = class {
|
|
@@ -923,8 +1216,37 @@ var ReasonerContext = class {
|
|
|
923
1216
|
this.did = params.did;
|
|
924
1217
|
}
|
|
925
1218
|
ai(prompt, options) {
|
|
1219
|
+
if (options?.tools) {
|
|
1220
|
+
return this.aiWithTools(prompt, options);
|
|
1221
|
+
}
|
|
926
1222
|
return this.aiClient.generate(prompt, options);
|
|
927
1223
|
}
|
|
1224
|
+
/**
|
|
1225
|
+
* AI call with automatic tool calling via discover -> ai -> call loop.
|
|
1226
|
+
*
|
|
1227
|
+
* Discovers available capabilities, presents them as tools to the LLM,
|
|
1228
|
+
* dispatches tool calls via agent.call(), and iterates until a final response.
|
|
1229
|
+
*
|
|
1230
|
+
* @returns Object with `text` (final response) and `trace` (observability data).
|
|
1231
|
+
*/
|
|
1232
|
+
async aiWithTools(prompt, options = {}) {
|
|
1233
|
+
const toolsParam = options.tools ?? "discover";
|
|
1234
|
+
const { tools, config, needsLazyHydration } = await buildToolConfig(toolsParam, this.agent);
|
|
1235
|
+
const mergedConfig = {
|
|
1236
|
+
...config,
|
|
1237
|
+
maxTurns: options.maxTurns ?? config.maxTurns ?? 10,
|
|
1238
|
+
maxToolCalls: options.maxToolCalls ?? config.maxToolCalls ?? 25
|
|
1239
|
+
};
|
|
1240
|
+
return executeToolCallLoop(
|
|
1241
|
+
this.agent,
|
|
1242
|
+
prompt,
|
|
1243
|
+
tools,
|
|
1244
|
+
mergedConfig,
|
|
1245
|
+
needsLazyHydration,
|
|
1246
|
+
() => this.aiClient.getModel(options),
|
|
1247
|
+
options
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
928
1250
|
aiStream(prompt, options) {
|
|
929
1251
|
return this.aiClient.stream(prompt, options);
|
|
930
1252
|
}
|
|
@@ -1288,6 +1610,13 @@ var AIClient = class {
|
|
|
1288
1610
|
);
|
|
1289
1611
|
return result.embeddings;
|
|
1290
1612
|
}
|
|
1613
|
+
/**
|
|
1614
|
+
* Build and return the AI model instance for a given set of options.
|
|
1615
|
+
* Exposed for use by the tool-calling loop.
|
|
1616
|
+
*/
|
|
1617
|
+
getModel(options = {}) {
|
|
1618
|
+
return this.buildModel(options);
|
|
1619
|
+
}
|
|
1291
1620
|
buildModel(options) {
|
|
1292
1621
|
const provider = options.provider ?? this.config.provider ?? "openai";
|
|
1293
1622
|
const modelName = options.model ?? this.config.model ?? "gpt-4o";
|
|
@@ -1346,7 +1675,7 @@ var AIClient = class {
|
|
|
1346
1675
|
apiKey: this.config.apiKey,
|
|
1347
1676
|
baseURL: this.config.baseUrl ?? "https://openrouter.ai/api/v1"
|
|
1348
1677
|
});
|
|
1349
|
-
return openrouter(modelName);
|
|
1678
|
+
return openrouter.chat(modelName);
|
|
1350
1679
|
}
|
|
1351
1680
|
case "ollama": {
|
|
1352
1681
|
const ollama = createOpenAI({
|
|
@@ -1354,7 +1683,7 @@ var AIClient = class {
|
|
|
1354
1683
|
// Ollama doesn't need real key
|
|
1355
1684
|
baseURL: this.config.baseUrl ?? "http://localhost:11434/v1"
|
|
1356
1685
|
});
|
|
1357
|
-
return ollama(modelName);
|
|
1686
|
+
return ollama.chat(modelName);
|
|
1358
1687
|
}
|
|
1359
1688
|
case "openai":
|
|
1360
1689
|
default: {
|
|
@@ -2535,16 +2864,16 @@ function toJsonSchema(schema) {
|
|
|
2535
2864
|
return {};
|
|
2536
2865
|
}
|
|
2537
2866
|
if (isZodSchema(schema)) {
|
|
2538
|
-
const
|
|
2867
|
+
const jsonSchema2 = zodToJsonSchema(schema, {
|
|
2539
2868
|
target: "openApi3",
|
|
2540
2869
|
$refStrategy: "none"
|
|
2541
2870
|
// Inline all definitions instead of using $ref
|
|
2542
2871
|
});
|
|
2543
|
-
if (typeof
|
|
2544
|
-
const { $schema, ...rest } =
|
|
2872
|
+
if (typeof jsonSchema2 === "object" && jsonSchema2 !== null) {
|
|
2873
|
+
const { $schema, ...rest } = jsonSchema2;
|
|
2545
2874
|
return rest;
|
|
2546
2875
|
}
|
|
2547
|
-
return
|
|
2876
|
+
return jsonSchema2;
|
|
2548
2877
|
}
|
|
2549
2878
|
if (typeof schema === "object") {
|
|
2550
2879
|
return schema;
|
|
@@ -2671,11 +3000,11 @@ var MCPClient = class {
|
|
|
2671
3000
|
return this.lastHealthy;
|
|
2672
3001
|
}
|
|
2673
3002
|
normalizeTools(tools) {
|
|
2674
|
-
return (tools ?? []).map((
|
|
2675
|
-
name:
|
|
2676
|
-
description:
|
|
2677
|
-
inputSchema:
|
|
2678
|
-
input_schema:
|
|
3003
|
+
return (tools ?? []).map((tool2) => ({
|
|
3004
|
+
name: tool2?.name ?? "unknown",
|
|
3005
|
+
description: tool2?.description,
|
|
3006
|
+
inputSchema: tool2?.inputSchema ?? tool2?.input_schema,
|
|
3007
|
+
input_schema: tool2?.input_schema
|
|
2679
3008
|
}));
|
|
2680
3009
|
}
|
|
2681
3010
|
};
|
|
@@ -2757,9 +3086,9 @@ var MCPToolRegistrar = class {
|
|
|
2757
3086
|
continue;
|
|
2758
3087
|
}
|
|
2759
3088
|
const tools = await client.listTools();
|
|
2760
|
-
for (const
|
|
2761
|
-
if (!
|
|
2762
|
-
const skillName = this.buildSkillName(client.alias,
|
|
3089
|
+
for (const tool2 of tools) {
|
|
3090
|
+
if (!tool2?.name) continue;
|
|
3091
|
+
const skillName = this.buildSkillName(client.alias, tool2.name);
|
|
2763
3092
|
if (this.registered.has(skillName) || this.agent.skills.get(skillName)) {
|
|
2764
3093
|
continue;
|
|
2765
3094
|
}
|
|
@@ -2767,22 +3096,22 @@ var MCPToolRegistrar = class {
|
|
|
2767
3096
|
skillName,
|
|
2768
3097
|
async (ctx) => {
|
|
2769
3098
|
const args = ctx.input && typeof ctx.input === "object" ? ctx.input : {};
|
|
2770
|
-
const result = await client.callTool(
|
|
3099
|
+
const result = await client.callTool(tool2.name, args);
|
|
2771
3100
|
return {
|
|
2772
3101
|
status: "success",
|
|
2773
3102
|
result,
|
|
2774
3103
|
server: client.alias,
|
|
2775
|
-
tool:
|
|
3104
|
+
tool: tool2.name
|
|
2776
3105
|
};
|
|
2777
3106
|
},
|
|
2778
3107
|
{
|
|
2779
|
-
description:
|
|
2780
|
-
inputSchema:
|
|
3108
|
+
description: tool2.description ?? `MCP tool ${tool2.name} from ${client.alias}`,
|
|
3109
|
+
inputSchema: tool2.inputSchema ?? tool2.input_schema ?? {},
|
|
2781
3110
|
tags: this.buildTags(client.alias)
|
|
2782
3111
|
}
|
|
2783
3112
|
);
|
|
2784
3113
|
this.registered.add(skillName);
|
|
2785
|
-
registrations.push({ server: client.alias, skillName, tool });
|
|
3114
|
+
registrations.push({ server: client.alias, skillName, tool: tool2 });
|
|
2786
3115
|
if (this.devMode) {
|
|
2787
3116
|
console.info(`Registered MCP skill ${skillName}`);
|
|
2788
3117
|
}
|
|
@@ -4202,6 +4531,6 @@ function sleep(ms) {
|
|
|
4202
4531
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4203
4532
|
}
|
|
4204
4533
|
|
|
4205
|
-
export { ACTIVE_STATUSES, AIClient, Agent, AgentRouter, ApprovalClient, CANONICAL_STATUSES, DIDAuthenticator, DidClient, DidInterface, DidManager, ExecutionContext, ExecutionStatus, HEADER_CALLER_DID, HEADER_DID_NONCE, HEADER_DID_SIGNATURE, HEADER_DID_TIMESTAMP, HarnessRunner, MCPClient, MCPClientRegistry, MCPToolRegistrar, MemoryClient, MemoryEventClient, MemoryInterface, RateLimitError, ReasonerContext, SUPPORTED_PROVIDERS, SkillContext, StatelessRateLimiter, TERMINAL_STATUSES, WorkflowReporter, buildProvider, createHarnessResult, createMetrics, createRawResult, getCurrentContext, getCurrentSkillContext, isActive, isTerminal, normalizeStatus };
|
|
4534
|
+
export { ACTIVE_STATUSES, AIClient, Agent, AgentRouter, ApprovalClient, CANONICAL_STATUSES, DIDAuthenticator, DidClient, DidInterface, DidManager, ExecutionContext, ExecutionStatus, HEADER_CALLER_DID, HEADER_DID_NONCE, HEADER_DID_SIGNATURE, HEADER_DID_TIMESTAMP, HarnessRunner, MCPClient, MCPClientRegistry, MCPToolRegistrar, MemoryClient, MemoryEventClient, MemoryInterface, RateLimitError, ReasonerContext, SUPPORTED_PROVIDERS, SkillContext, StatelessRateLimiter, TERMINAL_STATUSES, WorkflowReporter, buildProvider, buildToolConfig, capabilitiesToTools, capabilityToMetadataTool, capabilityToTool, createHarnessResult, createMetrics, createRawResult, executeToolCallLoop, getCurrentContext, getCurrentSkillContext, isActive, isTerminal, normalizeStatus };
|
|
4206
4535
|
//# sourceMappingURL=index.js.map
|
|
4207
4536
|
//# sourceMappingURL=index.js.map
|