@contractspec/lib.ai-agent 1.62.0 → 2.1.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 (216) hide show
  1. package/dist/agent/agent-factory.d.ts +0 -1
  2. package/dist/agent/agent-factory.js +296 -41
  3. package/dist/agent/agent.test.d.ts +0 -1
  4. package/dist/agent/contract-spec-agent.d.ts +3 -2
  5. package/dist/agent/contract-spec-agent.js +296 -41
  6. package/dist/agent/index.d.ts +0 -1
  7. package/dist/agent/index.js +298 -43
  8. package/dist/agent/json-runner.d.ts +0 -1
  9. package/dist/agent/json-runner.js +297 -42
  10. package/dist/agent/json-runner.test.d.ts +0 -1
  11. package/dist/agent/unified-agent.d.ts +0 -1
  12. package/dist/agent/unified-agent.js +297 -42
  13. package/dist/approval/index.d.ts +0 -1
  14. package/dist/approval/index.js +31 -5
  15. package/dist/approval/workflow.d.ts +7 -2
  16. package/dist/approval/workflow.js +31 -5
  17. package/dist/exporters/claude-agent-exporter.d.ts +0 -1
  18. package/dist/exporters/claude-agent-exporter.js +4 -4
  19. package/dist/exporters/index.d.ts +0 -1
  20. package/dist/exporters/index.js +4 -4
  21. package/dist/exporters/opencode-exporter.d.ts +0 -1
  22. package/dist/exporters/opencode-exporter.js +4 -4
  23. package/dist/exporters/types.d.ts +0 -1
  24. package/dist/i18n/catalogs/en.d.ts +1 -2
  25. package/dist/i18n/catalogs/en.js +1 -1
  26. package/dist/i18n/catalogs/es.d.ts +1 -2
  27. package/dist/i18n/catalogs/es.js +1 -1
  28. package/dist/i18n/catalogs/fr.d.ts +1 -2
  29. package/dist/i18n/catalogs/fr.js +1 -1
  30. package/dist/i18n/catalogs/index.d.ts +0 -1
  31. package/dist/i18n/catalogs/index.js +3 -3
  32. package/dist/i18n/i18n.test.d.ts +0 -1
  33. package/dist/i18n/index.d.ts +0 -1
  34. package/dist/i18n/index.js +4 -4
  35. package/dist/i18n/keys.d.ts +0 -1
  36. package/dist/i18n/locale.d.ts +0 -1
  37. package/dist/i18n/messages.d.ts +1 -2
  38. package/dist/i18n/messages.js +4 -4
  39. package/dist/index.d.ts +0 -14
  40. package/dist/index.js +6 -3523
  41. package/dist/interop/index.d.ts +0 -1
  42. package/dist/interop/index.js +4 -4
  43. package/dist/interop/spec-consumer.d.ts +0 -1
  44. package/dist/interop/spec-consumer.js +4 -4
  45. package/dist/interop/tool-consumer.d.ts +0 -1
  46. package/dist/interop/tool-consumer.js +4 -4
  47. package/dist/interop/types.d.ts +0 -1
  48. package/dist/knowledge/index.d.ts +0 -1
  49. package/dist/knowledge/index.js +4 -4
  50. package/dist/knowledge/injector.d.ts +0 -1
  51. package/dist/knowledge/injector.js +4 -4
  52. package/dist/memory/in-memory.d.ts +0 -1
  53. package/dist/memory/index.d.ts +0 -1
  54. package/dist/memory/manager.d.ts +0 -1
  55. package/dist/memory/memory.test.d.ts +0 -1
  56. package/dist/node/agent/agent-factory.js +296 -41
  57. package/dist/node/agent/contract-spec-agent.js +296 -41
  58. package/dist/node/agent/index.js +298 -43
  59. package/dist/node/agent/json-runner.js +297 -42
  60. package/dist/node/agent/unified-agent.js +297 -42
  61. package/dist/node/approval/index.js +31 -5
  62. package/dist/node/approval/workflow.js +31 -5
  63. package/dist/node/exporters/claude-agent-exporter.js +4 -4
  64. package/dist/node/exporters/index.js +4 -4
  65. package/dist/node/exporters/opencode-exporter.js +4 -4
  66. package/dist/node/i18n/catalogs/en.js +1 -1
  67. package/dist/node/i18n/catalogs/es.js +1 -1
  68. package/dist/node/i18n/catalogs/fr.js +1 -1
  69. package/dist/node/i18n/catalogs/index.js +3 -3
  70. package/dist/node/i18n/index.js +4 -4
  71. package/dist/node/i18n/messages.js +4 -4
  72. package/dist/node/index.js +6 -3523
  73. package/dist/node/interop/index.js +4 -4
  74. package/dist/node/interop/spec-consumer.js +4 -4
  75. package/dist/node/interop/tool-consumer.js +4 -4
  76. package/dist/node/knowledge/index.js +4 -4
  77. package/dist/node/knowledge/injector.js +4 -4
  78. package/dist/node/providers/claude-agent-sdk/adapter.js +4 -4
  79. package/dist/node/providers/claude-agent-sdk/index.js +4 -4
  80. package/dist/node/providers/claude-agent-sdk/tool-bridge.js +4 -4
  81. package/dist/node/providers/index.js +4 -4
  82. package/dist/node/providers/opencode-sdk/adapter.js +4 -4
  83. package/dist/node/providers/opencode-sdk/agent-bridge.js +4 -4
  84. package/dist/node/providers/opencode-sdk/index.js +4 -4
  85. package/dist/node/providers/opencode-sdk/tool-bridge.js +4 -4
  86. package/dist/node/providers/registry.js +4 -4
  87. package/dist/node/session/index.js +37 -2
  88. package/dist/node/session/store.js +37 -2
  89. package/dist/node/spec/index.js +5 -5
  90. package/dist/node/spec/registry.js +5 -5
  91. package/dist/node/spec/spec.js +4 -4
  92. package/dist/node/telemetry/adapter.js +84 -4
  93. package/dist/node/telemetry/index.js +165 -15
  94. package/dist/node/telemetry/posthog.js +81 -11
  95. package/dist/node/tools/index.js +4 -4
  96. package/dist/node/tools/knowledge-tool.js +4 -4
  97. package/dist/node/tools/mcp-server.js +4 -4
  98. package/dist/node/tools/tool-adapter.js +4 -4
  99. package/dist/providers/claude-agent-sdk/adapter.d.ts +0 -1
  100. package/dist/providers/claude-agent-sdk/adapter.js +4 -4
  101. package/dist/providers/claude-agent-sdk/index.d.ts +0 -1
  102. package/dist/providers/claude-agent-sdk/index.js +4 -4
  103. package/dist/providers/claude-agent-sdk/session-bridge.d.ts +0 -1
  104. package/dist/providers/claude-agent-sdk/tool-bridge.d.ts +0 -1
  105. package/dist/providers/claude-agent-sdk/tool-bridge.js +4 -4
  106. package/dist/providers/index.d.ts +0 -1
  107. package/dist/providers/index.js +4 -4
  108. package/dist/providers/opencode-sdk/adapter.d.ts +0 -1
  109. package/dist/providers/opencode-sdk/adapter.js +4 -4
  110. package/dist/providers/opencode-sdk/agent-bridge.d.ts +0 -1
  111. package/dist/providers/opencode-sdk/agent-bridge.js +4 -4
  112. package/dist/providers/opencode-sdk/index.d.ts +0 -1
  113. package/dist/providers/opencode-sdk/index.js +4 -4
  114. package/dist/providers/opencode-sdk/tool-bridge.d.ts +0 -1
  115. package/dist/providers/opencode-sdk/tool-bridge.js +4 -4
  116. package/dist/providers/registry.d.ts +0 -1
  117. package/dist/providers/registry.js +4 -4
  118. package/dist/providers/types.d.ts +0 -1
  119. package/dist/schema/index.d.ts +0 -1
  120. package/dist/schema/json-schema-to-zod.d.ts +0 -1
  121. package/dist/schema/schema-output.d.ts +0 -1
  122. package/dist/session/index.d.ts +0 -1
  123. package/dist/session/index.js +37 -2
  124. package/dist/session/store.d.ts +12 -2
  125. package/dist/session/store.js +37 -2
  126. package/dist/spec/index.d.ts +0 -1
  127. package/dist/spec/index.js +5 -5
  128. package/dist/spec/registry.d.ts +1 -2
  129. package/dist/spec/registry.js +5 -5
  130. package/dist/spec/spec.d.ts +3 -4
  131. package/dist/spec/spec.js +4 -4
  132. package/dist/telemetry/adapter.d.ts +10 -2
  133. package/dist/telemetry/adapter.js +84 -4
  134. package/dist/telemetry/adapter.test.d.ts +1 -0
  135. package/dist/telemetry/index.d.ts +0 -1
  136. package/dist/telemetry/index.js +165 -15
  137. package/dist/telemetry/posthog-types.d.ts +12 -1
  138. package/dist/telemetry/posthog.d.ts +0 -1
  139. package/dist/telemetry/posthog.js +81 -11
  140. package/dist/telemetry/posthog.test.d.ts +0 -1
  141. package/dist/tools/index.d.ts +0 -1
  142. package/dist/tools/index.js +4 -4
  143. package/dist/tools/knowledge-tool.d.ts +0 -1
  144. package/dist/tools/knowledge-tool.js +4 -4
  145. package/dist/tools/mcp-client.d.ts +0 -1
  146. package/dist/tools/mcp-server.d.ts +0 -1
  147. package/dist/tools/mcp-server.js +4 -4
  148. package/dist/tools/tool-adapter.d.ts +0 -1
  149. package/dist/tools/tool-adapter.js +4 -4
  150. package/dist/tools/tools.test.d.ts +0 -1
  151. package/dist/types.d.ts +0 -1
  152. package/package.json +12 -12
  153. package/dist/agent/agent-factory.d.ts.map +0 -1
  154. package/dist/agent/agent.test.d.ts.map +0 -1
  155. package/dist/agent/contract-spec-agent.d.ts.map +0 -1
  156. package/dist/agent/index.d.ts.map +0 -1
  157. package/dist/agent/json-runner.d.ts.map +0 -1
  158. package/dist/agent/json-runner.test.d.ts.map +0 -1
  159. package/dist/agent/unified-agent.d.ts.map +0 -1
  160. package/dist/approval/index.d.ts.map +0 -1
  161. package/dist/approval/workflow.d.ts.map +0 -1
  162. package/dist/exporters/claude-agent-exporter.d.ts.map +0 -1
  163. package/dist/exporters/index.d.ts.map +0 -1
  164. package/dist/exporters/opencode-exporter.d.ts.map +0 -1
  165. package/dist/exporters/types.d.ts.map +0 -1
  166. package/dist/i18n/catalogs/en.d.ts.map +0 -1
  167. package/dist/i18n/catalogs/es.d.ts.map +0 -1
  168. package/dist/i18n/catalogs/fr.d.ts.map +0 -1
  169. package/dist/i18n/catalogs/index.d.ts.map +0 -1
  170. package/dist/i18n/i18n.test.d.ts.map +0 -1
  171. package/dist/i18n/index.d.ts.map +0 -1
  172. package/dist/i18n/keys.d.ts.map +0 -1
  173. package/dist/i18n/locale.d.ts.map +0 -1
  174. package/dist/i18n/messages.d.ts.map +0 -1
  175. package/dist/index.d.ts.map +0 -1
  176. package/dist/interop/index.d.ts.map +0 -1
  177. package/dist/interop/spec-consumer.d.ts.map +0 -1
  178. package/dist/interop/tool-consumer.d.ts.map +0 -1
  179. package/dist/interop/types.d.ts.map +0 -1
  180. package/dist/knowledge/index.d.ts.map +0 -1
  181. package/dist/knowledge/injector.d.ts.map +0 -1
  182. package/dist/memory/in-memory.d.ts.map +0 -1
  183. package/dist/memory/index.d.ts.map +0 -1
  184. package/dist/memory/manager.d.ts.map +0 -1
  185. package/dist/memory/memory.test.d.ts.map +0 -1
  186. package/dist/providers/claude-agent-sdk/adapter.d.ts.map +0 -1
  187. package/dist/providers/claude-agent-sdk/index.d.ts.map +0 -1
  188. package/dist/providers/claude-agent-sdk/session-bridge.d.ts.map +0 -1
  189. package/dist/providers/claude-agent-sdk/tool-bridge.d.ts.map +0 -1
  190. package/dist/providers/index.d.ts.map +0 -1
  191. package/dist/providers/opencode-sdk/adapter.d.ts.map +0 -1
  192. package/dist/providers/opencode-sdk/agent-bridge.d.ts.map +0 -1
  193. package/dist/providers/opencode-sdk/index.d.ts.map +0 -1
  194. package/dist/providers/opencode-sdk/tool-bridge.d.ts.map +0 -1
  195. package/dist/providers/registry.d.ts.map +0 -1
  196. package/dist/providers/types.d.ts.map +0 -1
  197. package/dist/schema/index.d.ts.map +0 -1
  198. package/dist/schema/json-schema-to-zod.d.ts.map +0 -1
  199. package/dist/schema/schema-output.d.ts.map +0 -1
  200. package/dist/session/index.d.ts.map +0 -1
  201. package/dist/session/store.d.ts.map +0 -1
  202. package/dist/spec/index.d.ts.map +0 -1
  203. package/dist/spec/registry.d.ts.map +0 -1
  204. package/dist/spec/spec.d.ts.map +0 -1
  205. package/dist/telemetry/adapter.d.ts.map +0 -1
  206. package/dist/telemetry/index.d.ts.map +0 -1
  207. package/dist/telemetry/posthog-types.d.ts.map +0 -1
  208. package/dist/telemetry/posthog.d.ts.map +0 -1
  209. package/dist/telemetry/posthog.test.d.ts.map +0 -1
  210. package/dist/tools/index.d.ts.map +0 -1
  211. package/dist/tools/knowledge-tool.d.ts.map +0 -1
  212. package/dist/tools/mcp-client.d.ts.map +0 -1
  213. package/dist/tools/mcp-server.d.ts.map +0 -1
  214. package/dist/tools/tool-adapter.d.ts.map +0 -1
  215. package/dist/tools/tools.test.d.ts.map +0 -1
  216. package/dist/types.d.ts.map +0 -1
@@ -13,7 +13,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
13
  var __require = import.meta.require;
14
14
 
15
15
  // src/i18n/catalogs/en.ts
16
- import { defineTranslation } from "@contractspec/lib.contracts/translations";
16
+ import { defineTranslation } from "@contractspec/lib.contracts-spec/translations";
17
17
  var enMessages;
18
18
  var init_en = __esm(() => {
19
19
  enMessages = defineTranslation({
@@ -609,7 +609,7 @@ var init_en = __esm(() => {
609
609
  });
610
610
 
611
611
  // src/i18n/catalogs/fr.ts
612
- import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts/translations";
612
+ import { defineTranslation as defineTranslation2 } from "@contractspec/lib.contracts-spec/translations";
613
613
  var frMessages;
614
614
  var init_fr = __esm(() => {
615
615
  frMessages = defineTranslation2({
@@ -1220,7 +1220,7 @@ var init_fr = __esm(() => {
1220
1220
  });
1221
1221
 
1222
1222
  // src/i18n/catalogs/es.ts
1223
- import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts/translations";
1223
+ import { defineTranslation as defineTranslation3 } from "@contractspec/lib.contracts-spec/translations";
1224
1224
  var esMessages;
1225
1225
  var init_es = __esm(() => {
1226
1226
  esMessages = defineTranslation3({
@@ -1885,7 +1885,7 @@ var init_locale = __esm(() => {
1885
1885
  });
1886
1886
 
1887
1887
  // src/i18n/messages.ts
1888
- import { TranslationRegistry } from "@contractspec/lib.contracts/translations";
1888
+ import { TranslationRegistry } from "@contractspec/lib.contracts-spec/translations";
1889
1889
  function getRegistry() {
1890
1890
  if (!sharedRegistry) {
1891
1891
  sharedRegistry = new TranslationRegistry([
@@ -2430,10 +2430,19 @@ var init_injector = __esm(() => {
2430
2430
  // src/session/store.ts
2431
2431
  class InMemorySessionStore {
2432
2432
  sessions = new Map;
2433
+ maxSessions;
2434
+ maxMessagesPerSession;
2435
+ maxStepsPerSession;
2436
+ constructor(options = {}) {
2437
+ this.maxSessions = options.maxSessions ?? 500;
2438
+ this.maxMessagesPerSession = options.maxMessagesPerSession ?? 200;
2439
+ this.maxStepsPerSession = options.maxStepsPerSession ?? 200;
2440
+ }
2433
2441
  async get(sessionId) {
2434
2442
  return this.sessions.get(sessionId) ?? null;
2435
2443
  }
2436
2444
  async create(session) {
2445
+ this.evictIfNeeded();
2437
2446
  const now = new Date;
2438
2447
  const fullSession = {
2439
2448
  ...session,
@@ -2447,6 +2456,7 @@ class InMemorySessionStore {
2447
2456
  const session = this.sessions.get(sessionId);
2448
2457
  if (session) {
2449
2458
  session.steps.push(step);
2459
+ this.trimArray(session.steps, this.maxStepsPerSession);
2450
2460
  session.updatedAt = new Date;
2451
2461
  }
2452
2462
  }
@@ -2454,6 +2464,7 @@ class InMemorySessionStore {
2454
2464
  const session = this.sessions.get(sessionId);
2455
2465
  if (session) {
2456
2466
  session.messages.push(message);
2467
+ this.trimArray(session.messages, this.maxMessagesPerSession);
2457
2468
  session.updatedAt = new Date;
2458
2469
  }
2459
2470
  }
@@ -2491,9 +2502,33 @@ class InMemorySessionStore {
2491
2502
  clear() {
2492
2503
  this.sessions.clear();
2493
2504
  }
2505
+ evictIfNeeded() {
2506
+ if (this.sessions.size < this.maxSessions) {
2507
+ return;
2508
+ }
2509
+ let oldestSessionId = null;
2510
+ let oldestUpdatedAt = Number.POSITIVE_INFINITY;
2511
+ for (const [sessionId, session] of this.sessions.entries()) {
2512
+ const updatedAt = session.updatedAt.getTime();
2513
+ if (updatedAt < oldestUpdatedAt) {
2514
+ oldestUpdatedAt = updatedAt;
2515
+ oldestSessionId = sessionId;
2516
+ }
2517
+ }
2518
+ if (oldestSessionId) {
2519
+ this.sessions.delete(oldestSessionId);
2520
+ }
2521
+ }
2522
+ trimArray(items, maxItems) {
2523
+ if (items.length <= maxItems) {
2524
+ return;
2525
+ }
2526
+ const overflow = items.length - maxItems;
2527
+ items.splice(0, overflow);
2528
+ }
2494
2529
  }
2495
- function createInMemorySessionStore() {
2496
- return new InMemorySessionStore;
2530
+ function createInMemorySessionStore(options) {
2531
+ return new InMemorySessionStore(options);
2497
2532
  }
2498
2533
  function generateSessionId() {
2499
2534
  return `sess_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
@@ -2501,24 +2536,78 @@ function generateSessionId() {
2501
2536
 
2502
2537
  // src/telemetry/adapter.ts
2503
2538
  function parseAgentId(agentId) {
2504
- const match = agentId.match(/^(.+)\.v(\s+)$/);
2539
+ const match = agentId.match(/^(.+)\.v(\d+)$/);
2505
2540
  if (match) {
2506
2541
  return { name: match[1], version: match[2] };
2507
2542
  }
2508
2543
  return { name: agentId, version: "1.0.0" };
2509
2544
  }
2510
- async function trackAgentStep(collector, agentId, step, durationMs) {
2545
+ function getRecord(value) {
2546
+ return value && typeof value === "object" ? value : undefined;
2547
+ }
2548
+ function getStepResponse(step) {
2549
+ const response = getRecord(step.response);
2550
+ if (!response)
2551
+ return;
2552
+ return {
2553
+ id: response["id"],
2554
+ modelId: response["modelId"],
2555
+ timestamp: response["timestamp"],
2556
+ headers: response["headers"],
2557
+ body: response["body"],
2558
+ messages: response["messages"]
2559
+ };
2560
+ }
2561
+ function getRequestBodyValue(request, key) {
2562
+ const body = request?.["body"];
2563
+ if (!body)
2564
+ return;
2565
+ if (typeof body === "string") {
2566
+ try {
2567
+ const parsed = JSON.parse(body);
2568
+ return typeof parsed[key] === "string" ? parsed[key] : undefined;
2569
+ } catch {
2570
+ return;
2571
+ }
2572
+ }
2573
+ const record = getRecord(body);
2574
+ return typeof record?.[key] === "string" ? record[key] : undefined;
2575
+ }
2576
+ async function trackAgentStep(collector, agentId, step, durationMs, context) {
2511
2577
  const { name, version } = parseAgentId(agentId);
2578
+ const response = getStepResponse(step);
2579
+ const providerMetadata = step.providerMetadata;
2580
+ const warnings = step.warnings;
2581
+ const rawFinishReason = step.rawFinishReason;
2582
+ const request = getRecord(step.request);
2583
+ const traceId = context?.traceId ?? getRequestBodyValue(request, "$ai_trace_id");
2584
+ const sessionId = context?.sessionId ?? getRequestBodyValue(request, "$ai_session_id");
2585
+ const parentSpanId = response?.id;
2512
2586
  for (const toolCall of step.toolCalls ?? []) {
2587
+ const toolResult = step.toolResults?.find((r) => r.toolCallId === toolCall.toolCallId);
2588
+ const toolError = getRecord(toolResult?.output)?.["error"];
2513
2589
  const toolSample = {
2514
2590
  operation: { name: `${name}.${toolCall.toolName}`, version },
2515
2591
  durationMs: durationMs ?? 0,
2516
2592
  success: step.toolResults?.some((r) => r.toolCallId === toolCall.toolCallId && r.output !== undefined) ?? false,
2517
2593
  timestamp: new Date,
2518
2594
  metadata: {
2595
+ telemetryEvent: "span",
2596
+ traceId,
2597
+ sessionId,
2598
+ spanId: toolCall.toolCallId,
2599
+ parentSpanId,
2600
+ spanName: `tool.${toolCall.toolName}`,
2519
2601
  agentId,
2602
+ actorId: context?.actorId,
2603
+ tenantId: context?.tenantId,
2604
+ stepIndex: context?.stepIndex,
2520
2605
  toolName: toolCall.toolName,
2521
- finishReason: step.finishReason
2606
+ toolCallArgs: toolCall.input,
2607
+ toolResultOutput: toolResult?.output,
2608
+ errorMessage: typeof toolError === "string" ? toolError : typeof toolResult?.output === "string" ? toolResult.output : undefined,
2609
+ finishReason: step.finishReason,
2610
+ rawFinishReason
2522
2611
  }
2523
2612
  };
2524
2613
  await collector.collect(toolSample);
@@ -2529,10 +2618,36 @@ async function trackAgentStep(collector, agentId, step, durationMs) {
2529
2618
  success: step.finishReason !== "error",
2530
2619
  timestamp: new Date,
2531
2620
  metadata: {
2621
+ telemetryEvent: "generation",
2622
+ traceId,
2623
+ sessionId,
2624
+ spanId: response?.id,
2625
+ spanName: `agent.${name}.step`,
2532
2626
  agentId,
2627
+ actorId: context?.actorId,
2628
+ tenantId: context?.tenantId,
2629
+ stepIndex: context?.stepIndex,
2630
+ stepStartedAt: context?.stepStartedAt,
2533
2631
  finishReason: step.finishReason,
2632
+ rawFinishReason,
2534
2633
  tokenUsage: step.usage,
2535
- toolCallCount: step.toolCalls?.length ?? 0
2634
+ totalUsage: step.totalUsage,
2635
+ providerMetadata,
2636
+ warnings,
2637
+ stepText: step.text,
2638
+ stepReasoningText: step.reasoningText,
2639
+ responseId: response?.id,
2640
+ responseModelId: response?.modelId,
2641
+ responseTimestamp: response?.timestamp,
2642
+ responseHeaders: response?.headers,
2643
+ responseBody: response?.body,
2644
+ responseMessages: response?.messages,
2645
+ requestBody: request?.["body"],
2646
+ requestHeaders: request?.["headers"],
2647
+ toolCallCount: step.toolCalls?.length ?? 0,
2648
+ toolCalls: step.toolCalls,
2649
+ toolResults: step.toolResults,
2650
+ errorMessage: step.finishReason === "error" ? step.text : undefined
2536
2651
  }
2537
2652
  };
2538
2653
  await collector.collect(stepSample);
@@ -2592,23 +2707,60 @@ class PostHogTelemetryCollector {
2592
2707
  }
2593
2708
  async collect(sample) {
2594
2709
  const client = await this.getClient();
2595
- const distinctId = this.config.defaults?.posthogDistinctId ?? sample.metadata?.["actorId"] ?? "system";
2710
+ const metadata = asRecord(sample.metadata);
2711
+ const distinctId = this.config.defaults?.posthogDistinctId ?? asString(metadata["actorId"]) ?? "system";
2712
+ const traceId = asString(metadata["traceId"]) ?? this.config.defaults?.posthogTraceId;
2713
+ const sessionId = asString(metadata["sessionId"]);
2714
+ const telemetryEvent = asString(metadata["telemetryEvent"]);
2715
+ const event = telemetryEvent === "span" ? "$ai_span" : "$ai_generation";
2716
+ const tokenUsage = metadata["tokenUsage"];
2717
+ const totalUsage = metadata["totalUsage"];
2718
+ const errorMessage = asString(metadata["errorMessage"]);
2596
2719
  client.capture({
2597
2720
  distinctId,
2598
- event: "$ai_generation",
2721
+ event,
2599
2722
  properties: {
2600
- $ai_model: sample.operation.name,
2601
- $ai_provider: "contractspec",
2723
+ $ai_model: asString(metadata["responseModelId"]) ?? sample.operation.name,
2724
+ $ai_provider: asString(metadata["provider"]) ?? "contractspec",
2602
2725
  $ai_latency: sample.durationMs / 1000,
2603
2726
  $ai_is_error: !sample.success,
2604
- $ai_trace_id: this.config.defaults?.posthogTraceId,
2605
- ...sample.metadata?.["tokenUsage"] ? mapTokenUsage(sample.metadata["tokenUsage"]) : {},
2727
+ $ai_error: !sample.success ? errorMessage : undefined,
2728
+ $ai_trace_id: traceId,
2729
+ $ai_session_id: sessionId,
2730
+ $ai_span_id: asString(metadata["spanId"]),
2731
+ $ai_parent_id: asString(metadata["parentSpanId"]),
2732
+ $ai_span_name: asString(metadata["spanName"]) ?? sample.operation.name,
2733
+ ...tokenUsage ? mapTokenUsage(tokenUsage) : {},
2734
+ ...totalUsage ? mapTotalUsage(totalUsage) : {},
2735
+ $ai_http_status: asNumber(metadata["httpStatus"]),
2736
+ $ai_request_url: asString(metadata["requestUrl"]),
2737
+ $ai_base_url: asString(metadata["baseUrl"]),
2606
2738
  ...this.config.defaults?.posthogProperties,
2607
2739
  contractspec_operation: sample.operation.name,
2608
2740
  contractspec_version: sample.operation.version,
2609
- contractspec_agent_id: sample.metadata?.["agentId"],
2610
- contractspec_finish_reason: sample.metadata?.["finishReason"],
2611
- contractspec_tool_count: sample.metadata?.["toolCallCount"]
2741
+ contractspec_agent_id: asString(metadata["agentId"]),
2742
+ contractspec_tenant_id: asString(metadata["tenantId"]),
2743
+ contractspec_actor_id: asString(metadata["actorId"]),
2744
+ contractspec_step_index: asNumber(metadata["stepIndex"]),
2745
+ contractspec_step_started_at: asDateIso(metadata["stepStartedAt"]),
2746
+ contractspec_finish_reason: asString(metadata["finishReason"]),
2747
+ contractspec_finish_reason_raw: asString(metadata["rawFinishReason"]),
2748
+ contractspec_tool_count: asNumber(metadata["toolCallCount"]),
2749
+ contractspec_tool_name: asString(metadata["toolName"]),
2750
+ contractspec_tool_call_args: metadata["toolCallArgs"],
2751
+ contractspec_tool_result_output: metadata["toolResultOutput"],
2752
+ contractspec_provider_metadata: metadata["providerMetadata"],
2753
+ contractspec_step_warnings: metadata["warnings"],
2754
+ contractspec_response_id: asString(metadata["responseId"]),
2755
+ contractspec_response_model_id: asString(metadata["responseModelId"]),
2756
+ contractspec_response_timestamp: asDateIso(metadata["responseTimestamp"]),
2757
+ contractspec_response_headers: metadata["responseHeaders"],
2758
+ contractspec_response_body: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["responseBody"],
2759
+ contractspec_response_messages: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["responseMessages"],
2760
+ contractspec_request_headers: metadata["requestHeaders"],
2761
+ contractspec_request_body: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["requestBody"],
2762
+ contractspec_step_text: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["stepText"],
2763
+ contractspec_step_reasoning_text: this.config.defaults?.posthogPrivacyMode ? undefined : metadata["stepReasoningText"]
2612
2764
  },
2613
2765
  groups: this.config.defaults?.posthogGroups
2614
2766
  });
@@ -2669,11 +2821,44 @@ async function resolvePostHogClient(config) {
2669
2821
  }
2670
2822
  }
2671
2823
  function mapTokenUsage(usage) {
2824
+ const usageRecord = asRecord(usage);
2825
+ const inputTokenDetails = asRecord(usageRecord["inputTokenDetails"]);
2826
+ const outputTokenDetails = asRecord(usageRecord["outputTokenDetails"]);
2672
2827
  return {
2673
- $ai_input_tokens: usage["promptTokens"],
2674
- $ai_output_tokens: usage["completionTokens"]
2828
+ $ai_input_tokens: asNumber(usageRecord["inputTokens"]) ?? asNumber(usageRecord["promptTokens"]),
2829
+ $ai_output_tokens: asNumber(usageRecord["outputTokens"]) ?? asNumber(usageRecord["completionTokens"]),
2830
+ $ai_reasoning_tokens: asNumber(outputTokenDetails["reasoningTokens"]) ?? asNumber(usageRecord["reasoningTokens"]),
2831
+ $ai_cache_read_input_tokens: asNumber(inputTokenDetails["cacheReadTokens"]) ?? asNumber(usageRecord["cachedInputTokens"]),
2832
+ $ai_cache_creation_input_tokens: asNumber(inputTokenDetails["cacheWriteTokens"]),
2833
+ $ai_usage: maybeRecord(usageRecord["raw"]) ?? usageRecord
2675
2834
  };
2676
2835
  }
2836
+ function mapTotalUsage(usage) {
2837
+ const usageRecord = asRecord(usage);
2838
+ return {
2839
+ contractspec_total_input_tokens: asNumber(usageRecord["inputTokens"]),
2840
+ contractspec_total_output_tokens: asNumber(usageRecord["outputTokens"]),
2841
+ contractspec_total_tokens: asNumber(usageRecord["totalTokens"]),
2842
+ contractspec_total_usage_raw: maybeRecord(usageRecord["raw"]) ?? usageRecord
2843
+ };
2844
+ }
2845
+ function asRecord(value) {
2846
+ return value && typeof value === "object" ? value : {};
2847
+ }
2848
+ function maybeRecord(value) {
2849
+ return value && typeof value === "object" ? value : undefined;
2850
+ }
2851
+ function asString(value) {
2852
+ return typeof value === "string" && value.length > 0 ? value : undefined;
2853
+ }
2854
+ function asNumber(value) {
2855
+ return typeof value === "number" ? value : undefined;
2856
+ }
2857
+ function asDateIso(value) {
2858
+ if (value instanceof Date)
2859
+ return value.toISOString();
2860
+ return;
2861
+ }
2677
2862
 
2678
2863
  // src/agent/contract-spec-agent.ts
2679
2864
  var exports_contract_spec_agent = {};
@@ -2684,6 +2869,7 @@ import {
2684
2869
  Experimental_Agent as ToolLoopAgent,
2685
2870
  stepCountIs
2686
2871
  } from "ai";
2872
+ import { randomUUID } from "crypto";
2687
2873
  import * as z3 from "zod";
2688
2874
 
2689
2875
  class ContractSpecAgent {
@@ -2691,33 +2877,18 @@ class ContractSpecAgent {
2691
2877
  id;
2692
2878
  spec;
2693
2879
  tools;
2694
- inner;
2695
2880
  config;
2696
2881
  instructions;
2882
+ activeStepContexts = new Map;
2697
2883
  constructor(config, instructions, tools) {
2698
2884
  this.config = config;
2699
2885
  this.spec = config.spec;
2700
2886
  this.id = agentKey(config.spec.meta);
2701
2887
  this.tools = tools;
2702
2888
  this.instructions = instructions;
2703
- this.inner = new ToolLoopAgent({
2704
- model: config.model,
2705
- instructions,
2706
- tools,
2707
- stopWhen: stepCountIs(config.spec.maxSteps ?? 10),
2708
- callOptionsSchema: ContractSpecCallOptionsSchema,
2709
- onStepFinish: async (step) => {
2710
- await this.handleStepFinish(step);
2711
- }
2712
- });
2713
2889
  }
2714
2890
  static async create(config) {
2715
- let effectiveConfig = config;
2716
- if (config.posthogConfig) {
2717
- const { createPostHogTracedModel: createPostHogTracedModel2 } = await Promise.resolve().then(() => exports_posthog);
2718
- const tracedModel = await createPostHogTracedModel2(config.model, config.posthogConfig, config.posthogConfig.tracingOptions);
2719
- effectiveConfig = { ...config, model: tracedModel };
2720
- }
2891
+ const effectiveConfig = config;
2721
2892
  const instructions = await injectStaticKnowledge(effectiveConfig.spec.instructions, effectiveConfig.spec.knowledge ?? [], effectiveConfig.knowledgeRetriever);
2722
2893
  const specTools = specToolsToAISDKTools(effectiveConfig.spec.tools, effectiveConfig.toolHandlers, { agentId: agentKey(effectiveConfig.spec.meta) });
2723
2894
  const knowledgeTool = effectiveConfig.knowledgeRetriever ? createKnowledgeQueryTool(effectiveConfig.knowledgeRetriever, effectiveConfig.spec.knowledge ?? []) : null;
@@ -2730,6 +2901,14 @@ class ContractSpecAgent {
2730
2901
  }
2731
2902
  async generate(params) {
2732
2903
  const sessionId = params.options?.sessionId ?? generateSessionId();
2904
+ const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID();
2905
+ this.activeStepContexts.set(sessionId, {
2906
+ traceId,
2907
+ tenantId: params.options?.tenantId,
2908
+ actorId: params.options?.actorId,
2909
+ stepIndex: 0,
2910
+ stepStartedAt: new Date
2911
+ });
2733
2912
  if (this.config.sessionStore) {
2734
2913
  const existing = await this.config.sessionStore.get(sessionId);
2735
2914
  if (!existing) {
@@ -2750,7 +2929,13 @@ class ContractSpecAgent {
2750
2929
  ${params.systemOverride}
2751
2930
 
2752
2931
  ${params.prompt}` : params.prompt;
2753
- const result = await this.inner.generate({
2932
+ const model = await this.resolveModelForCall({
2933
+ sessionId,
2934
+ traceId,
2935
+ options: params.options
2936
+ });
2937
+ const inner = this.createInnerAgent(model);
2938
+ const result = await inner.generate({
2754
2939
  prompt,
2755
2940
  abortSignal: params.signal,
2756
2941
  options: {
@@ -2759,6 +2944,8 @@ ${params.prompt}` : params.prompt;
2759
2944
  sessionId,
2760
2945
  metadata: params.options?.metadata
2761
2946
  }
2947
+ }).finally(() => {
2948
+ this.activeStepContexts.delete(sessionId);
2762
2949
  });
2763
2950
  if (this.config.sessionStore) {
2764
2951
  await this.config.sessionStore.update(sessionId, {
@@ -2786,12 +2973,26 @@ ${params.prompt}` : params.prompt;
2786
2973
  }
2787
2974
  async stream(params) {
2788
2975
  const sessionId = params.options?.sessionId ?? generateSessionId();
2976
+ const traceId = params.options?.metadata?.["traceId"] ?? this.config.posthogConfig?.tracingOptions?.posthogTraceId ?? randomUUID();
2977
+ this.activeStepContexts.set(sessionId, {
2978
+ traceId,
2979
+ tenantId: params.options?.tenantId,
2980
+ actorId: params.options?.actorId,
2981
+ stepIndex: 0,
2982
+ stepStartedAt: new Date
2983
+ });
2789
2984
  const prompt = params.systemOverride ? `${this.instructions}
2790
2985
 
2791
2986
  ${params.systemOverride}
2792
2987
 
2793
2988
  ${params.prompt}` : params.prompt;
2794
- return this.inner.stream({
2989
+ const model = await this.resolveModelForCall({
2990
+ sessionId,
2991
+ traceId,
2992
+ options: params.options
2993
+ });
2994
+ const inner = this.createInnerAgent(model);
2995
+ return inner.stream({
2795
2996
  prompt,
2796
2997
  abortSignal: params.signal,
2797
2998
  options: {
@@ -2808,9 +3009,63 @@ ${params.prompt}` : params.prompt;
2808
3009
  await this.config.sessionStore.appendStep(sessionId, step);
2809
3010
  }
2810
3011
  if (this.config.telemetryCollector) {
2811
- await trackAgentStep(this.config.telemetryCollector, this.id, step);
3012
+ const now = new Date;
3013
+ const context = sessionId ? this.activeStepContexts.get(sessionId) : undefined;
3014
+ const stepStartedAt = context?.stepStartedAt ?? now;
3015
+ const durationMs = Math.max(now.getTime() - stepStartedAt.getTime(), 0);
3016
+ if (context) {
3017
+ context.stepIndex += 1;
3018
+ context.stepStartedAt = now;
3019
+ }
3020
+ await trackAgentStep(this.config.telemetryCollector, this.id, step, durationMs, {
3021
+ sessionId,
3022
+ tenantId: context?.tenantId,
3023
+ actorId: context?.actorId,
3024
+ traceId: context?.traceId,
3025
+ stepIndex: context?.stepIndex,
3026
+ stepStartedAt
3027
+ });
3028
+ if (sessionId && step.finishReason !== "tool-calls") {
3029
+ this.activeStepContexts.delete(sessionId);
3030
+ }
2812
3031
  }
2813
3032
  }
3033
+ createInnerAgent(model) {
3034
+ return new ToolLoopAgent({
3035
+ model,
3036
+ instructions: this.instructions,
3037
+ tools: this.tools,
3038
+ stopWhen: stepCountIs(this.spec.maxSteps ?? 10),
3039
+ callOptionsSchema: ContractSpecCallOptionsSchema,
3040
+ onStepFinish: async (step) => {
3041
+ await this.handleStepFinish(step);
3042
+ }
3043
+ });
3044
+ }
3045
+ async resolveModelForCall(params) {
3046
+ const posthogConfig = this.config.posthogConfig;
3047
+ if (!posthogConfig) {
3048
+ return this.config.model;
3049
+ }
3050
+ const mergedProperties = {
3051
+ ...posthogConfig.defaults?.posthogProperties,
3052
+ ...posthogConfig.tracingOptions?.posthogProperties,
3053
+ $ai_session_id: params.sessionId,
3054
+ contractspec_session_id: params.sessionId,
3055
+ contractspec_trace_id: params.traceId,
3056
+ contractspec_agent_id: this.id,
3057
+ contractspec_tenant_id: params.options?.tenantId,
3058
+ contractspec_actor_id: params.options?.actorId
3059
+ };
3060
+ const tracingOptions = {
3061
+ ...posthogConfig.tracingOptions,
3062
+ posthogDistinctId: posthogConfig.tracingOptions?.posthogDistinctId ?? params.options?.actorId,
3063
+ posthogTraceId: params.traceId,
3064
+ posthogProperties: mergedProperties
3065
+ };
3066
+ const { createPostHogTracedModel: createPostHogTracedModel2 } = await Promise.resolve().then(() => exports_posthog);
3067
+ return createPostHogTracedModel2(this.config.model, posthogConfig, tracingOptions);
3068
+ }
2814
3069
  }
2815
3070
  var ContractSpecCallOptionsSchema;
2816
3071
  var init_contract_spec_agent = __esm(() => {
@@ -3990,7 +4245,7 @@ var init_opencode_sdk = __esm(() => {
3990
4245
  init_i18n();
3991
4246
  init_contract_spec_agent();
3992
4247
  import { createProvider } from "@contractspec/lib.ai-providers/factory";
3993
- import { StabilityEnum } from "@contractspec/lib.contracts/ownership";
4248
+ import { StabilityEnum } from "@contractspec/lib.contracts-spec/ownership";
3994
4249
  function getJsonOnlyRules(locale) {
3995
4250
  const i18n = createAgentI18n(locale);
3996
4251
  return [
@@ -4075,7 +4330,6 @@ async function createAgentJsonRunner(options) {
4075
4330
 
4076
4331
  // src/agent/unified-agent.ts
4077
4332
  init_i18n();
4078
- import { createProvider as createProvider2 } from "@contractspec/lib.ai-providers/factory";
4079
4333
 
4080
4334
  class UnifiedAgent {
4081
4335
  spec;
@@ -4241,6 +4495,7 @@ class UnifiedAgent {
4241
4495
  if (backendConfig?.modelInstance) {
4242
4496
  model = backendConfig.modelInstance;
4243
4497
  } else if (backendConfig?.provider) {
4498
+ const { createProvider: createProvider2 } = await import("@contractspec/lib.ai-providers/factory");
4244
4499
  model = createProvider2(backendConfig.provider).getModel();
4245
4500
  } else {
4246
4501
  const { anthropic } = await import("@ai-sdk/anthropic");
@@ -16,4 +16,3 @@ export interface AgentJsonRunner {
16
16
  generateJson: (prompt: string) => Promise<string>;
17
17
  }
18
18
  export declare function createAgentJsonRunner(options: AgentJsonRunnerOptions): Promise<AgentJsonRunner>;
19
- //# sourceMappingURL=json-runner.d.ts.map