@poncho-ai/harness 0.52.2 → 0.55.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.52.2 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.55.0 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,9 +8,9 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 540.60 KB
12
11
  ESM dist/isolate-F2PPSUL6.js 53.82 KB
13
- ESM ⚡️ Build success in 204ms
12
+ ESM dist/index.js 545.48 KB
13
+ ESM ⚡️ Build success in 258ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 7242ms
16
- DTS dist/index.d.ts 93.60 KB
15
+ DTS ⚡️ Build success in 7628ms
16
+ DTS dist/index.d.ts 94.38 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.55.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#149](https://github.com/cesr/poncho-ai/pull/149) [`f5a8260`](https://github.com/cesr/poncho-ai/commit/f5a8260d0515038afc1797d00507908c334115ff) Thanks [@cesr](https://github.com/cesr)! - compaction: preserve subagent context and prior summaries, harden the split
8
+
9
+ Three improvements to context compaction (fires at ~75% context):
10
+ - **Split safety**: `findSafeSplitPoint` now refuses a split whose compacted
11
+ side would end on an assistant message with unanswered `tool_calls` (its
12
+ answering `role:"tool"` result having moved to the preserved side), walking
13
+ earlier to the next clean `user` boundary. Prevents orphaning a tool-call
14
+ relationship inside the summary boundary. Still returns `-1` when no safe
15
+ point exists.
16
+ - **Subagent ledger**: while compacting, scans for subagent-callback records
17
+ (metadata `_subagentCallback`/`subagentCallback`, or text starting with
18
+ `[Subagent Result]`) and any `## Subagents` block embedded in a prior
19
+ compaction summary, then renders a combined, deduped (by `subagentId`)
20
+ ledger that is appended VERBATIM after the LLM summary text — so the model
21
+ can never paraphrase or truncate subagent results away. Cumulative across
22
+ successive compactions.
23
+ - **Cumulative summary**: when the first compacted message is itself a prior
24
+ compaction summary, it is passed to the summarizer in full (not truncated
25
+ to 1200 chars) and the prompt instructs the model to merge-and-update the
26
+ prior working state rather than re-summarize it from scratch. All other
27
+ messages keep the 1200-char truncation.
28
+
29
+ ## 0.54.0
30
+
31
+ ### Minor Changes
32
+
33
+ - [#147](https://github.com/cesr/poncho-ai/pull/147) [`a3eed14`](https://github.com/cesr/poncho-ai/commit/a3eed142832318b6397cd73819d3296c79d6eff0) Thanks [@cesr](https://github.com/cesr)! - storage: add append-only conversation-entry substrate (unused groundwork)
34
+
35
+ Pure entry types + rebuild functions (`buildLlmContext`,
36
+ `buildDisplaySnapshot`, `getPendingSubagentResults`) for the eventual
37
+ append-only conversation model that removes the mutable-blob clobber race
38
+ (the root cause behind lost subagent results). No storage-engine wiring
39
+ and no live callers yet — additive, deploys nothing behavioral. The
40
+ rebuild logic (compaction overlay, amendment folding, callback-consumption)
41
+ is covered by unit tests so the design is proven before the bigger
42
+ dual-write / migration / cutover PRs.
43
+
44
+ ## 0.53.0
45
+
46
+ ### Minor Changes
47
+
48
+ - [#145](https://github.com/cesr/poncho-ai/pull/145) [`bfa4976`](https://github.com/cesr/poncho-ai/commit/bfa4976ac8b05a300e22271e23c3bae4aadae2a8) Thanks [@cesr](https://github.com/cesr)! - events: add stable identity so streaming clients match instead of guess
49
+
50
+ Additive fields that let a streaming client reconstruct view-state by
51
+ identity rather than inferring structure from event order (the source of a
52
+ class of reconnect/subagent rendering bugs):
53
+ - `tool:started` / `tool:completed` / `tool:error` now carry `toolCallId`
54
+ (already in scope as `call.id` / `result.callId`). Clients match tool
55
+ pills by id instead of by tool name.
56
+ - `subagent:spawned|completed|error|stopped` now carry `parentToolCallId`
57
+ (the `spawn_subagent` tool call's id) and `task`; `completed`/`error`
58
+ also carry `resultText`. Clients attach subagent state to the spawning
59
+ tool's pill and render the result inline — no header-regex or
60
+ sequential-cursor pairing needed.
61
+ - `ToolContext` gains `toolCallId` so the `spawn_subagent` handler can
62
+ record which call produced the subagent (plumbed: tool-dispatcher →
63
+ spawn handler → `SubagentSpawnOptions.parentToolCallId` →
64
+ `subagentMeta.parentToolCallId` → the events above).
65
+ - `run:started` gains an optional `cause` field in the type
66
+ (`user|continuation|subagent_callback|approval_resume`); emission is
67
+ deferred to a later pass.
68
+
69
+ All fields are additive; older clients ignore them.
70
+
71
+ ### Patch Changes
72
+
73
+ - Updated dependencies [[`bfa4976`](https://github.com/cesr/poncho-ai/commit/bfa4976ac8b05a300e22271e23c3bae4aadae2a8)]:
74
+ - @poncho-ai/sdk@1.15.0
75
+
3
76
  ## 0.52.2
4
77
 
5
78
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -96,6 +96,12 @@ declare const estimateTotalTokens: (systemPrompt: string, messages: Message[], t
96
96
  * and everything from it onward is preserved. The split always lands just
97
97
  * before a `user` message to avoid breaking assistant+tool pairs.
98
98
  *
99
+ * Defensive guard: even at a `user` boundary, refuse a split whose compacted
100
+ * side would END on an assistant message with unanswered tool_calls (its
101
+ * `tool` result having moved to the preserved side). Such a split would
102
+ * orphan the tool_calls inside the summary boundary. When that happens we
103
+ * walk earlier to the next safe `user` boundary.
104
+ *
99
105
  * Returns -1 if no valid split point is found.
100
106
  */
101
107
  declare const findSafeSplitPoint: (messages: Message[], keepRecentMessages: number) => number;
@@ -199,6 +205,9 @@ interface Conversation {
199
205
  * subagent's runs emit no telemetry (e.g. spawned from an incognito
200
206
  * turn). Read by the orchestrator's runSubagent / continuation. */
201
207
  suppressTelemetry?: boolean;
208
+ /** The parent's `spawn_subagent` tool call id — echoed onto subagent:*
209
+ * events so a client can attach subagent state to that tool's pill. */
210
+ parentToolCallId?: string;
202
211
  };
203
212
  channelMeta?: {
204
213
  platform: string;
@@ -1190,6 +1199,10 @@ interface SubagentManager {
1190
1199
  /** Inherit the parent run's telemetry choice — when true, the subagent
1191
1200
  * run (and its re-runs) emit no telemetry. */
1192
1201
  suppressTelemetry?: boolean;
1202
+ /** The id of the `spawn_subagent` tool call that produced this subagent,
1203
+ * so its events can carry `parentToolCallId` and a client can attach
1204
+ * subagent state to the spawning tool's pill. */
1205
+ parentToolCallId?: string;
1193
1206
  }): Promise<SubagentSpawnResult>;
1194
1207
  sendMessage(subagentId: string, message: string): Promise<SubagentSpawnResult>;
1195
1208
  stop(subagentId: string): Promise<void>;
package/dist/index.js CHANGED
@@ -374,6 +374,9 @@ var SUMMARIZATION_PROMPT = `Summarize the following conversation into a structur
374
374
 
375
375
  Be concise but preserve all information needed to continue the task.
376
376
  Omit any section that has no relevant content.`;
377
+ var CUMULATIVE_SUMMARY_PROMPT = `The FIRST message below (tagged [prior-summary]) is an existing working-state summary produced by an earlier compaction. Treat it as the authoritative prior working state: MERGE AND UPDATE it with the newer messages that follow it, carrying forward all still-relevant detail. Do NOT discard or re-compress information from the prior summary just because it is older \u2014 only drop it if the newer messages explicitly supersede it.`;
378
+ var SUBAGENT_DIGEST_CHARS = 500;
379
+ var SUBAGENT_LEDGER_HEADING = "## Subagents";
377
380
  var resolveCompactionConfig = (explicit) => {
378
381
  if (!explicit) return { ...DEFAULT_COMPACTION_CONFIG };
379
382
  return {
@@ -398,32 +401,57 @@ var estimateTotalTokens = (systemPrompt, messages, toolDefinitionsJson) => {
398
401
  }
399
402
  return tokens;
400
403
  };
404
+ var assistantHasToolCalls = (msg) => {
405
+ if (msg.role !== "assistant") return false;
406
+ if (typeof msg.content !== "string") return false;
407
+ if (!msg.content.includes('"tool_calls"')) return false;
408
+ try {
409
+ const parsed = JSON.parse(msg.content);
410
+ return Array.isArray(parsed.tool_calls) && parsed.tool_calls.length > 0;
411
+ } catch {
412
+ return false;
413
+ }
414
+ };
415
+ var splitOrphansToolCalls = (messages, idx) => {
416
+ if (idx <= 0 || idx >= messages.length) return false;
417
+ const lastCompacted = messages[idx - 1];
418
+ return assistantHasToolCalls(lastCompacted);
419
+ };
401
420
  var findSafeSplitPoint = (messages, keepRecentMessages) => {
402
421
  const candidateIdx = messages.length - keepRecentMessages;
403
422
  if (candidateIdx < MIN_COMPACTABLE_MESSAGES) return -1;
404
423
  for (let i = candidateIdx; i >= MIN_COMPACTABLE_MESSAGES; i--) {
405
- if (messages[i].role === "user") {
424
+ if (messages[i].role === "user" && !splitOrphansToolCalls(messages, i)) {
406
425
  return i;
407
426
  }
408
427
  }
409
428
  for (let i = candidateIdx + 1; i < messages.length - 1; i++) {
410
- if (messages[i].role === "user") {
429
+ if (messages[i].role === "user" && !splitOrphansToolCalls(messages, i)) {
411
430
  if (i < MIN_COMPACTABLE_MESSAGES) return -1;
412
431
  return i;
413
432
  }
414
433
  }
415
434
  return -1;
416
435
  };
436
+ var isCompactionSummary = (msg) => msg.metadata?.isCompactionSummary === true;
417
437
  var buildSummarizationMessages = (messagesToCompact, instructions) => {
438
+ const hasPriorSummary = messagesToCompact.length > 0 && isCompactionSummary(messagesToCompact[0]);
418
439
  const conversationLines = [];
419
- for (const msg of messagesToCompact) {
440
+ for (let i = 0; i < messagesToCompact.length; i++) {
441
+ const msg = messagesToCompact[i];
420
442
  const text = getTextContent(msg);
421
- const truncated = text.length > SUMMARIZATION_MESSAGE_TRUNCATION_CHARS ? text.slice(0, SUMMARIZATION_MESSAGE_TRUNCATION_CHARS) + "\n...[truncated]" : text;
422
- conversationLines.push(`[${msg.role}]: ${truncated}`);
443
+ const isPrior = i === 0 && hasPriorSummary;
444
+ const rendered = isPrior || text.length <= SUMMARIZATION_MESSAGE_TRUNCATION_CHARS ? text : text.slice(0, SUMMARIZATION_MESSAGE_TRUNCATION_CHARS) + "\n...[truncated]";
445
+ const tag = isPrior ? "prior-summary" : msg.role;
446
+ conversationLines.push(`[${tag}]: ${rendered}`);
423
447
  }
424
- const prompt = instructions ? `${SUMMARIZATION_PROMPT}
448
+ let prompt = SUMMARIZATION_PROMPT;
449
+ if (hasPriorSummary) prompt = `${prompt}
425
450
 
426
- Additional focus: ${instructions}` : SUMMARIZATION_PROMPT;
451
+ ${CUMULATIVE_SUMMARY_PROMPT}`;
452
+ if (instructions) prompt = `${prompt}
453
+
454
+ Additional focus: ${instructions}`;
427
455
  return [
428
456
  {
429
457
  role: "user",
@@ -435,6 +463,67 @@ ${conversationLines.join("\n\n")}`
435
463
  }
436
464
  ];
437
465
  };
466
+ var SUBAGENT_RESULT_HEADER = /^\[Subagent Result\] Subagent "([^"]*)" \(([^)]*)\) (\S+):/;
467
+ var parseSubagentCallback = (msg) => {
468
+ if (msg.role !== "user") return null;
469
+ const meta = msg.metadata ?? {};
470
+ const text = getTextContent(msg);
471
+ const hasMetaFlag = meta._subagentCallback === true || meta.subagentCallback === true;
472
+ const hasTextMarker = text.startsWith("[Subagent Result]");
473
+ if (!hasMetaFlag && !hasTextMarker) return null;
474
+ const headerMatch = text.match(SUBAGENT_RESULT_HEADER);
475
+ const subagentId = typeof meta.subagentId === "string" && meta.subagentId ? meta.subagentId : headerMatch?.[2] ?? "";
476
+ if (!subagentId) return null;
477
+ const task = typeof meta.task === "string" && meta.task ? meta.task : headerMatch?.[1] ?? "";
478
+ const status = headerMatch?.[3] ?? "completed";
479
+ const bodyStart = text.indexOf("\n\n");
480
+ const body = bodyStart >= 0 ? text.slice(bodyStart + 2) : text;
481
+ const digest = body.length > SUBAGENT_DIGEST_CHARS ? body.slice(0, SUBAGENT_DIGEST_CHARS) + "\u2026" : body;
482
+ return { subagentId, task, status, digest };
483
+ };
484
+ var parsePriorLedger = (summaryText) => {
485
+ const headingIdx = summaryText.indexOf(SUBAGENT_LEDGER_HEADING);
486
+ if (headingIdx < 0) return [];
487
+ const block = summaryText.slice(headingIdx + SUBAGENT_LEDGER_HEADING.length);
488
+ const entries = [];
489
+ const entryRe = /^- \*\*(.*?)\*\* \((.+?)\) — (\S+)\n {2}(.*)$/gm;
490
+ let m;
491
+ while ((m = entryRe.exec(block)) !== null) {
492
+ entries.push({
493
+ task: m[1],
494
+ subagentId: m[2],
495
+ status: m[3],
496
+ digest: m[4]
497
+ });
498
+ }
499
+ return entries;
500
+ };
501
+ var collectSubagentLedger = (messagesToCompact) => {
502
+ const byId = /* @__PURE__ */ new Map();
503
+ const order = [];
504
+ const upsert = (entry) => {
505
+ if (!byId.has(entry.subagentId)) order.push(entry.subagentId);
506
+ byId.set(entry.subagentId, entry);
507
+ };
508
+ for (const msg of messagesToCompact) {
509
+ if (isCompactionSummary(msg)) {
510
+ for (const prior of parsePriorLedger(getTextContent(msg))) upsert(prior);
511
+ continue;
512
+ }
513
+ const entry = parseSubagentCallback(msg);
514
+ if (entry) upsert(entry);
515
+ }
516
+ return order.map((id) => byId.get(id));
517
+ };
518
+ var renderSubagentLedger = (entries) => {
519
+ if (entries.length === 0) return "";
520
+ const lines = entries.map(
521
+ (e) => `- **${e.task}** (${e.subagentId}) \u2014 ${e.status}
522
+ ${e.digest.replace(/\n/g, " ")}`
523
+ );
524
+ return `${SUBAGENT_LEDGER_HEADING}
525
+ ${lines.join("\n")}`;
526
+ };
438
527
  var buildContinuationMessage = (summary) => ({
439
528
  role: "user",
440
529
  content: `[CONTEXT COMPACTION] This conversation was automatically compacted. The summary below covers earlier messages.
@@ -483,7 +572,11 @@ var compactMessages = async (model, messages, config, options) => {
483
572
  warning: "Summarization returned empty result"
484
573
  };
485
574
  }
486
- const continuationMessage = buildContinuationMessage(summary);
575
+ const ledger = renderSubagentLedger(collectSubagentLedger(toCompact));
576
+ const summaryWithLedger = ledger ? `${summary}
577
+
578
+ ${ledger}` : summary;
579
+ const continuationMessage = buildContinuationMessage(summaryWithLedger);
487
580
  const compactedMessages = [continuationMessage, ...toPreserve];
488
581
  return {
489
582
  compacted: true,
@@ -8323,7 +8416,8 @@ var createSubagentTools = (manager) => [
8323
8416
  parentConversationId: conversationId,
8324
8417
  ownerId,
8325
8418
  tenantId: context.tenantId,
8326
- suppressTelemetry: context.suppressTelemetry
8419
+ suppressTelemetry: context.suppressTelemetry,
8420
+ parentToolCallId: context.toolCallId
8327
8421
  });
8328
8422
  return { subagentId, status: "running" };
8329
8423
  }
@@ -8585,7 +8679,7 @@ var ToolDispatcher = class {
8585
8679
  };
8586
8680
  }
8587
8681
  try {
8588
- const output = await definition.handler(call.input, context);
8682
+ const output = await definition.handler(call.input, { ...context, toolCallId: call.id });
8589
8683
  if (context.abortSignal?.aborted) {
8590
8684
  return {
8591
8685
  callId: call.id,
@@ -11170,7 +11264,7 @@ ${textContent}` };
11170
11264
  return;
11171
11265
  }
11172
11266
  const runtimeToolName = exposedToolNames.get(call.name) ?? call.name;
11173
- yield pushEvent({ type: "tool:started", tool: runtimeToolName, input: call.input });
11267
+ yield pushEvent({ type: "tool:started", tool: runtimeToolName, toolCallId: call.id, input: call.input });
11174
11268
  if (this.requiresApprovalForToolCall(runtimeToolName, call.input)) {
11175
11269
  approvalNeeded.push({
11176
11270
  approvalId: `approval_${randomUUID5()}`,
@@ -11363,6 +11457,7 @@ ${textContent}` };
11363
11457
  yield pushEvent({
11364
11458
  type: "tool:error",
11365
11459
  tool: result2.tool,
11460
+ toolCallId: result2.callId,
11366
11461
  error: result2.error,
11367
11462
  recoverable: true
11368
11463
  });
@@ -11404,6 +11499,7 @@ ${textContent}` };
11404
11499
  yield pushEvent({
11405
11500
  type: "tool:completed",
11406
11501
  tool: result2.tool,
11502
+ toolCallId: result2.callId,
11407
11503
  input: callInputMap.get(result2.callId),
11408
11504
  output: result2.output,
11409
11505
  duration: now() - batchStart,
@@ -12826,11 +12922,14 @@ var AgentOrchestrator = class {
12826
12922
  result: { status: "completed", response: responseText, steps: 0, tokens: { input: 0, output: 0, cached: 0 }, duration: 0 },
12827
12923
  timestamp: Date.now()
12828
12924
  };
12829
- await this.conversationStore.appendSubagentResult(conv.parentConversationId, pendingResult);
12925
+ await this.appendSubagentResultReliable(conv.parentConversationId, pendingResult);
12830
12926
  await this.eventSink(conv.parentConversationId, {
12831
12927
  type: "subagent:completed",
12832
12928
  subagentId,
12833
- conversationId: subagentId
12929
+ conversationId: subagentId,
12930
+ task: conv.subagentMeta?.task ?? conv.title,
12931
+ parentToolCallId: conv.subagentMeta?.parentToolCallId,
12932
+ resultText: responseText
12834
12933
  });
12835
12934
  await this.triggerParentCallback(conv.parentConversationId);
12836
12935
  }
@@ -12906,9 +13005,11 @@ var AgentOrchestrator = class {
12906
13005
  let latestRunId = "";
12907
13006
  let runResult;
12908
13007
  let runError;
13008
+ let parentToolCallId;
12909
13009
  try {
12910
13010
  const conversation = await this.conversationStore.getWithArchive(childConversationId);
12911
13011
  if (!conversation) throw new Error("Subagent conversation not found");
13012
+ parentToolCallId = conversation.subagentMeta?.parentToolCallId;
12912
13013
  if (conversation.subagentMeta?.status === "stopped") return;
12913
13014
  conversation.lastActivityAt = Date.now();
12914
13015
  await this.conversationStore.update(conversation);
@@ -13126,7 +13227,10 @@ var AgentOrchestrator = class {
13126
13227
  await this.eventSink(parentConversationId, {
13127
13228
  type: "subagent:completed",
13128
13229
  subagentId: childConversationId,
13129
- conversationId: childConversationId
13230
+ conversationId: childConversationId,
13231
+ task,
13232
+ parentToolCallId,
13233
+ resultText: subagentResponse
13130
13234
  });
13131
13235
  this.triggerParentCallback(parentConversationId).catch(
13132
13236
  (err) => console.error(`[poncho][subagent] Parent callback failed:`, err instanceof Error ? err.message : err)
@@ -13157,7 +13261,9 @@ var AgentOrchestrator = class {
13157
13261
  type: "subagent:error",
13158
13262
  subagentId: childConversationId,
13159
13263
  conversationId: childConversationId,
13160
- error: errMsg
13264
+ error: errMsg,
13265
+ task,
13266
+ parentToolCallId
13161
13267
  });
13162
13268
  this.triggerParentCallback(parentConversationId).catch(
13163
13269
  (err2) => console.error(`[poncho][subagent] Parent callback failed:`, err2 instanceof Error ? err2.message : err2)
@@ -13486,7 +13592,10 @@ ${resultBody}`,
13486
13592
  await this.eventSink(parentConversationId, {
13487
13593
  type: "subagent:completed",
13488
13594
  subagentId: conversationId,
13489
- conversationId
13595
+ conversationId,
13596
+ task,
13597
+ parentToolCallId: conversation.subagentMeta?.parentToolCallId,
13598
+ resultText: subagentResponse
13490
13599
  });
13491
13600
  if (parentConv) {
13492
13601
  if (this.isServerless) {
@@ -13530,7 +13639,9 @@ ${resultBody}`,
13530
13639
  await this.eventSink(conversation.parentConversationId, {
13531
13640
  type: "subagent:completed",
13532
13641
  subagentId: conversationId,
13533
- conversationId
13642
+ conversationId,
13643
+ task,
13644
+ parentToolCallId: conversation.subagentMeta?.parentToolCallId
13534
13645
  });
13535
13646
  if (parentConv) {
13536
13647
  if (this.isServerless) {
@@ -13560,7 +13671,7 @@ ${resultBody}`,
13560
13671
  opts.tenantId ?? null,
13561
13672
  {
13562
13673
  parentConversationId: opts.parentConversationId,
13563
- subagentMeta: { task: opts.task, status: "running", suppressTelemetry: opts.suppressTelemetry },
13674
+ subagentMeta: { task: opts.task, status: "running", suppressTelemetry: opts.suppressTelemetry, parentToolCallId: opts.parentToolCallId },
13564
13675
  messages: [{ role: "user", content: opts.task }]
13565
13676
  }
13566
13677
  );
@@ -13572,7 +13683,8 @@ ${resultBody}`,
13572
13683
  type: "subagent:spawned",
13573
13684
  subagentId: conversation.conversationId,
13574
13685
  conversationId: conversation.conversationId,
13575
- task: opts.task
13686
+ task: opts.task,
13687
+ parentToolCallId: opts.parentToolCallId
13576
13688
  });
13577
13689
  if (this.isServerless) {
13578
13690
  this.hooks.dispatchBackground("subagent-run", conversation.conversationId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.52.2",
3
+ "version": "0.55.0",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,7 +34,7 @@
34
34
  "mustache": "^4.2.0",
35
35
  "yaml": "^2.4.0",
36
36
  "zod": "^3.22.0",
37
- "@poncho-ai/sdk": "1.14.0"
37
+ "@poncho-ai/sdk": "1.15.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "esbuild": ">=0.17.0",