@contractspec/lib.ai-agent 3.0.0 → 3.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.
Files changed (56) hide show
  1. package/README.md +14 -2
  2. package/dist/agent/agent-factory.d.ts +3 -0
  3. package/dist/agent/agent-factory.js +209 -27
  4. package/dist/agent/contract-spec-agent.d.ts +3 -0
  5. package/dist/agent/contract-spec-agent.js +207 -26
  6. package/dist/agent/index.js +218 -29
  7. package/dist/agent/json-runner.d.ts +3 -0
  8. package/dist/agent/json-runner.js +214 -28
  9. package/dist/agent/unified-agent.d.ts +3 -0
  10. package/dist/agent/unified-agent.js +211 -27
  11. package/dist/exporters/claude-agent-exporter.js +5 -0
  12. package/dist/exporters/index.js +5 -0
  13. package/dist/exporters/opencode-exporter.js +5 -0
  14. package/dist/index.js +5 -0
  15. package/dist/interop/index.d.ts +1 -0
  16. package/dist/interop/index.js +5 -0
  17. package/dist/interop/runtime-adapters.d.ts +36 -0
  18. package/dist/interop/runtime-adapters.js +1 -0
  19. package/dist/interop/spec-consumer.js +5 -0
  20. package/dist/node/agent/agent-factory.js +209 -27
  21. package/dist/node/agent/contract-spec-agent.js +207 -26
  22. package/dist/node/agent/index.js +218 -29
  23. package/dist/node/agent/json-runner.js +214 -28
  24. package/dist/node/agent/unified-agent.js +211 -27
  25. package/dist/node/exporters/claude-agent-exporter.js +5 -0
  26. package/dist/node/exporters/index.js +5 -0
  27. package/dist/node/exporters/opencode-exporter.js +5 -0
  28. package/dist/node/index.js +5 -0
  29. package/dist/node/interop/index.js +5 -0
  30. package/dist/node/interop/runtime-adapters.js +0 -0
  31. package/dist/node/interop/spec-consumer.js +5 -0
  32. package/dist/node/providers/claude-agent-sdk/adapter.js +5 -0
  33. package/dist/node/providers/claude-agent-sdk/index.js +5 -0
  34. package/dist/node/providers/index.js +5 -0
  35. package/dist/node/providers/opencode-sdk/adapter.js +5 -0
  36. package/dist/node/providers/opencode-sdk/index.js +5 -0
  37. package/dist/node/spec/index.js +5 -0
  38. package/dist/node/spec/spec.js +5 -0
  39. package/dist/node/tools/index.js +86 -10
  40. package/dist/node/tools/tool-adapter.js +86 -10
  41. package/dist/providers/claude-agent-sdk/adapter.js +5 -0
  42. package/dist/providers/claude-agent-sdk/index.js +5 -0
  43. package/dist/providers/index.js +5 -0
  44. package/dist/providers/opencode-sdk/adapter.js +5 -0
  45. package/dist/providers/opencode-sdk/index.js +5 -0
  46. package/dist/spec/index.js +5 -0
  47. package/dist/spec/spec.d.ts +27 -0
  48. package/dist/spec/spec.js +5 -0
  49. package/dist/spec/spec.test.d.ts +1 -0
  50. package/dist/tools/index.js +86 -10
  51. package/dist/tools/mcp-client.d.ts +6 -0
  52. package/dist/tools/mcp-server.d.ts +4 -0
  53. package/dist/tools/tool-adapter.js +86 -10
  54. package/dist/tools/tool-adapter.test.d.ts +1 -0
  55. package/dist/types.d.ts +15 -0
  56. package/package.json +26 -14
@@ -2142,6 +2142,11 @@ function defineAgent(spec) {
2142
2142
  if (!spec.tools?.length) {
2143
2143
  throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
2144
2144
  }
2145
+ for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2146
+ if (portRef !== undefined && portRef.trim().length === 0) {
2147
+ throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
2148
+ }
2149
+ }
2145
2150
  const toolNames = new Set;
2146
2151
  for (const tool of spec.tools) {
2147
2152
  if (toolNames.has(tool.name)) {
@@ -2142,6 +2142,11 @@ function defineAgent(spec) {
2142
2142
  if (!spec.tools?.length) {
2143
2143
  throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
2144
2144
  }
2145
+ for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2146
+ if (portRef !== undefined && portRef.trim().length === 0) {
2147
+ throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
2148
+ }
2149
+ }
2145
2150
  const toolNames = new Set;
2146
2151
  for (const tool of spec.tools) {
2147
2152
  if (toolNames.has(tool.name)) {
@@ -2142,6 +2142,11 @@ function defineAgent(spec) {
2142
2142
  if (!spec.tools?.length) {
2143
2143
  throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
2144
2144
  }
2145
+ for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2146
+ if (portRef !== undefined && portRef.trim().length === 0) {
2147
+ throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
2148
+ }
2149
+ }
2145
2150
  const toolNames = new Set;
2146
2151
  for (const tool of spec.tools) {
2147
2152
  if (toolNames.has(tool.name)) {
package/dist/index.js CHANGED
@@ -2142,6 +2142,11 @@ function defineAgent(spec) {
2142
2142
  if (!spec.tools?.length) {
2143
2143
  throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
2144
2144
  }
2145
+ for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2146
+ if (portRef !== undefined && portRef.trim().length === 0) {
2147
+ throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
2148
+ }
2149
+ }
2145
2150
  const toolNames = new Set;
2146
2151
  for (const tool of spec.tools) {
2147
2152
  if (toolNames.has(tool.name)) {
@@ -43,5 +43,6 @@
43
43
  * ```
44
44
  */
45
45
  export * from './types';
46
+ export * from './runtime-adapters';
46
47
  export { ContractSpecConsumer, createSpecConsumer, createSingleSpecConsumer, } from './spec-consumer';
47
48
  export { ContractSpecToolConsumer, createToolConsumer, createToolServer, exportToolsForExternalSDK, } from './tool-consumer';
@@ -2142,6 +2142,11 @@ function defineAgent(spec) {
2142
2142
  if (!spec.tools?.length) {
2143
2143
  throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
2144
2144
  }
2145
+ for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2146
+ if (portRef !== undefined && portRef.trim().length === 0) {
2147
+ throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
2148
+ }
2149
+ }
2145
2150
  const toolNames = new Set;
2146
2151
  for (const tool of spec.tools) {
2147
2152
  if (toolNames.has(tool.name)) {
@@ -0,0 +1,36 @@
1
+ import type { AgentSessionState } from '../types';
2
+ export type AgentRuntimeAdapterKey = 'langgraph' | 'langchain' | 'workflow-devkit';
3
+ export interface AgentCheckpointEnvelope {
4
+ sessionId: string;
5
+ threadId?: string;
6
+ state: AgentSessionState;
7
+ checkpointId?: string;
8
+ createdAt: Date;
9
+ }
10
+ export interface AgentCheckpointPort {
11
+ save(envelope: AgentCheckpointEnvelope): Promise<void>;
12
+ load(sessionId: string): Promise<AgentCheckpointEnvelope | null>;
13
+ delete(sessionId: string): Promise<void>;
14
+ }
15
+ export interface AgentSuspendResumePort {
16
+ suspend(params: {
17
+ sessionId: string;
18
+ reason: string;
19
+ metadata?: Record<string, string>;
20
+ }): Promise<void>;
21
+ resume(params: {
22
+ sessionId: string;
23
+ input?: string;
24
+ metadata?: Record<string, string>;
25
+ }): Promise<void>;
26
+ }
27
+ export interface AgentRuntimeMiddlewareHooks<TState = unknown> {
28
+ beforeModel?: (state: TState) => Promise<TState | undefined> | TState | undefined;
29
+ afterModel?: (state: TState) => Promise<TState | undefined> | TState | undefined;
30
+ }
31
+ export interface AgentRuntimeAdapterBundle<TState = unknown> {
32
+ key: AgentRuntimeAdapterKey;
33
+ checkpoint?: AgentCheckpointPort;
34
+ suspendResume?: AgentSuspendResumePort;
35
+ middleware?: AgentRuntimeMiddlewareHooks<TState>;
36
+ }
@@ -0,0 +1 @@
1
+ // @bun
@@ -2142,6 +2142,11 @@ function defineAgent(spec) {
2142
2142
  if (!spec.tools?.length) {
2143
2143
  throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
2144
2144
  }
2145
+ for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2146
+ if (portRef !== undefined && portRef.trim().length === 0) {
2147
+ throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
2148
+ }
2149
+ }
2145
2150
  const toolNames = new Set;
2146
2151
  for (const tool of spec.tools) {
2147
2152
  if (toolNames.has(tool.name)) {
@@ -2142,6 +2142,11 @@ function defineAgent(spec) {
2142
2142
  if (!spec.tools?.length) {
2143
2143
  throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
2144
2144
  }
2145
+ for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2146
+ if (portRef !== undefined && portRef.trim().length === 0) {
2147
+ throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
2148
+ }
2149
+ }
2145
2150
  const toolNames = new Set;
2146
2151
  for (const tool of spec.tools) {
2147
2152
  if (toolNames.has(tool.name)) {
@@ -2297,21 +2302,39 @@ var init_json_schema_to_zod = () => {};
2297
2302
  // src/tools/tool-adapter.ts
2298
2303
  import { tool } from "ai";
2299
2304
  function specToolToAISDKTool(specTool, handler, context = {}) {
2305
+ let lastInvocationAt;
2300
2306
  return tool({
2301
2307
  description: specTool.description ?? specTool.name,
2302
2308
  inputSchema: jsonSchemaToZodSafe(specTool.schema),
2303
2309
  needsApproval: specTool.requiresApproval ?? !specTool.automationSafe,
2304
2310
  execute: async (input) => {
2305
- const result = await handler(input, {
2306
- agentId: context.agentId ?? "unknown",
2307
- sessionId: context.sessionId ?? "unknown",
2308
- tenantId: context.tenantId,
2309
- actorId: context.actorId,
2310
- locale: context.locale,
2311
- metadata: context.metadata,
2312
- signal: context.signal
2313
- });
2314
- return typeof result === "string" ? result : JSON.stringify(result);
2311
+ const now = Date.now();
2312
+ const cooldownMs = normalizeDuration(specTool.cooldownMs);
2313
+ if (cooldownMs && lastInvocationAt !== undefined) {
2314
+ const elapsed = now - lastInvocationAt;
2315
+ if (elapsed < cooldownMs) {
2316
+ const retryAfterMs = cooldownMs - elapsed;
2317
+ throw createToolExecutionError(`Tool "${specTool.name}" is cooling down. Retry in ${retryAfterMs}ms.`, "TOOL_COOLDOWN_ACTIVE", retryAfterMs);
2318
+ }
2319
+ }
2320
+ const timeoutMs = normalizeDuration(specTool.timeoutMs);
2321
+ const { signal, dispose } = createTimeoutSignal(context.signal, timeoutMs);
2322
+ try {
2323
+ const execution = handler(input, {
2324
+ agentId: context.agentId ?? "unknown",
2325
+ sessionId: context.sessionId ?? "unknown",
2326
+ tenantId: context.tenantId,
2327
+ actorId: context.actorId,
2328
+ locale: context.locale,
2329
+ metadata: context.metadata,
2330
+ signal
2331
+ });
2332
+ const result = timeoutMs ? await withTimeout(execution, timeoutMs, specTool.name) : await execution;
2333
+ return typeof result === "string" ? result : JSON.stringify(result);
2334
+ } finally {
2335
+ dispose();
2336
+ lastInvocationAt = Date.now();
2337
+ }
2315
2338
  }
2316
2339
  });
2317
2340
  }
@@ -2336,6 +2359,64 @@ function createToolHandler(handler) {
2336
2359
  function buildToolHandlers(handlersObj) {
2337
2360
  return new Map(Object.entries(handlersObj));
2338
2361
  }
2362
+ function normalizeDuration(value) {
2363
+ if (value === undefined) {
2364
+ return;
2365
+ }
2366
+ if (!Number.isFinite(value)) {
2367
+ return;
2368
+ }
2369
+ if (value <= 0) {
2370
+ return;
2371
+ }
2372
+ return Math.round(value);
2373
+ }
2374
+ function withTimeout(execution, timeoutMs, toolName) {
2375
+ return new Promise((resolve, reject) => {
2376
+ const timeoutHandle = setTimeout(() => {
2377
+ reject(createToolExecutionError(`Tool "${toolName}" timed out after ${timeoutMs}ms.`, "TOOL_EXECUTION_TIMEOUT"));
2378
+ }, timeoutMs);
2379
+ execution.then((result) => {
2380
+ clearTimeout(timeoutHandle);
2381
+ resolve(result);
2382
+ }).catch((error) => {
2383
+ clearTimeout(timeoutHandle);
2384
+ reject(error);
2385
+ });
2386
+ });
2387
+ }
2388
+ function createTimeoutSignal(signal, timeoutMs) {
2389
+ const controller = new AbortController;
2390
+ const abortFromSource = () => controller.abort();
2391
+ if (signal) {
2392
+ if (signal.aborted) {
2393
+ controller.abort();
2394
+ } else {
2395
+ signal.addEventListener("abort", abortFromSource);
2396
+ }
2397
+ }
2398
+ const timeoutHandle = timeoutMs !== undefined ? setTimeout(() => {
2399
+ controller.abort();
2400
+ }, timeoutMs) : undefined;
2401
+ return {
2402
+ signal: controller.signal,
2403
+ dispose: () => {
2404
+ if (timeoutHandle !== undefined) {
2405
+ clearTimeout(timeoutHandle);
2406
+ }
2407
+ if (signal) {
2408
+ signal.removeEventListener("abort", abortFromSource);
2409
+ }
2410
+ }
2411
+ };
2412
+ }
2413
+ function createToolExecutionError(message, code, retryAfterMs) {
2414
+ return Object.assign(new Error(message), {
2415
+ code,
2416
+ kind: "retryable",
2417
+ retryAfterMs
2418
+ });
2419
+ }
2339
2420
  var init_tool_adapter = __esm(() => {
2340
2421
  init_json_schema_to_zod();
2341
2422
  init_i18n();
@@ -3151,7 +3232,13 @@ class ContractSpecAgent {
3151
3232
  steps: [],
3152
3233
  metadata: params.options?.metadata
3153
3234
  });
3235
+ } else if (existing.status !== "running") {
3236
+ await this.config.sessionStore.update(sessionId, { status: "running" });
3154
3237
  }
3238
+ await this.config.sessionStore.appendMessage(sessionId, {
3239
+ role: "user",
3240
+ content: params.prompt
3241
+ });
3155
3242
  }
3156
3243
  const prompt = params.systemOverride ? `${this.instructions}
3157
3244
 
@@ -3163,24 +3250,41 @@ ${params.prompt}` : params.prompt;
3163
3250
  traceId,
3164
3251
  options: params.options
3165
3252
  });
3166
- const inner = this.createInnerAgent(model);
3167
- const result = await inner.generate({
3168
- prompt,
3169
- abortSignal: params.signal,
3170
- options: {
3171
- tenantId: params.options?.tenantId,
3172
- actorId: params.options?.actorId,
3173
- sessionId,
3174
- metadata: params.options?.metadata
3253
+ const effectiveMaxSteps = resolveMaxSteps(params.maxSteps, this.spec.maxSteps);
3254
+ const inner = this.createInnerAgent(model, effectiveMaxSteps);
3255
+ let result;
3256
+ try {
3257
+ result = await inner.generate({
3258
+ prompt,
3259
+ abortSignal: params.signal,
3260
+ options: {
3261
+ tenantId: params.options?.tenantId,
3262
+ actorId: params.options?.actorId,
3263
+ sessionId,
3264
+ metadata: params.options?.metadata
3265
+ }
3266
+ });
3267
+ } catch (error) {
3268
+ if (this.config.sessionStore) {
3269
+ await this.config.sessionStore.update(sessionId, {
3270
+ status: "failed"
3271
+ });
3175
3272
  }
3176
- }).finally(() => {
3177
3273
  this.activeStepContexts.delete(sessionId);
3178
- });
3274
+ throw error;
3275
+ }
3276
+ this.activeStepContexts.delete(sessionId);
3277
+ const escalationError = resolveEscalationError(this.spec, result.finishReason);
3179
3278
  if (this.config.sessionStore) {
3279
+ await this.config.sessionStore.appendMessage(sessionId, {
3280
+ role: "assistant",
3281
+ content: result.text
3282
+ });
3180
3283
  await this.config.sessionStore.update(sessionId, {
3181
- status: "completed"
3284
+ status: escalationError ? "escalated" : "completed"
3182
3285
  });
3183
3286
  }
3287
+ const session = this.config.sessionStore ? await this.config.sessionStore.get(sessionId) : null;
3184
3288
  return {
3185
3289
  text: result.text,
3186
3290
  steps: result.steps,
@@ -3197,7 +3301,16 @@ ${params.prompt}` : params.prompt;
3197
3301
  output: tr.output
3198
3302
  })),
3199
3303
  finishReason: result.finishReason,
3200
- usage: result.usage
3304
+ usage: result.usage,
3305
+ session: session ?? undefined,
3306
+ pendingApproval: escalationError ? {
3307
+ toolName: this.spec.policy?.escalation?.approvalWorkflow ?? "approval_required",
3308
+ toolCallId: `approval_${sessionId}`,
3309
+ args: {
3310
+ reason: escalationError.message,
3311
+ code: escalationError.code
3312
+ }
3313
+ } : undefined
3201
3314
  };
3202
3315
  }
3203
3316
  async stream(params) {
@@ -3220,7 +3333,28 @@ ${params.prompt}` : params.prompt;
3220
3333
  traceId,
3221
3334
  options: params.options
3222
3335
  });
3223
- const inner = this.createInnerAgent(model);
3336
+ const effectiveMaxSteps = resolveMaxSteps(params.maxSteps, this.spec.maxSteps);
3337
+ const inner = this.createInnerAgent(model, effectiveMaxSteps);
3338
+ if (this.config.sessionStore) {
3339
+ const existing = await this.config.sessionStore.get(sessionId);
3340
+ if (!existing) {
3341
+ await this.config.sessionStore.create({
3342
+ sessionId,
3343
+ agentId: this.id,
3344
+ tenantId: params.options?.tenantId,
3345
+ actorId: params.options?.actorId,
3346
+ status: "running",
3347
+ messages: [],
3348
+ steps: [],
3349
+ metadata: params.options?.metadata
3350
+ });
3351
+ }
3352
+ await this.config.sessionStore.appendMessage(sessionId, {
3353
+ role: "user",
3354
+ content: params.prompt
3355
+ });
3356
+ await this.config.sessionStore.update(sessionId, { status: "running" });
3357
+ }
3224
3358
  return inner.stream({
3225
3359
  prompt,
3226
3360
  abortSignal: params.signal,
@@ -3236,6 +3370,9 @@ ${params.prompt}` : params.prompt;
3236
3370
  const sessionId = step.options?.sessionId;
3237
3371
  if (sessionId && this.config.sessionStore) {
3238
3372
  await this.config.sessionStore.appendStep(sessionId, step);
3373
+ await this.config.sessionStore.update(sessionId, {
3374
+ status: step.finishReason === "tool-calls" ? "waiting" : "running"
3375
+ });
3239
3376
  }
3240
3377
  if (this.config.telemetryCollector) {
3241
3378
  const now = new Date;
@@ -3259,12 +3396,12 @@ ${params.prompt}` : params.prompt;
3259
3396
  }
3260
3397
  }
3261
3398
  }
3262
- createInnerAgent(model) {
3399
+ createInnerAgent(model, maxSteps) {
3263
3400
  return new ToolLoopAgent({
3264
3401
  model,
3265
3402
  instructions: this.instructions,
3266
3403
  tools: this.tools,
3267
- stopWhen: stepCountIs(this.spec.maxSteps ?? 10),
3404
+ stopWhen: stepCountIs(maxSteps),
3268
3405
  callOptionsSchema: ContractSpecCallOptionsSchema,
3269
3406
  onStepFinish: async (step) => {
3270
3407
  await this.handleStepFinish(step);
@@ -3272,6 +3409,10 @@ ${params.prompt}` : params.prompt;
3272
3409
  });
3273
3410
  }
3274
3411
  async resolveModelForCall(params) {
3412
+ if (this.config.modelSelector && params.options?.selectionContext) {
3413
+ const { model } = await this.config.modelSelector.selectAndCreate(params.options.selectionContext);
3414
+ return model;
3415
+ }
3275
3416
  const posthogConfig = this.config.posthogConfig;
3276
3417
  if (!posthogConfig) {
3277
3418
  return this.config.model;
@@ -3296,6 +3437,46 @@ ${params.prompt}` : params.prompt;
3296
3437
  return createPostHogTracedModel2(this.config.model, posthogConfig, tracingOptions);
3297
3438
  }
3298
3439
  }
3440
+ function resolveMaxSteps(overrideMaxSteps, specMaxSteps) {
3441
+ const candidate = overrideMaxSteps ?? specMaxSteps ?? 10;
3442
+ if (!Number.isFinite(candidate)) {
3443
+ return 10;
3444
+ }
3445
+ if (candidate < 1) {
3446
+ return 1;
3447
+ }
3448
+ return Math.round(candidate);
3449
+ }
3450
+ function resolveEscalationError(spec, finishReason) {
3451
+ const escalation = spec.policy?.escalation;
3452
+ if (!escalation) {
3453
+ return;
3454
+ }
3455
+ if (escalation.onTimeout && finishReason === "length") {
3456
+ return {
3457
+ kind: "timeout",
3458
+ code: "AGENT_TIMEOUT_ESCALATION",
3459
+ message: "Agent reached max step budget and requires escalation."
3460
+ };
3461
+ }
3462
+ if (escalation.onToolFailure && finishReason === "error") {
3463
+ return {
3464
+ kind: "retryable",
3465
+ code: "AGENT_TOOL_FAILURE_ESCALATION",
3466
+ message: "Agent encountered a tool failure and requires escalation."
3467
+ };
3468
+ }
3469
+ const confidenceThreshold = escalation.confidenceThreshold;
3470
+ const defaultConfidence = spec.policy?.confidence?.default;
3471
+ if (confidenceThreshold !== undefined && defaultConfidence !== undefined && defaultConfidence < confidenceThreshold) {
3472
+ return {
3473
+ kind: "policy_blocked",
3474
+ code: "AGENT_CONFIDENCE_ESCALATION",
3475
+ message: `Agent default confidence (${defaultConfidence}) is below escalation threshold (${confidenceThreshold}).`
3476
+ };
3477
+ }
3478
+ return;
3479
+ }
3299
3480
  var ContractSpecCallOptionsSchema;
3300
3481
  var init_contract_spec_agent = __esm(() => {
3301
3482
  init_spec();
@@ -3349,7 +3530,8 @@ class AgentFactory {
3349
3530
  telemetryCollector: this.config.telemetryCollector,
3350
3531
  posthogConfig: this.config.posthogConfig,
3351
3532
  additionalTools: mergedTools,
3352
- mcpServers: mergedMcpServers.length > 0 ? mergedMcpServers : undefined
3533
+ mcpServers: mergedMcpServers.length > 0 ? mergedMcpServers : undefined,
3534
+ modelSelector: this.config.modelSelector
3353
3535
  });
3354
3536
  }
3355
3537
  async getOrCreate(name, version) {