@contractspec/lib.ai-agent 2.5.0 → 2.7.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 +33 -2
- package/dist/agent/agent-factory.d.ts +5 -0
- package/dist/agent/agent-factory.js +221 -11
- package/dist/agent/contract-spec-agent.d.ts +8 -0
- package/dist/agent/contract-spec-agent.js +210 -10
- package/dist/agent/index.js +334 -39
- package/dist/agent/json-runner.js +210 -10
- package/dist/agent/unified-agent.d.ts +4 -0
- package/dist/agent/unified-agent.js +334 -39
- package/dist/exporters/claude-agent-exporter.d.ts +1 -0
- package/dist/exporters/claude-agent-exporter.js +11 -1
- package/dist/exporters/index.js +11 -1
- package/dist/exporters/types.d.ts +3 -10
- package/dist/node/agent/agent-factory.js +221 -11
- package/dist/node/agent/contract-spec-agent.js +210 -10
- package/dist/node/agent/index.js +334 -39
- package/dist/node/agent/json-runner.js +210 -10
- package/dist/node/agent/unified-agent.js +334 -39
- package/dist/node/exporters/claude-agent-exporter.js +11 -1
- package/dist/node/exporters/index.js +11 -1
- package/dist/node/providers/claude-agent-sdk/adapter.js +260 -23
- package/dist/node/providers/claude-agent-sdk/index.js +260 -23
- package/dist/node/providers/index.js +260 -23
- package/dist/node/tools/index.js +154 -18
- package/dist/node/tools/mcp-client-helpers.js +106 -0
- package/dist/node/tools/mcp-client.js +155 -18
- package/dist/providers/claude-agent-sdk/adapter.d.ts +4 -0
- package/dist/providers/claude-agent-sdk/adapter.js +260 -23
- package/dist/providers/claude-agent-sdk/index.d.ts +8 -0
- package/dist/providers/claude-agent-sdk/index.js +260 -23
- package/dist/providers/index.js +260 -23
- package/dist/providers/types.d.ts +1 -1
- package/dist/tools/index.js +154 -18
- package/dist/tools/mcp-client-helpers.d.ts +12 -0
- package/dist/tools/mcp-client-helpers.js +106 -0
- package/dist/tools/mcp-client.d.ts +55 -3
- package/dist/tools/mcp-client.js +155 -18
- package/dist/tools/mcp-client.test.d.ts +1 -0
- package/package.json +24 -12
package/dist/node/agent/index.js
CHANGED
|
@@ -2400,6 +2400,171 @@ var init_knowledge_tool = __esm(() => {
|
|
|
2400
2400
|
init_i18n();
|
|
2401
2401
|
});
|
|
2402
2402
|
|
|
2403
|
+
// src/tools/mcp-client-helpers.ts
|
|
2404
|
+
import {
|
|
2405
|
+
Experimental_StdioMCPTransport as StdioClientTransport
|
|
2406
|
+
} from "@ai-sdk/mcp/mcp-stdio";
|
|
2407
|
+
function buildMcpTransport(config) {
|
|
2408
|
+
const transport = resolveTransportType(config);
|
|
2409
|
+
if (transport === "stdio") {
|
|
2410
|
+
const stdioConfig = resolveStdioConfig(config);
|
|
2411
|
+
return new StdioClientTransport(stdioConfig);
|
|
2412
|
+
}
|
|
2413
|
+
const remoteConfig = config;
|
|
2414
|
+
const headers = resolveRemoteHeaders(remoteConfig);
|
|
2415
|
+
const remoteTransport = {
|
|
2416
|
+
type: transport,
|
|
2417
|
+
url: requireNonEmptyString(remoteConfig.url, "url", config.name)
|
|
2418
|
+
};
|
|
2419
|
+
if (headers) {
|
|
2420
|
+
remoteTransport.headers = headers;
|
|
2421
|
+
}
|
|
2422
|
+
if (remoteConfig.authProvider) {
|
|
2423
|
+
remoteTransport.authProvider = remoteConfig.authProvider;
|
|
2424
|
+
}
|
|
2425
|
+
return remoteTransport;
|
|
2426
|
+
}
|
|
2427
|
+
function prefixToolNames(config, tools) {
|
|
2428
|
+
const prefix = config.toolPrefix?.trim();
|
|
2429
|
+
if (!prefix) {
|
|
2430
|
+
return tools;
|
|
2431
|
+
}
|
|
2432
|
+
const prefixedTools = {};
|
|
2433
|
+
for (const [toolName, tool3] of Object.entries(tools)) {
|
|
2434
|
+
prefixedTools[`${prefix}_${toolName}`] = tool3;
|
|
2435
|
+
}
|
|
2436
|
+
return prefixedTools;
|
|
2437
|
+
}
|
|
2438
|
+
function getErrorMessage(error) {
|
|
2439
|
+
if (error instanceof Error) {
|
|
2440
|
+
return error.message;
|
|
2441
|
+
}
|
|
2442
|
+
return String(error);
|
|
2443
|
+
}
|
|
2444
|
+
function resolveTransportType(config) {
|
|
2445
|
+
return config.transport ?? "stdio";
|
|
2446
|
+
}
|
|
2447
|
+
function resolveStdioConfig(config) {
|
|
2448
|
+
const stdioConfig = config;
|
|
2449
|
+
return {
|
|
2450
|
+
command: requireNonEmptyString(stdioConfig.command, "command", config.name),
|
|
2451
|
+
args: stdioConfig.args,
|
|
2452
|
+
env: stdioConfig.env,
|
|
2453
|
+
cwd: stdioConfig.cwd
|
|
2454
|
+
};
|
|
2455
|
+
}
|
|
2456
|
+
function resolveRemoteHeaders(config) {
|
|
2457
|
+
const headers = {
|
|
2458
|
+
...config.headers ?? {}
|
|
2459
|
+
};
|
|
2460
|
+
const accessToken = config.accessToken ?? resolveEnvToken(config.accessTokenEnvVar);
|
|
2461
|
+
if (accessToken && headers.Authorization === undefined) {
|
|
2462
|
+
headers.Authorization = `Bearer ${accessToken}`;
|
|
2463
|
+
}
|
|
2464
|
+
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
2465
|
+
}
|
|
2466
|
+
function resolveEnvToken(envVarName) {
|
|
2467
|
+
if (!envVarName) {
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
const value = process.env[envVarName];
|
|
2471
|
+
if (!value) {
|
|
2472
|
+
return;
|
|
2473
|
+
}
|
|
2474
|
+
const trimmed = value.trim();
|
|
2475
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
2476
|
+
}
|
|
2477
|
+
function requireNonEmptyString(value, field, serverName) {
|
|
2478
|
+
if (!value) {
|
|
2479
|
+
throw new Error(`MCP server "${serverName}" is missing required "${field}".`);
|
|
2480
|
+
}
|
|
2481
|
+
const trimmed = value.trim();
|
|
2482
|
+
if (trimmed.length === 0) {
|
|
2483
|
+
throw new Error(`MCP server "${serverName}" has an empty "${field}".`);
|
|
2484
|
+
}
|
|
2485
|
+
return trimmed;
|
|
2486
|
+
}
|
|
2487
|
+
var init_mcp_client_helpers = () => {};
|
|
2488
|
+
|
|
2489
|
+
// src/tools/mcp-client.ts
|
|
2490
|
+
import {
|
|
2491
|
+
experimental_createMCPClient
|
|
2492
|
+
} from "@ai-sdk/mcp";
|
|
2493
|
+
async function mcpServerToTools(config) {
|
|
2494
|
+
let client = null;
|
|
2495
|
+
try {
|
|
2496
|
+
const transport = buildMcpTransport(config);
|
|
2497
|
+
client = await experimental_createMCPClient({
|
|
2498
|
+
transport,
|
|
2499
|
+
name: config.clientName,
|
|
2500
|
+
version: config.clientVersion
|
|
2501
|
+
});
|
|
2502
|
+
const tools = await client.tools();
|
|
2503
|
+
const prefixedTools = prefixToolNames(config, tools);
|
|
2504
|
+
const connectedClient = client;
|
|
2505
|
+
return {
|
|
2506
|
+
tools: prefixedTools,
|
|
2507
|
+
cleanup: () => connectedClient.close(),
|
|
2508
|
+
serverToolNames: {
|
|
2509
|
+
[config.name]: Object.keys(prefixedTools)
|
|
2510
|
+
}
|
|
2511
|
+
};
|
|
2512
|
+
} catch (error) {
|
|
2513
|
+
if (client) {
|
|
2514
|
+
await client.close().catch(() => {
|
|
2515
|
+
return;
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
throw new Error(`[MCP:${config.name}] Failed to connect tools: ${getErrorMessage(error)}`);
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
async function createMcpToolsets(configs, options = {}) {
|
|
2522
|
+
const connected = [];
|
|
2523
|
+
try {
|
|
2524
|
+
for (const config of configs) {
|
|
2525
|
+
const result = await mcpServerToTools(config);
|
|
2526
|
+
connected.push(result);
|
|
2527
|
+
}
|
|
2528
|
+
} catch (error) {
|
|
2529
|
+
await Promise.allSettled(connected.map((result) => result.cleanup()));
|
|
2530
|
+
throw error;
|
|
2531
|
+
}
|
|
2532
|
+
const combinedTools = {};
|
|
2533
|
+
const serverToolNames = {};
|
|
2534
|
+
const collisionStrategy = options.onNameCollision ?? "overwrite";
|
|
2535
|
+
try {
|
|
2536
|
+
for (const result of connected) {
|
|
2537
|
+
for (const [serverName, toolNames] of Object.entries(result.serverToolNames)) {
|
|
2538
|
+
serverToolNames[serverName] = toolNames;
|
|
2539
|
+
}
|
|
2540
|
+
for (const [toolName, tool3] of Object.entries(result.tools)) {
|
|
2541
|
+
const hasCollision = combinedTools[toolName] !== undefined;
|
|
2542
|
+
if (hasCollision && collisionStrategy === "error") {
|
|
2543
|
+
throw new Error(`Duplicate MCP tool name "${toolName}" detected. Use "toolPrefix" or set onNameCollision to "overwrite".`);
|
|
2544
|
+
}
|
|
2545
|
+
combinedTools[toolName] = tool3;
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
} catch (error) {
|
|
2549
|
+
await Promise.allSettled(connected.map((result) => result.cleanup()));
|
|
2550
|
+
throw error;
|
|
2551
|
+
}
|
|
2552
|
+
return {
|
|
2553
|
+
tools: combinedTools,
|
|
2554
|
+
serverToolNames,
|
|
2555
|
+
cleanup: async () => {
|
|
2556
|
+
const cleanupResults = await Promise.allSettled(connected.map((result) => result.cleanup()));
|
|
2557
|
+
const failures = cleanupResults.filter((result) => result.status === "rejected");
|
|
2558
|
+
if (failures.length > 0) {
|
|
2559
|
+
throw new Error(`Failed to cleanup ${failures.length} MCP client connection(s).`);
|
|
2560
|
+
}
|
|
2561
|
+
}
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2564
|
+
var init_mcp_client = __esm(() => {
|
|
2565
|
+
init_mcp_client_helpers();
|
|
2566
|
+
});
|
|
2567
|
+
|
|
2403
2568
|
// src/knowledge/injector.ts
|
|
2404
2569
|
async function injectStaticKnowledge(instructions, knowledgeRefs, retriever, locale) {
|
|
2405
2570
|
if (!retriever)
|
|
@@ -2909,25 +3074,59 @@ class ContractSpecAgent {
|
|
|
2909
3074
|
tools;
|
|
2910
3075
|
config;
|
|
2911
3076
|
instructions;
|
|
3077
|
+
mcpCleanup;
|
|
2912
3078
|
activeStepContexts = new Map;
|
|
2913
|
-
constructor(config, instructions, tools) {
|
|
3079
|
+
constructor(config, instructions, tools, mcpCleanup) {
|
|
2914
3080
|
this.config = config;
|
|
2915
3081
|
this.spec = config.spec;
|
|
2916
3082
|
this.id = agentKey(config.spec.meta);
|
|
2917
3083
|
this.tools = tools;
|
|
2918
3084
|
this.instructions = instructions;
|
|
3085
|
+
this.mcpCleanup = mcpCleanup;
|
|
2919
3086
|
}
|
|
2920
3087
|
static async create(config) {
|
|
2921
3088
|
const effectiveConfig = config;
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
3089
|
+
let mcpToolset = null;
|
|
3090
|
+
if ((effectiveConfig.mcpServers?.length ?? 0) > 0) {
|
|
3091
|
+
mcpToolset = await createMcpToolsets(effectiveConfig.mcpServers ?? [], {
|
|
3092
|
+
onNameCollision: "error"
|
|
3093
|
+
});
|
|
3094
|
+
}
|
|
3095
|
+
try {
|
|
3096
|
+
const instructions = await injectStaticKnowledge(effectiveConfig.spec.instructions, effectiveConfig.spec.knowledge ?? [], effectiveConfig.knowledgeRetriever);
|
|
3097
|
+
const specTools = specToolsToAISDKTools(effectiveConfig.spec.tools, effectiveConfig.toolHandlers, { agentId: agentKey(effectiveConfig.spec.meta) });
|
|
3098
|
+
const knowledgeTool = effectiveConfig.knowledgeRetriever ? createKnowledgeQueryTool(effectiveConfig.knowledgeRetriever, effectiveConfig.spec.knowledge ?? []) : null;
|
|
3099
|
+
const reservedToolNames = new Set(Object.keys(specTools));
|
|
3100
|
+
if (knowledgeTool) {
|
|
3101
|
+
reservedToolNames.add("query_knowledge");
|
|
3102
|
+
}
|
|
3103
|
+
const conflictingMcpTools = Object.keys(mcpToolset?.tools ?? {}).filter((toolName) => reservedToolNames.has(toolName));
|
|
3104
|
+
if (conflictingMcpTools.length > 0) {
|
|
3105
|
+
throw new Error(`MCP tools conflict with agent tools: ${conflictingMcpTools.join(", ")}. Configure MCP toolPrefix values to avoid collisions.`);
|
|
3106
|
+
}
|
|
3107
|
+
const tools = {
|
|
3108
|
+
...specTools,
|
|
3109
|
+
...knowledgeTool ? { query_knowledge: knowledgeTool } : {},
|
|
3110
|
+
...mcpToolset?.tools ?? {},
|
|
3111
|
+
...effectiveConfig.additionalTools ?? {}
|
|
3112
|
+
};
|
|
3113
|
+
return new ContractSpecAgent(effectiveConfig, instructions, tools, mcpToolset?.cleanup);
|
|
3114
|
+
} catch (error) {
|
|
3115
|
+
if (mcpToolset) {
|
|
3116
|
+
await mcpToolset.cleanup().catch(() => {
|
|
3117
|
+
return;
|
|
3118
|
+
});
|
|
3119
|
+
}
|
|
3120
|
+
throw error;
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
async cleanup() {
|
|
3124
|
+
if (!this.mcpCleanup) {
|
|
3125
|
+
return;
|
|
3126
|
+
}
|
|
3127
|
+
const cleanup = this.mcpCleanup;
|
|
3128
|
+
this.mcpCleanup = undefined;
|
|
3129
|
+
await cleanup();
|
|
2931
3130
|
}
|
|
2932
3131
|
async generate(params) {
|
|
2933
3132
|
const sessionId = params.options?.sessionId ?? generateSessionId();
|
|
@@ -3102,6 +3301,7 @@ var init_contract_spec_agent = __esm(() => {
|
|
|
3102
3301
|
init_spec();
|
|
3103
3302
|
init_tool_adapter();
|
|
3104
3303
|
init_knowledge_tool();
|
|
3304
|
+
init_mcp_client();
|
|
3105
3305
|
init_injector();
|
|
3106
3306
|
init_adapter();
|
|
3107
3307
|
ContractSpecCallOptionsSchema = z3.object({
|
|
@@ -3375,6 +3575,8 @@ function summarizeSession(session) {
|
|
|
3375
3575
|
}
|
|
3376
3576
|
|
|
3377
3577
|
// src/providers/claude-agent-sdk/adapter.ts
|
|
3578
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
3579
|
+
|
|
3378
3580
|
class ClaudeAgentSDKProvider {
|
|
3379
3581
|
name = "claude-agent-sdk";
|
|
3380
3582
|
version = "1.0.0";
|
|
@@ -3407,11 +3609,23 @@ class ClaudeAgentSDKProvider {
|
|
|
3407
3609
|
if (!this.isAvailable()) {
|
|
3408
3610
|
throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.sdkNotConfigured"));
|
|
3409
3611
|
}
|
|
3612
|
+
let mcpToolset = null;
|
|
3410
3613
|
try {
|
|
3411
3614
|
const toolSet = {};
|
|
3412
3615
|
for (const tool3 of spec.tools) {
|
|
3413
3616
|
toolSet[tool3.name] = specToolToExternalTool(tool3);
|
|
3414
3617
|
}
|
|
3618
|
+
if ((this.config.mcpServers?.length ?? 0) > 0) {
|
|
3619
|
+
mcpToolset = await createMcpToolsets(this.config.mcpServers ?? [], {
|
|
3620
|
+
onNameCollision: "error"
|
|
3621
|
+
});
|
|
3622
|
+
for (const [toolName, mcpTool] of Object.entries(mcpToolset.tools)) {
|
|
3623
|
+
if (toolSet[toolName]) {
|
|
3624
|
+
throw new Error(`MCP tool "${toolName}" collides with a ContractSpec tool. Configure MCP toolPrefix values to avoid collisions.`);
|
|
3625
|
+
}
|
|
3626
|
+
toolSet[toolName] = this.mcpToolToExternalTool(toolName, mcpTool);
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3415
3629
|
const instructions = await injectStaticKnowledge(spec.instructions, spec.knowledge ?? [], undefined);
|
|
3416
3630
|
const contextId = `claude-${agentKey(spec.meta)}-${Date.now()}`;
|
|
3417
3631
|
const metadata = {
|
|
@@ -3419,6 +3633,7 @@ class ClaudeAgentSDKProvider {
|
|
|
3419
3633
|
extendedThinkingEnabled: this.config.extendedThinking ?? false,
|
|
3420
3634
|
mcpServerIds: this.config.mcpServers?.map((s) => s.name) ?? []
|
|
3421
3635
|
};
|
|
3636
|
+
const cleanupMcp = mcpToolset?.cleanup;
|
|
3422
3637
|
return {
|
|
3423
3638
|
id: contextId,
|
|
3424
3639
|
spec: {
|
|
@@ -3427,9 +3642,18 @@ class ClaudeAgentSDKProvider {
|
|
|
3427
3642
|
},
|
|
3428
3643
|
tools: toolSet,
|
|
3429
3644
|
metadata,
|
|
3430
|
-
cleanup: async () => {
|
|
3645
|
+
cleanup: async () => {
|
|
3646
|
+
if (cleanupMcp) {
|
|
3647
|
+
await cleanupMcp();
|
|
3648
|
+
}
|
|
3649
|
+
}
|
|
3431
3650
|
};
|
|
3432
3651
|
} catch (error) {
|
|
3652
|
+
if (mcpToolset) {
|
|
3653
|
+
await mcpToolset.cleanup().catch(() => {
|
|
3654
|
+
return;
|
|
3655
|
+
});
|
|
3656
|
+
}
|
|
3433
3657
|
throw new ContextCreationError(this.name, createAgentI18n(this.config.locale).t("error.provider.contextCreation", {
|
|
3434
3658
|
error: error instanceof Error ? error.message : String(error)
|
|
3435
3659
|
}), error instanceof Error ? error : undefined);
|
|
@@ -3444,7 +3668,7 @@ ${params.systemOverride}` : context.spec.instructions;
|
|
|
3444
3668
|
const claudeContext = buildClaudeAgentContext(params.options);
|
|
3445
3669
|
let session = createEmptyClaudeSession();
|
|
3446
3670
|
session = appendUserMessage(session, params.prompt);
|
|
3447
|
-
const claudeTools = this.prepareToolsForSDK(context
|
|
3671
|
+
const claudeTools = this.prepareToolsForSDK(context);
|
|
3448
3672
|
const rawResponse = await sdk.execute({
|
|
3449
3673
|
model: this.config.model,
|
|
3450
3674
|
system: systemPrompt,
|
|
@@ -3500,7 +3724,7 @@ ${params.systemOverride}` : context.spec.instructions;
|
|
|
3500
3724
|
|
|
3501
3725
|
${params.systemOverride}` : context.spec.instructions;
|
|
3502
3726
|
const claudeContext = buildClaudeAgentContext(params.options);
|
|
3503
|
-
const claudeTools = this.prepareToolsForSDK(context
|
|
3727
|
+
const claudeTools = this.prepareToolsForSDK(context);
|
|
3504
3728
|
const stream = await sdk.stream({
|
|
3505
3729
|
model: this.config.model,
|
|
3506
3730
|
system: systemPrompt,
|
|
@@ -3583,30 +3807,77 @@ ${params.systemOverride}` : context.spec.instructions;
|
|
|
3583
3807
|
throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.claudeSdkMissing"));
|
|
3584
3808
|
}
|
|
3585
3809
|
}
|
|
3586
|
-
prepareToolsForSDK(context
|
|
3587
|
-
const
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
if (externalTool
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3810
|
+
prepareToolsForSDK(context) {
|
|
3811
|
+
const i18n = createAgentI18n(this.config.locale);
|
|
3812
|
+
const toolsForSdk = [];
|
|
3813
|
+
for (const [toolName, externalTool] of Object.entries(context.tools)) {
|
|
3814
|
+
if (!externalTool.execute) {
|
|
3815
|
+
continue;
|
|
3816
|
+
}
|
|
3817
|
+
toolsForSdk.push({
|
|
3818
|
+
name: toolName,
|
|
3819
|
+
description: externalTool.description ?? i18n.t("tool.fallbackDescription", { name: toolName }),
|
|
3820
|
+
input_schema: this.normalizeToolSchemaForClaude(externalTool.inputSchema),
|
|
3821
|
+
requires_confirmation: externalTool.requiresApproval,
|
|
3822
|
+
execute: async (input) => {
|
|
3823
|
+
const result = await externalTool.execute?.(input);
|
|
3598
3824
|
return typeof result === "string" ? result : JSON.stringify(result);
|
|
3825
|
+
}
|
|
3826
|
+
});
|
|
3827
|
+
}
|
|
3828
|
+
return toolsForSdk;
|
|
3829
|
+
}
|
|
3830
|
+
mcpToolToExternalTool(toolName, tool3) {
|
|
3831
|
+
return {
|
|
3832
|
+
name: toolName,
|
|
3833
|
+
description: tool3.description ?? createAgentI18n(this.config.locale).t("tool.fallbackDescription", {
|
|
3834
|
+
name: toolName
|
|
3835
|
+
}),
|
|
3836
|
+
inputSchema: this.normalizeExternalInputSchema(tool3.inputSchema),
|
|
3837
|
+
execute: async (input) => {
|
|
3838
|
+
if (!tool3.execute) {
|
|
3839
|
+
throw new Error(createAgentI18n(this.config.locale).t("error.toolNoExecuteHandler", {
|
|
3840
|
+
name: toolName
|
|
3841
|
+
}));
|
|
3842
|
+
}
|
|
3843
|
+
return tool3.execute(input, {
|
|
3844
|
+
toolCallId: `mcp-${randomUUID2()}`,
|
|
3845
|
+
messages: []
|
|
3599
3846
|
});
|
|
3600
3847
|
}
|
|
3848
|
+
};
|
|
3849
|
+
}
|
|
3850
|
+
normalizeExternalInputSchema(schema) {
|
|
3851
|
+
if (this.isRecord(schema)) {
|
|
3852
|
+
const type = schema["type"];
|
|
3853
|
+
if (type === "object" || schema["properties"]) {
|
|
3854
|
+
return schema;
|
|
3855
|
+
}
|
|
3601
3856
|
}
|
|
3602
|
-
return
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3857
|
+
return {
|
|
3858
|
+
type: "object",
|
|
3859
|
+
properties: {}
|
|
3860
|
+
};
|
|
3861
|
+
}
|
|
3862
|
+
normalizeToolSchemaForClaude(schema) {
|
|
3863
|
+
if (schema.type === "object") {
|
|
3864
|
+
return {
|
|
3865
|
+
type: "object",
|
|
3866
|
+
properties: schema.properties,
|
|
3867
|
+
required: schema.required,
|
|
3868
|
+
additionalProperties: schema.additionalProperties
|
|
3869
|
+
};
|
|
3870
|
+
}
|
|
3871
|
+
return {
|
|
3872
|
+
type: "object",
|
|
3873
|
+
properties: {
|
|
3874
|
+
value: schema
|
|
3875
|
+
},
|
|
3876
|
+
required: ["value"]
|
|
3877
|
+
};
|
|
3878
|
+
}
|
|
3879
|
+
isRecord(value) {
|
|
3880
|
+
return typeof value === "object" && value !== null;
|
|
3610
3881
|
}
|
|
3611
3882
|
async executeTool(toolCall, context, _params) {
|
|
3612
3883
|
const tool3 = context.tools[toolCall.toolName];
|
|
@@ -3662,6 +3933,7 @@ var init_adapter2 = __esm(() => {
|
|
|
3662
3933
|
init_types();
|
|
3663
3934
|
init_tool_bridge();
|
|
3664
3935
|
init_injector();
|
|
3936
|
+
init_mcp_client();
|
|
3665
3937
|
init_i18n();
|
|
3666
3938
|
});
|
|
3667
3939
|
|
|
@@ -4409,6 +4681,7 @@ class UnifiedAgent {
|
|
|
4409
4681
|
} catch (error) {
|
|
4410
4682
|
this.state.lastError = error instanceof Error ? error : new Error(String(error));
|
|
4411
4683
|
if (this.config.fallbackBackend && this.config.fallbackBackend !== backend) {
|
|
4684
|
+
await this.cleanupProviderContext();
|
|
4412
4685
|
console.warn(this.i18n().t("log.unifiedAgent.fallback", {
|
|
4413
4686
|
backend: String(backend),
|
|
4414
4687
|
fallback: String(this.config.fallbackBackend)
|
|
@@ -4479,16 +4752,24 @@ class UnifiedAgent {
|
|
|
4479
4752
|
}
|
|
4480
4753
|
async runWithAISDK(message, options) {
|
|
4481
4754
|
const { ContractSpecAgent: ContractSpecAgent2 } = await Promise.resolve().then(() => (init_contract_spec_agent(), exports_contract_spec_agent));
|
|
4755
|
+
const backendConfig = this.getAISDKConfig();
|
|
4482
4756
|
const model = await this.resolveAISDKModel();
|
|
4483
4757
|
const agent = await ContractSpecAgent2.create({
|
|
4484
4758
|
spec: this.spec,
|
|
4485
4759
|
model,
|
|
4486
|
-
toolHandlers: this.tools
|
|
4487
|
-
|
|
4488
|
-
return await agent.generate({
|
|
4489
|
-
prompt: message,
|
|
4490
|
-
options
|
|
4760
|
+
toolHandlers: this.tools,
|
|
4761
|
+
mcpServers: backendConfig?.mcpServers
|
|
4491
4762
|
});
|
|
4763
|
+
try {
|
|
4764
|
+
return await agent.generate({
|
|
4765
|
+
prompt: message,
|
|
4766
|
+
options
|
|
4767
|
+
});
|
|
4768
|
+
} finally {
|
|
4769
|
+
await agent.cleanup().catch(() => {
|
|
4770
|
+
return;
|
|
4771
|
+
});
|
|
4772
|
+
}
|
|
4492
4773
|
}
|
|
4493
4774
|
async runWithExternalProvider(message, options) {
|
|
4494
4775
|
if (!this.provider || !this.context) {
|
|
@@ -4596,6 +4877,7 @@ class UnifiedAgent {
|
|
|
4596
4877
|
if (backend === this.state.backend) {
|
|
4597
4878
|
return;
|
|
4598
4879
|
}
|
|
4880
|
+
await this.cleanupProviderContext();
|
|
4599
4881
|
this.state.backend = backend;
|
|
4600
4882
|
this.state.isReady = false;
|
|
4601
4883
|
this.provider = undefined;
|
|
@@ -4606,8 +4888,20 @@ class UnifiedAgent {
|
|
|
4606
4888
|
this.state.messageCount = 0;
|
|
4607
4889
|
this.state.sessionId = undefined;
|
|
4608
4890
|
this.state.lastError = undefined;
|
|
4891
|
+
this.cleanupProviderContext().catch(() => {
|
|
4892
|
+
return;
|
|
4893
|
+
});
|
|
4609
4894
|
this.context = undefined;
|
|
4610
4895
|
}
|
|
4896
|
+
async cleanupProviderContext() {
|
|
4897
|
+
const context = this.context;
|
|
4898
|
+
this.context = undefined;
|
|
4899
|
+
if (context) {
|
|
4900
|
+
await context.cleanup().catch(() => {
|
|
4901
|
+
return;
|
|
4902
|
+
});
|
|
4903
|
+
}
|
|
4904
|
+
}
|
|
4611
4905
|
addTool(name, handler) {
|
|
4612
4906
|
this.tools.set(name, handler);
|
|
4613
4907
|
}
|
|
@@ -4627,7 +4921,8 @@ function createAISDKAgent(spec, options) {
|
|
|
4627
4921
|
modelInstance: options?.modelInstance,
|
|
4628
4922
|
provider: options?.provider,
|
|
4629
4923
|
temperature: options?.temperature,
|
|
4630
|
-
maxTokens: options?.maxTokens
|
|
4924
|
+
maxTokens: options?.maxTokens,
|
|
4925
|
+
mcpServers: options?.mcpServers
|
|
4631
4926
|
}
|
|
4632
4927
|
});
|
|
4633
4928
|
}
|