@poncho-ai/harness 0.50.1 → 0.50.3

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.50.1 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.50.3 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 530.75 KB
11
+ ESM dist/index.js 530.79 KB
12
12
  ESM dist/isolate-BNQ6P3HI.js 51.41 KB
13
- ESM ⚡️ Build success in 224ms
13
+ ESM ⚡️ Build success in 229ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 6878ms
16
- DTS dist/index.d.ts 89.28 KB
15
+ DTS ⚡️ Build success in 7430ms
16
+ DTS dist/index.d.ts 89.60 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.50.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`a67fb45`](https://github.com/cesr/poncho-ai/commit/a67fb45162823d832296ae9af137eb566d9f2f97) Thanks [@cesr](https://github.com/cesr)! - harness: forward `tenantId` through `continueFromToolResult`. Resumed runs (after an approval checkpoint) ran tools with `ctx.tenantId` undefined, so tenant-scoped stores (memory, VFS, todos) resolved the default `"__default__"` tenant instead of the caller's — surfacing as `memory_main_get` returning empty after an approval resume.
8
+
9
+ ## 0.50.2
10
+
11
+ ### Patch Changes
12
+
13
+ - [#133](https://github.com/cesr/poncho-ai/pull/133) [`60e21c8`](https://github.com/cesr/poncho-ai/commit/60e21c8c18054d2824cf7364b71dabfd07574b48) Thanks [@cesr](https://github.com/cesr)! - harness: don't inject the "interrupted by a time limit" bridge when resuming from tool results
14
+
15
+ A taskless `run()` (continuation checkpoint, or `continueFromToolResult` —
16
+ e.g. resuming after an approval gate) injected a synthetic user message
17
+ telling the model its turn was "interrupted by a time limit ... continue
18
+ EXACTLY from where you left off, do not re-summarize." That bridge is only
19
+ appropriate when the model was actually cut off mid-response (the last
20
+ message is an `assistant` turn, which some providers also reject as a
21
+ conversation-ending message).
22
+
23
+ When the last message is a `tool` result — which is the case for every
24
+ `continueFromToolResult` resume — the conversation already ends in a
25
+ provider-valid user `tool_result` block and the model continues from the
26
+ results naturally. Injecting the bridge there was a bug: after a normal
27
+ approval resolution the model was told its turn had been killed by a time
28
+ limit, causing it to distrust and re-derive context (re-reading the VFS,
29
+ concluding it had "hallucinated" data it had legitimately loaded). The
30
+ bridge is now only added when the last message is an `assistant` turn, and
31
+ its wording no longer hard-codes "time limit" (max-steps checkpoints use
32
+ the same path).
33
+
3
34
  ## 0.50.1
4
35
 
5
36
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1434,6 +1434,11 @@ declare class AgentHarness {
1434
1434
  error?: string;
1435
1435
  }>;
1436
1436
  conversationId?: string;
1437
+ /** Must be forwarded for the continuation run, otherwise tenant-scoped
1438
+ * tool stores (memory, VFS, todos) resolve the default "__default__"
1439
+ * tenant on resume instead of the caller's — e.g. memory_main_get
1440
+ * returns empty after an approval checkpoint. */
1441
+ tenantId?: string;
1437
1442
  parameters?: Record<string, unknown>;
1438
1443
  abortSignal?: AbortSignal;
1439
1444
  }): AsyncGenerator<AgentEvent>;
package/dist/index.js CHANGED
@@ -10441,10 +10441,10 @@ ${this.skillFingerprint}`;
10441
10441
  }
10442
10442
  } else {
10443
10443
  const lastMsg = messages[messages.length - 1];
10444
- if (lastMsg && lastMsg.role !== "user") {
10444
+ if (lastMsg && lastMsg.role === "assistant") {
10445
10445
  messages.push({
10446
10446
  role: "user",
10447
- content: "[System: Your previous turn was interrupted by a time limit. Your partial response above is already visible to the user. Continue EXACTLY from where you left off \u2014 do NOT restart, re-summarize, or repeat any content you already produced. If you were mid-sentence or mid-table, continue that sentence or table. Proceed directly with the next action or output.]",
10447
+ content: "[System: Your previous turn was interrupted before you finished. Your partial response above is already visible to the user. Continue EXACTLY from where you left off \u2014 do NOT restart, re-summarize, or repeat any content you already produced. If you were mid-sentence or mid-table, continue that sentence or table. Proceed directly with the next action or output.]",
10448
10448
  metadata: { timestamp: now(), id: randomUUID5() }
10449
10449
  });
10450
10450
  }
@@ -11568,6 +11568,7 @@ ${this.skillFingerprint}`;
11568
11568
  yield* this.runWithTelemetry({
11569
11569
  messages,
11570
11570
  conversationId: input.conversationId,
11571
+ tenantId: input.tenantId,
11571
11572
  parameters: input.parameters,
11572
11573
  abortSignal: input.abortSignal
11573
11574
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.50.1",
3
+ "version": "0.50.3",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
package/src/harness.ts CHANGED
@@ -2388,14 +2388,25 @@ Code is wrapped in an async IIFE — use \`return\` to return a value to the too
2388
2388
  });
2389
2389
  }
2390
2390
  } else {
2391
- // Continuation run (no explicit task). Some providers (Anthropic) require
2392
- // the conversation to end with a user message. Inject a transient signal
2393
- // that is sent to the LLM but never persisted to the conversation store.
2391
+ // Taskless run: either a genuine continuation checkpoint (the model
2392
+ // was cut off mid-response by a soft-deadline / max-steps boundary)
2393
+ // or a tool-result resume `continueFromToolResult`, e.g. after an
2394
+ // approval gate — whose last message is the tool results.
2395
+ //
2396
+ // Only the first case needs a bridge: ending on an assistant message
2397
+ // is invalid for some providers (Anthropic), and the model must be
2398
+ // told to continue rather than restart. A `tool` last message converts
2399
+ // to a user-role tool_result block, so the conversation already ends
2400
+ // "with a user message" and the model continues from the results
2401
+ // naturally. Injecting the bridge after tool results was a bug: it
2402
+ // told the model — after a normal approval resolution — that its turn
2403
+ // had been "interrupted by a time limit" and to not re-summarize,
2404
+ // which made it distrust and re-derive context it already had.
2394
2405
  const lastMsg = messages[messages.length - 1];
2395
- if (lastMsg && lastMsg.role !== "user") {
2406
+ if (lastMsg && lastMsg.role === "assistant") {
2396
2407
  messages.push({
2397
2408
  role: "user",
2398
- content: "[System: Your previous turn was interrupted by a time limit. Your partial response above is already visible to the user. Continue EXACTLY from where you left off — do NOT restart, re-summarize, or repeat any content you already produced. If you were mid-sentence or mid-table, continue that sentence or table. Proceed directly with the next action or output.]",
2409
+ content: "[System: Your previous turn was interrupted before you finished. Your partial response above is already visible to the user. Continue EXACTLY from where you left off — do NOT restart, re-summarize, or repeat any content you already produced. If you were mid-sentence or mid-table, continue that sentence or table. Proceed directly with the next action or output.]",
2399
2410
  metadata: { timestamp: now(), id: randomUUID() },
2400
2411
  });
2401
2412
  }
@@ -3716,6 +3727,11 @@ Code is wrapped in an async IIFE — use \`return\` to return a value to the too
3716
3727
  messages: Message[];
3717
3728
  toolResults: Array<{ callId: string; toolName: string; result?: unknown; error?: string }>;
3718
3729
  conversationId?: string;
3730
+ /** Must be forwarded for the continuation run, otherwise tenant-scoped
3731
+ * tool stores (memory, VFS, todos) resolve the default "__default__"
3732
+ * tenant on resume instead of the caller's — e.g. memory_main_get
3733
+ * returns empty after an approval checkpoint. */
3734
+ tenantId?: string;
3719
3735
  parameters?: Record<string, unknown>;
3720
3736
  abortSignal?: AbortSignal;
3721
3737
  }): AsyncGenerator<AgentEvent> {
@@ -3773,6 +3789,7 @@ Code is wrapped in an async IIFE — use \`return\` to return a value to the too
3773
3789
  yield* this.runWithTelemetry({
3774
3790
  messages,
3775
3791
  conversationId: input.conversationId,
3792
+ tenantId: input.tenantId,
3776
3793
  parameters: input.parameters,
3777
3794
  abortSignal: input.abortSignal,
3778
3795
  });