@cubicecho/agent-core 2.23.0 → 2.25.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 (71) hide show
  1. package/README.md +14 -9
  2. package/dist/agent-loop.d.ts +84 -204
  3. package/dist/agent-loop.js +416 -643
  4. package/dist/calibration.d.ts +14 -10
  5. package/dist/calibration.js +30 -22
  6. package/dist/capabilities.d.ts +140 -35
  7. package/dist/capabilities.js +345 -152
  8. package/dist/client.d.ts +104 -35
  9. package/dist/client.js +210 -78
  10. package/dist/compaction.d.ts +103 -60
  11. package/dist/compaction.js +163 -93
  12. package/dist/config.d.ts +48 -12
  13. package/dist/config.js +20 -1
  14. package/dist/continuation.d.ts +25 -17
  15. package/dist/continuation.js +70 -47
  16. package/dist/digest.d.ts +7 -0
  17. package/dist/digest.js +18 -0
  18. package/dist/errors.d.ts +24 -15
  19. package/dist/errors.js +23 -15
  20. package/dist/events.d.ts +108 -58
  21. package/dist/events.js +265 -128
  22. package/dist/guards.d.ts +53 -0
  23. package/dist/guards.js +55 -0
  24. package/dist/hook-events.d.ts +38 -0
  25. package/dist/hook-events.js +36 -0
  26. package/dist/hooks.d.ts +105 -83
  27. package/dist/hooks.js +224 -139
  28. package/dist/index.d.ts +30 -25
  29. package/dist/index.js +29 -23
  30. package/dist/ledger.d.ts +62 -30
  31. package/dist/ledger.js +163 -56
  32. package/dist/platform.d.ts +13 -0
  33. package/dist/platform.js +13 -0
  34. package/dist/preselect.d.ts +222 -0
  35. package/dist/preselect.js +290 -0
  36. package/dist/request-body.d.ts +32 -0
  37. package/dist/request-body.js +47 -0
  38. package/dist/reset.d.ts +1 -0
  39. package/dist/reset.js +7 -6
  40. package/dist/retry.d.ts +40 -143
  41. package/dist/retry.js +79 -285
  42. package/dist/run-calls.d.ts +123 -0
  43. package/dist/run-calls.js +351 -0
  44. package/dist/run-turn.d.ts +44 -16
  45. package/dist/run-turn.js +74 -37
  46. package/dist/runtime.d.ts +23 -17
  47. package/dist/runtime.js +34 -24
  48. package/dist/schema-compat.d.ts +51 -11
  49. package/dist/schema-compat.js +375 -193
  50. package/dist/scope.d.ts +28 -5
  51. package/dist/scope.js +37 -10
  52. package/dist/side-task.d.ts +127 -39
  53. package/dist/side-task.js +189 -100
  54. package/dist/snapshot.d.ts +12 -7
  55. package/dist/snapshot.js +87 -65
  56. package/dist/spec.d.ts +66 -36
  57. package/dist/spec.js +514 -265
  58. package/dist/stream.d.ts +73 -16
  59. package/dist/stream.js +228 -98
  60. package/dist/thinking.d.ts +23 -8
  61. package/dist/thinking.js +96 -46
  62. package/dist/tokens.d.ts +171 -6
  63. package/dist/tokens.js +326 -6
  64. package/dist/tool-calls.d.ts +89 -15
  65. package/dist/tool-calls.js +205 -85
  66. package/dist/tool-loading.d.ts +109 -187
  67. package/dist/tool-loading.js +286 -372
  68. package/dist/wire.d.ts +81 -0
  69. package/dist/wire.js +73 -0
  70. package/llms.txt +87 -43
  71. package/package.json +4 -4
@@ -1,20 +1,24 @@
1
- import OpenAI from "openai";
2
- import { modelCapabilitiesFor } from "./capabilities.js";
3
- import { errorMessage } from "./errors.js";
4
- import { ContextOverflow } from "./retry.js";
5
- import { runTurn } from "./run-turn.js";
1
+ import { modelCapabilitiesFor } from './capabilities.js';
2
+ import { errorMessage } from './errors.js';
3
+ import { ContextOverflow, refusesRequest } from './retry.js';
4
+ import { modelLabel, runTurn } from './run-turn.js';
5
+ import { addCounts } from './stream.js';
6
+ import { FinishReason, Role } from './wire.js';
6
7
  /**
7
8
  * Whether a turn is one a continuation can finish: cut off at the ceiling, with an answer begun
8
9
  * and no tool call in it.
9
10
  *
11
+ * @param turn - The turn as it came back.
12
+ * @returns False for a turn that stopped for any reason but `length`, whose content is blank, or
13
+ * that holds a tool call.
14
+ *
15
+ * @remarks
10
16
  * An answer not begun is a turn cut off in its scratchpad, and prefilling a half-closed fence is
11
17
  * the template's business rather than something this can do the same way everywhere — llama.cpp
12
18
  * refuses a prefill outright on a template with thinking enabled. A tool call is excluded because
13
19
  * its arguments are what was cut, and `parseToolArguments` already reports that truncation.
14
- *
15
- * @param turn The turn as it came back.
16
20
  */
17
- export const isContinuable = (turn) => turn.finishReason === "length" && turn.content.trim() !== "" && turn.toolCalls.length === 0;
21
+ export const isContinuable = (turn) => turn.finishReason === FinishReason.Length && turn.content.trim() !== '' && turn.toolCalls.length === 0;
18
22
  /** How much of the answer's opening a reply has to repeat to have started over. */
19
23
  const RESTART_PROBE = 40;
20
24
  /** The shortest opening worth testing for a restart; shorter ones are repeated by chance. */
@@ -22,6 +26,11 @@ const RESTART_MIN = 12;
22
26
  /**
23
27
  * Whether the continuation began the answer again rather than carrying it on — how a server that
24
28
  * ignores the prefill shows itself, since it takes the request without complaint.
29
+ *
30
+ * @param answer - The answer so far, as it was sent back as the prefill.
31
+ * @param continuation - The content the continuation came back with.
32
+ * @returns True where the continuation opens with the answer's own opening, leading whitespace
33
+ * aside on both. Never true for an answer whose opening is shorter than `RESTART_MIN`.
25
34
  */
26
35
  const restarted = (answer, continuation) => {
27
36
  const opening = answer.trimStart().slice(0, RESTART_PROBE);
@@ -29,42 +38,48 @@ const restarted = (answer, continuation) => {
29
38
  };
30
39
  /** The fields of a usage that add across two requests, when both reported them. */
31
40
  const ADDED = [
32
- "uncached",
33
- "reasoningTokens",
34
- "promptMs",
35
- "predictedMs",
36
- "draftTotal",
37
- "draftAccepted",
38
- "wallMs",
39
- "retries",
40
- "timeouts",
41
+ 'uncached',
42
+ 'reasoningTokens',
43
+ 'promptMs',
44
+ 'predictedMs',
45
+ 'draftTotal',
46
+ 'draftAccepted',
47
+ 'wallMs',
48
+ 'retries',
49
+ 'timeouts',
41
50
  ];
42
51
  /** A rate, and the duration it was measured over, which is what weights it in a mean. */
43
52
  const RATES = [
44
- ["promptTokensPerSecond", "promptMs"],
45
- ["tokensPerSecond", "predictedMs"],
53
+ ['promptTokensPerSecond', 'promptMs'],
54
+ ['tokensPerSecond', 'predictedMs'],
46
55
  ];
47
56
  /**
48
- * Two requests' usage as one turn's. The first request's own measurements and the loop's
49
- * comparison with the request before it stay as they were; a field only one of them reported is
50
- * dropped rather than passed off as the total.
57
+ * Two requests' usage as one turn's.
58
+ *
59
+ * @param first - The turn so far, which may itself be a joined one. Not written to.
60
+ * @param next - The continuation's usage. Not written to.
61
+ * @returns A new usage: the four counts summed, `continuations` one more than `first` had, and a
62
+ * rate both requests timed as the mean of the two, weighted by the time each was measured over.
63
+ *
64
+ * @remarks
65
+ * The first request's own measurements and the loop's comparison with the request before it stay
66
+ * as they were; a field only one of them reported is dropped rather than passed off as the total.
51
67
  */
52
68
  function joinUsage(first, next) {
53
69
  const joined = {
54
70
  ...first,
55
- prompt: first.prompt + next.prompt,
56
- completion: first.completion + next.completion,
57
- total: first.total + next.total,
58
- cached: first.cached + next.cached,
71
+ ...addCounts(first, next),
59
72
  continuations: (first.continuations ?? 0) + 1,
60
73
  };
61
74
  for (const field of ADDED) {
62
75
  const a = first[field];
63
76
  const b = next[field];
64
- if (a !== undefined && b !== undefined)
77
+ if (a !== undefined && b !== undefined) {
65
78
  joined[field] = a + b;
66
- else
79
+ }
80
+ else {
67
81
  delete joined[field];
82
+ }
68
83
  }
69
84
  for (const [rate, over] of RATES) {
70
85
  const a = first[rate];
@@ -72,19 +87,31 @@ function joinUsage(first, next) {
72
87
  const aMs = first[over];
73
88
  const bMs = next[over];
74
89
  // Tokens over time for both together, which is each rate weighted by the time it held.
75
- if (a !== undefined && b !== undefined && aMs !== undefined && bMs !== undefined && aMs + bMs)
90
+ const bothTimed = a !== undefined && b !== undefined && aMs !== undefined && bMs !== undefined;
91
+ if (bothTimed && aMs + bMs) {
76
92
  joined[rate] = (a * aMs + b * bMs) / (aMs + bMs);
77
- else
93
+ }
94
+ else {
78
95
  delete joined[rate];
96
+ }
79
97
  }
80
98
  return joined;
81
99
  }
82
- /** Whether a failure is the endpoint refusing the request as written, rather than losing it. */
83
- const refusesRequest = (error) => error instanceof OpenAI.APIError && (error.status === 400 || error.status === 422);
84
100
  /**
85
101
  * Carries on an answer the token ceiling cut off, by sending the transcript again with the answer
86
102
  * so far as a trailing assistant message, and joins the pieces into one turn.
87
103
  *
104
+ * @param client - The pooled client for this endpoint.
105
+ * @param supports - What the endpoint has already refused.
106
+ * @param request - Builds the body the cut-off turn was sent, exactly as `runTurn` was given it. The
107
+ * prefill is appended to what it builds.
108
+ * @param turn - The turn that came back cut off.
109
+ * @param [options] - `runTurn`'s options, with `model` needed for the latch — without one nothing is
110
+ * latched and each continuation finds out again — and the cap on continuations.
111
+ * @returns `turn` itself where nothing was joined to it; otherwise a new turn, with the last
112
+ * continuation's `finishReason` and tool calls.
113
+ *
114
+ * @remarks
88
115
  * Only a turn `isContinuable` accepts is continued; any other comes back as it was. Content and
89
116
  * reasoning are joined in order, the tool calls a continuation makes are kept, and usage is summed
90
117
  * across the requests with `continuations` counting them. The continuation is read as starting in
@@ -98,22 +125,15 @@ const refusesRequest = (error) => error instanceof OpenAI.APIError && (error.sta
98
125
  * that check is only as good as a restart being word for word. Either way the answer so far is
99
126
  * kept, with a notice. So is it when the continuation fails any other way, since the tokens
100
127
  * already in hand are worth more than the error; only a stop is thrown.
101
- *
102
- * @param client The pooled client for this endpoint.
103
- * @param supports What the endpoint has already refused.
104
- * @param request Builds the body the cut-off turn was sent, exactly as `runTurn` was given it. The
105
- * prefill is appended to what it builds.
106
- * @param turn The turn that came back cut off.
107
- * @param options `runTurn`'s options, with `model` needed for the latch — without one nothing is
108
- * latched and each continuation finds out again — and the cap on continuations.
109
128
  */
110
129
  export async function continueTurn(client, supports, request, turn, { maxContinuations = 1, ...options } = {}) {
111
130
  const refused = options.model === undefined ? undefined : modelCapabilitiesFor(supports, options.model);
112
- const who = options.model ?? "the model";
131
+ const who = modelLabel(options.model);
113
132
  let joined = turn;
114
133
  for (let count = 0; count < maxContinuations && isContinuable(joined); count++) {
115
- if (refused?.assistantPrefill === false)
134
+ if (refused?.assistantPrefill === false) {
116
135
  break;
136
+ }
117
137
  const answer = joined.content;
118
138
  let next;
119
139
  try {
@@ -121,19 +141,21 @@ export async function continueTurn(client, supports, request, turn, { maxContinu
121
141
  const body = request(capabilities, forModel);
122
142
  return {
123
143
  ...body,
124
- messages: [...body.messages, { role: "assistant", content: answer }],
144
+ messages: [...body.messages, { role: Role.Assistant, content: answer }],
125
145
  };
126
146
  }, { ...options, startInReasoning: false });
127
147
  }
128
148
  catch (error) {
129
- if (options.signal?.aborted)
149
+ if (options.signal?.aborted) {
130
150
  throw error;
151
+ }
131
152
  if (error instanceof ContextOverflow) {
132
- options.onNotice?.("no room left in the window to continue the cut-off reply");
153
+ options.onNotice?.('no room left in the window to continue the cut-off reply');
133
154
  }
134
155
  else if (refusesRequest(error)) {
135
- if (refused)
156
+ if (refused) {
136
157
  refused.assistantPrefill = false;
158
+ }
137
159
  options.onNotice?.(`${who} refused a trailing assistant message (${errorMessage(error)}); keeping the cut-off reply`);
138
160
  }
139
161
  else {
@@ -142,8 +164,9 @@ export async function continueTurn(client, supports, request, turn, { maxContinu
142
164
  break;
143
165
  }
144
166
  if (restarted(answer, next.content)) {
145
- if (refused)
167
+ if (refused) {
146
168
  refused.assistantPrefill = false;
169
+ }
147
170
  options.onNotice?.(`${who} answered afresh instead of continuing its reply; keeping the cut-off reply`);
148
171
  break;
149
172
  }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * A text's SHA-256, in hex.
3
+ *
4
+ * @param text - What to hash.
5
+ * @returns Sixty-four hex characters, the same for the same text on any machine.
6
+ */
7
+ export declare const digestOf: (text: string) => string;
package/dist/digest.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The one digest this package takes, of an endpoint's key and of a turn's text.
3
+ *
4
+ * Apart from `platform.ts` because it loads `node:crypto`, which a browser-safe module must not
5
+ * come to import by reaching for a constant.
6
+ */
7
+ import { createHash } from 'node:crypto';
8
+ /** The hash every digest here is taken with. */
9
+ const DIGEST_ALGORITHM = 'sha256';
10
+ /** How a digest is written out. */
11
+ const DIGEST_ENCODING = 'hex';
12
+ /**
13
+ * A text's SHA-256, in hex.
14
+ *
15
+ * @param text - What to hash.
16
+ * @returns Sixty-four hex characters, the same for the same text on any machine.
17
+ */
18
+ export const digestOf = (text) => createHash(DIGEST_ALGORITHM).update(text).digest(DIGEST_ENCODING);
package/dist/errors.d.ts CHANGED
@@ -1,20 +1,24 @@
1
- import type OpenAI from "openai";
2
- import type { ToolCallOutcome } from "./agent-loop.ts";
3
- import { ContextOverflow } from "./retry.ts";
4
- import type { TurnUsage } from "./stream.ts";
1
+ import type OpenAI from 'openai';
2
+ import { ContextOverflow } from './retry.ts';
3
+ import type { TurnUsage } from './stream.ts';
4
+ import type { ToolCallOutcome } from './tool-calls.ts';
5
5
  /**
6
6
  * What went wrong, as a string.
7
7
  *
8
+ * @param error - Whatever a `catch` bound. Anything that is not an `Error` is stringified.
9
+ * @returns An `Error`'s `message` as it is, empty included; otherwise `String(error)`, so a thrown
10
+ * `undefined` reads `undefined`.
11
+ *
12
+ * @remarks
8
13
  * Almost everything caught here ends up in a run row, a tool result or a log line, and a
9
14
  * `catch` binds `unknown` — so the same three-branch ternary was being written at every site
10
15
  * that had to say what happened.
11
- *
12
- * @param error Whatever a `catch` bound. Anything that is not an `Error` is stringified.
13
16
  */
14
17
  export declare const errorMessage: (error: unknown) => string;
15
18
  /**
16
19
  * A run as it stood when `runAgentLoop` gave up on it.
17
20
  *
21
+ * @remarks
18
22
  * The loop works on its own copy of the transcript and hands it back only on success, so without
19
23
  * this a spent budget, a stop or a refused request took every step before it along — steps whose
20
24
  * assistant turns and tool results were real, and that a host storing its transcript has to keep.
@@ -38,6 +42,7 @@ export interface AgentLoopFailure {
38
42
  /**
39
43
  * What `runAgentLoop` throws, carrying the run as it stood and what was caught as `cause`.
40
44
  *
45
+ * @remarks
41
46
  * Its own class rather than fields hung on the error that was caught, because a stop throws the
42
47
  * signal's reason and that is one object for every run under the signal. The message is the
43
48
  * cause's own, so a host that logs `errorMessage(error)` logs what it always did. A stop is told
@@ -51,15 +56,16 @@ export declare class AgentLoopError extends Error implements AgentLoopFailure {
51
56
  readonly loaded: string[];
52
57
  readonly used: string[];
53
58
  /**
54
- * @param message What went wrong — the cause's own message, where there is a cause.
55
- * @param run The run as it stood. Held, not copied.
56
- * @param options The standard `cause`: what the loop caught, absent where the loop itself gave up.
59
+ * @param message - What went wrong — the cause's own message, where there is a cause.
60
+ * @param run - The run as it stood. Held, not copied.
61
+ * @param [options] - The standard `cause`: what the loop caught, absent where the loop itself gave up.
57
62
  */
58
63
  constructor(message: string, run: AgentLoopFailure, options?: ErrorOptions);
59
64
  }
60
65
  /**
61
66
  * `maxToolIterations` was spent with the model still asking for tools.
62
67
  *
68
+ * @remarks
63
69
  * Named so a host can tell it from a failure without matching the message, which is the same
64
70
  * sentence it has always been. There is no `cause`: nothing was caught, the loop stopped itself.
65
71
  */
@@ -69,6 +75,7 @@ export declare class ToolIterationLimit extends AgentLoopError {
69
75
  /**
70
76
  * A `ContextOverflow` out of `runAgentLoop`, carrying the run as it stood.
71
77
  *
78
+ * @remarks
72
79
  * A subclass of `ContextOverflow` rather than an `AgentLoopError` around one, because
73
80
  * `instanceof ContextOverflow` is how a caller knows to compact and send again, and wrapping
74
81
  * would have made that test quietly false. The overflow the loop caught is the `cause`, and the
@@ -81,19 +88,21 @@ export declare class AgentLoopOverflow extends ContextOverflow implements AgentL
81
88
  readonly loaded: string[];
82
89
  readonly used: string[];
83
90
  /**
84
- * @param message The overflow's own message.
85
- * @param run The run as it stood. Held, not copied.
86
- * @param options The standard `cause`: the `ContextOverflow` the loop caught.
91
+ * @param message - The overflow's own message.
92
+ * @param run - The run as it stood. Held, not copied.
93
+ * @param [options] - The standard `cause`: the `ContextOverflow` the loop caught.
87
94
  */
88
95
  constructor(message: string, run: AgentLoopFailure, options?: ErrorOptions);
89
96
  }
90
97
  /**
91
98
  * The run a failed `runAgentLoop` left behind, read off whatever it threw, or nothing.
92
99
  *
100
+ * @param error - Whatever a `catch` around `runAgentLoop` bound. Anything the loop did not throw
101
+ * answers `undefined`.
102
+ * @returns The error itself, read as the run it carries — the same object, not a copy.
103
+ *
104
+ * @remarks
93
105
  * Two classes carry it — an overflow has to stay a `ContextOverflow` and so cannot also be an
94
106
  * `AgentLoopError` — and a `catch` that only wants the transcript should not have to name both.
95
- *
96
- * @param error Whatever a `catch` around `runAgentLoop` bound. Anything the loop did not throw
97
- * answers `undefined`.
98
107
  */
99
108
  export declare const failedRun: (error: unknown) => AgentLoopFailure | undefined;
package/dist/errors.js CHANGED
@@ -1,33 +1,37 @@
1
- import { ContextOverflow } from "./retry.js";
1
+ import { ContextOverflow } from './retry.js';
2
2
  /**
3
3
  * What went wrong, as a string.
4
4
  *
5
+ * @param error - Whatever a `catch` bound. Anything that is not an `Error` is stringified.
6
+ * @returns An `Error`'s `message` as it is, empty included; otherwise `String(error)`, so a thrown
7
+ * `undefined` reads `undefined`.
8
+ *
9
+ * @remarks
5
10
  * Almost everything caught here ends up in a run row, a tool result or a log line, and a
6
11
  * `catch` binds `unknown` — so the same three-branch ternary was being written at every site
7
12
  * that had to say what happened.
8
- *
9
- * @param error Whatever a `catch` bound. Anything that is not an `Error` is stringified.
10
13
  */
11
- export const errorMessage = (error) => error instanceof Error ? error.message : String(error);
14
+ export const errorMessage = (error) => (error instanceof Error ? error.message : String(error));
12
15
  /**
13
16
  * What `runAgentLoop` throws, carrying the run as it stood and what was caught as `cause`.
14
17
  *
18
+ * @remarks
15
19
  * Its own class rather than fields hung on the error that was caught, because a stop throws the
16
20
  * signal's reason and that is one object for every run under the signal. The message is the
17
21
  * cause's own, so a host that logs `errorMessage(error)` logs what it always did. A stop is told
18
22
  * the way it was before — by the signal the host aborted, not by the class of what came out.
19
23
  */
20
24
  export class AgentLoopError extends Error {
21
- name = "AgentLoopError";
25
+ name = 'AgentLoopError';
22
26
  messages;
23
27
  usage;
24
28
  toolCalls;
25
29
  loaded;
26
30
  used;
27
31
  /**
28
- * @param message What went wrong — the cause's own message, where there is a cause.
29
- * @param run The run as it stood. Held, not copied.
30
- * @param options The standard `cause`: what the loop caught, absent where the loop itself gave up.
32
+ * @param message - What went wrong — the cause's own message, where there is a cause.
33
+ * @param run - The run as it stood. Held, not copied.
34
+ * @param [options] - The standard `cause`: what the loop caught, absent where the loop itself gave up.
31
35
  */
32
36
  constructor(message, run, options) {
33
37
  super(message, options);
@@ -41,15 +45,17 @@ export class AgentLoopError extends Error {
41
45
  /**
42
46
  * `maxToolIterations` was spent with the model still asking for tools.
43
47
  *
48
+ * @remarks
44
49
  * Named so a host can tell it from a failure without matching the message, which is the same
45
50
  * sentence it has always been. There is no `cause`: nothing was caught, the loop stopped itself.
46
51
  */
47
52
  export class ToolIterationLimit extends AgentLoopError {
48
- name = "ToolIterationLimit";
53
+ name = 'ToolIterationLimit';
49
54
  }
50
55
  /**
51
56
  * A `ContextOverflow` out of `runAgentLoop`, carrying the run as it stood.
52
57
  *
58
+ * @remarks
53
59
  * A subclass of `ContextOverflow` rather than an `AgentLoopError` around one, because
54
60
  * `instanceof ContextOverflow` is how a caller knows to compact and send again, and wrapping
55
61
  * would have made that test quietly false. The overflow the loop caught is the `cause`, and the
@@ -62,9 +68,9 @@ export class AgentLoopOverflow extends ContextOverflow {
62
68
  loaded;
63
69
  used;
64
70
  /**
65
- * @param message The overflow's own message.
66
- * @param run The run as it stood. Held, not copied.
67
- * @param options The standard `cause`: the `ContextOverflow` the loop caught.
71
+ * @param message - The overflow's own message.
72
+ * @param run - The run as it stood. Held, not copied.
73
+ * @param [options] - The standard `cause`: the `ContextOverflow` the loop caught.
68
74
  */
69
75
  constructor(message, run, options) {
70
76
  super(message, options);
@@ -78,10 +84,12 @@ export class AgentLoopOverflow extends ContextOverflow {
78
84
  /**
79
85
  * The run a failed `runAgentLoop` left behind, read off whatever it threw, or nothing.
80
86
  *
87
+ * @param error - Whatever a `catch` around `runAgentLoop` bound. Anything the loop did not throw
88
+ * answers `undefined`.
89
+ * @returns The error itself, read as the run it carries — the same object, not a copy.
90
+ *
91
+ * @remarks
81
92
  * Two classes carry it — an overflow has to stay a `ContextOverflow` and so cannot also be an
82
93
  * `AgentLoopError` — and a `catch` that only wants the transcript should not have to name both.
83
- *
84
- * @param error Whatever a `catch` around `runAgentLoop` bound. Anything the loop did not throw
85
- * answers `undefined`.
86
94
  */
87
95
  export const failedRun = (error) => error instanceof AgentLoopError || error instanceof AgentLoopOverflow ? error : undefined;