@averyyy/pi-coding-agent 0.84.1-piclient.3 → 0.84.2-piclient.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.
Files changed (140) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +1 -0
  3. package/dist/cli/args.d.ts +1 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +11 -0
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-command.d.ts.map +1 -1
  8. package/dist/cli/auth-command.js +5 -4
  9. package/dist/cli/auth-command.js.map +1 -1
  10. package/dist/core/agent-session.d.ts +7 -2
  11. package/dist/core/agent-session.d.ts.map +1 -1
  12. package/dist/core/agent-session.js +6 -6
  13. package/dist/core/agent-session.js.map +1 -1
  14. package/dist/core/experimental.d.ts +4 -0
  15. package/dist/core/experimental.d.ts.map +1 -1
  16. package/dist/core/experimental.js +4 -0
  17. package/dist/core/experimental.js.map +1 -1
  18. package/dist/core/extensions/types.d.ts +4 -0
  19. package/dist/core/extensions/types.d.ts.map +1 -1
  20. package/dist/core/extensions/types.js.map +1 -1
  21. package/dist/core/keybindings.d.ts +24 -0
  22. package/dist/core/keybindings.d.ts.map +1 -1
  23. package/dist/core/model-config.d.ts +5 -0
  24. package/dist/core/model-config.d.ts.map +1 -1
  25. package/dist/core/model-config.js +1 -0
  26. package/dist/core/model-config.js.map +1 -1
  27. package/dist/core/pi-server-client.d.ts +0 -1
  28. package/dist/core/pi-server-client.d.ts.map +1 -1
  29. package/dist/core/pi-server-client.js +148 -65
  30. package/dist/core/pi-server-client.js.map +1 -1
  31. package/dist/core/project-trust.d.ts.map +1 -1
  32. package/dist/core/project-trust.js +2 -2
  33. package/dist/core/project-trust.js.map +1 -1
  34. package/dist/core/sdk.d.ts +5 -3
  35. package/dist/core/sdk.d.ts.map +1 -1
  36. package/dist/core/sdk.js +2 -1
  37. package/dist/core/sdk.js.map +1 -1
  38. package/dist/core/session-manager.d.ts.map +1 -1
  39. package/dist/core/session-manager.js +2 -2
  40. package/dist/core/session-manager.js.map +1 -1
  41. package/dist/core/settings-manager.d.ts +6 -0
  42. package/dist/core/settings-manager.d.ts.map +1 -1
  43. package/dist/core/settings-manager.js +12 -0
  44. package/dist/core/settings-manager.js.map +1 -1
  45. package/dist/core/system-prompt.d.ts.map +1 -1
  46. package/dist/core/system-prompt.js +1 -1
  47. package/dist/core/system-prompt.js.map +1 -1
  48. package/dist/core/tools/bash.d.ts.map +1 -1
  49. package/dist/core/tools/bash.js +2 -0
  50. package/dist/core/tools/bash.js.map +1 -1
  51. package/dist/core/tools/edit.d.ts.map +1 -1
  52. package/dist/core/tools/edit.js +2 -0
  53. package/dist/core/tools/edit.js.map +1 -1
  54. package/dist/core/tools/find.d.ts.map +1 -1
  55. package/dist/core/tools/find.js +1 -1
  56. package/dist/core/tools/find.js.map +1 -1
  57. package/dist/core/tools/grep.d.ts.map +1 -1
  58. package/dist/core/tools/grep.js +1 -1
  59. package/dist/core/tools/grep.js.map +1 -1
  60. package/dist/core/tools/read.d.ts.map +1 -1
  61. package/dist/core/tools/read.js +2 -0
  62. package/dist/core/tools/read.js.map +1 -1
  63. package/dist/core/tools/write.d.ts.map +1 -1
  64. package/dist/core/tools/write.js +2 -0
  65. package/dist/core/tools/write.js.map +1 -1
  66. package/dist/index.d.ts +1 -1
  67. package/dist/index.d.ts.map +1 -1
  68. package/dist/index.js.map +1 -1
  69. package/dist/main.d.ts.map +1 -1
  70. package/dist/main.js +5 -1
  71. package/dist/main.js.map +1 -1
  72. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  73. package/dist/modes/interactive/components/model-selector.js +2 -1
  74. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  75. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  76. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  77. package/dist/modes/interactive/components/settings-selector.js +10 -0
  78. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  79. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  80. package/dist/modes/interactive/components/tool-execution.js +10 -1
  81. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  82. package/dist/modes/interactive/interactive-mode.d.ts +8 -2
  83. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  84. package/dist/modes/interactive/interactive-mode.js +76 -25
  85. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  86. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  87. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  88. package/dist/modes/interactive/model-catalog-refresh.js +34 -0
  89. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  90. package/dist/modes/interactive/theme/dark.json +2 -0
  91. package/dist/modes/interactive/theme/light.json +2 -0
  92. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  93. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  94. package/dist/modes/interactive/theme/theme-controller.js +25 -11
  95. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  96. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  97. package/dist/modes/interactive/theme/theme.d.ts +5 -3
  98. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  99. package/dist/modes/interactive/theme/theme.js +12 -2
  100. package/dist/modes/interactive/theme/theme.js.map +1 -1
  101. package/dist/modes/json-event.d.ts +4 -1
  102. package/dist/modes/json-event.d.ts.map +1 -1
  103. package/dist/modes/json-event.js +5 -2
  104. package/dist/modes/json-event.js.map +1 -1
  105. package/dist/package-manager-cli.d.ts.map +1 -1
  106. package/dist/package-manager-cli.js +1 -1
  107. package/dist/package-manager-cli.js.map +1 -1
  108. package/dist/server/create-harness.d.ts.map +1 -1
  109. package/dist/server/create-harness.js +2 -0
  110. package/dist/server/create-harness.js.map +1 -1
  111. package/dist/utils/tools-manager.d.ts +10 -1
  112. package/dist/utils/tools-manager.d.ts.map +1 -1
  113. package/dist/utils/tools-manager.js +14 -19
  114. package/dist/utils/tools-manager.js.map +1 -1
  115. package/docs/compaction.md +6 -6
  116. package/docs/custom-provider.md +1 -1
  117. package/docs/environment-variables.md +8 -2
  118. package/docs/extensions.md +4 -0
  119. package/docs/json.md +6 -4
  120. package/docs/keybindings.md +8 -2
  121. package/docs/rpc.md +15 -4
  122. package/docs/sdk.md +9 -0
  123. package/docs/settings.md +31 -0
  124. package/docs/terminal-setup.md +23 -2
  125. package/docs/themes.md +24 -3
  126. package/docs/tui.md +2 -2
  127. package/docs/usage.md +3 -2
  128. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  129. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  130. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  131. package/examples/extensions/gondolin/package-lock.json +2 -2
  132. package/examples/extensions/gondolin/package.json +1 -1
  133. package/examples/extensions/sandbox/package-lock.json +2 -2
  134. package/examples/extensions/sandbox/package.json +1 -1
  135. package/examples/extensions/subagent/README.md +2 -0
  136. package/examples/extensions/subagent/agents.ts +40 -9
  137. package/examples/extensions/subagent/index.ts +21 -3
  138. package/examples/extensions/with-deps/package-lock.json +2 -2
  139. package/examples/extensions/with-deps/package.json +1 -1
  140. package/package.json +6 -6
@@ -36,6 +36,14 @@ const sessionHasTemporaryTree = new Set();
36
36
  const RESPONSE_BODY_EXCERPT_CHARS = 500;
37
37
  const TRANSIENT_PI_SERVER_RETRY_DELAYS_MS = [250, 750, 1500];
38
38
  const TRANSIENT_PI_SERVER_STATUS_CODES = new Set([502, 503, 504, 530]);
39
+ const PI_SERVER_RUN_RECOVERY_POLL_MS = 250;
40
+ const DEFAULT_PI_SERVER_RUN_RECOVERY_TIMEOUT_MS = 10 * 60 * 1000;
41
+ class PiServerRunRecoveryTimeoutError extends Error {
42
+ constructor() {
43
+ super("pi-server run recovery timed out; the server may still be processing the request");
44
+ this.name = "PiServerRunRecoveryTimeoutError";
45
+ }
46
+ }
39
47
  export function hashStaticContext(ctx) {
40
48
  return hashPiServerStaticContext(ctx);
41
49
  }
@@ -74,6 +82,63 @@ export function resetAllSessionTracking() {
74
82
  sessionTreeLeafIds.clear();
75
83
  sessionHasTemporaryTree.clear();
76
84
  }
85
+ class PiServerResponseError extends Error {
86
+ code;
87
+ details;
88
+ constructor(message, code, details) {
89
+ super(message);
90
+ this.name = "PiServerResponseError";
91
+ this.code = code;
92
+ this.details = details;
93
+ }
94
+ }
95
+ class ServerSentEventParser {
96
+ buffer = "";
97
+ event = "message";
98
+ dataLines = [];
99
+ feed(text) {
100
+ this.buffer += text;
101
+ const lines = this.buffer.split("\n");
102
+ this.buffer = lines.pop() ?? "";
103
+ return lines.flatMap((line) => this.consumeLine(line));
104
+ }
105
+ finish() {
106
+ const events = [];
107
+ if (this.buffer.length > 0) {
108
+ events.push(...this.consumeLine(this.buffer));
109
+ this.buffer = "";
110
+ }
111
+ const final = this.flush();
112
+ if (final)
113
+ events.push(final);
114
+ return events;
115
+ }
116
+ consumeLine(rawLine) {
117
+ const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
118
+ if (line === "") {
119
+ const event = this.flush();
120
+ return event ? [event] : [];
121
+ }
122
+ if (line.startsWith(":"))
123
+ return [];
124
+ if (line.startsWith("event:")) {
125
+ this.event = getServerSentEventFieldValue(line, "event");
126
+ return [];
127
+ }
128
+ if (line.startsWith("data:")) {
129
+ this.dataLines.push(getServerSentEventFieldValue(line, "data"));
130
+ }
131
+ return [];
132
+ }
133
+ flush() {
134
+ if (this.dataLines.length === 0)
135
+ return undefined;
136
+ const event = { event: this.event, data: this.dataLines.join("\n") };
137
+ this.event = "message";
138
+ this.dataLines = [];
139
+ return event;
140
+ }
141
+ }
77
142
  function isObject(value) {
78
143
  return typeof value === "object" && value !== null && !Array.isArray(value);
79
144
  }
@@ -91,34 +156,46 @@ function getBodyExcerpt(text) {
91
156
  const excerpt = trimmed.slice(0, RESPONSE_BODY_EXCERPT_CHARS);
92
157
  return excerpt.length < trimmed.length ? `${excerpt}...` : excerpt;
93
158
  }
94
- function getJsonErrorText(text) {
159
+ function getJsonErrorResponse(text) {
95
160
  if (!text)
96
161
  return undefined;
97
162
  try {
98
163
  const parsed = JSON.parse(text);
99
- if (!isObject(parsed))
164
+ if (!isObject(parsed) || typeof parsed.error !== "string" || parsed.error.length === 0)
100
165
  return undefined;
101
- const error = parsed.error;
102
- return typeof error === "string" && error.length > 0 ? error : undefined;
166
+ const code = parsed.code;
167
+ return {
168
+ error: parsed.error,
169
+ code: typeof code === "string" ? code : undefined,
170
+ details: isObject(parsed.details) ? parsed.details : undefined,
171
+ };
103
172
  }
104
173
  catch {
105
174
  return undefined;
106
175
  }
107
176
  }
177
+ function getJsonErrorText(text) {
178
+ return getJsonErrorResponse(text)?.error;
179
+ }
108
180
  function formatResponseDetails(response, bodyText) {
109
181
  const body = getJsonErrorText(bodyText) ?? getBodyExcerpt(bodyText);
110
182
  return `${getResponseStatus(response)}; content-type: ${getResponseContentType(response)}; body excerpt: ${body}`;
111
183
  }
112
184
  async function readPiServerFailure(response) {
113
185
  const bodyText = await response.text();
186
+ const errorResponse = getJsonErrorResponse(bodyText);
114
187
  return {
115
188
  details: formatResponseDetails(response, bodyText),
116
- matchText: getJsonErrorText(bodyText) ?? bodyText,
189
+ code: errorResponse?.code,
117
190
  };
118
191
  }
119
192
  async function readPiServerJson(response, errorPrefix) {
120
193
  const bodyText = await response.text();
121
194
  if (!response.ok) {
195
+ const errorResponse = getJsonErrorResponse(bodyText);
196
+ if (errorResponse) {
197
+ throw new PiServerResponseError(`${errorPrefix} (${formatResponseDetails(response, bodyText)})`, errorResponse.code, errorResponse.details);
198
+ }
122
199
  throw new Error(`${errorPrefix} (${formatResponseDetails(response, bodyText)})`);
123
200
  }
124
201
  try {
@@ -134,33 +211,8 @@ function getServerSentEventFieldValue(line, field) {
134
211
  return value.startsWith(" ") ? value.slice(1) : value;
135
212
  }
136
213
  function parseServerSentEvents(bodyText) {
137
- const events = [];
138
- let event = "message";
139
- let dataLines = [];
140
- const flush = () => {
141
- if (dataLines.length === 0)
142
- return;
143
- events.push({ event, data: dataLines.join("\n") });
144
- event = "message";
145
- dataLines = [];
146
- };
147
- for (const line of bodyText.split(/\r?\n/)) {
148
- if (line === "") {
149
- flush();
150
- continue;
151
- }
152
- if (line.startsWith(":"))
153
- continue;
154
- if (line.startsWith("event:")) {
155
- event = getServerSentEventFieldValue(line, "event");
156
- continue;
157
- }
158
- if (line.startsWith("data:")) {
159
- dataLines.push(getServerSentEventFieldValue(line, "data"));
160
- }
161
- }
162
- flush();
163
- return events;
214
+ const parser = new ServerSentEventParser();
215
+ return [...parser.feed(bodyText), ...parser.finish()];
164
216
  }
165
217
  function parseServerSentEventData(event, errorPrefix) {
166
218
  try {
@@ -233,6 +285,10 @@ async function postPiServerJsonWithTransientRetry(request, endpoint, body, error
233
285
  await waitForPiServerRetry(attempt, request.options.signal);
234
286
  continue;
235
287
  }
288
+ const errorResponse = getJsonErrorResponse(bodyText);
289
+ if (errorResponse) {
290
+ throw new PiServerResponseError(`${errorPrefix} (${formatResponseDetails(response, bodyText)})`, errorResponse.code, errorResponse.details);
291
+ }
236
292
  throw new Error(`${errorPrefix} (${formatResponseDetails(response, bodyText)})`);
237
293
  }
238
294
  try {
@@ -337,6 +393,17 @@ async function fetchPiServerRun(sessionId, runId, request) {
337
393
  }
338
394
  return readPiServerJson(response, "Session run recovery failed");
339
395
  }
396
+ async function waitForPiServerRunCompletion(sessionId, runId, request, options) {
397
+ const deadline = Date.now() + DEFAULT_PI_SERVER_RUN_RECOVERY_TIMEOUT_MS;
398
+ for (;;) {
399
+ const run = await fetchPiServerRun(sessionId, runId, request);
400
+ if (!run || run.status !== "running")
401
+ return run;
402
+ if (Date.now() >= deadline)
403
+ throw new PiServerRunRecoveryTimeoutError();
404
+ await sleep(PI_SERVER_RUN_RECOVERY_POLL_MS, undefined, { signal: options?.signal });
405
+ }
406
+ }
340
407
  function getKnownServerPrefixIds(sessionId, entries) {
341
408
  const entryCount = sessionTreeEntryCounts.get(sessionId);
342
409
  const treeHash = sessionTreeHashes.get(sessionId);
@@ -351,14 +418,25 @@ function getKnownServerPrefixIds(sessionId, entries) {
351
418
  sessionSyncedEntryIds.set(sessionId, ids);
352
419
  return ids;
353
420
  }
421
+ function isRecoverableTreeDivergenceCode(code) {
422
+ return code === "PARENT_ENTRY_NOT_FOUND" || code === "LEAF_ID_NOT_FOUND" || code === "ENTRY_ALREADY_EXISTS";
423
+ }
424
+ function isRecoverableMissingServerStateCode(code) {
425
+ return code === "SESSION_NOT_FOUND" || code === "SESSION_NO_STATIC_CONTEXT" || isRecoverableTreeDivergenceCode(code);
426
+ }
354
427
  function isRecoverableTreeDivergenceError(error) {
355
- const message = error instanceof Error ? error.message : String(error);
356
- return /parent entry .* does not exist|leafId .* does not exist|entry .* already exists/i.test(message);
428
+ if (error instanceof PiServerResponseError) {
429
+ return isRecoverableTreeDivergenceCode(error.code);
430
+ }
431
+ if (error && typeof error === "object" && "code" in error) {
432
+ return isRecoverableTreeDivergenceCode(error.code);
433
+ }
434
+ return false;
357
435
  }
358
- function isRecoverableMissingServerState(response, errorBody) {
436
+ function isRecoverableMissingServerState(response, errorCode) {
359
437
  if (response.status !== 400 && response.status !== 404)
360
438
  return false;
361
- return /Session has no static context|session not found|parent entry .* does not exist|leafId .* does not exist|entry .* already exists/i.test(errorBody);
439
+ return isRecoverableMissingServerStateCode(errorCode);
362
440
  }
363
441
  async function syncFullPiServerTree(sessionId, context, tree, request) {
364
442
  await postTreeJson(request, "/api/session/tree/sync", {
@@ -473,13 +551,13 @@ export async function compactPiServer(model, context, options) {
473
551
  let response = await request.postJson("/api/session/compact", makeBody());
474
552
  if (!response.ok) {
475
553
  let failure = await readPiServerFailure(response);
476
- if (!options?.signal?.aborted && isRecoverableMissingServerState(response, failure.matchText)) {
554
+ if (!options?.signal?.aborted && isRecoverableMissingServerState(response, failure.code)) {
477
555
  resetSessionTracking(sessionId);
478
556
  await ensureSessionInit(sessionId, context, request);
479
557
  await syncPiServerTreeWithRequest(sessionId, context, tree, request, options?.onHistoryReconciled);
480
558
  response = await request.postJson("/api/session/compact", makeBody());
481
559
  if (response.ok) {
482
- failure = { details: "", matchText: "" };
560
+ failure = { details: "", code: undefined };
483
561
  }
484
562
  else {
485
563
  failure = await readPiServerFailure(response);
@@ -510,11 +588,6 @@ export async function compactPiServer(model, context, options) {
510
588
  messages: result.messages ?? [],
511
589
  };
512
590
  }
513
- export async function dropLastPiServerAssistantError(sessionId) {
514
- const request = createPiServerRequest();
515
- const response = await request.postJson("/api/session/drop-last-assistant-error", { sessionId });
516
- await readPiServerJson(response, "Dropping server assistant error failed");
517
- }
518
591
  export async function streamPiServer(model, context, options) {
519
592
  const sessionId = options?.sessionId ?? randomUUID();
520
593
  const runId = randomUUID();
@@ -556,12 +629,12 @@ export async function streamPiServer(model, context, options) {
556
629
  let response = await request.postJson("/api/stream", makeBody());
557
630
  if (!response.ok) {
558
631
  let failure = await readPiServerFailure(response);
559
- if (!options?.signal?.aborted && isRecoverableMissingServerState(response, failure.matchText)) {
632
+ if (!options?.signal?.aborted && isRecoverableMissingServerState(response, failure.code)) {
560
633
  resetSessionTracking(sessionId);
561
634
  await ensureSessionInit(sessionId, context, request);
562
635
  response = await request.postJson("/api/stream", makeBody());
563
636
  if (response.ok) {
564
- failure = { details: "", matchText: "" };
637
+ failure = { details: "", code: undefined };
565
638
  }
566
639
  else {
567
640
  failure = await readPiServerFailure(response);
@@ -574,7 +647,19 @@ export async function streamPiServer(model, context, options) {
574
647
  await ensurePiServerEventStream(response);
575
648
  const reader = response.body.getReader();
576
649
  const decoder = new TextDecoder();
577
- let buffer = "";
650
+ const parser = new ServerSentEventParser();
651
+ let terminalReceived = false;
652
+ const consumeEvents = (events) => {
653
+ for (const serverEvent of events) {
654
+ const proxyEvent = parseServerSentEventData(serverEvent, "pi-server stream");
655
+ const event = processProxyEvent(proxyEvent, partial);
656
+ if (!event)
657
+ continue;
658
+ if (event.type === "done" || event.type === "error")
659
+ terminalReceived = true;
660
+ stream.push(event);
661
+ }
662
+ };
578
663
  while (true) {
579
664
  const { done, value } = await reader.read();
580
665
  if (done)
@@ -582,35 +667,26 @@ export async function streamPiServer(model, context, options) {
582
667
  if (options?.signal?.aborted) {
583
668
  throw new Error("Request aborted by user");
584
669
  }
585
- buffer += decoder.decode(value, { stream: true });
586
- const lines = buffer.split("\n");
587
- buffer = lines.pop() || "";
588
- for (const line of lines) {
589
- if (line.startsWith("data: ")) {
590
- const data = line.slice(6).trim();
591
- if (!data)
592
- continue;
593
- const proxyEvent = JSON.parse(data);
594
- const event = processProxyEvent(proxyEvent, partial);
595
- if (event) {
596
- stream.push(event);
597
- }
598
- }
599
- }
670
+ consumeEvents(parser.feed(decoder.decode(value, { stream: true })));
600
671
  }
672
+ consumeEvents(parser.feed(decoder.decode()));
673
+ consumeEvents(parser.finish());
601
674
  if (options?.signal?.aborted) {
602
675
  throw new Error("Request aborted by user");
603
676
  }
677
+ if (!terminalReceived) {
678
+ throw new Error("pi-server stream ended before a terminal response event");
679
+ }
604
680
  if (isEphemeralSession) {
605
681
  resetSessionTracking(sessionId);
606
682
  }
607
683
  stream.end();
608
684
  }
609
685
  catch (error) {
610
- const errorMessage = error instanceof Error ? error.message : String(error);
686
+ let errorMessage = error instanceof Error ? error.message : String(error);
611
687
  if (!options?.signal?.aborted && phase === "provider_stream") {
612
688
  try {
613
- const recoveredRun = await fetchPiServerRun(sessionId, runId, createPiServerRequest());
689
+ const recoveredRun = await waitForPiServerRunCompletion(sessionId, runId, createPiServerRequest(options?.signal), options);
614
690
  if (recoveredRun?.status === "completed" && recoveredRun.message) {
615
691
  switch (recoveredRun.message.stopReason) {
616
692
  case "stop":
@@ -633,9 +709,13 @@ export async function streamPiServer(model, context, options) {
633
709
  stream.end();
634
710
  return;
635
711
  }
712
+ if (recoveredRun?.status === "failed" && recoveredRun.errorMessage) {
713
+ errorMessage = recoveredRun.errorMessage;
714
+ }
636
715
  }
637
- catch {
638
- // Keep the original stream error authoritative.
716
+ catch (recoveryError) {
717
+ phase = "history_reconcile";
718
+ errorMessage = recoveryError instanceof Error ? recoveryError.message : String(recoveryError);
639
719
  }
640
720
  }
641
721
  const reason = options?.signal?.aborted ? "aborted" : "error";
@@ -724,12 +804,15 @@ function processProxyEvent(proxyEvent, partial) {
724
804
  case "toolcall_end": {
725
805
  const content = partial.content[proxyEvent.contentIndex];
726
806
  if (content?.type === "toolCall") {
807
+ Object.assign(content, proxyEvent.toolCall);
727
808
  delete content.partialJson;
728
809
  return { type: "toolcall_end", contentIndex: proxyEvent.contentIndex, toolCall: content, partial };
729
810
  }
730
811
  return undefined;
731
812
  }
732
813
  case "done":
814
+ if (proxyEvent.message)
815
+ return { type: "done", reason: proxyEvent.reason, message: proxyEvent.message };
733
816
  partial.stopReason = proxyEvent.reason;
734
817
  partial.usage = proxyEvent.usage;
735
818
  partial.deferred = proxyEvent.deferred;