@cubicecho/agent-core 2.22.0 → 2.24.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 (49) hide show
  1. package/README.md +61 -6
  2. package/dist/agent-loop.d.ts +3 -2
  3. package/dist/agent-loop.js +385 -303
  4. package/dist/calibration.js +8 -6
  5. package/dist/capabilities.d.ts +36 -0
  6. package/dist/capabilities.js +116 -65
  7. package/dist/client.d.ts +5 -4
  8. package/dist/client.js +62 -57
  9. package/dist/compaction.js +5 -9
  10. package/dist/continuation.d.ts +4 -4
  11. package/dist/continuation.js +1 -4
  12. package/dist/events.d.ts +16 -1
  13. package/dist/events.js +64 -44
  14. package/dist/guards.d.ts +22 -0
  15. package/dist/guards.js +22 -0
  16. package/dist/hook-events.d.ts +22 -0
  17. package/dist/hook-events.js +22 -0
  18. package/dist/hooks.d.ts +15 -16
  19. package/dist/hooks.js +44 -44
  20. package/dist/index.d.ts +6 -4
  21. package/dist/index.js +6 -4
  22. package/dist/reset.d.ts +6 -2
  23. package/dist/reset.js +6 -2
  24. package/dist/retry.d.ts +13 -7
  25. package/dist/retry.js +14 -7
  26. package/dist/run-turn.d.ts +8 -1
  27. package/dist/runtime.d.ts +120 -0
  28. package/dist/runtime.js +113 -0
  29. package/dist/schema-compat.d.ts +23 -0
  30. package/dist/schema-compat.js +76 -59
  31. package/dist/scope.d.ts +35 -0
  32. package/dist/scope.js +42 -0
  33. package/dist/side-task.d.ts +5 -0
  34. package/dist/side-task.js +24 -52
  35. package/dist/snapshot.d.ts +2 -2
  36. package/dist/snapshot.js +27 -48
  37. package/dist/spec.d.ts +11 -12
  38. package/dist/spec.js +36 -66
  39. package/dist/stream.d.ts +7 -0
  40. package/dist/stream.js +8 -1
  41. package/dist/thinking.js +6 -4
  42. package/dist/tokens.d.ts +9 -2
  43. package/dist/tokens.js +10 -3
  44. package/dist/tool-calls.d.ts +9 -0
  45. package/dist/tool-calls.js +11 -6
  46. package/dist/tool-loading.d.ts +10 -0
  47. package/dist/tool-loading.js +15 -7
  48. package/llms.txt +19 -5
  49. package/package.json +1 -1
@@ -26,6 +26,15 @@ export declare class ToolArgumentsError extends Error {
26
26
  */
27
27
  constructor(kind: "truncated" | "malformed", message: string);
28
28
  }
29
+ /**
30
+ * JSON as it was written, then repaired, then undefined. A string holding JSON is opened once.
31
+ *
32
+ * Read as written first, so the repair can only ever add to what parses: nothing valid is
33
+ * reinterpreted on its way through.
34
+ *
35
+ * @param text What a model wrote where JSON was asked for, with no prose around it.
36
+ */
37
+ export declare function looseJson(text: string): unknown;
29
38
  /**
30
39
  * A tool call's arguments as the object the tool is handed. Empty is no arguments.
31
40
  *
@@ -1,3 +1,4 @@
1
+ import { isRecord } from "./guards.js";
1
2
  /**
2
3
  * Tool arguments that could not be read as an object, with why.
3
4
  *
@@ -18,7 +19,6 @@ export class ToolArgumentsError extends Error {
18
19
  this.kind = kind;
19
20
  }
20
21
  }
21
- const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
22
22
  /**
23
23
  * Rewrites the almost-JSON local models write into JSON, in one pass that knows where strings are.
24
24
  *
@@ -71,8 +71,15 @@ function repairJson(text) {
71
71
  }
72
72
  return out;
73
73
  }
74
- /** JSON as it was written, then repaired, then undefined. A string holding JSON is opened once. */
75
- function looseJson(text) {
74
+ /**
75
+ * JSON as it was written, then repaired, then undefined. A string holding JSON is opened once.
76
+ *
77
+ * Read as written first, so the repair can only ever add to what parses: nothing valid is
78
+ * reinterpreted on its way through.
79
+ *
80
+ * @param text What a model wrote where JSON was asked for, with no prose around it.
81
+ */
82
+ export function looseJson(text) {
76
83
  for (const candidate of [text, repairJson(text)]) {
77
84
  try {
78
85
  const value = JSON.parse(candidate);
@@ -178,9 +185,7 @@ function toCall(entry) {
178
185
  function toCalls(value) {
179
186
  const entries = Array.isArray(value) ? value : [value];
180
187
  const calls = entries.map(toCall);
181
- return calls.length && calls.every((call) => call)
182
- ? calls
183
- : undefined;
188
+ return calls.length && calls.every((call) => call) ? calls : undefined;
184
189
  }
185
190
  /** A value read as text: JSON where it parses, the string where it does not. */
186
191
  function scalar(text) {
@@ -53,6 +53,16 @@ export declare function catalogList(catalog: CatalogServer[], loaded?: ReadonlyS
53
53
  * not mind the cache. Absent marks nothing.
54
54
  */
55
55
  export declare function catalogPrompt(catalog: CatalogServer[], loaded?: ReadonlySet<string>): string;
56
+ /**
57
+ * The name a tool definition is called by, or `undefined` for one that is not a function.
58
+ *
59
+ * Undefined rather than empty, so a caller that skips such a tool and one that has to place it
60
+ * somewhere each say which they mean — a sort and a positional comparison want `?? ""`, a lookup
61
+ * by name wants the tool left out.
62
+ *
63
+ * @param tool The definition, as a request declares it.
64
+ */
65
+ export declare const toolName: (tool: OpenAI.ChatCompletionTool) => string | undefined;
56
66
  /**
57
67
  * A tool array with newly loaded definitions appended, in the order they were loaded.
58
68
  *
@@ -1,3 +1,4 @@
1
+ import { isRecord } from "./guards.js";
1
2
  /**
2
3
  * On-demand tool loading.
3
4
  *
@@ -104,6 +105,16 @@ export function catalogPrompt(catalog, loaded) {
104
105
  ].join("\n");
105
106
  }
106
107
  const flatten = (catalog) => catalog.flatMap((server) => server.tools);
108
+ /**
109
+ * The name a tool definition is called by, or `undefined` for one that is not a function.
110
+ *
111
+ * Undefined rather than empty, so a caller that skips such a tool and one that has to place it
112
+ * somewhere each say which they mean — a sort and a positional comparison want `?? ""`, a lookup
113
+ * by name wants the tool left out.
114
+ *
115
+ * @param tool The definition, as a request declares it.
116
+ */
117
+ export const toolName = (tool) => tool.type === "function" ? tool.function.name : undefined;
107
118
  /**
108
119
  * A tool array with newly loaded definitions appended, in the order they were loaded.
109
120
  *
@@ -116,11 +127,10 @@ const flatten = (catalog) => catalog.flatMap((server) => server.tools);
116
127
  * this list, are skipped rather than moved.
117
128
  */
118
129
  export function loadedTools(previous, matched) {
119
- const nameOf = (tool) => tool.type === "function" ? tool.function.name : undefined;
120
- const declared = new Set(previous.map(nameOf));
130
+ const declared = new Set(previous.map(toolName));
121
131
  const tools = [...previous];
122
132
  for (const tool of matched) {
123
- const name = nameOf(tool);
133
+ const name = toolName(tool);
124
134
  if (name !== undefined && declared.has(name))
125
135
  continue;
126
136
  declared.add(name);
@@ -151,7 +161,7 @@ export function loadedTools(previous, matched) {
151
161
  export function orderTools(tools, order = true) {
152
162
  if (order === false)
153
163
  return tools;
154
- const nameOf = (tool) => tool.type === "function" ? tool.function.name : "";
164
+ const nameOf = (tool) => toolName(tool) ?? "";
155
165
  // Code-unit order rather than `localeCompare`, whose answer depends on the host's locale —
156
166
  // which is the kind of instability this exists to remove.
157
167
  const compare = typeof order === "function" ? order : (a, b) => (a < b ? -1 : a > b ? 1 : 0);
@@ -618,9 +628,7 @@ export const preselectInput = (catalog, prompt, maxPromptChars = PRESELECT_PROMP
618
628
  * `preselectSystem` was given, or the model is being held to a cap it was never told about.
619
629
  */
620
630
  export function preselection(names, catalog, maxPerLoad = MAX_PER_LOAD) {
621
- const list = names && typeof names === "object" && !Array.isArray(names)
622
- ? names.tools
623
- : names;
631
+ const list = isRecord(names) ? names.tools : names;
624
632
  if (!Array.isArray(list))
625
633
  return [];
626
634
  const wanted = list.filter((name) => typeof name === "string");
package/llms.txt CHANGED
@@ -144,6 +144,14 @@ What a run is doing, while it is doing it.
144
144
  - `TurnReport` (type) — One turn's usage and measurements as a `usage` event carries them.
145
145
  - `watch` — Everything that has happened on a run, then everything that happens next, until it ends.
146
146
 
147
+ ### hook-events
148
+
149
+ The points in a session a hook can be bound to, apart from everything that runs one.
150
+
151
+ - `HOOK_EVENTS` — Every event a hook can be bound to, in the order a session meets them.
152
+ - `HookEvent` (type) — A point in a session a hook can be bound to.
153
+ - `INJECT_EVENTS` — The events whose hooks run before a request, and so the only ones whose output can reach it.
154
+
147
155
  ### hooks
148
156
 
149
157
  Lifecycle hooks, from the host's side: what a session looks like to them, where their context lands in a request, and what is said about each one.
@@ -154,16 +162,13 @@ Lifecycle hooks, from the host's side: what a session looks like to them, where
154
162
  - `Gathered` (type) — The context a set of outcomes adds to a request, and a note for each hook worth mentioning.
155
163
  - `gather` — Runs the hooks ahead of a request and builds what they add to it.
156
164
  - `HOOK_CONTEXT_TOKENS` — The most context all of a request's hooks add between them by default, in estimated tokens.
157
- - `HOOK_EVENTS` — Every event a hook can be bound to, in the order a session meets them.
158
165
  - `HOOK_PREFACE` — Said once, above the blocks, so the model reads them as background rather than instructions.
159
166
  - `HookContext` (type) — What a host knows at an event.
160
- - `HookEvent` (type) — A point in a session a hook can be bound to.
161
167
  - `HookMessage` (type) — One message of a session as a hook is handed it.
162
168
  - `HookNote` (type) — One hook's line for whoever is watching: the context it added, or why it added none.
163
169
  - `HookOptions` (type) — What hooks are held to across a process.
164
170
  - `HookOutcome` (type) — What one hook did.
165
171
  - `HookRunner` (type) — Runs one event's hooks.
166
- - `INJECT_EVENTS` — The events whose hooks run before a request, and so the only ones whose output can reach it.
167
172
  - `notify` — Runs the hooks for an event that reads what happened and adds nothing to a request.
168
173
  - `resetHooks` — Test seam: puts `configureHooks` back to the defaults, so one test's budget or preface is not the next's.
169
174
  - `turnIndex` — Which turn of a session begins at a point, from 0: the user messages ahead of it.
@@ -194,7 +199,6 @@ What stretches of a transcript cost, read off the prompt counts the server alrea
194
199
  Everything about a request failing that is not about what the request said.
195
200
 
196
201
  - `backoffMs` — Exponential, with jitter so several tasks failing at once do not return in lockstep.
197
- - `CHARS_PER_TOKEN` — The divisor behind `estimateTokens`, applied here to a character count rather than a string.
198
202
  - `ContextBreakdown` (type) — What a request is made of, by the part of it a consumer can actually do something about.
199
203
  - `ContextBreakdownOptions` (type) — What `contextTokens` takes besides the request.
200
204
  - `ContextOverflow` — The request was bigger than the model will read.
@@ -222,12 +226,21 @@ One turn, given as many attempts as the caller allows.
222
226
  - `RunTurnOptions` (type) — A retry is not the same event as a downgrade, but a watcher wants to be told about both.
223
227
  - `runTurn` — `request` is a callback rather than a body because the body has to be rebuilt from whatever the last attempt latched off: the tools it sends depend on `strictSchemas`, and `relaxTools` has to apply to the schemas that were just sanitised.
224
228
 
229
+ ### runtime
230
+
231
+ - `createRuntime` — A runtime of its own: separate clients, listings, capability latches, hints, event bus and hook settings from the process's and from every other runtime's.
232
+ - `defaultRuntime` — The runtime the top-level functions use when no other is running.
233
+ - `Runtime` (type) — One set of the package's caches, with the functions that use them as methods.
234
+ - `RuntimeOptions` (type) — What a runtime starts out configured with.
235
+
225
236
  ### schema-compat
226
237
 
227
238
  JSON Schema compatibility for llama.cpp-backed servers.
228
239
 
229
240
  - `isGrammarError` — Does this failure look like the server could not build a grammar from our tool schemas?
241
+ - `relaxSchema` — One schema without its `pattern` and `format` keywords, for a schema that is not a tool's.
230
242
  - `relaxTools` — The retry shape: llama.cpp's converter rejects regex escape classes (`\d`, `\w`, `\s`) in `pattern` and most `format` values, both of which only ever narrowed a string the tool re-validates anyway.
243
+ - `sanitizeSchema` — One JSON Schema as a strict server will accept it, for a schema that is not a tool's parameters.
231
244
  - `sanitizeTools` — Tool definitions a strict server will accept, remembered per definition object.
232
245
 
233
246
  ### side-task
@@ -279,7 +292,7 @@ A JSON document that defines an agent, and the rules for reading one.
279
292
  - `ResolvedTask` (type) — One side task, resolved: a model, and the endpoint it is reached through.
280
293
  - `RetrySpec` (type) — What to do about a request lost before the model produced anything.
281
294
  - `resolveAgentSpec` — Layers documents into the flat object the loop takes, weakest first.
282
- - `SPEC_EVENTS` — Every event a hook may be bound to, restated so this module stays free of `node:crypto`.
295
+ - `SPEC_EVENTS` — Every event a hook may be bound to: `HOOK_EVENTS`, under the name a document's reader knows.
283
296
  - `SpecBundle` (type) — What an agent carries so it can travel whole: the definitions of the servers it names.
284
297
  - `SpecServer` (type) — A bundled MCP server, validated only as far as a round trip needs and otherwise passed through.
285
298
  - `TaskSpec` (type) — One side task, which may run on a different model — and a different machine — than the agent.
@@ -310,6 +323,7 @@ Telling a model's scratchpad from its answer when both arrive in `content`.
310
323
 
311
324
  ### tokens
312
325
 
326
+ - `CHARS_PER_TOKEN` — The characters one token is taken to be, where nothing has measured it.
313
327
  - `estimateTokens` — Rough token count.
314
328
 
315
329
  ### tool-calls
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubicecho/agent-core",
3
- "version": "2.22.0",
3
+ "version": "2.24.0",
4
4
  "description": "The endpoint-agnostic half of an OpenAI-compatible agent loop: tool-schema compatibility, on-demand tool loading, one-shot side tasks, run events, and a pooled client.",
5
5
  "keywords": [
6
6
  "openai",