privateer-agent 0.12.23 → 0.12.24

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "privateer-agent",
3
- "version": "0.12.23",
3
+ "version": "0.12.24",
4
4
  "description": "Privacy-first terminal coding agent — bring your own model across 20 providers (Anthropic, OpenAI, OpenRouter, Google, local Ollama…). Safe-by-default permissions, MCP, sub-agents, workflows, and verifiable TEE inference. Built on the Pi toolkit.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,6 +20,8 @@ import {
20
20
  type EngineEvent,
21
21
  type UsageTotals,
22
22
  } from "../engine/events.ts";
23
+ import { describeErrorText } from "../engine/errors.ts";
24
+ import { redactText } from "../util/redact.ts";
23
25
 
24
26
  // Minimal structural view of the Pi session events we read. Kept loose (not the
25
27
  // full Pi union) so this module type-checks without pinning to Pi's internals;
@@ -108,16 +110,41 @@ export function createEngineEventAdapter() {
108
110
  ];
109
111
 
110
112
  case "turn_end": {
111
- const turn = normUsage((ev.message as any)?.usage);
113
+ const msg = ev.message as any;
114
+ const turn = normUsage(msg?.usage);
112
115
  sessionTotal = addUsage(sessionTotal, turn);
113
116
  const finishReason =
114
- (ev.finishReason as string) ??
115
- ((ev.message as any)?.stopReason as string) ??
116
- "stop";
117
- return [
118
- { type: "usage", usage: sessionTotal, turn },
119
- { type: "finish", usage: sessionTotal, finishReason },
120
- ];
117
+ (ev.finishReason as string) ?? (msg?.stopReason as string) ?? "stop";
118
+ const out: EngineEvent[] = [{ type: "usage", usage: sessionTotal, turn }];
119
+ // A FAILED turn ends here, not by throwing — and this is the only place the
120
+ // app can learn it failed.
121
+ //
122
+ // Pi reports a dead model call as an assistant message with
123
+ // `stopReason: "error"` and an `errorMessage`; `prompt()` then resolves
124
+ // NORMALLY, so the desktop's runTurn catch never fires. Our own pi patch
125
+ // widened that path deliberately (a hard 4xx, and a 429 that outlived the
126
+ // retry budget, both end the turn instead of re-entering the agent loop),
127
+ // which is right for the CLI — its TUI reads the assistant message and
128
+ // prints describeErrorText. The app reads EngineEvents, and this adapter
129
+ // used to drop `errorMessage` on the floor: the turn arrived as a bare
130
+ // `finish`, which RemoteDriveContext closes as a green ✓ "done". A signed-in
131
+ // user whose first turn 401'd or hit their cap saw a tick and no words.
132
+ //
133
+ // So say it. Same wording the terminal gets, ahead of the finish so the feed
134
+ // reads in order, and redacted either way because an unrecognised body goes
135
+ // out verbatim.
136
+ if (msg?.stopReason === "error") {
137
+ const raw = typeof msg.errorMessage === "string" ? msg.errorMessage : "";
138
+ const described = describeErrorText(raw);
139
+ out.push({
140
+ type: "error",
141
+ error: described?.message ?? redactText(raw || "The model call failed."),
142
+ ...(described?.hint ? { hint: described.hint } : {}),
143
+ ...(described?.retryable != null ? { retryable: described.retryable } : {}),
144
+ });
145
+ }
146
+ out.push({ type: "finish", usage: sessionTotal, finishReason });
147
+ return out;
121
148
  }
122
149
 
123
150
  // Compaction: Pi collapses history to free context. TODO(verify) field
@@ -146,8 +173,14 @@ export function createEngineEventAdapter() {
146
173
  },
147
174
  ];
148
175
 
149
- // Terminal error surfaced at the end of an agent run. TODO(verify) shape;
150
- // Phase 1 re-points errors/errors.ts (describeError) here.
176
+ // Terminal error surfaced at the end of an agent run.
177
+ //
178
+ // ⚠️ Pi 0.84's `agent_end` is `{ messages, willRetry }` — there is NO `error`
179
+ // field, so this branch has been returning [] for every run since the 0.84
180
+ // refactor. It is kept (harmless, and other Pi versions have carried one)
181
+ // but it is NOT the error path: a failed model call arrives on `turn_end`
182
+ // above, which is where the real mapping lives. Do not "restore" error
183
+ // reporting here and delete it there.
151
184
  case "agent_end": {
152
185
  const err = (ev as any).error;
153
186
  if (!err) return [];