@cubicecho/agent-core 2.12.0 → 2.14.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.
@@ -56,16 +56,41 @@ export declare function catalogPrompt(catalog: CatalogServer[], loaded?: Readonl
56
56
  /**
57
57
  * A tool array with newly loaded definitions appended, in the order they were loaded.
58
58
  *
59
- * Never re-sorted and never rebuilt from a set. A template renders the tool array into the
60
- * prompt near its head, and a load that moved an earlier definition moved everything after it,
61
- * so the cache was lost from there on every load; appended, the definitions already sent stay
62
- * a prefix of the new array.
59
+ * Appended and never rebuilt from a set, so what a load adds is decided by the load and not by
60
+ * the shape of whatever collection the definitions came out of. Where the appended array ends up
61
+ * in the request is `orderTools`' business, which the loop applies after this.
63
62
  *
64
63
  * @param previous What the last request declared, `load_tools` included. Not written to.
65
64
  * @param matched The definitions to add. Ones whose name is already declared, here or earlier in
66
65
  * this list, are skipped rather than moved.
67
66
  */
68
67
  export declare function loadedTools(previous: readonly OpenAI.ChatCompletionTool[], matched: readonly OpenAI.ChatCompletionTool[]): OpenAI.ChatCompletionTool[];
68
+ /**
69
+ * How a tool array is ordered before it is sent: `true` by name, `false` as the caller built it,
70
+ * or a comparator over the two names.
71
+ */
72
+ export type ToolOrder = boolean | ((a: string, b: string) => number);
73
+ /**
74
+ * The tool array in a stable order, so the same set of tools renders the same way twice.
75
+ *
76
+ * A chat template renders the declared tools ahead of the system prompt, which makes the tool
77
+ * array the first thing a prompt cache has to match — and an array assembled from a map, from
78
+ * database rows, or from the order servers happened to connect in changes between processes and
79
+ * between reconnects. Every such change costs the cache for the whole transcript rather than for
80
+ * the tools alone, and nothing about the request the model sees is different. Ordering by name
81
+ * makes the array a property of the set instead of of how it was built, at the price of a load
82
+ * inserting rather than appending. Definitions come back by identity, so `sanitizeTools` still
83
+ * finds each one in its cache.
84
+ *
85
+ * `false` is for a caller that means its order: the model reads the array top to bottom, and a
86
+ * host may be putting what it wants reached for first at the front.
87
+ *
88
+ * @param tools The definitions to order. Not written to.
89
+ * @param order `true` for name order, `false` to leave it alone, or a comparator over the names.
90
+ * A tool that is not a function orders as the empty name.
91
+ * @returns `tools` itself when it is already in that order, so the common case copies nothing.
92
+ */
93
+ export declare function orderTools(tools: OpenAI.ChatCompletionTool[], order?: ToolOrder): OpenAI.ChatCompletionTool[];
69
94
  /**
70
95
  * The most a single `load_tools` call may pull in.
71
96
  *
@@ -107,10 +107,9 @@ const flatten = (catalog) => catalog.flatMap((server) => server.tools);
107
107
  /**
108
108
  * A tool array with newly loaded definitions appended, in the order they were loaded.
109
109
  *
110
- * Never re-sorted and never rebuilt from a set. A template renders the tool array into the
111
- * prompt near its head, and a load that moved an earlier definition moved everything after it,
112
- * so the cache was lost from there on every load; appended, the definitions already sent stay
113
- * a prefix of the new array.
110
+ * Appended and never rebuilt from a set, so what a load adds is decided by the load and not by
111
+ * the shape of whatever collection the definitions came out of. Where the appended array ends up
112
+ * in the request is `orderTools`' business, which the loop applies after this.
114
113
  *
115
114
  * @param previous What the last request declared, `load_tools` included. Not written to.
116
115
  * @param matched The definitions to add. Ones whose name is already declared, here or earlier in
@@ -129,6 +128,36 @@ export function loadedTools(previous, matched) {
129
128
  }
130
129
  return tools;
131
130
  }
131
+ /**
132
+ * The tool array in a stable order, so the same set of tools renders the same way twice.
133
+ *
134
+ * A chat template renders the declared tools ahead of the system prompt, which makes the tool
135
+ * array the first thing a prompt cache has to match — and an array assembled from a map, from
136
+ * database rows, or from the order servers happened to connect in changes between processes and
137
+ * between reconnects. Every such change costs the cache for the whole transcript rather than for
138
+ * the tools alone, and nothing about the request the model sees is different. Ordering by name
139
+ * makes the array a property of the set instead of of how it was built, at the price of a load
140
+ * inserting rather than appending. Definitions come back by identity, so `sanitizeTools` still
141
+ * finds each one in its cache.
142
+ *
143
+ * `false` is for a caller that means its order: the model reads the array top to bottom, and a
144
+ * host may be putting what it wants reached for first at the front.
145
+ *
146
+ * @param tools The definitions to order. Not written to.
147
+ * @param order `true` for name order, `false` to leave it alone, or a comparator over the names.
148
+ * A tool that is not a function orders as the empty name.
149
+ * @returns `tools` itself when it is already in that order, so the common case copies nothing.
150
+ */
151
+ export function orderTools(tools, order = true) {
152
+ if (order === false)
153
+ return tools;
154
+ const nameOf = (tool) => tool.type === "function" ? tool.function.name : "";
155
+ // Code-unit order rather than `localeCompare`, whose answer depends on the host's locale —
156
+ // which is the kind of instability this exists to remove.
157
+ const compare = typeof order === "function" ? order : (a, b) => (a < b ? -1 : a > b ? 1 : 0);
158
+ const sorted = [...tools].sort((a, b) => compare(nameOf(a), nameOf(b)));
159
+ return sorted.some((tool, at) => tool !== tools[at]) ? sorted : tools;
160
+ }
132
161
  /**
133
162
  * The most a single `load_tools` call may pull in.
134
163
  *
package/llms.txt CHANGED
@@ -38,11 +38,12 @@ What an endpoint turned out not to support, and answering it when it says so.
38
38
 
39
39
  - `Capabilities` (type) — What one endpoint turned out not to support.
40
40
  - `capabilitiesFor` — What this endpoint is known not to support.
41
+ - `expireCapabilities` — Forgets every endpoint whose entry is older than this, so the next request finds out again.
41
42
  - `ModelCapabilities` (type) — What one model on that endpoint turned out not to support.
42
43
  - `modelCapabilitiesFor` — What this model on this endpoint is known not to support.
43
44
  - `NegotiateOptions` (type) — What `negotiate` takes besides the request.
44
45
  - `negotiate` — Sends a request, re-sending it each time the answer is this endpoint refusing something the request can do without.
45
- - `resetCapabilities` — Forgets every endpoint's capabilities.
46
+ - `resetCapabilities` — Forgets what one endpoint refused, or every endpoint's when told none.
46
47
 
47
48
  ### catalog
48
49
 
@@ -71,14 +72,19 @@ The contract between whatever holds the tools and the loop that offers them to a
71
72
 
72
73
  Keeping a long run inside its window: stale tool results cleared, and the oldest stretch folded into a summary the model writes itself.
73
74
 
75
+ - `applyCompaction` — The transcript as the server should see it: the folded head replaced by its summary.
74
76
  - `COMPACT_AT` — The fraction of the window in use before a summary is worth its own round trip.
75
77
  - `CompactionOptions` (type) — What `planCompaction` takes.
76
78
  - `CompactionPlan` (type) — Where to cut, as `compactTranscript` takes it.
79
+ - `CompactionRecord` (type) — One fold, as a host that keeps its transcript append-only stores it.
80
+ - `CompactionRunOptions` (type) — What `runCompaction` and `compactTranscript` take beside the plan.
77
81
  - `compactTranscript` — The transcript with the plan's stretch replaced by one system message holding its summary.
78
82
  - `KEEP_RATIO` — The fraction of the window the kept tail may fill, leaving room for the run to grow again.
79
83
  - `PruneOptions` (type) — What `pruneToolResults` takes.
80
84
  - `planCompaction` — Where to fold a transcript that has grown into its window, or `undefined` when it should not be.
81
85
  - `pruneToolResults` — The transcript with every tool result but the latest few replaced by a one-line stub.
86
+ - `requestIndex` — Where a stored index sits in the request `applyCompaction` builds, once a fold has shifted everything after it.
87
+ - `runCompaction` — The hooks and the summariser for a plan, as a record to store rather than a transcript to send.
82
88
  - `SUMMARY_LEAD` — How a summary message opens, which is also how `planCompaction` knows one from a system prompt.
83
89
  - `SUMMARY_PROMPT` — The summariser's instruction when the caller gives none.
84
90
  - `summariser` — A summariser that asks `model` with `SUMMARY_PROMPT`, for `compactTranscript`.
@@ -165,8 +171,12 @@ Everything about a request failing that is not about what the request said.
165
171
 
166
172
  - `backoffMs` — Exponential, with jitter so several tasks failing at once do not return in lockstep.
167
173
  - `CHARS_PER_TOKEN` — The divisor behind `estimateTokens`, applied here to a character count rather than a string.
174
+ - `ContextBreakdown` (type) — What a request is made of, by the part of it a consumer can actually do something about.
175
+ - `ContextBreakdownOptions` (type) — What `contextTokens` takes besides the request.
168
176
  - `ContextOverflow` — The request was bigger than the model will read.
169
177
  - `compact` — 1234 → "1.2k".
178
+ - `contextChars` — What each part of a request is worth in characters, by the same walk `requestTokens` divides.
179
+ - `contextTokens` — What each part of a request costs the window, in tokens, adding up to the whole.
170
180
  - `EndpointSilent` — The endpoint stopped answering mid-request.
171
181
  - `isModelLoading` — Whether a failure is a local server still loading the model, rather than one failing to serve.
172
182
  - `isOverflow` — Whether a refusal means the request was too big, rather than merely refused.
@@ -271,9 +281,11 @@ Reading what a model meant by a tool call when it did not write one cleanly.
271
281
  - `loadResult` — What `load_tools` reports back: the descriptions, now that they are worth their tokens.
272
282
  - `MAX_CARRIED` — The most a conversation carries between turns.
273
283
  - `MAX_PER_LOAD` — The most a single `load_tools` call may pull in.
284
+ - `orderTools` — The tool array in a stable order, so the same set of tools renders the same way twice.
274
285
  - `PRESELECT_SCHEMA` — The shape a preselector's answer is held to where the server takes a schema: `{ tools: [...] }`.
275
286
  - `PRESELECT_SYSTEM` — The preselection system prompt at the default cap, for a caller that never changes it.
276
287
  - `preselectInput` — The user message for a preselection call: the catalogue, then the request.
277
288
  - `preselection` — Resolves a preselection against the catalogue: unknown names dropped, count capped.
278
289
  - `preselectSystem` — The system prompt a preselector is given, holding it to the cap its answer will be held to.
279
290
  - `requestedNames` — `load_tools` arguments, defensively — a model may send a bare string or a nested object.
291
+ - `ToolOrder` (type) — How a tool array is ordered before it is sent: `true` by name, `false` as the caller built it, or a comparator over the two names.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubicecho/agent-core",
3
- "version": "2.12.0",
3
+ "version": "2.14.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",