@contractspec/lib.ai-agent 7.0.7 → 8.0.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 (81) hide show
  1. package/README.md +45 -4
  2. package/dist/agent/agent-factory.d.ts +14 -3
  3. package/dist/agent/agent-factory.js +676 -111
  4. package/dist/agent/contract-spec-agent.d.ts +16 -2
  5. package/dist/agent/contract-spec-agent.js +672 -110
  6. package/dist/agent/index.js +685 -118
  7. package/dist/agent/json-runner.d.ts +1 -1
  8. package/dist/agent/json-runner.js +672 -110
  9. package/dist/agent/unified-agent.d.ts +2 -2
  10. package/dist/agent/unified-agent.js +685 -118
  11. package/dist/approval/index.js +6 -1
  12. package/dist/approval/workflow.js +5 -1
  13. package/dist/exporters/claude-agent-exporter.d.ts +1 -1
  14. package/dist/exporters/claude-agent-exporter.js +3 -51
  15. package/dist/exporters/index.js +8 -54
  16. package/dist/exporters/opencode-exporter.d.ts +1 -1
  17. package/dist/exporters/opencode-exporter.js +3 -51
  18. package/dist/exporters/types.d.ts +1 -1
  19. package/dist/index.d.ts +2 -1
  20. package/dist/index.js +3805 -71
  21. package/dist/interop/index.js +3 -51
  22. package/dist/interop/spec-consumer.d.ts +1 -1
  23. package/dist/interop/spec-consumer.js +3 -51
  24. package/dist/interop/tool-consumer.d.ts +1 -1
  25. package/dist/interop/types.d.ts +1 -1
  26. package/dist/knowledge/injector.d.ts +1 -1
  27. package/dist/node/agent/agent-factory.js +676 -111
  28. package/dist/node/agent/contract-spec-agent.js +672 -110
  29. package/dist/node/agent/index.js +685 -118
  30. package/dist/node/agent/json-runner.js +672 -110
  31. package/dist/node/agent/unified-agent.js +685 -118
  32. package/dist/node/approval/index.js +6 -1
  33. package/dist/node/approval/workflow.js +5 -1
  34. package/dist/node/exporters/claude-agent-exporter.js +3 -51
  35. package/dist/node/exporters/index.js +8 -54
  36. package/dist/node/exporters/opencode-exporter.js +3 -51
  37. package/dist/node/index.js +3805 -71
  38. package/dist/node/interop/index.js +3 -51
  39. package/dist/node/interop/spec-consumer.js +3 -51
  40. package/dist/node/providers/claude-agent-sdk/adapter.js +3 -51
  41. package/dist/node/providers/claude-agent-sdk/index.js +3 -51
  42. package/dist/node/providers/index.js +8 -53
  43. package/dist/node/providers/opencode-sdk/adapter.js +4 -51
  44. package/dist/node/providers/opencode-sdk/index.js +4 -51
  45. package/dist/node/session/index.js +26 -1
  46. package/dist/node/session/store.js +26 -1
  47. package/dist/node/telemetry/adapter.js +2 -0
  48. package/dist/node/telemetry/index.js +2 -0
  49. package/dist/providers/claude-agent-sdk/adapter.d.ts +1 -1
  50. package/dist/providers/claude-agent-sdk/adapter.js +3 -51
  51. package/dist/providers/claude-agent-sdk/index.js +3 -51
  52. package/dist/providers/claude-agent-sdk/tool-bridge.d.ts +1 -8
  53. package/dist/providers/index.js +8 -53
  54. package/dist/providers/opencode-sdk/adapter.d.ts +1 -13
  55. package/dist/providers/opencode-sdk/adapter.js +4 -51
  56. package/dist/providers/opencode-sdk/agent-bridge.d.ts +1 -10
  57. package/dist/providers/opencode-sdk/index.js +4 -51
  58. package/dist/providers/opencode-sdk/tool-bridge.d.ts +1 -4
  59. package/dist/providers/types.d.ts +1 -8
  60. package/dist/session/index.js +26 -1
  61. package/dist/session/store.d.ts +2 -2
  62. package/dist/session/store.js +26 -1
  63. package/dist/telemetry/adapter.d.ts +1 -0
  64. package/dist/telemetry/adapter.js +2 -0
  65. package/dist/telemetry/index.js +2 -0
  66. package/dist/tools/knowledge-tool.d.ts +1 -1
  67. package/dist/tools/mcp-server.d.ts +1 -1
  68. package/dist/tools/operation-tool-handler.d.ts +1 -1
  69. package/dist/tools/tool-adapter.d.ts +1 -1
  70. package/dist/types.d.ts +13 -0
  71. package/package.json +8 -44
  72. package/dist/node/spec/index.js +0 -2233
  73. package/dist/node/spec/registry.js +0 -2178
  74. package/dist/node/spec/spec.js +0 -2188
  75. package/dist/spec/index.d.ts +0 -2
  76. package/dist/spec/index.js +0 -2233
  77. package/dist/spec/registry.d.ts +0 -41
  78. package/dist/spec/registry.js +0 -2178
  79. package/dist/spec/spec.d.ts +0 -218
  80. package/dist/spec/spec.js +0 -2188
  81. /package/dist/{spec/spec.test.d.ts → session/store.test.d.ts} +0 -0
@@ -2131,103 +2131,3837 @@ var init_i18n = __esm(() => {
2131
2131
  init_messages();
2132
2132
  });
2133
2133
 
2134
- // src/spec/spec.ts
2135
- function defineAgent(spec) {
2136
- const i18n = createAgentI18n(spec.locale);
2137
- if (!spec.meta?.key) {
2138
- throw new Error(i18n.t("error.agentKeyRequired"));
2134
+ // src/approval/workflow.ts
2135
+ import { randomUUID } from "node:crypto";
2136
+
2137
+ class InMemoryApprovalStore {
2138
+ items = new Map;
2139
+ maxItems;
2140
+ constructor(options = {}) {
2141
+ this.maxItems = options.maxItems ?? 1000;
2142
+ }
2143
+ async create(request) {
2144
+ this.evictIfNeeded();
2145
+ this.items.set(request.id, request);
2146
+ }
2147
+ async get(id) {
2148
+ return this.items.get(id) ?? null;
2149
+ }
2150
+ async getByToolCallId(toolCallId) {
2151
+ for (const request of this.items.values()) {
2152
+ if (request.toolCallId === toolCallId) {
2153
+ return request;
2154
+ }
2155
+ }
2156
+ return null;
2157
+ }
2158
+ async update(id, updates) {
2159
+ const existing = this.items.get(id);
2160
+ if (existing) {
2161
+ this.items.set(id, { ...existing, ...updates });
2162
+ }
2163
+ }
2164
+ async list(options) {
2165
+ let results = [...this.items.values()];
2166
+ if (options?.status) {
2167
+ results = results.filter((r) => r.status === options.status);
2168
+ }
2169
+ if (options?.agentId) {
2170
+ results = results.filter((r) => r.agentId === options.agentId);
2171
+ }
2172
+ if (options?.tenantId) {
2173
+ results = results.filter((r) => r.tenantId === options.tenantId);
2174
+ }
2175
+ return results.sort((a, b) => b.requestedAt.getTime() - a.requestedAt.getTime());
2176
+ }
2177
+ clear() {
2178
+ this.items.clear();
2179
+ }
2180
+ evictIfNeeded() {
2181
+ if (this.items.size < this.maxItems) {
2182
+ return;
2183
+ }
2184
+ let oldestId = null;
2185
+ let oldestTimestamp = Number.POSITIVE_INFINITY;
2186
+ for (const [id, request] of this.items.entries()) {
2187
+ const ts = request.requestedAt.getTime();
2188
+ if (ts < oldestTimestamp) {
2189
+ oldestTimestamp = ts;
2190
+ oldestId = id;
2191
+ }
2192
+ }
2193
+ if (oldestId) {
2194
+ this.items.delete(oldestId);
2195
+ }
2196
+ }
2197
+ }
2198
+
2199
+ class ApprovalWorkflow {
2200
+ store;
2201
+ constructor(store = new InMemoryApprovalStore) {
2202
+ this.store = store;
2203
+ }
2204
+ async requestApproval(params) {
2205
+ const request = {
2206
+ id: randomUUID(),
2207
+ sessionId: params.sessionId,
2208
+ agentId: params.agentId,
2209
+ tenantId: params.tenantId,
2210
+ toolName: params.toolName,
2211
+ toolCallId: params.toolCallId,
2212
+ toolArgs: params.toolArgs,
2213
+ reason: params.reason,
2214
+ requestedAt: new Date,
2215
+ status: "pending",
2216
+ payload: params.payload
2217
+ };
2218
+ await this.store.create(request);
2219
+ return request;
2220
+ }
2221
+ async requestApprovalFromToolCall(toolCall, context) {
2222
+ return this.requestApproval({
2223
+ sessionId: context.sessionId,
2224
+ agentId: context.agentId,
2225
+ tenantId: context.tenantId,
2226
+ toolName: toolCall.toolName,
2227
+ toolCallId: toolCall.toolCallId,
2228
+ toolArgs: toolCall.args,
2229
+ reason: context.reason ?? createAgentI18n(context.locale).t("approval.toolRequiresApproval", {
2230
+ name: toolCall.toolName
2231
+ })
2232
+ });
2233
+ }
2234
+ async approve(id, reviewer, notes) {
2235
+ await this.store.update(id, {
2236
+ status: "approved",
2237
+ reviewer,
2238
+ resolvedAt: new Date,
2239
+ notes
2240
+ });
2241
+ }
2242
+ async reject(id, reviewer, notes) {
2243
+ await this.store.update(id, {
2244
+ status: "rejected",
2245
+ reviewer,
2246
+ resolvedAt: new Date,
2247
+ notes
2248
+ });
2249
+ }
2250
+ async getStatus(toolCallId) {
2251
+ const request = await this.store.getByToolCallId(toolCallId);
2252
+ return request?.status ?? null;
2253
+ }
2254
+ async isApproved(toolCallId) {
2255
+ const status = await this.getStatus(toolCallId);
2256
+ return status === "approved";
2257
+ }
2258
+ async listPending(options) {
2259
+ return this.store.list({ ...options, status: "pending" });
2260
+ }
2261
+ async get(id) {
2262
+ return this.store.get(id);
2263
+ }
2264
+ }
2265
+ function createApprovalWorkflow(store) {
2266
+ if (store && typeof store === "object" && "create" in store && typeof store.create === "function") {
2267
+ return new ApprovalWorkflow(store);
2268
+ }
2269
+ const options = store;
2270
+ return new ApprovalWorkflow(new InMemoryApprovalStore(options));
2271
+ }
2272
+ var init_workflow = __esm(() => {
2273
+ init_i18n();
2274
+ });
2275
+
2276
+ // src/knowledge/injector.ts
2277
+ async function injectStaticKnowledge(instructions, knowledgeRefs, retriever, locale) {
2278
+ if (!retriever)
2279
+ return instructions;
2280
+ const requiredRefs = knowledgeRefs.filter((ref) => ref.required);
2281
+ if (requiredRefs.length === 0)
2282
+ return instructions;
2283
+ const i18n = createAgentI18n(locale);
2284
+ const blocks = [];
2285
+ for (const ref of requiredRefs) {
2286
+ if (!retriever.supportsSpace(ref.key)) {
2287
+ console.warn(i18n.t("log.knowledge.spaceNotAvailable", { key: ref.key }));
2288
+ continue;
2289
+ }
2290
+ try {
2291
+ const content = await retriever.getStatic(ref.key);
2292
+ if (content) {
2293
+ const header = ref.instructions ? `## ${ref.key}
2294
+ ${ref.instructions}` : `## ${ref.key}`;
2295
+ blocks.push(`${header}
2296
+
2297
+ ${content}`);
2298
+ }
2299
+ } catch (error) {
2300
+ console.warn(i18n.t("log.knowledge.loadFailed", { key: ref.key }), error);
2301
+ }
2302
+ }
2303
+ if (blocks.length === 0)
2304
+ return instructions;
2305
+ return `${instructions}
2306
+
2307
+ ---
2308
+
2309
+ # ${i18n.t("knowledge.header")}
2310
+
2311
+ ${i18n.t("knowledge.description")}
2312
+
2313
+ ${blocks.join(`
2314
+
2315
+ ---
2316
+
2317
+ `)}`;
2318
+ }
2319
+ function createKnowledgeInjector(retriever, locale) {
2320
+ return {
2321
+ inject: (instructions, knowledgeRefs) => injectStaticKnowledge(instructions, knowledgeRefs, retriever, locale),
2322
+ hasSpace: (spaceKey) => retriever?.supportsSpace(spaceKey) ?? false,
2323
+ listSpaces: () => retriever?.listSpaces() ?? []
2324
+ };
2325
+ }
2326
+ var init_injector = __esm(() => {
2327
+ init_i18n();
2328
+ });
2329
+
2330
+ // src/session/store.ts
2331
+ class InMemorySessionStore {
2332
+ sessions = new Map;
2333
+ maxSessions;
2334
+ maxMessagesPerSession;
2335
+ maxStepsPerSession;
2336
+ constructor(options = {}) {
2337
+ this.maxSessions = options.maxSessions ?? 500;
2338
+ this.maxMessagesPerSession = options.maxMessagesPerSession ?? 200;
2339
+ this.maxStepsPerSession = options.maxStepsPerSession ?? 200;
2340
+ }
2341
+ async get(sessionId) {
2342
+ return this.sessions.get(sessionId) ?? null;
2343
+ }
2344
+ async create(session) {
2345
+ this.evictIfNeeded();
2346
+ const now = new Date;
2347
+ const fullSession = {
2348
+ ...session,
2349
+ createdAt: now,
2350
+ updatedAt: now
2351
+ };
2352
+ this.sessions.set(session.sessionId, fullSession);
2353
+ return fullSession;
2354
+ }
2355
+ async appendStep(sessionId, step) {
2356
+ const session = this.sessions.get(sessionId);
2357
+ if (session) {
2358
+ session.steps.push(step);
2359
+ this.trimArray(session.steps, this.maxStepsPerSession);
2360
+ session.updatedAt = new Date;
2361
+ }
2362
+ }
2363
+ async appendMessage(sessionId, message) {
2364
+ const session = this.sessions.get(sessionId);
2365
+ if (session) {
2366
+ session.messages.push(message);
2367
+ this.trimArray(session.messages, this.maxMessagesPerSession);
2368
+ session.updatedAt = new Date;
2369
+ }
2370
+ }
2371
+ async update(sessionId, updates) {
2372
+ const session = this.sessions.get(sessionId);
2373
+ if (session) {
2374
+ Object.assign(session, updates, { updatedAt: new Date });
2375
+ }
2376
+ }
2377
+ async delete(sessionId) {
2378
+ return this.sessions.delete(sessionId);
2379
+ }
2380
+ async listByAgent(agentId, limit = 100) {
2381
+ const results = [];
2382
+ for (const session of this.sessions.values()) {
2383
+ if (session.agentId === agentId) {
2384
+ results.push(session);
2385
+ if (results.length >= limit)
2386
+ break;
2387
+ }
2388
+ }
2389
+ return results.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
2390
+ }
2391
+ async listByTenant(tenantId, limit = 100) {
2392
+ const results = [];
2393
+ for (const session of this.sessions.values()) {
2394
+ if (session.tenantId === tenantId) {
2395
+ results.push(session);
2396
+ if (results.length >= limit)
2397
+ break;
2398
+ }
2399
+ }
2400
+ return results.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
2401
+ }
2402
+ clear() {
2403
+ this.sessions.clear();
2404
+ }
2405
+ evictIfNeeded() {
2406
+ if (this.sessions.size < this.maxSessions) {
2407
+ return;
2408
+ }
2409
+ let oldestSessionId = null;
2410
+ let oldestUpdatedAt = Number.POSITIVE_INFINITY;
2411
+ for (const [sessionId, session] of this.sessions.entries()) {
2412
+ const updatedAt = session.updatedAt.getTime();
2413
+ if (updatedAt < oldestUpdatedAt) {
2414
+ oldestUpdatedAt = updatedAt;
2415
+ oldestSessionId = sessionId;
2416
+ }
2417
+ }
2418
+ if (oldestSessionId) {
2419
+ this.sessions.delete(oldestSessionId);
2420
+ }
2421
+ }
2422
+ trimArray(items, maxItems) {
2423
+ if (items.length <= maxItems) {
2424
+ return;
2425
+ }
2426
+ const overflow = items.length - maxItems;
2427
+ items.splice(0, overflow);
2428
+ }
2429
+ }
2430
+ function createInMemorySessionStore(options) {
2431
+ return new InMemorySessionStore(options);
2432
+ }
2433
+ function createSecureSessionToken() {
2434
+ const cryptoApi = globalThis.crypto;
2435
+ if (typeof cryptoApi?.randomUUID === "function") {
2436
+ return cryptoApi.randomUUID();
2437
+ }
2438
+ if (typeof cryptoApi?.getRandomValues === "function") {
2439
+ const bytes = cryptoApi.getRandomValues(new Uint8Array(16));
2440
+ const versionByte = bytes.at(6);
2441
+ const variantByte = bytes.at(8);
2442
+ if (versionByte === undefined || variantByte === undefined) {
2443
+ throw new Error("Secure session token generation requires 16 random bytes.");
2444
+ }
2445
+ bytes[6] = versionByte & 15 | 64;
2446
+ bytes[8] = variantByte & 63 | 128;
2447
+ const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, "0"));
2448
+ return [
2449
+ hex.slice(0, 4).join(""),
2450
+ hex.slice(4, 6).join(""),
2451
+ hex.slice(6, 8).join(""),
2452
+ hex.slice(8, 10).join(""),
2453
+ hex.slice(10, 16).join("")
2454
+ ].join("-");
2455
+ }
2456
+ throw new Error("Secure session IDs require Web Crypto support.");
2457
+ }
2458
+ function generateSessionId() {
2459
+ return `sess_${createSecureSessionToken()}`;
2460
+ }
2461
+
2462
+ // src/telemetry/adapter.ts
2463
+ function parseAgentId(agentId) {
2464
+ const match = agentId.match(/^(.+)\.v(\d+)$/);
2465
+ if (match) {
2466
+ return { name: match[1], version: match[2] };
2467
+ }
2468
+ return { name: agentId, version: "1.0.0" };
2469
+ }
2470
+ function getRecord(value) {
2471
+ return value && typeof value === "object" ? value : undefined;
2472
+ }
2473
+ function getStepResponse(step) {
2474
+ const response = getRecord(step.response);
2475
+ if (!response)
2476
+ return;
2477
+ return {
2478
+ id: response["id"],
2479
+ modelId: response["modelId"],
2480
+ timestamp: response["timestamp"],
2481
+ headers: response["headers"],
2482
+ body: response["body"],
2483
+ messages: response["messages"]
2484
+ };
2485
+ }
2486
+ function getRequestBodyValue(request, key) {
2487
+ const body = request?.["body"];
2488
+ if (!body)
2489
+ return;
2490
+ if (typeof body === "string") {
2491
+ try {
2492
+ const parsed = JSON.parse(body);
2493
+ return typeof parsed[key] === "string" ? parsed[key] : undefined;
2494
+ } catch {
2495
+ return;
2496
+ }
2497
+ }
2498
+ const record = getRecord(body);
2499
+ return typeof record?.[key] === "string" ? record[key] : undefined;
2500
+ }
2501
+ async function trackAgentStep(collector, agentId, step, durationMs, context) {
2502
+ const { name, version } = parseAgentId(agentId);
2503
+ const response = getStepResponse(step);
2504
+ const providerMetadata = step.providerMetadata;
2505
+ const warnings = step.warnings;
2506
+ const rawFinishReason = step.rawFinishReason;
2507
+ const request = getRecord(step.request);
2508
+ const traceId = context?.traceId ?? getRequestBodyValue(request, "$ai_trace_id");
2509
+ const sessionId = context?.sessionId ?? getRequestBodyValue(request, "$ai_session_id");
2510
+ const parentSpanId = response?.id;
2511
+ for (const toolCall of step.toolCalls ?? []) {
2512
+ const toolResult = step.toolResults?.find((r) => r.toolCallId === toolCall.toolCallId);
2513
+ const toolError = getRecord(toolResult?.output)?.["error"];
2514
+ const toolSample = {
2515
+ operation: { name: `${name}.${toolCall.toolName}`, version },
2516
+ durationMs: durationMs ?? 0,
2517
+ success: step.toolResults?.some((r) => r.toolCallId === toolCall.toolCallId && r.output !== undefined) ?? false,
2518
+ timestamp: new Date,
2519
+ metadata: {
2520
+ telemetryEvent: "span",
2521
+ traceId,
2522
+ sessionId,
2523
+ spanId: toolCall.toolCallId,
2524
+ parentSpanId,
2525
+ spanName: `tool.${toolCall.toolName}`,
2526
+ agentId,
2527
+ actorId: context?.actorId,
2528
+ tenantId: context?.tenantId,
2529
+ workflowId: context?.workflowId,
2530
+ stepIndex: context?.stepIndex,
2531
+ toolName: toolCall.toolName,
2532
+ toolCallArgs: toolCall.input,
2533
+ toolResultOutput: toolResult?.output,
2534
+ errorMessage: typeof toolError === "string" ? toolError : typeof toolResult?.output === "string" ? toolResult.output : undefined,
2535
+ finishReason: step.finishReason,
2536
+ rawFinishReason
2537
+ }
2538
+ };
2539
+ await collector.collect(toolSample);
2540
+ }
2541
+ const stepSample = {
2542
+ operation: { name, version },
2543
+ durationMs: durationMs ?? 0,
2544
+ success: step.finishReason !== "error",
2545
+ timestamp: new Date,
2546
+ metadata: {
2547
+ telemetryEvent: "generation",
2548
+ traceId,
2549
+ sessionId,
2550
+ spanId: response?.id,
2551
+ spanName: `agent.${name}.step`,
2552
+ agentId,
2553
+ actorId: context?.actorId,
2554
+ tenantId: context?.tenantId,
2555
+ workflowId: context?.workflowId,
2556
+ stepIndex: context?.stepIndex,
2557
+ stepStartedAt: context?.stepStartedAt,
2558
+ finishReason: step.finishReason,
2559
+ rawFinishReason,
2560
+ tokenUsage: step.usage,
2561
+ totalUsage: step.totalUsage,
2562
+ providerMetadata,
2563
+ warnings,
2564
+ stepText: step.text,
2565
+ stepReasoningText: step.reasoningText,
2566
+ responseId: response?.id,
2567
+ responseModelId: response?.modelId,
2568
+ responseTimestamp: response?.timestamp,
2569
+ responseHeaders: response?.headers,
2570
+ responseBody: response?.body,
2571
+ responseMessages: response?.messages,
2572
+ requestBody: request?.["body"],
2573
+ requestHeaders: request?.["headers"],
2574
+ toolCallCount: step.toolCalls?.length ?? 0,
2575
+ toolCalls: step.toolCalls,
2576
+ toolResults: step.toolResults,
2577
+ errorMessage: step.finishReason === "error" ? step.text : undefined
2578
+ }
2579
+ };
2580
+ await collector.collect(stepSample);
2581
+ }
2582
+
2583
+ class InMemoryTelemetryCollector {
2584
+ samples = [];
2585
+ async collect(sample) {
2586
+ this.samples.push(sample);
2587
+ }
2588
+ getSamples() {
2589
+ return [...this.samples];
2590
+ }
2591
+ getSamplesForOperation(operationName) {
2592
+ return this.samples.filter((s) => s.operation.name === operationName);
2593
+ }
2594
+ clear() {
2595
+ this.samples.length = 0;
2596
+ }
2597
+ }
2598
+ function createInMemoryTelemetryCollector() {
2599
+ return new InMemoryTelemetryCollector;
2600
+ }
2601
+ var noopTelemetryCollector;
2602
+ var init_adapter = __esm(() => {
2603
+ noopTelemetryCollector = {
2604
+ collect: async () => {}
2605
+ };
2606
+ });
2607
+
2608
+ // src/tools/knowledge-tool.ts
2609
+ import { tool } from "ai";
2610
+ import * as z from "zod";
2611
+ function createKnowledgeQueryTool(retriever, knowledgeRefs, locale) {
2612
+ const i18n = createAgentI18n(locale);
2613
+ const optionalSpaces = knowledgeRefs.filter((k) => !k.required).map((k) => k.key).filter((key) => retriever.supportsSpace(key));
2614
+ if (optionalSpaces.length === 0) {
2615
+ return null;
2616
+ }
2617
+ const spaceDescriptions = knowledgeRefs.filter((k) => !k.required && retriever.supportsSpace(k.key)).map((k) => `- ${k.key}: ${k.instructions ?? i18n.t("tool.knowledge.spaceDefault")}`).join(`
2618
+ `);
2619
+ return tool({
2620
+ description: `${i18n.t("tool.knowledge.description")}
2621
+
2622
+ ${i18n.t("tool.knowledge.availableSpaces")}
2623
+ ${spaceDescriptions}`,
2624
+ inputSchema: z.object({
2625
+ query: z.string().describe(i18n.t("tool.knowledge.param.query")),
2626
+ spaceKey: z.enum(optionalSpaces).optional().describe(i18n.t("tool.knowledge.param.spaceKey")),
2627
+ topK: z.number().optional().default(5).describe(i18n.t("tool.knowledge.param.topK"))
2628
+ }),
2629
+ execute: async ({ query, spaceKey, topK }) => {
2630
+ const spacesToSearch = spaceKey ? [spaceKey] : optionalSpaces;
2631
+ const allResults = [];
2632
+ for (const space of spacesToSearch) {
2633
+ try {
2634
+ const results = await retriever.retrieve(query, {
2635
+ spaceKey: space,
2636
+ topK: topK ?? 5
2637
+ });
2638
+ for (const result of results) {
2639
+ allResults.push({
2640
+ space,
2641
+ content: result.content,
2642
+ score: result.score
2643
+ });
2644
+ }
2645
+ } catch (error) {
2646
+ console.warn(i18n.t("log.knowledge.queryFailed", { space }), error);
2647
+ }
2648
+ }
2649
+ if (allResults.length === 0) {
2650
+ return i18n.t("tool.knowledge.noResults");
2651
+ }
2652
+ allResults.sort((a, b) => b.score - a.score);
2653
+ const topResults = allResults.slice(0, topK ?? 5);
2654
+ return topResults.map((r, i) => `${i18n.t("tool.knowledge.sourceLabel", { index: i + 1, space: r.space, score: (r.score * 100).toFixed(0) })}
2655
+ ${r.content}`).join(`
2656
+
2657
+ ---
2658
+
2659
+ `);
2660
+ }
2661
+ });
2662
+ }
2663
+ var init_knowledge_tool = __esm(() => {
2664
+ init_i18n();
2665
+ });
2666
+
2667
+ // src/tools/mcp-client-helpers.ts
2668
+ import {
2669
+ Experimental_StdioMCPTransport as StdioClientTransport
2670
+ } from "@ai-sdk/mcp/mcp-stdio";
2671
+ function buildMcpTransport(config) {
2672
+ const transport = resolveTransportType(config);
2673
+ if (transport === "stdio") {
2674
+ const stdioConfig = resolveStdioConfig(config);
2675
+ return new StdioClientTransport(stdioConfig);
2676
+ }
2677
+ const remoteConfig = config;
2678
+ const headers = resolveRemoteHeaders(remoteConfig);
2679
+ const remoteTransport = {
2680
+ type: transport,
2681
+ url: requireNonEmptyString(remoteConfig.url, "url", config.name)
2682
+ };
2683
+ if (headers) {
2684
+ remoteTransport.headers = headers;
2685
+ }
2686
+ if (remoteConfig.authProvider) {
2687
+ remoteTransport.authProvider = remoteConfig.authProvider;
2688
+ }
2689
+ return remoteTransport;
2690
+ }
2691
+ function prefixToolNames(config, tools) {
2692
+ const prefix = config.toolPrefix?.trim();
2693
+ if (!prefix) {
2694
+ return tools;
2695
+ }
2696
+ const prefixedTools = {};
2697
+ for (const [toolName, tool2] of Object.entries(tools)) {
2698
+ prefixedTools[`${prefix}_${toolName}`] = tool2;
2699
+ }
2700
+ return prefixedTools;
2701
+ }
2702
+ function getErrorMessage(error) {
2703
+ if (error instanceof Error) {
2704
+ return error.message;
2705
+ }
2706
+ return String(error);
2707
+ }
2708
+ function resolveTransportType(config) {
2709
+ return config.transport ?? "stdio";
2710
+ }
2711
+ function resolveStdioConfig(config) {
2712
+ const stdioConfig = config;
2713
+ return {
2714
+ command: requireNonEmptyString(stdioConfig.command, "command", config.name),
2715
+ args: stdioConfig.args,
2716
+ env: stdioConfig.env,
2717
+ cwd: stdioConfig.cwd
2718
+ };
2719
+ }
2720
+ function resolveRemoteHeaders(config) {
2721
+ const headers = {
2722
+ ...config.headers ?? {}
2723
+ };
2724
+ const accessToken = config.accessToken ?? resolveEnvToken(config.accessTokenEnvVar);
2725
+ if (accessToken && headers.Authorization === undefined) {
2726
+ headers.Authorization = `Bearer ${accessToken}`;
2727
+ }
2728
+ return Object.keys(headers).length > 0 ? headers : undefined;
2729
+ }
2730
+ function resolveEnvToken(envVarName) {
2731
+ if (!envVarName) {
2732
+ return;
2733
+ }
2734
+ const value = process.env[envVarName];
2735
+ if (!value) {
2736
+ return;
2737
+ }
2738
+ const trimmed = value.trim();
2739
+ return trimmed.length > 0 ? trimmed : undefined;
2740
+ }
2741
+ function requireNonEmptyString(value, field, serverName) {
2742
+ if (!value) {
2743
+ throw new Error(`MCP server "${serverName}" is missing required "${field}".`);
2744
+ }
2745
+ const trimmed = value.trim();
2746
+ if (trimmed.length === 0) {
2747
+ throw new Error(`MCP server "${serverName}" has an empty "${field}".`);
2748
+ }
2749
+ return trimmed;
2750
+ }
2751
+ var init_mcp_client_helpers = () => {};
2752
+
2753
+ // src/tools/mcp-client.ts
2754
+ import {
2755
+ experimental_createMCPClient
2756
+ } from "@ai-sdk/mcp";
2757
+ async function mcpServerToTools(config) {
2758
+ let client = null;
2759
+ try {
2760
+ const transport = buildMcpTransport(config);
2761
+ client = await experimental_createMCPClient({
2762
+ transport,
2763
+ name: config.clientName,
2764
+ version: config.clientVersion
2765
+ });
2766
+ const tools = await client.tools();
2767
+ const prefixedTools = prefixToolNames(config, tools);
2768
+ const connectedClient = client;
2769
+ return {
2770
+ tools: prefixedTools,
2771
+ cleanup: () => connectedClient.close(),
2772
+ serverToolNames: {
2773
+ [config.name]: Object.keys(prefixedTools)
2774
+ }
2775
+ };
2776
+ } catch (error) {
2777
+ if (client) {
2778
+ await client.close().catch(() => {
2779
+ return;
2780
+ });
2781
+ }
2782
+ throw new Error(`[MCP:${config.name}] Failed to connect tools: ${getErrorMessage(error)}`);
2783
+ }
2784
+ }
2785
+ async function createMcpToolsets(configs, options = {}) {
2786
+ const connected = [];
2787
+ try {
2788
+ for (const config of configs) {
2789
+ const result = await mcpServerToTools(config);
2790
+ connected.push(result);
2791
+ }
2792
+ } catch (error) {
2793
+ await Promise.allSettled(connected.map((result) => result.cleanup()));
2794
+ throw error;
2795
+ }
2796
+ const combinedTools = {};
2797
+ const serverToolNames = {};
2798
+ const collisionStrategy = options.onNameCollision ?? "overwrite";
2799
+ try {
2800
+ for (const result of connected) {
2801
+ for (const [serverName, toolNames] of Object.entries(result.serverToolNames)) {
2802
+ serverToolNames[serverName] = toolNames;
2803
+ }
2804
+ for (const [toolName, tool2] of Object.entries(result.tools)) {
2805
+ const hasCollision = combinedTools[toolName] !== undefined;
2806
+ if (hasCollision && collisionStrategy === "error") {
2807
+ throw new Error(`Duplicate MCP tool name "${toolName}" detected. Use "toolPrefix" or set onNameCollision to "overwrite".`);
2808
+ }
2809
+ combinedTools[toolName] = tool2;
2810
+ }
2811
+ }
2812
+ } catch (error) {
2813
+ await Promise.allSettled(connected.map((result) => result.cleanup()));
2814
+ throw error;
2815
+ }
2816
+ return {
2817
+ tools: combinedTools,
2818
+ serverToolNames,
2819
+ cleanup: async () => {
2820
+ const cleanupResults = await Promise.allSettled(connected.map((result) => result.cleanup()));
2821
+ const failures = cleanupResults.filter((result) => result.status === "rejected");
2822
+ if (failures.length > 0) {
2823
+ throw new Error(`Failed to cleanup ${failures.length} MCP client connection(s).`);
2824
+ }
2825
+ }
2826
+ };
2827
+ }
2828
+ var init_mcp_client = __esm(() => {
2829
+ init_mcp_client_helpers();
2830
+ });
2831
+
2832
+ // src/tools/memory-tools.ts
2833
+ import { anthropic } from "@ai-sdk/anthropic";
2834
+ function createAnthropicMemoryTool(store) {
2835
+ const memory = anthropic.tools.memory_20250818({
2836
+ execute: async (action) => {
2837
+ switch (action.command) {
2838
+ case "view":
2839
+ return store.view(action.path ?? "/memories", action.view_range);
2840
+ case "create":
2841
+ return store.create(action.path ?? "/memories/untitled", action.file_text ?? "");
2842
+ case "str_replace":
2843
+ return store.strReplace(action.path ?? "/memories", action.old_str ?? "", action.new_str ?? "");
2844
+ case "insert":
2845
+ return store.insert(action.path ?? "/memories", action.insert_line ?? 0, action.insert_text ?? "");
2846
+ case "delete":
2847
+ return store.delete(action.path ?? "/memories");
2848
+ case "rename":
2849
+ return store.rename(action.old_path ?? "/memories", action.new_path ?? "/memories");
2850
+ default:
2851
+ return `Unknown command: ${action.command}`;
2852
+ }
2853
+ }
2854
+ });
2855
+ return memory;
2856
+ }
2857
+ var init_memory_tools = () => {};
2858
+
2859
+ // src/schema/json-schema-to-zod.ts
2860
+ import { z as z2 } from "zod";
2861
+ function jsonSchemaToZod(schema) {
2862
+ const s = schema;
2863
+ const makeNullable = (zodSchema) => {
2864
+ return s.nullable ? z2.union([zodSchema, z2.null()]) : zodSchema;
2865
+ };
2866
+ if (s.const !== undefined) {
2867
+ return z2.literal(s.const);
2868
+ }
2869
+ if (s.enum) {
2870
+ const values = s.enum;
2871
+ return makeNullable(z2.enum(values.map(String)));
2872
+ }
2873
+ if (s.anyOf && s.anyOf.length > 0) {
2874
+ const schemas = s.anyOf.map((sub) => jsonSchemaToZod(sub));
2875
+ if (schemas.length === 1)
2876
+ return schemas[0] ?? z2.unknown();
2877
+ return z2.union([
2878
+ schemas[0] ?? z2.unknown(),
2879
+ schemas[1] ?? z2.unknown(),
2880
+ ...schemas.slice(2)
2881
+ ]);
2882
+ }
2883
+ if (s.oneOf && s.oneOf.length > 0) {
2884
+ const schemas = s.oneOf.map((sub) => jsonSchemaToZod(sub));
2885
+ if (schemas.length === 1)
2886
+ return schemas[0] ?? z2.unknown();
2887
+ return z2.union([
2888
+ schemas[0] ?? z2.unknown(),
2889
+ schemas[1] ?? z2.unknown(),
2890
+ ...schemas.slice(2)
2891
+ ]);
2892
+ }
2893
+ if (s.allOf && s.allOf.length > 0) {
2894
+ const schemas = s.allOf.map((sub) => jsonSchemaToZod(sub));
2895
+ return schemas.reduce((acc, curr) => z2.intersection(acc, curr));
2896
+ }
2897
+ switch (s.type) {
2898
+ case "string":
2899
+ return makeNullable(buildStringSchema(s));
2900
+ case "number":
2901
+ case "integer":
2902
+ return makeNullable(buildNumberSchema(s));
2903
+ case "boolean":
2904
+ return makeNullable(z2.boolean());
2905
+ case "null":
2906
+ return z2.null();
2907
+ case "array":
2908
+ return makeNullable(buildArraySchema(s));
2909
+ case "object":
2910
+ return makeNullable(buildObjectSchema(s));
2911
+ default:
2912
+ return z2.unknown();
2913
+ }
2914
+ }
2915
+ function buildStringSchema(schema) {
2916
+ let zodSchema = z2.string();
2917
+ if (schema.description) {
2918
+ zodSchema = zodSchema.describe(schema.description);
2919
+ }
2920
+ switch (schema.format) {
2921
+ case "email":
2922
+ zodSchema = zodSchema.email();
2923
+ break;
2924
+ case "uri":
2925
+ case "url":
2926
+ zodSchema = zodSchema.url();
2927
+ break;
2928
+ case "uuid":
2929
+ zodSchema = zodSchema.uuid();
2930
+ break;
2931
+ case "date-time":
2932
+ zodSchema = zodSchema.datetime();
2933
+ break;
2934
+ case "date":
2935
+ zodSchema = zodSchema.date();
2936
+ break;
2937
+ }
2938
+ if (schema.minLength !== undefined) {
2939
+ zodSchema = zodSchema.min(schema.minLength);
2940
+ }
2941
+ if (schema.maxLength !== undefined) {
2942
+ zodSchema = zodSchema.max(schema.maxLength);
2943
+ }
2944
+ if (schema.pattern) {
2945
+ zodSchema = zodSchema.regex(new RegExp(schema.pattern));
2946
+ }
2947
+ return zodSchema;
2948
+ }
2949
+ function buildNumberSchema(schema) {
2950
+ let zodSchema = schema.type === "integer" ? z2.number().int() : z2.number();
2951
+ if (schema.description) {
2952
+ zodSchema = zodSchema.describe(schema.description);
2953
+ }
2954
+ if (schema.minimum !== undefined) {
2955
+ zodSchema = zodSchema.min(schema.minimum);
2956
+ }
2957
+ if (schema.maximum !== undefined) {
2958
+ zodSchema = zodSchema.max(schema.maximum);
2959
+ }
2960
+ return zodSchema;
2961
+ }
2962
+ function buildArraySchema(schema) {
2963
+ const itemsSchema = schema.items ? jsonSchemaToZod(schema.items) : z2.unknown();
2964
+ let zodSchema = z2.array(itemsSchema);
2965
+ if (schema.description) {
2966
+ zodSchema = zodSchema.describe(schema.description);
2967
+ }
2968
+ return zodSchema;
2969
+ }
2970
+ function buildObjectSchema(schema) {
2971
+ const properties = schema.properties ?? {};
2972
+ const required = new Set(schema.required ?? []);
2973
+ const shape = {};
2974
+ for (const [key, propSchema] of Object.entries(properties)) {
2975
+ const zodProp = jsonSchemaToZod(propSchema);
2976
+ shape[key] = required.has(key) ? zodProp : zodProp.optional();
2977
+ }
2978
+ let zodSchema = z2.object(shape);
2979
+ if (schema.description) {
2980
+ zodSchema = zodSchema.describe(schema.description);
2981
+ }
2982
+ return zodSchema;
2983
+ }
2984
+ function jsonSchemaToZodSafe(schema) {
2985
+ if (!schema || Object.keys(schema).length === 0) {
2986
+ return z2.object({});
2987
+ }
2988
+ return jsonSchemaToZod(schema);
2989
+ }
2990
+ var init_json_schema_to_zod = () => {};
2991
+
2992
+ // src/tools/operation-tool-handler.ts
2993
+ function toolCtxToHandlerCtx(ctx) {
2994
+ return {
2995
+ traceId: ctx.metadata?.traceId,
2996
+ organizationId: ctx.tenantId ?? null,
2997
+ userId: ctx.actorId ?? null,
2998
+ actor: ctx.actorId ? "user" : "anonymous",
2999
+ channel: "agent",
3000
+ roles: []
3001
+ };
3002
+ }
3003
+ function createOperationToolHandler(registry, operationRef) {
3004
+ return async (input, context) => {
3005
+ const handlerCtx = toolCtxToHandlerCtx(context);
3006
+ const result = await registry.execute(operationRef.key, operationRef.version, input ?? {}, handlerCtx);
3007
+ return result;
3008
+ };
3009
+ }
3010
+
3011
+ // src/tools/subagent-tool.ts
3012
+ import { readUIMessageStream, tool as tool2 } from "ai";
3013
+ import { z as z3 } from "zod";
3014
+ function toReadableStream(iterable) {
3015
+ if (iterable instanceof ReadableStream) {
3016
+ return iterable;
3017
+ }
3018
+ return new ReadableStream({
3019
+ async start(controller) {
3020
+ try {
3021
+ for await (const chunk of iterable) {
3022
+ controller.enqueue(chunk);
3023
+ }
3024
+ } finally {
3025
+ controller.close();
3026
+ }
3027
+ }
3028
+ });
3029
+ }
3030
+ function createSubagentTool(options) {
3031
+ const {
3032
+ subagent,
3033
+ description = "Research a topic or question in depth.",
3034
+ taskParam = "task",
3035
+ toModelSummary = true,
3036
+ passConversationHistory = false
3037
+ } = options;
3038
+ const inputSchema = z3.object({
3039
+ [taskParam]: z3.string().describe("The research task to complete")
3040
+ });
3041
+ const execute = async function* (input, options2) {
3042
+ const task = String(input[taskParam] ?? input.task ?? "");
3043
+ const { abortSignal, messages } = options2 ?? {};
3044
+ if (passConversationHistory && messages && messages.length > 0 && typeof subagent.generate === "function") {
3045
+ const result2 = await subagent.generate({
3046
+ messages: [...messages, { role: "user", content: task }],
3047
+ abortSignal
3048
+ });
3049
+ yield { parts: [{ type: "text", text: result2.text }] };
3050
+ return;
3051
+ }
3052
+ const result = await subagent.stream({
3053
+ prompt: task,
3054
+ abortSignal
3055
+ });
3056
+ const uiStream = result.toUIMessageStream();
3057
+ const stream = toReadableStream(uiStream);
3058
+ for await (const message of readUIMessageStream({
3059
+ stream
3060
+ })) {
3061
+ yield message;
3062
+ }
3063
+ };
3064
+ const toolOptions = {
3065
+ description,
3066
+ inputSchema,
3067
+ execute,
3068
+ ...toModelSummary && {
3069
+ toModelOutput: ({
3070
+ output
3071
+ }) => {
3072
+ const parts = output?.parts;
3073
+ if (!Array.isArray(parts)) {
3074
+ return { type: "text", value: "Task completed." };
3075
+ }
3076
+ const lastTextPart = [...parts].reverse().find((p) => p?.type === "text");
3077
+ return {
3078
+ type: "text",
3079
+ value: lastTextPart?.text ?? "Task completed."
3080
+ };
3081
+ }
3082
+ }
3083
+ };
3084
+ return tool2(toolOptions);
3085
+ }
3086
+ var init_subagent_tool = () => {};
3087
+
3088
+ // src/tools/tool-adapter.ts
3089
+ import { tool as tool3 } from "ai";
3090
+ function isAsyncGenerator(value) {
3091
+ return typeof value === "object" && value !== null && typeof value.next === "function" && typeof value[Symbol.asyncIterator] === "function";
3092
+ }
3093
+ function specToolToAISDKTool(specTool, handler, context = {}, effectiveInputSchema, operationSpec) {
3094
+ let lastInvocationAt;
3095
+ const inputSchema = effectiveInputSchema ?? jsonSchemaToZodSafe(specTool.schema);
3096
+ const buildContext = (signal) => ({
3097
+ agentId: context.agentId ?? "unknown",
3098
+ sessionId: context.sessionId ?? "unknown",
3099
+ tenantId: context.tenantId,
3100
+ actorId: context.actorId,
3101
+ locale: context.locale,
3102
+ metadata: context.metadata,
3103
+ signal
3104
+ });
3105
+ return tool3({
3106
+ description: specTool.description ?? specTool.name,
3107
+ inputSchema,
3108
+ needsApproval: specTool.requiresApproval ?? !specTool.automationSafe,
3109
+ execute: async function* (input, options) {
3110
+ const now = Date.now();
3111
+ const cooldownMs = normalizeDuration(specTool.cooldownMs);
3112
+ if (cooldownMs && lastInvocationAt !== undefined) {
3113
+ const elapsed = now - lastInvocationAt;
3114
+ if (elapsed < cooldownMs) {
3115
+ const retryAfterMs = cooldownMs - elapsed;
3116
+ throw createToolExecutionError(`Tool "${specTool.name}" is cooling down. Retry in ${retryAfterMs}ms.`, "TOOL_COOLDOWN_ACTIVE", retryAfterMs);
3117
+ }
3118
+ }
3119
+ const timeoutMs = normalizeDuration(specTool.timeoutMs);
3120
+ const signal = options?.abortSignal ?? context.signal;
3121
+ const { signal: timeoutSignal, dispose } = createTimeoutSignal(signal, timeoutMs);
3122
+ try {
3123
+ const execution = handler(input, buildContext(timeoutSignal));
3124
+ if (isAsyncGenerator(execution)) {
3125
+ for await (const raw of execution) {
3126
+ const wrapped = wrapToolOutputForRendering(specTool, raw, operationSpec);
3127
+ yield typeof wrapped === "string" ? wrapped : wrapped;
3128
+ }
3129
+ } else {
3130
+ const raw = timeoutMs ? await withTimeout(Promise.resolve(execution), timeoutMs, specTool.name) : await Promise.resolve(execution);
3131
+ const wrapped = wrapToolOutputForRendering(specTool, raw, operationSpec);
3132
+ yield typeof wrapped === "string" ? wrapped : wrapped;
3133
+ }
3134
+ } finally {
3135
+ dispose();
3136
+ lastInvocationAt = Date.now();
3137
+ }
3138
+ }
3139
+ });
3140
+ }
3141
+ function specToolsToAISDKTools(specTools, handlers, context = {}, options) {
3142
+ const tools = {};
3143
+ for (const specTool of specTools) {
3144
+ if (specTool.subagentRef && options?.subagentRegistry) {
3145
+ const subagent = options.subagentRegistry.get(specTool.subagentRef.agentId);
3146
+ if (!subagent) {
3147
+ throw new Error(`Subagent not found: ${specTool.subagentRef.agentId}. Register it in subagentRegistry.`);
3148
+ }
3149
+ if (specTool.requiresApproval === true || specTool.automationSafe === false) {
3150
+ console.warn(`[ContractSpec] Subagent tool "${specTool.name}" cannot use needsApproval. ` + `requiresApproval and automationSafe are ignored for subagent tools (AI SDK limitation). ` + `See https://ai-sdk.dev/docs/agents/subagents#no-tool-approvals-in-subagents`);
3151
+ }
3152
+ tools[specTool.name] = createSubagentTool({
3153
+ subagent,
3154
+ description: specTool.description ?? specTool.name,
3155
+ toModelSummary: specTool.subagentRef.toModelSummary ?? true,
3156
+ passConversationHistory: specTool.subagentRef.passConversationHistory
3157
+ });
3158
+ continue;
3159
+ }
3160
+ let handler;
3161
+ let effectiveInputSchema;
3162
+ let op;
3163
+ if (specTool.operationRef && options?.operationRegistry) {
3164
+ op = options.operationRegistry.get(specTool.operationRef.key, specTool.operationRef.version);
3165
+ if (!op) {
3166
+ throw new Error(`Operation not found: ${specTool.operationRef.key}${specTool.operationRef.version ? `.v${specTool.operationRef.version}` : ""}`);
3167
+ }
3168
+ handler = createOperationToolHandler(options.operationRegistry, specTool.operationRef);
3169
+ effectiveInputSchema = op.io.input?.getZod?.();
3170
+ } else {
3171
+ const manualHandler = handlers.get(specTool.name);
3172
+ if (!manualHandler) {
3173
+ if (specTool.subagentRef) {
3174
+ throw new Error(`Subagent tool "${specTool.name}" requires subagentRegistry. Pass subagentRegistry in ContractSpecAgentConfig.`);
3175
+ }
3176
+ throw new Error(createAgentI18n(context.locale).t("error.missingToolHandler", {
3177
+ name: specTool.name
3178
+ }));
3179
+ }
3180
+ handler = manualHandler;
3181
+ }
3182
+ tools[specTool.name] = specToolToAISDKTool(specTool, handler, context, effectiveInputSchema, op);
3183
+ }
3184
+ return tools;
3185
+ }
3186
+ function createToolHandler(handler) {
3187
+ return (input, context) => {
3188
+ return handler(input, context);
3189
+ };
3190
+ }
3191
+ function buildToolHandlers(handlersObj) {
3192
+ return new Map(Object.entries(handlersObj));
3193
+ }
3194
+ function wrapToolOutputForRendering(specTool, result, operationSpec) {
3195
+ const presentation = specTool.outputPresentation ?? operationSpec?.outputPresentation;
3196
+ const form = specTool.outputForm ?? operationSpec?.outputForm;
3197
+ const dataView = specTool.outputDataView ?? operationSpec?.outputDataView;
3198
+ if (presentation) {
3199
+ return {
3200
+ presentationKey: presentation.key,
3201
+ data: result
3202
+ };
3203
+ }
3204
+ if (form) {
3205
+ return {
3206
+ formKey: form.key,
3207
+ defaultValues: typeof result === "object" && result !== null ? result : {}
3208
+ };
3209
+ }
3210
+ if (dataView) {
3211
+ return {
3212
+ dataViewKey: dataView.key,
3213
+ items: Array.isArray(result) ? result : result != null ? [result] : []
3214
+ };
3215
+ }
3216
+ return result;
3217
+ }
3218
+ function normalizeDuration(value) {
3219
+ if (value === undefined) {
3220
+ return;
3221
+ }
3222
+ if (!Number.isFinite(value)) {
3223
+ return;
3224
+ }
3225
+ if (value <= 0) {
3226
+ return;
3227
+ }
3228
+ return Math.round(value);
3229
+ }
3230
+ function withTimeout(execution, timeoutMs, toolName) {
3231
+ return new Promise((resolve, reject) => {
3232
+ const timeoutHandle = setTimeout(() => {
3233
+ reject(createToolExecutionError(`Tool "${toolName}" timed out after ${timeoutMs}ms.`, "TOOL_EXECUTION_TIMEOUT"));
3234
+ }, timeoutMs);
3235
+ execution.then((result) => {
3236
+ clearTimeout(timeoutHandle);
3237
+ resolve(result);
3238
+ }).catch((error) => {
3239
+ clearTimeout(timeoutHandle);
3240
+ reject(error);
3241
+ });
3242
+ });
3243
+ }
3244
+ function createTimeoutSignal(signal, timeoutMs) {
3245
+ const controller = new AbortController;
3246
+ const abortFromSource = () => controller.abort();
3247
+ if (signal) {
3248
+ if (signal.aborted) {
3249
+ controller.abort();
3250
+ } else {
3251
+ signal.addEventListener("abort", abortFromSource);
3252
+ }
3253
+ }
3254
+ const timeoutHandle = timeoutMs !== undefined ? setTimeout(() => {
3255
+ controller.abort();
3256
+ }, timeoutMs) : undefined;
3257
+ return {
3258
+ signal: controller.signal,
3259
+ dispose: () => {
3260
+ if (timeoutHandle !== undefined) {
3261
+ clearTimeout(timeoutHandle);
3262
+ }
3263
+ if (signal) {
3264
+ signal.removeEventListener("abort", abortFromSource);
3265
+ }
3266
+ }
3267
+ };
3268
+ }
3269
+ function createToolExecutionError(message, code, retryAfterMs) {
3270
+ return Object.assign(new Error(message), {
3271
+ code,
3272
+ kind: "retryable",
3273
+ retryAfterMs
3274
+ });
3275
+ }
3276
+ var init_tool_adapter = __esm(() => {
3277
+ init_i18n();
3278
+ init_json_schema_to_zod();
3279
+ init_subagent_tool();
3280
+ });
3281
+
3282
+ // src/telemetry/posthog.ts
3283
+ var exports_posthog = {};
3284
+ __export(exports_posthog, {
3285
+ createPostHogTracedModel: () => createPostHogTracedModel,
3286
+ createPostHogTelemetryCollector: () => createPostHogTelemetryCollector,
3287
+ createCompositeTelemetryCollector: () => createCompositeTelemetryCollector,
3288
+ PostHogTelemetryCollector: () => PostHogTelemetryCollector,
3289
+ CompositeTelemetryCollector: () => CompositeTelemetryCollector
3290
+ });
3291
+ async function createPostHogTracedModel(model, config, overrides) {
3292
+ const { withTracing } = await importPostHogAI();
3293
+ const phClient = await resolvePostHogClient(config);
3294
+ const tracingOptions = {
3295
+ ...config.defaults,
3296
+ ...overrides
3297
+ };
3298
+ return withTracing(model, phClient, tracingOptions);
3299
+ }
3300
+
3301
+ class PostHogTelemetryCollector {
3302
+ phClient;
3303
+ config;
3304
+ initPromise;
3305
+ constructor(config) {
3306
+ this.config = config;
3307
+ this.phClient = config.client;
3308
+ }
3309
+ async collect(sample) {
3310
+ const client = await this.getClient();
3311
+ const metadata = asRecord(sample.metadata);
3312
+ const distinctId = this.config.defaults?.posthogDistinctId ?? asString(metadata["actorId"]) ?? "system";
3313
+ const traceId = asString(metadata["traceId"]) ?? this.config.defaults?.posthogTraceId;
3314
+ const sessionId = asString(metadata["sessionId"]);
3315
+ const telemetryEvent = asString(metadata["telemetryEvent"]);
3316
+ const event = telemetryEvent === "span" ? "$ai_span" : "$ai_generation";
3317
+ const tokenUsage = metadata["tokenUsage"];
3318
+ const totalUsage = metadata["totalUsage"];
3319
+ const errorMessage = asString(metadata["errorMessage"]);
3320
+ client.capture({
3321
+ distinctId,
3322
+ event,
3323
+ properties: {
3324
+ $ai_model: asString(metadata["responseModelId"]) ?? sample.operation.name,
3325
+ $ai_provider: asString(metadata["provider"]) ?? "contractspec",
3326
+ $ai_latency: sample.durationMs / 1000,
3327
+ $ai_is_error: !sample.success,
3328
+ $ai_error: !sample.success ? errorMessage : undefined,
3329
+ $ai_trace_id: traceId,
3330
+ $ai_session_id: sessionId,
3331
+ $ai_span_id: asString(metadata["spanId"]),
3332
+ $ai_parent_id: asString(metadata["parentSpanId"]),
3333
+ $ai_span_name: asString(metadata["spanName"]) ?? sample.operation.name,
3334
+ ...tokenUsage ? mapTokenUsage(tokenUsage) : {},
3335
+ ...totalUsage ? mapTotalUsage(totalUsage) : {},
3336
+ $ai_http_status: asNumber(metadata["httpStatus"]),
3337
+ $ai_request_url: asString(metadata["requestUrl"]),
3338
+ $ai_base_url: asString(metadata["baseUrl"]),
3339
+ ...this.config.defaults?.posthogProperties,
3340
+ contractspec_operation: sample.operation.name,
3341
+ contractspec_version: sample.operation.version,
3342
+ contractspec_agent_id: asString(metadata["agentId"]),
3343
+ contractspec_tenant_id: asString(metadata["tenantId"]),
3344
+ contractspec_actor_id: asString(metadata["actorId"]),
3345
+ contractspec_step_index: asNumber(metadata["stepIndex"]),
3346
+ contractspec_step_started_at: asDateIso(metadata["stepStartedAt"]),
3347
+ contractspec_finish_reason: asString(metadata["finishReason"]),
3348
+ contractspec_finish_reason_raw: asString(metadata["rawFinishReason"]),
3349
+ contractspec_tool_count: asNumber(metadata["toolCallCount"]),
3350
+ contractspec_tool_name: asString(metadata["toolName"]),
3351
+ contractspec_tool_call_args: metadata["toolCallArgs"],
3352
+ contractspec_tool_result_output: metadata["toolResultOutput"],
3353
+ contractspec_provider_metadata: metadata["providerMetadata"],
3354
+ contractspec_step_warnings: metadata["warnings"],
3355
+ contractspec_response_id: asString(metadata["responseId"]),
3356
+ contractspec_response_model_id: asString(metadata["responseModelId"]),
3357
+ contractspec_response_timestamp: asDateIso(metadata["responseTimestamp"]),
3358
+ contractspec_response_headers: metadata["responseHeaders"],
3359
+ contractspec_response_body: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["responseBody"],
3360
+ contractspec_response_messages: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["responseMessages"],
3361
+ contractspec_request_headers: metadata["requestHeaders"],
3362
+ contractspec_request_body: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["requestBody"],
3363
+ contractspec_step_text: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["stepText"],
3364
+ contractspec_step_reasoning_text: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["stepReasoningText"]
3365
+ },
3366
+ groups: this.config.defaults?.posthogGroups
3367
+ });
3368
+ }
3369
+ async shutdown() {
3370
+ if (this.phClient?.shutdown) {
3371
+ await this.phClient.shutdown();
3372
+ }
3373
+ }
3374
+ async getClient() {
3375
+ if (this.phClient)
3376
+ return this.phClient;
3377
+ if (!this.initPromise) {
3378
+ this.initPromise = resolvePostHogClient(this.config).then((client) => {
3379
+ this.phClient = client;
3380
+ return client;
3381
+ });
3382
+ }
3383
+ return this.initPromise;
3384
+ }
3385
+ }
3386
+ function createPostHogTelemetryCollector(config) {
3387
+ return new PostHogTelemetryCollector(config);
3388
+ }
3389
+
3390
+ class CompositeTelemetryCollector {
3391
+ collectors;
3392
+ constructor(collectors) {
3393
+ this.collectors = collectors;
3394
+ }
3395
+ async collect(sample) {
3396
+ await Promise.all(this.collectors.map((c) => c.collect(sample)));
3397
+ }
3398
+ }
3399
+ function createCompositeTelemetryCollector(collectors) {
3400
+ return new CompositeTelemetryCollector(collectors);
3401
+ }
3402
+ async function importPostHogAI() {
3403
+ try {
3404
+ return await runtimeImport("@posthog/ai");
3405
+ } catch {
3406
+ throw new Error(createAgentI18n().t("error.telemetry.posthogAiRequired"));
3407
+ }
3408
+ }
3409
+ async function resolvePostHogClient(config) {
3410
+ if (config.client)
3411
+ return config.client;
3412
+ if (!config.apiKey) {
3413
+ throw new Error(createAgentI18n().t("error.telemetry.posthogClientOrKeyRequired"));
3414
+ }
3415
+ try {
3416
+ const { PostHog } = await runtimeImport("posthog-node");
3417
+ return new PostHog(config.apiKey, {
3418
+ host: config.host ?? "https://us.i.posthog.com"
3419
+ });
3420
+ } catch {
3421
+ throw new Error(createAgentI18n().t("error.telemetry.posthogNodeRequired"));
3422
+ }
3423
+ }
3424
+ function mapTokenUsage(usage) {
3425
+ const usageRecord = asRecord(usage);
3426
+ const inputTokenDetails = asRecord(usageRecord["inputTokenDetails"]);
3427
+ const outputTokenDetails = asRecord(usageRecord["outputTokenDetails"]);
3428
+ return {
3429
+ $ai_input_tokens: asNumber(usageRecord["inputTokens"]) ?? asNumber(usageRecord["promptTokens"]),
3430
+ $ai_output_tokens: asNumber(usageRecord["outputTokens"]) ?? asNumber(usageRecord["completionTokens"]),
3431
+ $ai_reasoning_tokens: asNumber(outputTokenDetails["reasoningTokens"]) ?? asNumber(usageRecord["reasoningTokens"]),
3432
+ $ai_cache_read_input_tokens: asNumber(inputTokenDetails["cacheReadTokens"]) ?? asNumber(usageRecord["cachedInputTokens"]),
3433
+ $ai_cache_creation_input_tokens: asNumber(inputTokenDetails["cacheWriteTokens"]),
3434
+ $ai_usage: maybeRecord(usageRecord["raw"]) ?? usageRecord
3435
+ };
3436
+ }
3437
+ function mapTotalUsage(usage) {
3438
+ const usageRecord = asRecord(usage);
3439
+ return {
3440
+ contractspec_total_input_tokens: asNumber(usageRecord["inputTokens"]),
3441
+ contractspec_total_output_tokens: asNumber(usageRecord["outputTokens"]),
3442
+ contractspec_total_tokens: asNumber(usageRecord["totalTokens"]),
3443
+ contractspec_total_usage_raw: maybeRecord(usageRecord["raw"]) ?? usageRecord
3444
+ };
3445
+ }
3446
+ function asRecord(value) {
3447
+ return value && typeof value === "object" ? value : {};
3448
+ }
3449
+ function maybeRecord(value) {
3450
+ return value && typeof value === "object" ? value : undefined;
3451
+ }
3452
+ function asString(value) {
3453
+ return typeof value === "string" && value.length > 0 ? value : undefined;
3454
+ }
3455
+ function asNumber(value) {
3456
+ return typeof value === "number" ? value : undefined;
3457
+ }
3458
+ function asDateIso(value) {
3459
+ if (value instanceof Date)
3460
+ return value.toISOString();
3461
+ return;
3462
+ }
3463
+ var runtimeImport;
3464
+ var init_posthog = __esm(() => {
3465
+ init_i18n();
3466
+ runtimeImport = new Function("specifier", "return import(specifier)");
3467
+ });
3468
+
3469
+ // src/agent/contract-spec-agent.ts
3470
+ var exports_contract_spec_agent = {};
3471
+ __export(exports_contract_spec_agent, {
3472
+ ContractSpecAgent: () => ContractSpecAgent
3473
+ });
3474
+ import { randomUUID as randomUUID2 } from "node:crypto";
3475
+ import {
3476
+ agentKey
3477
+ } from "@contractspec/lib.contracts-spec/agent";
3478
+ import {
3479
+ stepCountIs,
3480
+ Experimental_Agent as ToolLoopAgent
3481
+ } from "ai";
3482
+ import * as z4 from "zod";
3483
+
3484
+ class ContractSpecAgent {
3485
+ version = "agent-v1";
3486
+ id;
3487
+ spec;
3488
+ tools;
3489
+ config;
3490
+ instructions;
3491
+ mcpCleanup;
3492
+ activeStepContexts = new Map;
3493
+ constructor(config, instructions, tools, mcpCleanup) {
3494
+ this.config = config;
3495
+ this.spec = config.spec;
3496
+ this.id = agentKey(config.spec.meta);
3497
+ this.tools = tools;
3498
+ this.instructions = instructions;
3499
+ this.mcpCleanup = mcpCleanup;
3500
+ }
3501
+ static async create(config) {
3502
+ const effectiveConfig = {
3503
+ ...config,
3504
+ approvalWorkflow: config.approvalWorkflow ?? (config.spec.policy?.escalation?.approvalWorkflow ? createApprovalWorkflow() : undefined)
3505
+ };
3506
+ let mcpToolset = null;
3507
+ if ((effectiveConfig.mcpServers?.length ?? 0) > 0) {
3508
+ mcpToolset = await createMcpToolsets(effectiveConfig.mcpServers ?? [], {
3509
+ onNameCollision: "error"
3510
+ });
3511
+ }
3512
+ try {
3513
+ const instructions = await injectStaticKnowledge(effectiveConfig.spec.instructions, effectiveConfig.spec.knowledge ?? [], effectiveConfig.knowledgeRetriever);
3514
+ const specTools = specToolsToAISDKTools(effectiveConfig.spec.tools, effectiveConfig.toolHandlers, { agentId: agentKey(effectiveConfig.spec.meta) }, {
3515
+ operationRegistry: effectiveConfig.operationRegistry,
3516
+ subagentRegistry: effectiveConfig.subagentRegistry
3517
+ });
3518
+ const knowledgeTool = effectiveConfig.knowledgeRetriever ? createKnowledgeQueryTool(effectiveConfig.knowledgeRetriever, effectiveConfig.spec.knowledge ?? []) : null;
3519
+ const memoryTool = effectiveConfig.spec.memoryTools?.provider === "anthropic" && effectiveConfig.agentMemoryStore ? createAnthropicMemoryTool(effectiveConfig.agentMemoryStore) : null;
3520
+ const reservedToolNames = new Set(Object.keys(specTools));
3521
+ if (knowledgeTool) {
3522
+ reservedToolNames.add("query_knowledge");
3523
+ }
3524
+ if (memoryTool) {
3525
+ reservedToolNames.add("memory");
3526
+ }
3527
+ const conflictingMcpTools = Object.keys(mcpToolset?.tools ?? {}).filter((toolName) => reservedToolNames.has(toolName));
3528
+ if (conflictingMcpTools.length > 0) {
3529
+ throw new Error(`MCP tools conflict with agent tools: ${conflictingMcpTools.join(", ")}. Configure MCP toolPrefix values to avoid collisions.`);
3530
+ }
3531
+ const tools = {
3532
+ ...specTools,
3533
+ ...knowledgeTool ? { query_knowledge: knowledgeTool } : {},
3534
+ ...memoryTool ? { memory: memoryTool } : {},
3535
+ ...mcpToolset?.tools ?? {},
3536
+ ...effectiveConfig.additionalTools ?? {}
3537
+ };
3538
+ return new ContractSpecAgent(effectiveConfig, instructions, tools, mcpToolset?.cleanup);
3539
+ } catch (error) {
3540
+ if (mcpToolset) {
3541
+ await mcpToolset.cleanup().catch(() => {
3542
+ return;
3543
+ });
3544
+ }
3545
+ throw error;
3546
+ }
3547
+ }
3548
+ async cleanup() {
3549
+ if (!this.mcpCleanup) {
3550
+ return;
3551
+ }
3552
+ const cleanup = this.mcpCleanup;
3553
+ this.mcpCleanup = undefined;
3554
+ await cleanup();
3555
+ }
3556
+ async generate(params) {
3557
+ const sessionId = params.options?.sessionId ?? generateSessionId();
3558
+ const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID2();
3559
+ const workflowId = params.options?.workflowId ?? params.options?.metadata?.["workflowId"];
3560
+ const threadId = params.options?.threadId ?? params.options?.metadata?.["threadId"];
3561
+ const runtimeAdapter = this.resolveRuntimeAdapter();
3562
+ this.activeStepContexts.set(sessionId, {
3563
+ traceId,
3564
+ tenantId: params.options?.tenantId,
3565
+ actorId: params.options?.actorId,
3566
+ workflowId,
3567
+ threadId,
3568
+ stepIndex: 0,
3569
+ stepStartedAt: new Date
3570
+ });
3571
+ if (!params.messages?.length) {
3572
+ await this.ensureSession({
3573
+ sessionId,
3574
+ prompt: params.prompt ?? "",
3575
+ options: params.options,
3576
+ traceId
3577
+ });
3578
+ await this.runSessionMiddleware(sessionId, runtimeAdapter?.middleware?.beforeModel);
3579
+ }
3580
+ const model = await this.resolveModelForCall({
3581
+ sessionId,
3582
+ traceId,
3583
+ options: params.options
3584
+ });
3585
+ const effectiveMaxSteps = resolveMaxSteps(params.maxSteps, this.spec.maxSteps);
3586
+ const inner = this.createInnerAgent(model, effectiveMaxSteps);
3587
+ const generateOptions = {
3588
+ abortSignal: params.signal,
3589
+ options: {
3590
+ tenantId: params.options?.tenantId,
3591
+ actorId: params.options?.actorId,
3592
+ sessionId,
3593
+ workflowId,
3594
+ threadId,
3595
+ metadata: params.options?.metadata
3596
+ }
3597
+ };
3598
+ let result;
3599
+ try {
3600
+ if (params.messages && params.messages.length > 0) {
3601
+ result = await inner.generate({
3602
+ messages: params.messages,
3603
+ ...generateOptions
3604
+ });
3605
+ } else {
3606
+ const prompt = params.systemOverride && params.prompt ? `${this.instructions}
3607
+
3608
+ ${params.systemOverride}
3609
+
3610
+ ${params.prompt}` : params.prompt ?? "";
3611
+ result = await inner.generate({
3612
+ prompt,
3613
+ ...generateOptions
3614
+ });
3615
+ }
3616
+ } catch (error) {
3617
+ const executionError = toAgentExecutionError(error);
3618
+ if (this.config.sessionStore) {
3619
+ await this.config.sessionStore.update(sessionId, {
3620
+ status: "failed",
3621
+ traceId,
3622
+ workflowId,
3623
+ threadId,
3624
+ lastError: executionError
3625
+ });
3626
+ await this.syncSessionCheckpoint(sessionId);
3627
+ }
3628
+ await this.emitAgentEvent("agent.failed", {
3629
+ sessionId,
3630
+ tenantId: params.options?.tenantId,
3631
+ workflowId,
3632
+ traceId,
3633
+ metadata: {
3634
+ error: executionError.message,
3635
+ code: executionError.code ?? executionError.kind
3636
+ }
3637
+ });
3638
+ this.activeStepContexts.delete(sessionId);
3639
+ throw error;
3640
+ }
3641
+ if (!params.messages?.length) {
3642
+ await this.runSessionMiddleware(sessionId, runtimeAdapter?.middleware?.afterModel);
3643
+ }
3644
+ let pendingApproval = this.activeStepContexts.get(sessionId)?.pendingApproval;
3645
+ const escalationError = pendingApproval ? undefined : resolveEscalationError(this.spec, result.finishReason);
3646
+ if (this.config.sessionStore && result.text.trim().length > 0) {
3647
+ const currentSession = await this.config.sessionStore.get(sessionId);
3648
+ const lastMessage = currentSession?.messages.at(-1);
3649
+ const lastContent = lastMessage && "content" in lastMessage ? lastMessage.content : undefined;
3650
+ if (lastMessage?.role !== "assistant" || lastContent !== result.text) {
3651
+ await this.config.sessionStore.appendMessage(sessionId, {
3652
+ role: "assistant",
3653
+ content: result.text
3654
+ });
3655
+ }
3656
+ }
3657
+ if (!pendingApproval && escalationError) {
3658
+ pendingApproval = await this.requestApproval(sessionId, {
3659
+ toolName: this.spec.policy?.escalation?.approvalWorkflow ?? "approval_required",
3660
+ toolCallId: `approval_${sessionId}`,
3661
+ args: {
3662
+ finishReason: result.finishReason,
3663
+ threshold: this.spec.policy?.escalation?.confidenceThreshold ?? this.spec.policy?.confidence?.min
3664
+ },
3665
+ reason: escalationError.message,
3666
+ error: escalationError
3667
+ });
3668
+ }
3669
+ const finalStatus = pendingApproval ? "escalated" : "completed";
3670
+ if (this.config.sessionStore) {
3671
+ await this.config.sessionStore.update(sessionId, {
3672
+ status: finalStatus,
3673
+ traceId,
3674
+ workflowId,
3675
+ threadId,
3676
+ pendingApprovalRequestId: pendingApproval?.id,
3677
+ lastError: pendingApproval ? escalationError : undefined
3678
+ });
3679
+ await this.syncSessionCheckpoint(sessionId);
3680
+ }
3681
+ if (pendingApproval) {
3682
+ await this.emitAgentEvent("agent.escalated", {
3683
+ sessionId,
3684
+ tenantId: params.options?.tenantId,
3685
+ workflowId,
3686
+ traceId,
3687
+ metadata: {
3688
+ approvalRequestId: pendingApproval.id,
3689
+ reason: pendingApproval.reason
3690
+ }
3691
+ });
3692
+ } else {
3693
+ await this.emitAgentEvent("agent.completed", {
3694
+ sessionId,
3695
+ tenantId: params.options?.tenantId,
3696
+ workflowId,
3697
+ traceId,
3698
+ metadata: {
3699
+ finishReason: result.finishReason
3700
+ }
3701
+ });
3702
+ }
3703
+ const session = this.config.sessionStore ? await this.config.sessionStore.get(sessionId) : null;
3704
+ this.activeStepContexts.delete(sessionId);
3705
+ return {
3706
+ text: result.text,
3707
+ steps: result.steps,
3708
+ toolCalls: result.toolCalls.map((tc) => ({
3709
+ type: "tool-call",
3710
+ toolCallId: tc.toolCallId,
3711
+ toolName: tc.toolName,
3712
+ args: "args" in tc ? tc.args : ("input" in tc) ? tc.input : undefined
3713
+ })),
3714
+ toolResults: result.toolResults.map((tr) => ({
3715
+ type: "tool-result",
3716
+ toolCallId: tr.toolCallId,
3717
+ toolName: tr.toolName,
3718
+ output: tr.output
3719
+ })),
3720
+ finishReason: result.finishReason,
3721
+ usage: result.usage,
3722
+ session: session ?? undefined,
3723
+ pendingApproval: pendingApproval ? {
3724
+ toolName: pendingApproval.toolName,
3725
+ toolCallId: pendingApproval.toolCallId,
3726
+ args: pendingApproval.toolArgs
3727
+ } : undefined
3728
+ };
3729
+ }
3730
+ async stream(params) {
3731
+ const sessionId = params.options?.sessionId ?? generateSessionId();
3732
+ const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID2();
3733
+ const workflowId = params.options?.workflowId ?? params.options?.metadata?.["workflowId"];
3734
+ const threadId = params.options?.threadId ?? params.options?.metadata?.["threadId"];
3735
+ const runtimeAdapter = this.resolveRuntimeAdapter();
3736
+ this.activeStepContexts.set(sessionId, {
3737
+ traceId,
3738
+ tenantId: params.options?.tenantId,
3739
+ actorId: params.options?.actorId,
3740
+ workflowId,
3741
+ threadId,
3742
+ stepIndex: 0,
3743
+ stepStartedAt: new Date
3744
+ });
3745
+ const prompt = params.systemOverride && params.prompt ? `${this.instructions}
3746
+
3747
+ ${params.systemOverride}
3748
+
3749
+ ${params.prompt}` : params.prompt ?? "";
3750
+ await this.ensureSession({
3751
+ sessionId,
3752
+ prompt,
3753
+ options: params.options,
3754
+ traceId
3755
+ });
3756
+ await this.runSessionMiddleware(sessionId, runtimeAdapter?.middleware?.beforeModel);
3757
+ const model = await this.resolveModelForCall({
3758
+ sessionId,
3759
+ traceId,
3760
+ options: params.options
3761
+ });
3762
+ const effectiveMaxSteps = resolveMaxSteps(params.maxSteps, this.spec.maxSteps);
3763
+ const inner = this.createInnerAgent(model, effectiveMaxSteps);
3764
+ return inner.stream({
3765
+ prompt,
3766
+ abortSignal: params.signal,
3767
+ options: {
3768
+ tenantId: params.options?.tenantId,
3769
+ actorId: params.options?.actorId,
3770
+ sessionId,
3771
+ workflowId,
3772
+ threadId,
3773
+ metadata: params.options?.metadata
3774
+ }
3775
+ });
3776
+ }
3777
+ async handleStepFinish(step) {
3778
+ const sessionId = step.options?.sessionId;
3779
+ const context = sessionId ? this.activeStepContexts.get(sessionId) : undefined;
3780
+ if (sessionId && this.config.sessionStore) {
3781
+ await this.config.sessionStore.appendStep(sessionId, step);
3782
+ if (step.text.trim().length > 0) {
3783
+ await this.config.sessionStore.appendMessage(sessionId, {
3784
+ role: "assistant",
3785
+ content: step.text
3786
+ });
3787
+ }
3788
+ for (const toolCall of step.toolCalls ?? []) {
3789
+ await this.emitAgentEvent("agent.tool.called", {
3790
+ sessionId,
3791
+ tenantId: context?.tenantId,
3792
+ workflowId: context?.workflowId,
3793
+ traceId: context?.traceId,
3794
+ stepIndex: context?.stepIndex,
3795
+ toolName: toolCall.toolName,
3796
+ metadata: {
3797
+ toolCallId: toolCall.toolCallId
3798
+ }
3799
+ });
3800
+ }
3801
+ for (const toolResult of step.toolResults ?? []) {
3802
+ const toolCall = step.toolCalls?.find((candidate) => candidate.toolCallId === toolResult.toolCallId);
3803
+ const toolError = extractToolExecutionError(toolResult.output);
3804
+ await this.config.sessionStore.appendMessage(sessionId, {
3805
+ role: "tool",
3806
+ content: stringifyToolResult(toolResult.toolName, toolResult.output)
3807
+ });
3808
+ if (toolError) {
3809
+ await this.emitAgentEvent("agent.tool.failed", {
3810
+ sessionId,
3811
+ tenantId: context?.tenantId,
3812
+ workflowId: context?.workflowId,
3813
+ traceId: context?.traceId,
3814
+ stepIndex: context?.stepIndex,
3815
+ toolName: toolResult.toolName,
3816
+ metadata: {
3817
+ toolCallId: toolResult.toolCallId,
3818
+ error: toolError.message,
3819
+ code: toolError.code
3820
+ }
3821
+ });
3822
+ const shouldEscalate = toolError.kind === "timeout" && this.spec.policy?.escalation?.onTimeout || toolError.kind !== "timeout" && this.spec.policy?.escalation?.onToolFailure;
3823
+ if (shouldEscalate && toolCall && !context?.pendingApproval) {
3824
+ await this.requestApproval(sessionId, {
3825
+ toolName: toolCall.toolName,
3826
+ toolCallId: toolCall.toolCallId,
3827
+ args: toolCall.input,
3828
+ reason: toolError.message,
3829
+ error: toolError
3830
+ });
3831
+ }
3832
+ } else {
3833
+ await this.emitAgentEvent("agent.tool.completed", {
3834
+ sessionId,
3835
+ tenantId: context?.tenantId,
3836
+ workflowId: context?.workflowId,
3837
+ traceId: context?.traceId,
3838
+ stepIndex: context?.stepIndex,
3839
+ toolName: toolResult.toolName,
3840
+ metadata: {
3841
+ toolCallId: toolResult.toolCallId
3842
+ }
3843
+ });
3844
+ }
3845
+ }
3846
+ await this.config.sessionStore.update(sessionId, {
3847
+ status: context?.pendingApproval ? "escalated" : step.finishReason === "tool-calls" ? "waiting" : "running",
3848
+ workflowId: context?.workflowId,
3849
+ threadId: context?.threadId,
3850
+ traceId: context?.traceId,
3851
+ pendingApprovalRequestId: context?.pendingApproval?.id
3852
+ });
3853
+ await this.syncSessionCheckpoint(sessionId);
3854
+ }
3855
+ if (this.config.telemetryCollector) {
3856
+ const now = new Date;
3857
+ const stepStartedAt = context?.stepStartedAt ?? now;
3858
+ const durationMs = Math.max(now.getTime() - stepStartedAt.getTime(), 0);
3859
+ if (context) {
3860
+ context.stepIndex += 1;
3861
+ context.stepStartedAt = now;
3862
+ }
3863
+ await trackAgentStep(this.config.telemetryCollector, this.id, step, durationMs, {
3864
+ sessionId,
3865
+ tenantId: context?.tenantId,
3866
+ actorId: context?.actorId,
3867
+ workflowId: context?.workflowId,
3868
+ traceId: context?.traceId,
3869
+ stepIndex: context?.stepIndex,
3870
+ stepStartedAt
3871
+ });
3872
+ if (sessionId && step.finishReason !== "tool-calls") {
3873
+ this.activeStepContexts.delete(sessionId);
3874
+ }
3875
+ }
3876
+ }
3877
+ async ensureSession(params) {
3878
+ if (!this.config.sessionStore) {
3879
+ return;
3880
+ }
3881
+ const runtimeAdapter = this.resolveRuntimeAdapter();
3882
+ let session = await this.config.sessionStore.get(params.sessionId);
3883
+ const previousStatus = session?.status;
3884
+ if (!session && runtimeAdapter?.checkpoint) {
3885
+ const checkpoint = await runtimeAdapter.checkpoint.load(params.sessionId);
3886
+ if (checkpoint) {
3887
+ session = await this.config.sessionStore.create({
3888
+ ...omitSessionTimestamps(checkpoint.state),
3889
+ workflowId: params.options?.workflowId ?? checkpoint.state.workflowId,
3890
+ threadId: params.options?.threadId ?? checkpoint.state.threadId,
3891
+ traceId: params.traceId,
3892
+ checkpointId: checkpoint.checkpointId,
3893
+ status: "running",
3894
+ pendingApprovalRequestId: undefined,
3895
+ lastError: undefined,
3896
+ metadata: params.options?.metadata ?? checkpoint.state.metadata
3897
+ });
3898
+ }
3899
+ }
3900
+ if (!session) {
3901
+ session = await this.config.sessionStore.create({
3902
+ sessionId: params.sessionId,
3903
+ agentId: this.id,
3904
+ tenantId: params.options?.tenantId,
3905
+ actorId: params.options?.actorId,
3906
+ workflowId: params.options?.workflowId,
3907
+ threadId: params.options?.threadId,
3908
+ traceId: params.traceId,
3909
+ status: "running",
3910
+ messages: [],
3911
+ steps: [],
3912
+ metadata: params.options?.metadata
3913
+ });
3914
+ await this.emitAgentEvent("agent.session.created", {
3915
+ sessionId: params.sessionId,
3916
+ tenantId: params.options?.tenantId,
3917
+ workflowId: params.options?.workflowId,
3918
+ traceId: params.traceId
3919
+ });
3920
+ } else {
3921
+ await this.config.sessionStore.update(params.sessionId, {
3922
+ status: "running",
3923
+ workflowId: params.options?.workflowId ?? session.workflowId,
3924
+ threadId: params.options?.threadId ?? session.threadId,
3925
+ traceId: params.traceId,
3926
+ metadata: params.options?.metadata ?? session.metadata,
3927
+ pendingApprovalRequestId: undefined,
3928
+ lastError: undefined
3929
+ });
3930
+ await this.emitAgentEvent("agent.session.updated", {
3931
+ sessionId: params.sessionId,
3932
+ tenantId: params.options?.tenantId ?? session.tenantId,
3933
+ workflowId: params.options?.workflowId ?? session.workflowId,
3934
+ traceId: params.traceId,
3935
+ metadata: {
3936
+ previousStatus: previousStatus ?? "idle",
3937
+ nextStatus: "running"
3938
+ }
3939
+ });
3940
+ }
3941
+ await this.config.sessionStore.appendMessage(params.sessionId, {
3942
+ role: "user",
3943
+ content: params.prompt
3944
+ });
3945
+ if (runtimeAdapter?.suspendResume && (previousStatus === "waiting" || previousStatus === "escalated")) {
3946
+ await runtimeAdapter.suspendResume.resume({
3947
+ sessionId: params.sessionId,
3948
+ input: params.prompt,
3949
+ metadata: compactStringRecord({
3950
+ traceId: params.traceId,
3951
+ workflowId: params.options?.workflowId,
3952
+ threadId: params.options?.threadId
3953
+ })
3954
+ });
3955
+ }
3956
+ await this.syncSessionCheckpoint(params.sessionId);
3957
+ }
3958
+ resolveRuntimeAdapter() {
3959
+ return resolveRuntimeAdapterBundle(this.spec, this.config.runtimeAdapters);
3960
+ }
3961
+ async syncSessionCheckpoint(sessionId) {
3962
+ if (!this.config.sessionStore) {
3963
+ return null;
3964
+ }
3965
+ const runtimeAdapter = this.resolveRuntimeAdapter();
3966
+ const session = await this.config.sessionStore.get(sessionId);
3967
+ if (!runtimeAdapter?.checkpoint || !session) {
3968
+ return session;
3969
+ }
3970
+ const checkpointId = `${sessionId}:${Date.now()}`;
3971
+ await runtimeAdapter.checkpoint.save({
3972
+ sessionId,
3973
+ threadId: session.threadId,
3974
+ state: session,
3975
+ checkpointId,
3976
+ createdAt: new Date
3977
+ });
3978
+ await this.config.sessionStore.update(sessionId, {
3979
+ checkpointId
3980
+ });
3981
+ return this.config.sessionStore.get(sessionId);
3982
+ }
3983
+ async runSessionMiddleware(sessionId, hook) {
3984
+ if (!hook || !this.config.sessionStore) {
3985
+ return;
3986
+ }
3987
+ const session = await this.config.sessionStore.get(sessionId);
3988
+ if (!session) {
3989
+ return;
3990
+ }
3991
+ const next = await hook(session);
3992
+ if (!next) {
3993
+ return;
3994
+ }
3995
+ await this.config.sessionStore.update(sessionId, {
3996
+ status: next.status,
3997
+ metadata: next.metadata,
3998
+ workflowId: next.workflowId,
3999
+ threadId: next.threadId,
4000
+ traceId: next.traceId,
4001
+ checkpointId: next.checkpointId,
4002
+ pendingApprovalRequestId: next.pendingApprovalRequestId,
4003
+ lastError: next.lastError
4004
+ });
4005
+ await this.syncSessionCheckpoint(sessionId);
4006
+ }
4007
+ async requestApproval(sessionId, params) {
4008
+ const approvalWorkflow = this.config.approvalWorkflow;
4009
+ const context = this.activeStepContexts.get(sessionId);
4010
+ if (!approvalWorkflow || !context || context.pendingApproval) {
4011
+ return context?.pendingApproval;
4012
+ }
4013
+ const request = await approvalWorkflow.requestApproval({
4014
+ sessionId,
4015
+ agentId: this.id,
4016
+ tenantId: context.tenantId,
4017
+ toolName: params.toolName,
4018
+ toolCallId: params.toolCallId,
4019
+ toolArgs: params.args,
4020
+ reason: params.reason,
4021
+ payload: {
4022
+ traceId: context.traceId,
4023
+ workflowId: context.workflowId,
4024
+ threadId: context.threadId,
4025
+ code: params.error?.code
4026
+ }
4027
+ });
4028
+ context.pendingApproval = request;
4029
+ if (this.config.sessionStore) {
4030
+ await this.config.sessionStore.update(sessionId, {
4031
+ status: "escalated",
4032
+ pendingApprovalRequestId: request.id,
4033
+ lastError: params.error
4034
+ });
4035
+ await this.syncSessionCheckpoint(sessionId);
4036
+ }
4037
+ await this.emitAgentEvent("agent.tool.approval_requested", {
4038
+ sessionId,
4039
+ tenantId: context.tenantId,
4040
+ workflowId: context.workflowId,
4041
+ traceId: context.traceId,
4042
+ stepIndex: context.stepIndex,
4043
+ toolName: params.toolName,
4044
+ metadata: {
4045
+ approvalRequestId: request.id,
4046
+ toolCallId: params.toolCallId,
4047
+ reason: params.reason
4048
+ }
4049
+ });
4050
+ await this.emitAgentEvent("agent.escalated", {
4051
+ sessionId,
4052
+ tenantId: context.tenantId,
4053
+ workflowId: context.workflowId,
4054
+ traceId: context.traceId,
4055
+ stepIndex: context.stepIndex,
4056
+ toolName: params.toolName,
4057
+ metadata: {
4058
+ approvalRequestId: request.id,
4059
+ reason: params.reason
4060
+ }
4061
+ });
4062
+ const runtimeAdapter = this.resolveRuntimeAdapter();
4063
+ if (runtimeAdapter?.suspendResume) {
4064
+ await runtimeAdapter.suspendResume.suspend({
4065
+ sessionId,
4066
+ reason: params.reason,
4067
+ metadata: compactStringRecord({
4068
+ traceId: context.traceId,
4069
+ workflowId: context.workflowId,
4070
+ threadId: context.threadId,
4071
+ approvalRequestId: request.id
4072
+ })
4073
+ });
4074
+ }
4075
+ return request;
4076
+ }
4077
+ async emitAgentEvent(event, payload) {
4078
+ if (!this.config.eventEmitter) {
4079
+ return;
4080
+ }
4081
+ await this.config.eventEmitter(event, {
4082
+ agentId: this.id,
4083
+ ...payload
4084
+ });
4085
+ }
4086
+ createInnerAgent(model, maxSteps) {
4087
+ return new ToolLoopAgent({
4088
+ model,
4089
+ instructions: this.instructions,
4090
+ tools: this.tools,
4091
+ stopWhen: stepCountIs(maxSteps),
4092
+ callOptionsSchema: ContractSpecCallOptionsSchema,
4093
+ onStepFinish: async (step) => {
4094
+ await this.handleStepFinish(step);
4095
+ }
4096
+ });
4097
+ }
4098
+ async resolveModelForCall(params) {
4099
+ if (this.config.modelSelector && params.options?.selectionContext) {
4100
+ const { model } = await this.config.modelSelector.selectAndCreate(params.options.selectionContext);
4101
+ return model;
4102
+ }
4103
+ const posthogConfig = this.config.posthogConfig;
4104
+ if (!posthogConfig) {
4105
+ return this.config.model;
4106
+ }
4107
+ const mergedProperties = {
4108
+ ...posthogConfig.defaults?.posthogProperties,
4109
+ ...posthogConfig.tracingOptions?.posthogProperties,
4110
+ $ai_session_id: params.sessionId,
4111
+ contractspec_session_id: params.sessionId,
4112
+ contractspec_trace_id: params.traceId,
4113
+ contractspec_agent_id: this.id,
4114
+ contractspec_tenant_id: params.options?.tenantId,
4115
+ contractspec_actor_id: params.options?.actorId,
4116
+ contractspec_workflow_id: params.options?.workflowId,
4117
+ contractspec_thread_id: params.options?.threadId
4118
+ };
4119
+ const tracingOptions = {
4120
+ ...posthogConfig.tracingOptions,
4121
+ posthogDistinctId: posthogConfig.tracingOptions?.posthogDistinctId ?? params.options?.actorId,
4122
+ posthogTraceId: params.traceId,
4123
+ posthogProperties: mergedProperties
4124
+ };
4125
+ const { createPostHogTracedModel: createPostHogTracedModel2 } = await Promise.resolve().then(() => (init_posthog(), exports_posthog));
4126
+ return createPostHogTracedModel2(this.config.model, posthogConfig, tracingOptions);
4127
+ }
4128
+ }
4129
+ function omitSessionTimestamps(session) {
4130
+ const { createdAt: _createdAt, updatedAt: _updatedAt, ...rest } = session;
4131
+ return rest;
4132
+ }
4133
+ function resolveRuntimeAdapterBundle(spec, runtimeAdapters) {
4134
+ if (!runtimeAdapters) {
4135
+ return;
4136
+ }
4137
+ const preferredKeys = [
4138
+ "langgraph",
4139
+ "langchain",
4140
+ "workflow-devkit"
4141
+ ];
4142
+ for (const key of preferredKeys) {
4143
+ if (spec.runtime?.capabilities?.adapters?.[key] && runtimeAdapters[key]) {
4144
+ return runtimeAdapters[key];
4145
+ }
4146
+ }
4147
+ for (const key of preferredKeys) {
4148
+ if (runtimeAdapters[key]) {
4149
+ return runtimeAdapters[key];
4150
+ }
4151
+ }
4152
+ return;
4153
+ }
4154
+ function compactStringRecord(input) {
4155
+ return Object.fromEntries(Object.entries(input).filter((entry) => typeof entry[1] === "string" && entry[1].length > 0));
4156
+ }
4157
+ function toAgentExecutionError(error) {
4158
+ if (error && typeof error === "object" && "kind" in error && typeof error.kind === "string" && "message" in error && typeof error.message === "string") {
4159
+ return {
4160
+ kind: error.kind,
4161
+ message: error.message,
4162
+ code: "code" in error && typeof error.code === "string" ? error.code : undefined,
4163
+ retryAfterMs: "retryAfterMs" in error && typeof error.retryAfterMs === "number" ? error.retryAfterMs : undefined
4164
+ };
4165
+ }
4166
+ if (error instanceof Error) {
4167
+ return {
4168
+ kind: error.message.toLowerCase().includes("timeout") || error.code === "TOOL_EXECUTION_TIMEOUT" ? "timeout" : "fatal",
4169
+ message: error.message,
4170
+ code: error.code
4171
+ };
4172
+ }
4173
+ return {
4174
+ kind: "fatal",
4175
+ message: String(error)
4176
+ };
4177
+ }
4178
+ function extractToolExecutionError(output) {
4179
+ if (!output) {
4180
+ return;
4181
+ }
4182
+ if (typeof output === "string") {
4183
+ if (output.toLowerCase().includes("error")) {
4184
+ return {
4185
+ kind: output.toLowerCase().includes("timeout") ? "timeout" : "retryable",
4186
+ message: output
4187
+ };
4188
+ }
4189
+ return;
4190
+ }
4191
+ if (typeof output !== "object") {
4192
+ return;
4193
+ }
4194
+ const record2 = output;
4195
+ const nestedError = record2["error"];
4196
+ if (nestedError instanceof Error) {
4197
+ return toAgentExecutionError(nestedError);
4198
+ }
4199
+ if (nestedError && typeof nestedError === "object") {
4200
+ return toAgentExecutionError(nestedError);
4201
+ }
4202
+ if (typeof record2["message"] === "string" && typeof record2["kind"] === "string") {
4203
+ return {
4204
+ kind: record2["kind"],
4205
+ message: record2["message"],
4206
+ code: typeof record2["code"] === "string" ? record2["code"] : undefined,
4207
+ retryAfterMs: typeof record2["retryAfterMs"] === "number" ? record2["retryAfterMs"] : undefined
4208
+ };
4209
+ }
4210
+ if (typeof record2["errorMessage"] === "string") {
4211
+ return {
4212
+ kind: typeof record2["errorCode"] === "string" && record2["errorCode"].includes("TIMEOUT") ? "timeout" : "retryable",
4213
+ message: record2["errorMessage"],
4214
+ code: typeof record2["errorCode"] === "string" ? record2["errorCode"] : undefined
4215
+ };
4216
+ }
4217
+ return;
4218
+ }
4219
+ function stringifyToolResult(toolName, output) {
4220
+ if (typeof output === "string") {
4221
+ return `[${toolName}] ${output}`;
4222
+ }
4223
+ try {
4224
+ return `[${toolName}] ${JSON.stringify(output)}`;
4225
+ } catch {
4226
+ return `[${toolName}] [unserializable result]`;
4227
+ }
4228
+ }
4229
+ function resolveMaxSteps(overrideMaxSteps, specMaxSteps) {
4230
+ const candidate = overrideMaxSteps ?? specMaxSteps ?? 10;
4231
+ if (!Number.isFinite(candidate)) {
4232
+ return 10;
4233
+ }
4234
+ if (candidate < 1) {
4235
+ return 1;
4236
+ }
4237
+ return Math.round(candidate);
4238
+ }
4239
+ function resolveEscalationError(spec, finishReason) {
4240
+ const escalation = spec.policy?.escalation;
4241
+ if (!escalation) {
4242
+ return;
4243
+ }
4244
+ if (escalation.onTimeout && finishReason === "length") {
4245
+ return {
4246
+ kind: "timeout",
4247
+ code: "AGENT_TIMEOUT_ESCALATION",
4248
+ message: "Agent reached max step budget and requires escalation."
4249
+ };
4250
+ }
4251
+ if (escalation.onToolFailure && finishReason === "error") {
4252
+ return {
4253
+ kind: "retryable",
4254
+ code: "AGENT_TOOL_FAILURE_ESCALATION",
4255
+ message: "Agent encountered a tool failure and requires escalation."
4256
+ };
4257
+ }
4258
+ const confidenceThreshold = escalation.confidenceThreshold;
4259
+ const defaultConfidence = spec.policy?.confidence?.default;
4260
+ if (confidenceThreshold !== undefined && defaultConfidence !== undefined && defaultConfidence < confidenceThreshold) {
4261
+ return {
4262
+ kind: "policy_blocked",
4263
+ code: "AGENT_CONFIDENCE_ESCALATION",
4264
+ message: `Agent default confidence (${defaultConfidence}) is below escalation threshold (${confidenceThreshold}).`
4265
+ };
4266
+ }
4267
+ return;
4268
+ }
4269
+ var ContractSpecCallOptionsSchema;
4270
+ var init_contract_spec_agent = __esm(() => {
4271
+ init_workflow();
4272
+ init_injector();
4273
+ init_adapter();
4274
+ init_knowledge_tool();
4275
+ init_mcp_client();
4276
+ init_memory_tools();
4277
+ init_tool_adapter();
4278
+ ContractSpecCallOptionsSchema = z4.object({
4279
+ tenantId: z4.string().optional(),
4280
+ actorId: z4.string().optional(),
4281
+ sessionId: z4.string().optional(),
4282
+ workflowId: z4.string().optional(),
4283
+ threadId: z4.string().optional(),
4284
+ metadata: z4.record(z4.string(), z4.unknown()).optional()
4285
+ });
4286
+ });
4287
+
4288
+ // src/providers/types.ts
4289
+ var ExternalProviderError, ProviderNotAvailableError, ProviderExecutionError, ContextCreationError;
4290
+ var init_types = __esm(() => {
4291
+ init_i18n();
4292
+ ExternalProviderError = class ExternalProviderError extends Error {
4293
+ provider;
4294
+ code;
4295
+ cause;
4296
+ constructor(message, provider, code, cause) {
4297
+ super(message);
4298
+ this.provider = provider;
4299
+ this.code = code;
4300
+ this.cause = cause;
4301
+ this.name = "ExternalProviderError";
4302
+ }
4303
+ };
4304
+ ProviderNotAvailableError = class ProviderNotAvailableError extends ExternalProviderError {
4305
+ constructor(provider, reason, locale) {
4306
+ const i18n = createAgentI18n(locale);
4307
+ super(i18n.t("error.provider.notAvailable", {
4308
+ provider,
4309
+ reason: reason ? `: ${reason}` : ""
4310
+ }), provider, "PROVIDER_NOT_AVAILABLE");
4311
+ this.name = "ProviderNotAvailableError";
4312
+ }
4313
+ };
4314
+ ProviderExecutionError = class ProviderExecutionError extends ExternalProviderError {
4315
+ constructor(provider, message, cause) {
4316
+ super(message, provider, "EXECUTION_FAILED", cause);
4317
+ this.name = "ProviderExecutionError";
4318
+ }
4319
+ };
4320
+ ContextCreationError = class ContextCreationError extends ExternalProviderError {
4321
+ constructor(provider, message, cause) {
4322
+ super(message, provider, "CONTEXT_CREATION_FAILED", cause);
4323
+ this.name = "ContextCreationError";
4324
+ }
4325
+ };
4326
+ });
4327
+
4328
+ // src/providers/claude-agent-sdk/session-bridge.ts
4329
+ function toClaudeAgentSession(state) {
4330
+ const messages = [];
4331
+ for (const msg of state.messages) {
4332
+ if (msg.role === "user" || msg.role === "assistant") {
4333
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
4334
+ messages.push({
4335
+ role: msg.role,
4336
+ content
4337
+ });
4338
+ }
4339
+ }
4340
+ return {
4341
+ sessionId: state.sessionId,
4342
+ messages,
4343
+ metadata: {
4344
+ agentId: state.agentId,
4345
+ tenantId: state.tenantId,
4346
+ actorId: state.actorId
4347
+ }
4348
+ };
4349
+ }
4350
+ function createClaudeAgentSession(options) {
4351
+ return {
4352
+ sessionId: options?.sessionId,
4353
+ messages: [],
4354
+ metadata: {
4355
+ tenantId: options?.tenantId,
4356
+ actorId: options?.actorId,
4357
+ ...options?.metadata
4358
+ }
4359
+ };
4360
+ }
4361
+ function createEmptyClaudeSession() {
4362
+ return createClaudeAgentSession();
4363
+ }
4364
+ function buildClaudeAgentContext(options) {
4365
+ return {
4366
+ tenantId: options?.tenantId,
4367
+ actorId: options?.actorId,
4368
+ sessionId: options?.sessionId,
4369
+ ...options?.metadata
4370
+ };
4371
+ }
4372
+ function appendUserMessage(session, content) {
4373
+ return {
4374
+ ...session,
4375
+ messages: [...session.messages, { role: "user", content }]
4376
+ };
4377
+ }
4378
+ function appendAssistantMessage(session, content) {
4379
+ return {
4380
+ ...session,
4381
+ messages: [...session.messages, { role: "assistant", content }]
4382
+ };
4383
+ }
4384
+ function clearSession(session) {
4385
+ return {
4386
+ ...session,
4387
+ messages: []
4388
+ };
4389
+ }
4390
+ function getRecentMessages(session, count) {
4391
+ return session.messages.slice(-count);
4392
+ }
4393
+ function extractToolUseBlocks(content) {
4394
+ if (typeof content === "string") {
4395
+ return [];
4396
+ }
4397
+ return content.filter((block) => block.type === "tool_use");
4398
+ }
4399
+ function createToolResultBlock(toolUseId, result, isError = false) {
4400
+ return {
4401
+ type: "tool_result",
4402
+ tool_use_id: toolUseId,
4403
+ content: typeof result === "string" ? result : JSON.stringify(result),
4404
+ is_error: isError
4405
+ };
4406
+ }
4407
+ function updateSessionMetadata(session, metadata) {
4408
+ return {
4409
+ ...session,
4410
+ metadata: {
4411
+ ...session.metadata,
4412
+ ...metadata
4413
+ }
4414
+ };
4415
+ }
4416
+ function getMessageCount(session) {
4417
+ return session.messages.length;
4418
+ }
4419
+ function estimateTokens(session) {
4420
+ let chars = 0;
4421
+ for (const msg of session.messages) {
4422
+ if (typeof msg.content === "string") {
4423
+ chars += msg.content.length;
4424
+ } else {
4425
+ chars += JSON.stringify(msg.content).length;
4426
+ }
4427
+ }
4428
+ return Math.ceil(chars / 4);
4429
+ }
4430
+ function summarizeSession(session) {
4431
+ let userMessages = 0;
4432
+ let assistantMessages = 0;
4433
+ for (const msg of session.messages) {
4434
+ if (msg.role === "user") {
4435
+ userMessages++;
4436
+ } else {
4437
+ assistantMessages++;
4438
+ }
4439
+ }
4440
+ return {
4441
+ messageCount: session.messages.length,
4442
+ userMessages,
4443
+ assistantMessages,
4444
+ estimatedTokens: estimateTokens(session)
4445
+ };
4446
+ }
4447
+
4448
+ // src/providers/claude-agent-sdk/tool-bridge.ts
4449
+ function specToolToClaudeAgentTool(tool4, handler, context) {
4450
+ return {
4451
+ name: tool4.name,
4452
+ description: tool4.description ?? createAgentI18n().t("tool.fallbackDescription", { name: tool4.name }),
4453
+ input_schema: normalizeSchema(tool4.schema),
4454
+ requires_confirmation: tool4.requiresApproval ?? !tool4.automationSafe,
4455
+ execute: async (input) => {
4456
+ const fullContext = {
4457
+ agentId: context.agentId ?? "unknown",
4458
+ sessionId: context.sessionId ?? "unknown",
4459
+ tenantId: context.tenantId,
4460
+ actorId: context.actorId,
4461
+ metadata: context.metadata,
4462
+ signal: context.signal
4463
+ };
4464
+ return handler(input, fullContext);
4465
+ }
4466
+ };
4467
+ }
4468
+ function specToolsToClaudeAgentTools(tools, handlers, context) {
4469
+ return tools.filter((tool4) => handlers.has(tool4.name)).map((tool4) => {
4470
+ const handler = handlers.get(tool4.name);
4471
+ if (!handler) {
4472
+ throw new Error(createAgentI18n().t("error.handlerNotFoundForTool", {
4473
+ name: tool4.name
4474
+ }));
4475
+ }
4476
+ return specToolToClaudeAgentTool(tool4, handler, context);
4477
+ });
4478
+ }
4479
+ function claudeAgentToolToSpecTool(claudeTool, execute) {
4480
+ const config = {
4481
+ name: claudeTool.name,
4482
+ description: claudeTool.description,
4483
+ schema: claudeTool.input_schema,
4484
+ requiresApproval: claudeTool.requires_confirmation,
4485
+ automationSafe: !claudeTool.requires_confirmation
4486
+ };
4487
+ const handler = execute ? async (input, _ctx) => String(await execute(input)) : undefined;
4488
+ return { config, handler };
4489
+ }
4490
+ function claudeAgentToolsToSpecTools(claudeTools) {
4491
+ const configs = [];
4492
+ const handlers = new Map;
4493
+ for (const claudeTool of claudeTools) {
4494
+ const { config, handler } = claudeAgentToolToSpecTool(claudeTool, claudeTool.execute);
4495
+ configs.push(config);
4496
+ if (handler) {
4497
+ handlers.set(config.name, handler);
4498
+ }
4499
+ }
4500
+ return { configs, handlers };
4501
+ }
4502
+ function specToolToExternalTool(tool4, handler, context) {
4503
+ return {
4504
+ name: tool4.name,
4505
+ description: tool4.description ?? createAgentI18n().t("tool.fallbackDescription", { name: tool4.name }),
4506
+ inputSchema: tool4.schema ?? { type: "object" },
4507
+ requiresApproval: tool4.requiresApproval ?? !tool4.automationSafe,
4508
+ execute: handler ? async (input) => {
4509
+ const fullContext = {
4510
+ agentId: context?.agentId ?? "unknown",
4511
+ sessionId: context?.sessionId ?? "unknown",
4512
+ tenantId: context?.tenantId,
4513
+ actorId: context?.actorId,
4514
+ metadata: context?.metadata,
4515
+ signal: context?.signal
4516
+ };
4517
+ return handler(input, fullContext);
4518
+ } : undefined
4519
+ };
4520
+ }
4521
+ function normalizeSchema(schema) {
4522
+ if (!schema) {
4523
+ return { type: "object" };
2139
4524
  }
2140
- if (typeof spec.meta.version !== "string") {
2141
- throw new Error(i18n.t("error.agentMissingVersion", { key: spec.meta.key }));
4525
+ if (schema.type === "object") {
4526
+ return schema;
2142
4527
  }
2143
- if (!spec.instructions?.trim()) {
2144
- throw new Error(i18n.t("error.agentRequiresInstructions", { key: spec.meta.key }));
4528
+ return {
4529
+ type: "object",
4530
+ properties: {
4531
+ value: schema
4532
+ },
4533
+ required: ["value"]
4534
+ };
4535
+ }
4536
+ function extractToolCalls(response) {
4537
+ if (!response.content) {
4538
+ return [];
2145
4539
  }
2146
- if (!spec.tools?.length) {
2147
- throw new Error(i18n.t("error.agentRequiresTool", { key: spec.meta.key }));
4540
+ return response.content.filter((block) => block.type === "tool_use").map((block) => ({
4541
+ toolCallId: block.id ?? "",
4542
+ toolName: block.name ?? "",
4543
+ args: block.input
4544
+ }));
4545
+ }
4546
+ var init_tool_bridge = __esm(() => {
4547
+ init_i18n();
4548
+ });
4549
+
4550
+ // src/providers/claude-agent-sdk/adapter.ts
4551
+ import { randomUUID as randomUUID3 } from "node:crypto";
4552
+ import {
4553
+ agentKey as agentKey2
4554
+ } from "@contractspec/lib.contracts-spec/agent";
4555
+
4556
+ class ClaudeAgentSDKProvider {
4557
+ name = "claude-agent-sdk";
4558
+ version = "1.0.0";
4559
+ config;
4560
+ sdkAvailable = null;
4561
+ constructor(config = {}) {
4562
+ this.config = {
4563
+ model: "claude-sonnet-4-20250514",
4564
+ extendedThinking: false,
4565
+ computerUse: false,
4566
+ maxTokens: 4096,
4567
+ temperature: 0.7,
4568
+ ...config
4569
+ };
2148
4570
  }
2149
- for (const [portName, portRef] of Object.entries(spec.runtime?.ports ?? {})) {
2150
- if (portRef !== undefined && portRef.trim().length === 0) {
2151
- throw new Error(`Agent ${spec.meta.key} has invalid runtime config: port "${portName}" must not be empty`);
4571
+ isAvailable() {
4572
+ if (this.sdkAvailable !== null) {
4573
+ return this.sdkAvailable;
4574
+ }
4575
+ try {
4576
+ __require.resolve("@anthropic-ai/claude-agent-sdk");
4577
+ const apiKey = this.config.apiKey ?? process.env.ANTHROPIC_API_KEY;
4578
+ this.sdkAvailable = Boolean(apiKey);
4579
+ } catch {
4580
+ this.sdkAvailable = false;
2152
4581
  }
4582
+ return this.sdkAvailable;
2153
4583
  }
2154
- const toolNames = new Set;
2155
- for (const tool of spec.tools) {
2156
- if (toolNames.has(tool.name)) {
2157
- throw new Error(i18n.t("error.agentDuplicateTool", {
2158
- key: spec.meta.key,
2159
- name: tool.name
2160
- }));
4584
+ async createContext(spec) {
4585
+ if (!this.isAvailable()) {
4586
+ throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.sdkNotConfigured"));
4587
+ }
4588
+ let mcpToolset = null;
4589
+ try {
4590
+ const toolSet = {};
4591
+ for (const tool4 of spec.tools) {
4592
+ toolSet[tool4.name] = specToolToExternalTool(tool4);
4593
+ }
4594
+ if ((this.config.mcpServers?.length ?? 0) > 0) {
4595
+ mcpToolset = await createMcpToolsets(this.config.mcpServers ?? [], {
4596
+ onNameCollision: "error"
4597
+ });
4598
+ for (const [toolName, mcpTool] of Object.entries(mcpToolset.tools)) {
4599
+ if (toolSet[toolName]) {
4600
+ throw new Error(`MCP tool "${toolName}" collides with a ContractSpec tool. Configure MCP toolPrefix values to avoid collisions.`);
4601
+ }
4602
+ toolSet[toolName] = this.mcpToolToExternalTool(toolName, mcpTool);
4603
+ }
4604
+ }
4605
+ const instructions = await injectStaticKnowledge(spec.instructions, spec.knowledge ?? [], undefined);
4606
+ const contextId = `claude-${agentKey2(spec.meta)}-${Date.now()}`;
4607
+ const metadata = {
4608
+ computerUseEnabled: this.config.computerUse ?? false,
4609
+ extendedThinkingEnabled: this.config.extendedThinking ?? false,
4610
+ mcpServerIds: this.config.mcpServers?.map((s) => s.name) ?? []
4611
+ };
4612
+ const cleanupMcp = mcpToolset?.cleanup;
4613
+ return {
4614
+ id: contextId,
4615
+ spec: {
4616
+ ...spec,
4617
+ instructions
4618
+ },
4619
+ tools: toolSet,
4620
+ metadata,
4621
+ cleanup: async () => {
4622
+ if (cleanupMcp) {
4623
+ await cleanupMcp();
4624
+ }
4625
+ }
4626
+ };
4627
+ } catch (error) {
4628
+ if (mcpToolset) {
4629
+ await mcpToolset.cleanup().catch(() => {
4630
+ return;
4631
+ });
4632
+ }
4633
+ throw new ContextCreationError(this.name, createAgentI18n(this.config.locale).t("error.provider.contextCreation", {
4634
+ error: error instanceof Error ? error.message : String(error)
4635
+ }), error instanceof Error ? error : undefined);
4636
+ }
4637
+ }
4638
+ async execute(context, params) {
4639
+ try {
4640
+ const sdk = await this.loadSDK();
4641
+ const systemPrompt = params.systemOverride ? `${context.spec.instructions}
4642
+
4643
+ ${params.systemOverride}` : context.spec.instructions;
4644
+ const claudeContext = buildClaudeAgentContext(params.options);
4645
+ let session = createEmptyClaudeSession();
4646
+ session = appendUserMessage(session, params.prompt);
4647
+ const claudeTools = this.prepareToolsForSDK(context);
4648
+ const rawResponse = await sdk.execute({
4649
+ model: this.config.model,
4650
+ system: systemPrompt,
4651
+ messages: session.messages,
4652
+ tools: claudeTools,
4653
+ max_tokens: this.config.maxTokens,
4654
+ temperature: this.config.temperature,
4655
+ metadata: claudeContext,
4656
+ extended_thinking: this.config.extendedThinking,
4657
+ computer_use: this.config.computerUse
4658
+ });
4659
+ const response = rawResponse;
4660
+ const toolCalls = extractToolCalls(response);
4661
+ const toolResults = await this.executeTools(toolCalls, context, params);
4662
+ if (response.content) {
4663
+ const content = response.content;
4664
+ session = appendAssistantMessage(session, content);
4665
+ }
4666
+ return {
4667
+ text: this.extractTextContent(response),
4668
+ toolCalls: toolCalls.map((tc) => ({
4669
+ type: "tool-call",
4670
+ toolCallId: tc.toolCallId,
4671
+ toolName: tc.toolName,
4672
+ args: tc.args
4673
+ })),
4674
+ toolResults: toolResults.map((tr) => ({
4675
+ type: "tool-result",
4676
+ toolCallId: tr.toolCallId,
4677
+ toolName: tr.toolName,
4678
+ output: tr.output
4679
+ })),
4680
+ usage: {
4681
+ inputTokens: response.usage?.input_tokens ?? 0,
4682
+ outputTokens: response.usage?.output_tokens ?? 0
4683
+ },
4684
+ finishReason: this.mapStopReason(response.stop_reason),
4685
+ metadata: {
4686
+ sessionId: context.metadata?.sessionId,
4687
+ model: response.model
4688
+ }
4689
+ };
4690
+ } catch (error) {
4691
+ throw new ProviderExecutionError(this.name, createAgentI18n(this.config.locale).t("error.provider.executionFailed", {
4692
+ error: error instanceof Error ? error.message : String(error)
4693
+ }), error instanceof Error ? error : undefined);
4694
+ }
4695
+ }
4696
+ async* stream(context, params) {
4697
+ try {
4698
+ const sdk = await this.loadSDK();
4699
+ const systemPrompt = params.systemOverride ? `${context.spec.instructions}
4700
+
4701
+ ${params.systemOverride}` : context.spec.instructions;
4702
+ const claudeContext = buildClaudeAgentContext(params.options);
4703
+ const claudeTools = this.prepareToolsForSDK(context);
4704
+ const stream = await sdk.stream({
4705
+ model: this.config.model,
4706
+ system: systemPrompt,
4707
+ messages: [{ role: "user", content: params.prompt }],
4708
+ tools: claudeTools,
4709
+ max_tokens: this.config.maxTokens,
4710
+ temperature: this.config.temperature,
4711
+ metadata: claudeContext,
4712
+ extended_thinking: this.config.extendedThinking,
4713
+ computer_use: this.config.computerUse
4714
+ });
4715
+ let fullText = "";
4716
+ const allToolCalls = [];
4717
+ const allToolResults = [];
4718
+ let stepIndex = 0;
4719
+ for await (const event of stream) {
4720
+ if (event.type === "content_block_delta" && event.delta?.type === "text_delta") {
4721
+ const text = event.delta.text ?? "";
4722
+ fullText += text;
4723
+ yield { type: "text", text };
4724
+ }
4725
+ if (event.type === "content_block_start" && event.content_block?.type === "tool_use") {
4726
+ const toolCall = {
4727
+ toolCallId: event.content_block.id ?? "",
4728
+ toolName: event.content_block.name ?? "",
4729
+ args: event.content_block.input
4730
+ };
4731
+ allToolCalls.push(toolCall);
4732
+ yield {
4733
+ type: "tool-call",
4734
+ toolCall: {
4735
+ type: "tool-call",
4736
+ ...toolCall
4737
+ }
4738
+ };
4739
+ }
4740
+ if (event.type === "message_stop") {
4741
+ stepIndex++;
4742
+ yield { type: "step-complete", stepIndex };
4743
+ }
4744
+ }
4745
+ for (const toolCall of allToolCalls) {
4746
+ const result = await this.executeTool(toolCall, context, params);
4747
+ allToolResults.push(result);
4748
+ yield {
4749
+ type: "tool-result",
4750
+ toolResult: {
4751
+ type: "tool-result",
4752
+ ...result
4753
+ }
4754
+ };
4755
+ }
4756
+ yield {
4757
+ type: "done",
4758
+ result: {
4759
+ text: fullText,
4760
+ toolCalls: allToolCalls.map((tc) => ({
4761
+ type: "tool-call",
4762
+ ...tc
4763
+ })),
4764
+ toolResults: allToolResults.map((tr) => ({
4765
+ type: "tool-result",
4766
+ ...tr
4767
+ })),
4768
+ usage: { inputTokens: 0, outputTokens: 0 },
4769
+ finishReason: "stop"
4770
+ }
4771
+ };
4772
+ } catch (error) {
4773
+ throw new ProviderExecutionError(this.name, createAgentI18n(this.config.locale).t("error.provider.streamFailed", {
4774
+ error: error instanceof Error ? error.message : String(error)
4775
+ }), error instanceof Error ? error : undefined);
4776
+ }
4777
+ }
4778
+ async loadSDK() {
4779
+ try {
4780
+ const module = __require("@anthropic-ai/claude-agent-sdk");
4781
+ return module.default ?? module;
4782
+ } catch {
4783
+ throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.claudeSdkMissing"));
4784
+ }
4785
+ }
4786
+ prepareToolsForSDK(context) {
4787
+ const i18n = createAgentI18n(this.config.locale);
4788
+ const toolsForSdk = [];
4789
+ for (const [toolName, externalTool] of Object.entries(context.tools)) {
4790
+ if (!externalTool.execute) {
4791
+ continue;
4792
+ }
4793
+ toolsForSdk.push({
4794
+ name: toolName,
4795
+ description: externalTool.description ?? i18n.t("tool.fallbackDescription", { name: toolName }),
4796
+ input_schema: this.normalizeToolSchemaForClaude(externalTool.inputSchema),
4797
+ requires_confirmation: externalTool.requiresApproval,
4798
+ execute: async (input) => {
4799
+ const result = await externalTool.execute?.(input);
4800
+ return typeof result === "string" ? result : JSON.stringify(result);
4801
+ }
4802
+ });
4803
+ }
4804
+ return toolsForSdk;
4805
+ }
4806
+ mcpToolToExternalTool(toolName, tool4) {
4807
+ return {
4808
+ name: toolName,
4809
+ description: tool4.description ?? createAgentI18n(this.config.locale).t("tool.fallbackDescription", {
4810
+ name: toolName
4811
+ }),
4812
+ inputSchema: this.normalizeExternalInputSchema(tool4.inputSchema),
4813
+ execute: async (input) => {
4814
+ if (!tool4.execute) {
4815
+ throw new Error(createAgentI18n(this.config.locale).t("error.toolNoExecuteHandler", {
4816
+ name: toolName
4817
+ }));
4818
+ }
4819
+ return tool4.execute(input, {
4820
+ toolCallId: `mcp-${randomUUID3()}`,
4821
+ messages: []
4822
+ });
4823
+ }
4824
+ };
4825
+ }
4826
+ normalizeExternalInputSchema(schema) {
4827
+ if (this.isRecord(schema)) {
4828
+ const type = schema["type"];
4829
+ if (type === "object" || schema["properties"]) {
4830
+ return schema;
4831
+ }
4832
+ }
4833
+ return {
4834
+ type: "object",
4835
+ properties: {}
4836
+ };
4837
+ }
4838
+ normalizeToolSchemaForClaude(schema) {
4839
+ if (schema.type === "object") {
4840
+ return {
4841
+ type: "object",
4842
+ properties: schema.properties,
4843
+ required: schema.required,
4844
+ additionalProperties: schema.additionalProperties
4845
+ };
4846
+ }
4847
+ return {
4848
+ type: "object",
4849
+ properties: {
4850
+ value: schema
4851
+ },
4852
+ required: ["value"]
4853
+ };
4854
+ }
4855
+ isRecord(value) {
4856
+ return typeof value === "object" && value !== null;
4857
+ }
4858
+ async executeTool(toolCall, context, _params) {
4859
+ const tool4 = context.tools[toolCall.toolName];
4860
+ if (!tool4?.execute) {
4861
+ return {
4862
+ toolCallId: toolCall.toolCallId,
4863
+ toolName: toolCall.toolName,
4864
+ output: createAgentI18n(this.config.locale).t("error.toolNotFoundOrNoHandler", {
4865
+ name: toolCall.toolName
4866
+ })
4867
+ };
4868
+ }
4869
+ try {
4870
+ const output = await tool4.execute(toolCall.args);
4871
+ return {
4872
+ toolCallId: toolCall.toolCallId,
4873
+ toolName: toolCall.toolName,
4874
+ output
4875
+ };
4876
+ } catch (error) {
4877
+ return {
4878
+ toolCallId: toolCall.toolCallId,
4879
+ toolName: toolCall.toolName,
4880
+ output: `Error: ${error instanceof Error ? error.message : String(error)}`
4881
+ };
4882
+ }
4883
+ }
4884
+ async executeTools(toolCalls, context, params) {
4885
+ return Promise.all(toolCalls.map((tc) => this.executeTool(tc, context, params)));
4886
+ }
4887
+ extractTextContent(response) {
4888
+ if (!response.content) {
4889
+ return "";
4890
+ }
4891
+ return response.content.filter((block) => typeof block === "object" && block !== null && block.type === "text").map((block) => block.text).join("");
4892
+ }
4893
+ mapStopReason(stopReason) {
4894
+ switch (stopReason) {
4895
+ case "end_turn":
4896
+ case "stop_sequence":
4897
+ return "stop";
4898
+ case "tool_use":
4899
+ return "tool-calls";
4900
+ case "max_tokens":
4901
+ return "length";
4902
+ default:
4903
+ return "stop";
4904
+ }
4905
+ }
4906
+ }
4907
+ var init_adapter2 = __esm(() => {
4908
+ init_i18n();
4909
+ init_injector();
4910
+ init_mcp_client();
4911
+ init_types();
4912
+ init_tool_bridge();
4913
+ });
4914
+
4915
+ // src/providers/claude-agent-sdk/index.ts
4916
+ var exports_claude_agent_sdk = {};
4917
+ __export(exports_claude_agent_sdk, {
4918
+ updateSessionMetadata: () => updateSessionMetadata,
4919
+ toClaudeAgentSession: () => toClaudeAgentSession,
4920
+ summarizeSession: () => summarizeSession,
4921
+ specToolsToClaudeAgentTools: () => specToolsToClaudeAgentTools,
4922
+ specToolToExternalTool: () => specToolToExternalTool,
4923
+ specToolToClaudeAgentTool: () => specToolToClaudeAgentTool,
4924
+ getRecentMessages: () => getRecentMessages,
4925
+ getMessageCount: () => getMessageCount,
4926
+ extractToolUseBlocks: () => extractToolUseBlocks,
4927
+ extractToolCalls: () => extractToolCalls,
4928
+ estimateTokens: () => estimateTokens,
4929
+ createToolResultBlock: () => createToolResultBlock,
4930
+ createEmptyClaudeSession: () => createEmptyClaudeSession,
4931
+ createClaudeAgentSession: () => createClaudeAgentSession,
4932
+ clearSession: () => clearSession,
4933
+ claudeAgentToolsToSpecTools: () => claudeAgentToolsToSpecTools,
4934
+ claudeAgentToolToSpecTool: () => claudeAgentToolToSpecTool,
4935
+ buildClaudeAgentContext: () => buildClaudeAgentContext,
4936
+ appendUserMessage: () => appendUserMessage,
4937
+ appendAssistantMessage: () => appendAssistantMessage,
4938
+ ClaudeAgentSDKProvider: () => ClaudeAgentSDKProvider
4939
+ });
4940
+ var init_claude_agent_sdk = __esm(() => {
4941
+ init_adapter2();
4942
+ init_tool_bridge();
4943
+ });
4944
+
4945
+ // src/providers/opencode-sdk/tool-bridge.ts
4946
+ function specToolToOpenCodeTool(tool4) {
4947
+ return {
4948
+ name: tool4.name,
4949
+ description: tool4.description ?? createAgentI18n().t("tool.fallbackDescription", { name: tool4.name }),
4950
+ parameters: normalizeToOpenCodeParameters(tool4.schema),
4951
+ permission: getPermissionLevel(tool4)
4952
+ };
4953
+ }
4954
+ function specToolsToOpenCodeTools(tools) {
4955
+ return tools.map(specToolToOpenCodeTool);
4956
+ }
4957
+ function getPermissionLevel(tool4) {
4958
+ if (tool4.requiresApproval) {
4959
+ return "ask";
4960
+ }
4961
+ if (tool4.automationSafe === false) {
4962
+ return "ask";
4963
+ }
4964
+ return "allow";
4965
+ }
4966
+ function openCodeToolToSpecTool(openCodeTool) {
4967
+ return {
4968
+ name: openCodeTool.name,
4969
+ description: openCodeTool.description,
4970
+ schema: openCodeTool.parameters,
4971
+ requiresApproval: openCodeTool.permission === "ask",
4972
+ automationSafe: openCodeTool.permission === "allow"
4973
+ };
4974
+ }
4975
+ function openCodeToolsToSpecTools(openCodeTools) {
4976
+ return openCodeTools.map(openCodeToolToSpecTool);
4977
+ }
4978
+ function specToolToExternalToolForOpenCode(tool4, handler, context) {
4979
+ return {
4980
+ name: tool4.name,
4981
+ description: tool4.description ?? createAgentI18n().t("tool.fallbackDescription", { name: tool4.name }),
4982
+ inputSchema: tool4.schema ?? { type: "object" },
4983
+ requiresApproval: tool4.requiresApproval ?? !tool4.automationSafe,
4984
+ execute: handler ? async (input) => {
4985
+ const fullContext = {
4986
+ agentId: context?.agentId ?? "unknown",
4987
+ sessionId: context?.sessionId ?? "unknown",
4988
+ tenantId: context?.tenantId,
4989
+ actorId: context?.actorId,
4990
+ metadata: context?.metadata,
4991
+ signal: context?.signal
4992
+ };
4993
+ return handler(input, fullContext);
4994
+ } : undefined
4995
+ };
4996
+ }
4997
+ function normalizeToOpenCodeParameters(schema) {
4998
+ if (!schema) {
4999
+ return { type: "object" };
5000
+ }
5001
+ if (schema.type === "object") {
5002
+ return {
5003
+ type: "object",
5004
+ properties: schema.properties,
5005
+ required: schema.required
5006
+ };
5007
+ }
5008
+ return {
5009
+ type: "object",
5010
+ properties: {
5011
+ value: convertToOpenCodeParameter(schema)
5012
+ },
5013
+ required: ["value"]
5014
+ };
5015
+ }
5016
+ function convertToOpenCodeParameter(schema) {
5017
+ const param = {
5018
+ type: schema.type ?? "string"
5019
+ };
5020
+ if (schema.description) {
5021
+ param.description = schema.description;
5022
+ }
5023
+ if (schema.enum) {
5024
+ param.enum = schema.enum;
5025
+ }
5026
+ if (schema.default !== undefined) {
5027
+ param.default = schema.default;
5028
+ }
5029
+ return param;
5030
+ }
5031
+ function createToolHandlerMap(tools) {
5032
+ const handlers = new Map;
5033
+ for (const [name, tool4] of Object.entries(tools)) {
5034
+ if (tool4.execute) {
5035
+ handlers.set(name, tool4.execute);
5036
+ }
5037
+ }
5038
+ return handlers;
5039
+ }
5040
+ async function executeToolCall(toolCall, handlers) {
5041
+ const handler = handlers.get(toolCall.name);
5042
+ if (!handler) {
5043
+ return {
5044
+ tool_call_id: toolCall.id,
5045
+ output: createAgentI18n().t("error.toolNotFoundOrNoHandler", {
5046
+ name: toolCall.name
5047
+ }),
5048
+ is_error: true
5049
+ };
5050
+ }
5051
+ try {
5052
+ const result = await handler(toolCall.arguments);
5053
+ return {
5054
+ tool_call_id: toolCall.id,
5055
+ output: typeof result === "string" ? result : JSON.stringify(result)
5056
+ };
5057
+ } catch (error) {
5058
+ return {
5059
+ tool_call_id: toolCall.id,
5060
+ output: `Error: ${error instanceof Error ? error.message : String(error)}`,
5061
+ is_error: true
5062
+ };
5063
+ }
5064
+ }
5065
+ var init_tool_bridge2 = __esm(() => {
5066
+ init_i18n();
5067
+ });
5068
+
5069
+ // src/providers/opencode-sdk/agent-bridge.ts
5070
+ function inferAgentType(spec) {
5071
+ const hasCodeTools = spec.tools.some((tool4) => [
5072
+ "write_file",
5073
+ "edit_file",
5074
+ "create_file",
5075
+ "delete_file",
5076
+ "bash",
5077
+ "execute",
5078
+ "run_command",
5079
+ "terminal"
5080
+ ].includes(tool4.name.toLowerCase()));
5081
+ const instructionsLower = spec.instructions.toLowerCase();
5082
+ const hasPlanningKeywords = /\b(plan|design|architect|strategy|analyze|review|assess|evaluate)\b/.test(instructionsLower);
5083
+ const hasExplorationKeywords = /\b(search|find|explore|discover|locate|grep|pattern)\b/.test(instructionsLower);
5084
+ const hasResearchKeywords = /\b(research|investigate|understand|learn|gather|collect)\b/.test(instructionsLower);
5085
+ if (hasCodeTools) {
5086
+ return "build";
5087
+ }
5088
+ if (hasPlanningKeywords && !hasCodeTools) {
5089
+ return "plan";
5090
+ }
5091
+ if (hasExplorationKeywords && !hasResearchKeywords) {
5092
+ return "explore";
5093
+ }
5094
+ return "general";
5095
+ }
5096
+ function specToOpenCodeConfig(spec, options) {
5097
+ const agentType = options?.agentType ?? inferAgentType(spec);
5098
+ return {
5099
+ name: spec.meta.key,
5100
+ version: spec.meta.version,
5101
+ description: spec.description ?? spec.meta.description,
5102
+ instructions: spec.instructions,
5103
+ agent_type: agentType,
5104
+ tools: specToolsToOpenCodeTools(spec.tools),
5105
+ config: {
5106
+ max_steps: options?.maxSteps ?? spec.maxSteps ?? 10,
5107
+ temperature: options?.temperature ?? 0.7,
5108
+ model: options?.model,
5109
+ permissions: buildPermissions(spec)
5110
+ }
5111
+ };
5112
+ }
5113
+ function buildPermissions(spec) {
5114
+ const permissions = {};
5115
+ for (const tool4 of spec.tools) {
5116
+ if (tool4.requiresApproval) {
5117
+ permissions[tool4.name] = "ask";
5118
+ } else if (tool4.automationSafe === false) {
5119
+ permissions[tool4.name] = "ask";
5120
+ } else {
5121
+ permissions[tool4.name] = "allow";
5122
+ }
5123
+ }
5124
+ return permissions;
5125
+ }
5126
+ function specToOpenCodeMarkdown(spec, options) {
5127
+ const agentType = options?.agentType ?? inferAgentType(spec);
5128
+ return {
5129
+ frontmatter: {
5130
+ name: spec.meta.key,
5131
+ type: agentType,
5132
+ version: spec.meta.version,
5133
+ model: options?.model,
5134
+ temperature: options?.temperature ?? 0.7,
5135
+ max_steps: options?.maxSteps ?? spec.maxSteps ?? 10,
5136
+ tools: spec.tools.map((t) => t.name)
5137
+ },
5138
+ body: buildMarkdownBody(spec)
5139
+ };
5140
+ }
5141
+ function buildMarkdownBody(spec) {
5142
+ const i18n = createAgentI18n(spec.locale);
5143
+ const lines = [];
5144
+ lines.push(`# ${spec.meta.key}`);
5145
+ lines.push("");
5146
+ if (spec.description ?? spec.meta.description) {
5147
+ lines.push(spec.description ?? spec.meta.description ?? "");
5148
+ lines.push("");
5149
+ }
5150
+ lines.push(i18n.t("export.instructions"));
5151
+ lines.push("");
5152
+ lines.push(spec.instructions);
5153
+ lines.push("");
5154
+ if (spec.tools.length > 0) {
5155
+ lines.push(i18n.t("export.tools"));
5156
+ lines.push("");
5157
+ for (const tool4 of spec.tools) {
5158
+ const permission = tool4.requiresApproval ? i18n.t("export.bridge.requiresApproval") : tool4.automationSafe === false ? i18n.t("export.bridge.askMode") : "";
5159
+ lines.push(`- **${tool4.name}**: ${tool4.description ?? i18n.t("export.noDescription")} ${permission}`.trim());
2161
5160
  }
2162
- toolNames.add(tool.name);
2163
- if (tool.subagentRef && tool.operationRef) {
2164
- throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" cannot have both subagentRef and operationRef. Use one.`);
5161
+ lines.push("");
5162
+ }
5163
+ if (spec.knowledge && spec.knowledge.length > 0) {
5164
+ lines.push(i18n.t("export.knowledgeSources"));
5165
+ lines.push("");
5166
+ for (const k of spec.knowledge) {
5167
+ const required = k.required ? i18n.t("export.required") : i18n.t("export.optional");
5168
+ lines.push(`- ${k.key} ${required}`);
2165
5169
  }
2166
- const outputRefCount = [
2167
- tool.outputPresentation,
2168
- tool.outputForm,
2169
- tool.outputDataView
2170
- ].filter(Boolean).length;
2171
- if (outputRefCount > 1) {
2172
- throw new Error(`Agent ${spec.meta.key} tool "${tool.name}" has multiple output refs (outputPresentation, outputForm, outputDataView). Use at most one.`);
5170
+ lines.push("");
5171
+ }
5172
+ return lines.join(`
5173
+ `);
5174
+ }
5175
+ function serializeOpenCodeMarkdown(markdown) {
5176
+ const lines = [];
5177
+ lines.push("---");
5178
+ lines.push(`name: ${markdown.frontmatter.name}`);
5179
+ lines.push(`type: ${markdown.frontmatter.type}`);
5180
+ if (markdown.frontmatter.version) {
5181
+ lines.push(`version: ${markdown.frontmatter.version}`);
5182
+ }
5183
+ if (markdown.frontmatter.model) {
5184
+ lines.push(`model: ${markdown.frontmatter.model}`);
5185
+ }
5186
+ if (markdown.frontmatter.temperature !== undefined) {
5187
+ lines.push(`temperature: ${markdown.frontmatter.temperature}`);
5188
+ }
5189
+ if (markdown.frontmatter.max_steps !== undefined) {
5190
+ lines.push(`max_steps: ${markdown.frontmatter.max_steps}`);
5191
+ }
5192
+ if (markdown.frontmatter.tools && markdown.frontmatter.tools.length > 0) {
5193
+ lines.push(`tools:`);
5194
+ for (const tool4 of markdown.frontmatter.tools) {
5195
+ lines.push(` - ${tool4}`);
2173
5196
  }
2174
5197
  }
2175
- return Object.freeze(spec);
5198
+ lines.push("---");
5199
+ lines.push("");
5200
+ lines.push(markdown.body);
5201
+ return lines.join(`
5202
+ `);
5203
+ }
5204
+ function openCodeConfigToSpec(config) {
5205
+ return {
5206
+ meta: {
5207
+ key: config.name,
5208
+ version: config.version ?? "1.0.0",
5209
+ description: config.description ?? "",
5210
+ stability: "experimental",
5211
+ owners: [],
5212
+ tags: []
5213
+ },
5214
+ description: config.description,
5215
+ instructions: config.instructions ?? "",
5216
+ tools: config.tools?.map((tool4) => ({
5217
+ name: tool4.name,
5218
+ description: tool4.description,
5219
+ schema: tool4.parameters,
5220
+ requiresApproval: tool4.permission === "ask",
5221
+ automationSafe: tool4.permission === "allow"
5222
+ })) ?? [],
5223
+ maxSteps: config.config?.max_steps ?? 10
5224
+ };
2176
5225
  }
2177
- function agentKey(meta) {
2178
- return `${meta.key}.v${meta.version}`;
5226
+ var init_agent_bridge = __esm(() => {
5227
+ init_i18n();
5228
+ init_tool_bridge2();
5229
+ });
5230
+
5231
+ // src/providers/opencode-sdk/adapter.ts
5232
+ import {
5233
+ agentKey as agentKey3
5234
+ } from "@contractspec/lib.contracts-spec/agent";
5235
+
5236
+ class OpenCodeSDKProvider {
5237
+ name = "opencode-sdk";
5238
+ version = "1.0.0";
5239
+ config;
5240
+ sdkAvailable = null;
5241
+ constructor(config = {}) {
5242
+ this.config = {
5243
+ serverUrl: "http://127.0.0.1:4096",
5244
+ port: 4096,
5245
+ agentType: "general",
5246
+ temperature: 0.7,
5247
+ timeout: 30000,
5248
+ ...config
5249
+ };
5250
+ if (!config.serverUrl && config.port) {
5251
+ this.config.serverUrl = `http://127.0.0.1:${config.port}`;
5252
+ }
5253
+ }
5254
+ isAvailable() {
5255
+ if (this.sdkAvailable !== null) {
5256
+ return this.sdkAvailable;
5257
+ }
5258
+ try {
5259
+ __require.resolve("@opencode-ai/sdk");
5260
+ this.sdkAvailable = true;
5261
+ } catch {
5262
+ this.sdkAvailable = false;
5263
+ }
5264
+ return this.sdkAvailable;
5265
+ }
5266
+ async createContext(spec) {
5267
+ if (!this.isAvailable()) {
5268
+ throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.sdkNotInstalled"));
5269
+ }
5270
+ try {
5271
+ const sdk = await this.loadSDK();
5272
+ const { client } = await sdk.createOpencode({
5273
+ hostname: this.getHostname(),
5274
+ port: this.config.port ?? 4096,
5275
+ timeout: this.config.timeout
5276
+ });
5277
+ const session = await client.session.create({
5278
+ agent: this.config.agentType ?? inferAgentType(spec),
5279
+ model: this.config.model
5280
+ });
5281
+ const toolSet = {};
5282
+ for (const tool4 of spec.tools) {
5283
+ toolSet[tool4.name] = specToolToExternalToolForOpenCode(tool4);
5284
+ }
5285
+ const instructions = await injectStaticKnowledge(spec.instructions, spec.knowledge ?? [], undefined);
5286
+ const contextId = `opencode-${agentKey3(spec.meta)}-${Date.now()}`;
5287
+ const metadata = {
5288
+ sessionId: session.id,
5289
+ agentType: this.config.agentType ?? inferAgentType(spec),
5290
+ serverUrl: this.config.serverUrl ?? `http://127.0.0.1:${this.config.port ?? 4096}`
5291
+ };
5292
+ return {
5293
+ id: contextId,
5294
+ spec: {
5295
+ ...spec,
5296
+ instructions
5297
+ },
5298
+ tools: toolSet,
5299
+ metadata,
5300
+ cleanup: async () => {
5301
+ try {
5302
+ await client.session.delete({ id: session.id });
5303
+ } catch {}
5304
+ }
5305
+ };
5306
+ } catch (error) {
5307
+ throw new ContextCreationError(this.name, createAgentI18n(this.config.locale).t("error.provider.contextCreation", {
5308
+ error: error instanceof Error ? error.message : String(error)
5309
+ }), error instanceof Error ? error : undefined);
5310
+ }
5311
+ }
5312
+ async execute(context, params) {
5313
+ try {
5314
+ const sdk = await this.loadSDK();
5315
+ const metadata = context.metadata;
5316
+ const { client } = await sdk.createOpencodeClient({
5317
+ baseUrl: metadata.serverUrl
5318
+ });
5319
+ const systemPrompt = params.systemOverride ? `${context.spec.instructions}
5320
+
5321
+ ${params.systemOverride}` : context.spec.instructions;
5322
+ const response = await client.session.prompt({
5323
+ id: metadata.sessionId,
5324
+ body: {
5325
+ content: params.prompt,
5326
+ system: systemPrompt
5327
+ }
5328
+ });
5329
+ const toolCalls = this.extractToolCalls(response);
5330
+ const toolHandlers = createToolHandlerMap(context.tools);
5331
+ const toolResults = await Promise.all(toolCalls.map((tc) => executeToolCall(tc, toolHandlers)));
5332
+ return {
5333
+ text: this.extractTextContent(response),
5334
+ toolCalls: toolCalls.map((tc) => ({
5335
+ type: "tool-call",
5336
+ toolCallId: tc.id,
5337
+ toolName: tc.name,
5338
+ args: tc.arguments
5339
+ })),
5340
+ toolResults: toolResults.map((tr) => ({
5341
+ type: "tool-result",
5342
+ toolCallId: tr.tool_call_id,
5343
+ toolName: toolCalls.find((tc) => tc.id === tr.tool_call_id)?.name ?? "",
5344
+ output: tr.output
5345
+ })),
5346
+ usage: {
5347
+ inputTokens: response.usage?.input_tokens ?? 0,
5348
+ outputTokens: response.usage?.output_tokens ?? 0
5349
+ },
5350
+ finishReason: this.mapFinishReason(response.finish_reason),
5351
+ metadata: {
5352
+ sessionId: metadata.sessionId,
5353
+ agentType: metadata.agentType
5354
+ }
5355
+ };
5356
+ } catch (error) {
5357
+ throw new ProviderExecutionError(this.name, createAgentI18n(this.config.locale).t("error.provider.executionFailed", {
5358
+ error: error instanceof Error ? error.message : String(error)
5359
+ }), error instanceof Error ? error : undefined);
5360
+ }
5361
+ }
5362
+ async* stream(context, params) {
5363
+ try {
5364
+ const sdk = await this.loadSDK();
5365
+ const metadata = context.metadata;
5366
+ const { client } = await sdk.createOpencodeClient({
5367
+ baseUrl: metadata.serverUrl
5368
+ });
5369
+ const systemPrompt = params.systemOverride ? `${context.spec.instructions}
5370
+
5371
+ ${params.systemOverride}` : context.spec.instructions;
5372
+ const events = client.session.subscribe({
5373
+ id: metadata.sessionId
5374
+ });
5375
+ await client.session.prompt({
5376
+ id: metadata.sessionId,
5377
+ body: {
5378
+ content: params.prompt,
5379
+ system: systemPrompt
5380
+ }
5381
+ });
5382
+ let fullText = "";
5383
+ const allToolCalls = [];
5384
+ const toolHandlers = createToolHandlerMap(context.tools);
5385
+ let stepIndex = 0;
5386
+ for await (const event of events) {
5387
+ if (event.type === "message.delta") {
5388
+ const text = event.delta?.content ?? "";
5389
+ fullText += text;
5390
+ yield { type: "text", text };
5391
+ }
5392
+ if (event.type === "tool.call") {
5393
+ const toolCall = {
5394
+ id: event.tool_call_id ?? `tc-${Date.now()}`,
5395
+ name: event.tool_name ?? "",
5396
+ arguments: event.arguments ?? {}
5397
+ };
5398
+ allToolCalls.push(toolCall);
5399
+ yield {
5400
+ type: "tool-call",
5401
+ toolCall: {
5402
+ type: "tool-call",
5403
+ toolCallId: toolCall.id,
5404
+ toolName: toolCall.name,
5405
+ args: toolCall.arguments
5406
+ }
5407
+ };
5408
+ }
5409
+ if (event.type === "step.complete") {
5410
+ stepIndex++;
5411
+ yield { type: "step-complete", stepIndex };
5412
+ }
5413
+ if (event.type === "message.complete") {
5414
+ break;
5415
+ }
5416
+ }
5417
+ for (const toolCall of allToolCalls) {
5418
+ const result = await executeToolCall(toolCall, toolHandlers);
5419
+ yield {
5420
+ type: "tool-result",
5421
+ toolResult: {
5422
+ type: "tool-result",
5423
+ toolCallId: result.tool_call_id,
5424
+ toolName: toolCall.name,
5425
+ output: result.output
5426
+ }
5427
+ };
5428
+ }
5429
+ yield {
5430
+ type: "done",
5431
+ result: {
5432
+ text: fullText,
5433
+ toolCalls: allToolCalls.map((tc) => ({
5434
+ type: "tool-call",
5435
+ toolCallId: tc.id,
5436
+ toolName: tc.name,
5437
+ args: tc.arguments
5438
+ })),
5439
+ toolResults: [],
5440
+ usage: { inputTokens: 0, outputTokens: 0 },
5441
+ finishReason: "stop"
5442
+ }
5443
+ };
5444
+ } catch (error) {
5445
+ throw new ProviderExecutionError(this.name, createAgentI18n(this.config.locale).t("error.provider.streamFailed", {
5446
+ error: error instanceof Error ? error.message : String(error)
5447
+ }), error instanceof Error ? error : undefined);
5448
+ }
5449
+ }
5450
+ async loadSDK() {
5451
+ try {
5452
+ const module = __require("@opencode-ai/sdk");
5453
+ return module;
5454
+ } catch {
5455
+ throw new ProviderNotAvailableError(this.name, createAgentI18n(this.config.locale).t("error.provider.opencodeSdkMissing"));
5456
+ }
5457
+ }
5458
+ getHostname() {
5459
+ if (!this.config.serverUrl) {
5460
+ return "127.0.0.1";
5461
+ }
5462
+ try {
5463
+ const url = new URL(this.config.serverUrl);
5464
+ return url.hostname;
5465
+ } catch {
5466
+ return "127.0.0.1";
5467
+ }
5468
+ }
5469
+ extractToolCalls(response) {
5470
+ if (!response.tool_calls) {
5471
+ return [];
5472
+ }
5473
+ return response.tool_calls.map((tc) => ({
5474
+ id: tc.id,
5475
+ name: tc.name,
5476
+ arguments: tc.arguments ?? {}
5477
+ }));
5478
+ }
5479
+ extractTextContent(response) {
5480
+ return response.content ?? response.message?.content ?? "";
5481
+ }
5482
+ mapFinishReason(finishReason) {
5483
+ switch (finishReason) {
5484
+ case "stop":
5485
+ case "end":
5486
+ return "stop";
5487
+ case "tool_use":
5488
+ case "tool_calls":
5489
+ return "tool-calls";
5490
+ case "length":
5491
+ case "max_tokens":
5492
+ return "length";
5493
+ default:
5494
+ return "stop";
5495
+ }
5496
+ }
2179
5497
  }
2180
- var init_spec = __esm(() => {
5498
+ var init_adapter3 = __esm(() => {
2181
5499
  init_i18n();
5500
+ init_injector();
5501
+ init_types();
5502
+ init_agent_bridge();
5503
+ init_tool_bridge2();
5504
+ });
5505
+
5506
+ // src/providers/opencode-sdk/index.ts
5507
+ var exports_opencode_sdk = {};
5508
+ __export(exports_opencode_sdk, {
5509
+ specToolsToOpenCodeTools: () => specToolsToOpenCodeTools,
5510
+ specToolToOpenCodeTool: () => specToolToOpenCodeTool,
5511
+ specToolToExternalToolForOpenCode: () => specToolToExternalToolForOpenCode,
5512
+ specToOpenCodeMarkdown: () => specToOpenCodeMarkdown,
5513
+ specToOpenCodeConfig: () => specToOpenCodeConfig,
5514
+ serializeOpenCodeMarkdown: () => serializeOpenCodeMarkdown,
5515
+ openCodeToolsToSpecTools: () => openCodeToolsToSpecTools,
5516
+ openCodeToolToSpecTool: () => openCodeToolToSpecTool,
5517
+ openCodeConfigToSpec: () => openCodeConfigToSpec,
5518
+ inferAgentType: () => inferAgentType,
5519
+ executeToolCall: () => executeToolCall,
5520
+ createToolHandlerMap: () => createToolHandlerMap,
5521
+ OpenCodeSDKProvider: () => OpenCodeSDKProvider
5522
+ });
5523
+ var init_opencode_sdk = __esm(() => {
5524
+ init_adapter3();
5525
+ init_agent_bridge();
5526
+ init_tool_bridge2();
2182
5527
  });
2183
5528
 
2184
- // src/spec/registry.ts
5529
+ // src/agent/json-runner.ts
2185
5530
  init_i18n();
2186
- import { SpecContractRegistry } from "@contractspec/lib.contracts-spec/registry";
2187
- import { compareVersions } from "compare-versions";
5531
+ init_contract_spec_agent();
5532
+ import { createProvider } from "@contractspec/lib.ai-providers/factory";
5533
+ import { StabilityEnum } from "@contractspec/lib.contracts-spec/ownership";
5534
+ function getJsonOnlyRules(locale) {
5535
+ const i18n = createAgentI18n(locale);
5536
+ return [
5537
+ i18n.t("agent.json.rules.validJsonOnly"),
5538
+ i18n.t("agent.json.rules.noMarkdownFences"),
5539
+ i18n.t("agent.json.rules.noCommentary"),
5540
+ i18n.t("agent.json.rules.doubleQuotes"),
5541
+ i18n.t("agent.json.rules.noTrailingCommas")
5542
+ ].join(`
5543
+ `);
5544
+ }
5545
+ function getDefaultSpec(locale) {
5546
+ const i18n = createAgentI18n(locale);
5547
+ return {
5548
+ meta: {
5549
+ key: "agent.json-runner",
5550
+ version: "1.0.0",
5551
+ description: i18n.t("agent.json.defaultDescription"),
5552
+ stability: StabilityEnum.Experimental,
5553
+ owners: ["platform.core"],
5554
+ tags: ["json", "agent"]
5555
+ },
5556
+ instructions: i18n.t("agent.json.systemPrompt"),
5557
+ tools: []
5558
+ };
5559
+ }
5560
+ async function resolveModel(options) {
5561
+ if (options.modelSelector && options.selectionContext) {
5562
+ const { model } = await options.modelSelector.selectAndCreate(options.selectionContext);
5563
+ return model;
5564
+ }
5565
+ if (options.model)
5566
+ return options.model;
5567
+ if (options.provider) {
5568
+ return createProvider(options.provider).getModel();
5569
+ }
5570
+ throw new Error(createAgentI18n(options.locale).t("error.jsonRunner.requiresModel"));
5571
+ }
5572
+ function applyModelSettings(model, settings) {
5573
+ const { temperature } = settings;
5574
+ if (temperature === undefined)
5575
+ return model;
5576
+ const withSettings = model;
5577
+ if (typeof withSettings.withSettings === "function") {
5578
+ return withSettings.withSettings({ temperature });
5579
+ }
5580
+ return model;
5581
+ }
5582
+ function buildInstructions(base, locale, system) {
5583
+ return [base, getJsonOnlyRules(locale), system].filter(Boolean).join(`
2188
5584
 
2189
- class AgentRegistry extends SpecContractRegistry {
2190
- constructor(items) {
2191
- super("agent", items);
2192
- }
2193
- listNames() {
2194
- const names = new Set;
2195
- for (const spec of this.items.values()) {
2196
- names.add(spec.meta.key);
2197
- }
2198
- return [...names];
2199
- }
2200
- require(name, version, locale) {
2201
- const spec = this.get(name, version);
2202
- if (!spec) {
2203
- throw new Error(createAgentI18n(locale).t("error.agentSpecNotFound", {
2204
- name: `${name}${version != null ? `.v${version}` : ""}`
5585
+ `);
5586
+ }
5587
+ function ensureToolHandlers(spec, handlers, locale) {
5588
+ for (const tool4 of spec.tools) {
5589
+ if (!handlers.has(tool4.name)) {
5590
+ throw new Error(createAgentI18n(locale).t("error.missingToolHandler", {
5591
+ name: tool4.name
2205
5592
  }));
2206
5593
  }
2207
- return spec;
2208
5594
  }
2209
- has(name, version) {
2210
- return this.get(name, version) !== undefined;
5595
+ }
5596
+ async function createAgentJsonRunner(options) {
5597
+ const resolved = await resolveModel(options);
5598
+ const model = applyModelSettings(resolved, {
5599
+ temperature: options.temperature ?? 0
5600
+ });
5601
+ const baseSpec = options.spec ?? getDefaultSpec(options.locale);
5602
+ const spec = {
5603
+ ...baseSpec,
5604
+ locale: options.spec?.locale ?? options.locale,
5605
+ instructions: buildInstructions(baseSpec.instructions, options.locale, options.system),
5606
+ maxSteps: options.maxSteps ?? baseSpec.maxSteps
5607
+ };
5608
+ const toolHandlers = options.toolHandlers ?? new Map;
5609
+ ensureToolHandlers(spec, toolHandlers, options.locale);
5610
+ const agent = await ContractSpecAgent.create({
5611
+ spec,
5612
+ model,
5613
+ toolHandlers
5614
+ });
5615
+ return {
5616
+ async generateJson(prompt) {
5617
+ const result = await agent.generate({ prompt });
5618
+ return result.text;
5619
+ }
5620
+ };
5621
+ }
5622
+
5623
+ // src/agent/unified-agent.ts
5624
+ init_i18n();
5625
+
5626
+ class UnifiedAgent {
5627
+ spec;
5628
+ config;
5629
+ tools;
5630
+ provider;
5631
+ context;
5632
+ state;
5633
+ constructor(spec, config) {
5634
+ this.spec = spec;
5635
+ this.config = config;
5636
+ this.tools = config.tools ?? new Map;
5637
+ this.state = {
5638
+ backend: config.backend,
5639
+ isReady: false,
5640
+ messageCount: 0
5641
+ };
5642
+ }
5643
+ i18n(runtimeLocale) {
5644
+ return createAgentI18n(this.spec.locale, runtimeLocale ?? this.config.locale);
5645
+ }
5646
+ async initialize() {
5647
+ const backend = this.config.backend;
5648
+ try {
5649
+ switch (backend) {
5650
+ case "ai-sdk":
5651
+ this.state.isReady = true;
5652
+ break;
5653
+ case "claude-agent-sdk":
5654
+ await this.initializeClaudeAgentSDK();
5655
+ break;
5656
+ case "opencode-sdk":
5657
+ await this.initializeOpenCodeSDK();
5658
+ break;
5659
+ default:
5660
+ throw new Error(this.i18n().t("error.unknownBackend", {
5661
+ backend: String(backend)
5662
+ }));
5663
+ }
5664
+ } catch (error) {
5665
+ this.state.lastError = error instanceof Error ? error : new Error(String(error));
5666
+ if (this.config.fallbackBackend && this.config.fallbackBackend !== backend) {
5667
+ await this.cleanupProviderContext();
5668
+ console.warn(this.i18n().t("log.unifiedAgent.fallback", {
5669
+ backend: String(backend),
5670
+ fallback: String(this.config.fallbackBackend)
5671
+ }));
5672
+ this.state.backend = this.config.fallbackBackend;
5673
+ await this.initialize();
5674
+ } else {
5675
+ throw error;
5676
+ }
5677
+ }
5678
+ }
5679
+ async initializeClaudeAgentSDK() {
5680
+ try {
5681
+ const { ClaudeAgentSDKProvider: ClaudeAgentSDKProvider2 } = await Promise.resolve().then(() => (init_claude_agent_sdk(), exports_claude_agent_sdk));
5682
+ const config = this.config.config;
5683
+ this.provider = new ClaudeAgentSDKProvider2(config ?? {});
5684
+ if (!this.provider.isAvailable()) {
5685
+ throw new Error(this.i18n().t("error.claudeSdk.notAvailable"));
5686
+ }
5687
+ this.context = await this.provider.createContext(this.spec);
5688
+ this.state.isReady = true;
5689
+ } catch (error) {
5690
+ if (error.code === "MODULE_NOT_FOUND") {
5691
+ throw new Error(this.i18n().t("error.claudeSdk.notInstalled"));
5692
+ }
5693
+ throw error;
5694
+ }
5695
+ }
5696
+ async initializeOpenCodeSDK() {
5697
+ try {
5698
+ const { OpenCodeSDKProvider: OpenCodeSDKProvider2 } = await Promise.resolve().then(() => (init_opencode_sdk(), exports_opencode_sdk));
5699
+ const config = this.config.config;
5700
+ this.provider = new OpenCodeSDKProvider2(config ?? {});
5701
+ if (!this.provider.isAvailable()) {
5702
+ throw new Error(this.i18n().t("error.opencodeSdk.notAvailable"));
5703
+ }
5704
+ this.context = await this.provider.createContext(this.spec);
5705
+ this.state.isReady = true;
5706
+ } catch (error) {
5707
+ if (error.code === "MODULE_NOT_FOUND") {
5708
+ throw new Error(this.i18n().t("error.opencodeSdk.notInstalled"));
5709
+ }
5710
+ throw error;
5711
+ }
2211
5712
  }
2212
- getVersions(name) {
2213
- const versions = [];
2214
- for (const spec of this.items.values()) {
2215
- if (spec.meta.key === name) {
2216
- versions.push(spec);
5713
+ async run(message, options) {
5714
+ if (!this.state.isReady) {
5715
+ await this.initialize();
5716
+ }
5717
+ const backend = options?.backend ?? this.state.backend;
5718
+ this.state.messageCount++;
5719
+ try {
5720
+ switch (backend) {
5721
+ case "ai-sdk":
5722
+ return await this.runWithAISDK(message, options);
5723
+ case "claude-agent-sdk":
5724
+ case "opencode-sdk":
5725
+ return await this.runWithExternalProvider(message, options);
5726
+ default:
5727
+ throw new Error(this.i18n().t("error.unknownBackend", {
5728
+ backend: String(backend)
5729
+ }));
2217
5730
  }
5731
+ } catch (error) {
5732
+ this.state.lastError = error instanceof Error ? error : new Error(String(error));
5733
+ throw error;
5734
+ }
5735
+ }
5736
+ async runWithAISDK(message, options) {
5737
+ const { ContractSpecAgent: ContractSpecAgent2 } = await Promise.resolve().then(() => (init_contract_spec_agent(), exports_contract_spec_agent));
5738
+ const backendConfig = this.getAISDKConfig();
5739
+ const model = await this.resolveAISDKModel();
5740
+ const agent = await ContractSpecAgent2.create({
5741
+ spec: this.spec,
5742
+ model,
5743
+ toolHandlers: this.tools,
5744
+ mcpServers: backendConfig?.mcpServers
5745
+ });
5746
+ try {
5747
+ return await agent.generate({
5748
+ prompt: message,
5749
+ options
5750
+ });
5751
+ } finally {
5752
+ await agent.cleanup().catch(() => {
5753
+ return;
5754
+ });
5755
+ }
5756
+ }
5757
+ async runWithExternalProvider(message, options) {
5758
+ if (!this.provider || !this.context) {
5759
+ throw new Error(this.i18n().t("error.providerNotInitialized"));
5760
+ }
5761
+ const result = await this.provider.execute(this.context, {
5762
+ prompt: message,
5763
+ options
5764
+ });
5765
+ return this.convertExternalResult(result);
5766
+ }
5767
+ convertExternalResult(result) {
5768
+ return {
5769
+ text: result.text,
5770
+ steps: [],
5771
+ toolCalls: result.toolCalls.map((tc) => ({
5772
+ type: "tool-call",
5773
+ toolCallId: tc.toolCallId,
5774
+ toolName: tc.toolName,
5775
+ args: tc.args
5776
+ })),
5777
+ toolResults: result.toolResults.map((tr) => ({
5778
+ type: "tool-result",
5779
+ toolCallId: tr.toolCallId,
5780
+ toolName: tr.toolName,
5781
+ output: tr.output
5782
+ })),
5783
+ finishReason: result.finishReason,
5784
+ usage: result.usage ? {
5785
+ promptTokens: result.usage.inputTokens,
5786
+ completionTokens: result.usage.outputTokens,
5787
+ totalTokens: result.usage.totalTokens ?? result.usage.inputTokens + result.usage.outputTokens
5788
+ } : undefined
5789
+ };
5790
+ }
5791
+ getAISDKConfig() {
5792
+ if (this.config.backend !== "ai-sdk")
5793
+ return;
5794
+ return this.config.config;
5795
+ }
5796
+ async resolveAISDKModel() {
5797
+ const backendConfig = this.getAISDKConfig();
5798
+ let model;
5799
+ if (backendConfig?.modelSelector && backendConfig.selectionContext) {
5800
+ const result = await backendConfig.modelSelector.selectAndCreate(backendConfig.selectionContext);
5801
+ model = result.model;
5802
+ } else if (backendConfig?.modelInstance) {
5803
+ model = backendConfig.modelInstance;
5804
+ } else if (backendConfig?.provider) {
5805
+ const { createProvider: createProvider2 } = await import("@contractspec/lib.ai-providers/factory");
5806
+ model = createProvider2(backendConfig.provider).getModel();
5807
+ } else {
5808
+ const { anthropic: anthropic2 } = await import("@ai-sdk/anthropic");
5809
+ model = anthropic2(backendConfig?.model ?? "claude-3-5-sonnet-20240620");
5810
+ }
5811
+ return this.applyModelSettings(model, {
5812
+ temperature: backendConfig?.temperature,
5813
+ maxTokens: backendConfig?.maxTokens
5814
+ });
5815
+ }
5816
+ applyModelSettings(model, settings) {
5817
+ if (settings.temperature === undefined && settings.maxTokens === undefined) {
5818
+ return model;
5819
+ }
5820
+ const withSettings = model;
5821
+ if (typeof withSettings.withSettings === "function") {
5822
+ return withSettings.withSettings({
5823
+ temperature: settings.temperature,
5824
+ maxTokens: settings.maxTokens
5825
+ });
5826
+ }
5827
+ return model;
5828
+ }
5829
+ getState() {
5830
+ return { ...this.state };
5831
+ }
5832
+ getSpec() {
5833
+ return this.spec;
5834
+ }
5835
+ getBackend() {
5836
+ return this.state.backend;
5837
+ }
5838
+ async isBackendAvailable(backend) {
5839
+ switch (backend) {
5840
+ case "ai-sdk":
5841
+ return true;
5842
+ case "claude-agent-sdk":
5843
+ try {
5844
+ const { ClaudeAgentSDKProvider: ClaudeAgentSDKProvider2 } = await Promise.resolve().then(() => (init_claude_agent_sdk(), exports_claude_agent_sdk));
5845
+ const provider = new ClaudeAgentSDKProvider2({});
5846
+ return provider.isAvailable();
5847
+ } catch {
5848
+ return false;
5849
+ }
5850
+ case "opencode-sdk":
5851
+ try {
5852
+ const { OpenCodeSDKProvider: OpenCodeSDKProvider2 } = await Promise.resolve().then(() => (init_opencode_sdk(), exports_opencode_sdk));
5853
+ const provider = new OpenCodeSDKProvider2({});
5854
+ return provider.isAvailable();
5855
+ } catch {
5856
+ return false;
5857
+ }
5858
+ default:
5859
+ return false;
5860
+ }
5861
+ }
5862
+ async switchBackend(backend) {
5863
+ if (backend === this.state.backend) {
5864
+ return;
5865
+ }
5866
+ await this.cleanupProviderContext();
5867
+ this.state.backend = backend;
5868
+ this.state.isReady = false;
5869
+ this.provider = undefined;
5870
+ this.context = undefined;
5871
+ await this.initialize();
5872
+ }
5873
+ reset() {
5874
+ this.state.messageCount = 0;
5875
+ this.state.sessionId = undefined;
5876
+ this.state.lastError = undefined;
5877
+ this.cleanupProviderContext().catch(() => {
5878
+ return;
5879
+ });
5880
+ this.context = undefined;
5881
+ }
5882
+ async cleanupProviderContext() {
5883
+ const context = this.context;
5884
+ this.context = undefined;
5885
+ if (context) {
5886
+ await context.cleanup().catch(() => {
5887
+ return;
5888
+ });
2218
5889
  }
2219
- return versions.sort((a, b) => compareVersions(a.meta.version, b.meta.version));
2220
5890
  }
5891
+ addTool(name, handler) {
5892
+ this.tools.set(name, handler);
5893
+ }
5894
+ removeTool(name) {
5895
+ return this.tools.delete(name);
5896
+ }
5897
+ }
5898
+ function createUnifiedAgent(spec, config) {
5899
+ return new UnifiedAgent(spec, config);
5900
+ }
5901
+ function createAISDKAgent(spec, options) {
5902
+ return new UnifiedAgent(spec, {
5903
+ backend: "ai-sdk",
5904
+ tools: options?.tools,
5905
+ config: {
5906
+ model: options?.model,
5907
+ modelInstance: options?.modelInstance,
5908
+ provider: options?.provider,
5909
+ temperature: options?.temperature,
5910
+ maxTokens: options?.maxTokens,
5911
+ mcpServers: options?.mcpServers
5912
+ }
5913
+ });
5914
+ }
5915
+ function createClaudeAgentSDKAgent(spec, config) {
5916
+ const { tools, ...sdkConfig } = config ?? {};
5917
+ return new UnifiedAgent(spec, {
5918
+ backend: "claude-agent-sdk",
5919
+ tools,
5920
+ config: sdkConfig
5921
+ });
5922
+ }
5923
+ function createOpenCodeSDKAgent(spec, config) {
5924
+ const { tools, ...sdkConfig } = config ?? {};
5925
+ return new UnifiedAgent(spec, {
5926
+ backend: "opencode-sdk",
5927
+ tools,
5928
+ config: sdkConfig
5929
+ });
2221
5930
  }
2222
- function createAgentRegistry() {
2223
- return new AgentRegistry;
5931
+ async function getAvailableBackends() {
5932
+ const backends = ["ai-sdk"];
5933
+ try {
5934
+ const { ClaudeAgentSDKProvider: ClaudeAgentSDKProvider2 } = await Promise.resolve().then(() => (init_claude_agent_sdk(), exports_claude_agent_sdk));
5935
+ const provider = new ClaudeAgentSDKProvider2({});
5936
+ if (provider.isAvailable()) {
5937
+ backends.push("claude-agent-sdk");
5938
+ }
5939
+ } catch {}
5940
+ try {
5941
+ const { OpenCodeSDKProvider: OpenCodeSDKProvider2 } = await Promise.resolve().then(() => (init_opencode_sdk(), exports_opencode_sdk));
5942
+ const provider = new OpenCodeSDKProvider2({});
5943
+ if (provider.isAvailable()) {
5944
+ backends.push("opencode-sdk");
5945
+ }
5946
+ } catch {}
5947
+ return backends;
2224
5948
  }
2225
5949
 
2226
- // src/spec/index.ts
2227
- init_spec();
5950
+ // src/agent/index.ts
5951
+ init_contract_spec_agent();
5952
+
5953
+ // src/approval/index.ts
5954
+ init_workflow();
2228
5955
  export {
2229
- defineAgent,
2230
- createAgentRegistry,
2231
- agentKey,
2232
- AgentRegistry
5956
+ getAvailableBackends,
5957
+ createUnifiedAgent,
5958
+ createOpenCodeSDKAgent,
5959
+ createClaudeAgentSDKAgent,
5960
+ createApprovalWorkflow,
5961
+ createAgentJsonRunner,
5962
+ createAISDKAgent,
5963
+ UnifiedAgent,
5964
+ InMemoryApprovalStore,
5965
+ ContractSpecAgent,
5966
+ ApprovalWorkflow
2233
5967
  };