@cubicecho/agent-core 2.24.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.
- package/README.md +10 -7
- package/dist/agent-loop.d.ts +84 -205
- package/dist/agent-loop.js +288 -597
- package/dist/calibration.d.ts +14 -10
- package/dist/calibration.js +30 -23
- package/dist/capabilities.d.ts +111 -42
- package/dist/capabilities.js +281 -138
- package/dist/client.d.ts +104 -35
- package/dist/client.js +205 -74
- package/dist/compaction.d.ts +103 -60
- package/dist/compaction.js +160 -86
- package/dist/config.d.ts +48 -12
- package/dist/config.js +20 -1
- package/dist/continuation.d.ts +24 -16
- package/dist/continuation.js +70 -44
- package/dist/digest.d.ts +7 -0
- package/dist/digest.js +18 -0
- package/dist/errors.d.ts +24 -15
- package/dist/errors.js +23 -15
- package/dist/events.d.ts +100 -63
- package/dist/events.js +250 -120
- package/dist/guards.d.ts +35 -4
- package/dist/guards.js +38 -5
- package/dist/hook-events.d.ts +21 -5
- package/dist/hook-events.js +23 -9
- package/dist/hooks.d.ts +96 -73
- package/dist/hooks.js +202 -116
- package/dist/index.d.ts +30 -26
- package/dist/index.js +29 -24
- package/dist/ledger.d.ts +62 -30
- package/dist/ledger.js +163 -56
- package/dist/platform.d.ts +13 -0
- package/dist/platform.js +13 -0
- package/dist/preselect.d.ts +222 -0
- package/dist/preselect.js +290 -0
- package/dist/request-body.d.ts +32 -0
- package/dist/request-body.js +47 -0
- package/dist/reset.d.ts +1 -0
- package/dist/reset.js +7 -6
- package/dist/retry.d.ts +29 -138
- package/dist/retry.js +69 -282
- package/dist/run-calls.d.ts +123 -0
- package/dist/run-calls.js +351 -0
- package/dist/run-turn.d.ts +36 -15
- package/dist/run-turn.js +74 -37
- package/dist/runtime.d.ts +23 -17
- package/dist/runtime.js +34 -24
- package/dist/schema-compat.d.ts +35 -18
- package/dist/schema-compat.js +340 -175
- package/dist/scope.d.ts +28 -5
- package/dist/scope.js +37 -10
- package/dist/side-task.d.ts +123 -40
- package/dist/side-task.js +181 -63
- package/dist/snapshot.d.ts +10 -5
- package/dist/snapshot.js +73 -30
- package/dist/spec.d.ts +56 -25
- package/dist/spec.js +494 -215
- package/dist/stream.d.ts +66 -16
- package/dist/stream.js +220 -97
- package/dist/thinking.d.ts +23 -8
- package/dist/thinking.js +92 -44
- package/dist/tokens.d.ts +164 -6
- package/dist/tokens.js +319 -6
- package/dist/tool-calls.d.ts +82 -17
- package/dist/tool-calls.js +198 -83
- package/dist/tool-loading.d.ts +101 -189
- package/dist/tool-loading.js +277 -371
- package/dist/wire.d.ts +81 -0
- package/dist/wire.js +73 -0
- package/llms.txt +76 -39
- package/package.json +4 -4
package/dist/calibration.d.ts
CHANGED
|
@@ -1,32 +1,36 @@
|
|
|
1
|
-
import type OpenAI from
|
|
2
|
-
import type { Capabilities } from
|
|
1
|
+
import type OpenAI from 'openai';
|
|
2
|
+
import type { Capabilities } from './capabilities.ts';
|
|
3
3
|
/**
|
|
4
4
|
* The characters per token to size a request to this model with, `CHARS_PER_TOKEN` until a turn
|
|
5
5
|
* has reported one.
|
|
6
6
|
*
|
|
7
|
+
* @param supports - The endpoint, as `capabilitiesFor` hands it over.
|
|
8
|
+
* @param model - The name the endpoint knows the model as, as it goes in the body.
|
|
9
|
+
* @returns The highest of the readings held for the model in the current runtime, or
|
|
10
|
+
* `CHARS_PER_TOKEN` where it holds none.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
7
13
|
* The highest of the model's last few readings rather than their mean. The estimate guards a
|
|
8
14
|
* window, and `estimateTokens` says which side of wrong that should be on: a count that comes out
|
|
9
15
|
* high refuses a run that would have fit, one that comes out low only costs the round trip the
|
|
10
16
|
* guard was saving. The highest ratio is the lowest count, and the last few rather than all of
|
|
11
17
|
* them because a run's transcript grows by appending, so the latest requests are the best
|
|
12
18
|
* likeness of the next.
|
|
13
|
-
*
|
|
14
|
-
* @param supports The endpoint, as `capabilitiesFor` hands it over.
|
|
15
|
-
* @param model The name the endpoint knows the model as, as it goes in the body.
|
|
16
19
|
*/
|
|
17
20
|
export declare function charsPerTokenFor(supports: Capabilities, model: string): number;
|
|
18
21
|
/**
|
|
19
22
|
* Takes one reading from a request that was answered, so the next one to this model is sized by it.
|
|
20
23
|
*
|
|
24
|
+
* @param supports - The endpoint the request went to.
|
|
25
|
+
* @param body - The request as it was last sent, which names the model.
|
|
26
|
+
* @param promptTokens - The prompt count the endpoint reported for it. Zero or less is no report.
|
|
27
|
+
* @returns The ratio now in force for the model.
|
|
28
|
+
*
|
|
29
|
+
* @remarks
|
|
21
30
|
* `runTurn` calls it after every turn whose prompt was reported, so a caller using that has
|
|
22
31
|
* nothing to do. A request carrying an image or audio is not read: a vision model charges a
|
|
23
32
|
* picture hundreds of tokens its characters say nothing about. Neither is a reading outside what a
|
|
24
33
|
* tokenizer could produce, which is a miscount and not a tokenizer.
|
|
25
|
-
*
|
|
26
|
-
* @param supports The endpoint the request went to.
|
|
27
|
-
* @param body The request as it was last sent, which names the model.
|
|
28
|
-
* @param promptTokens The prompt count the endpoint reported for it. Zero or less is no report.
|
|
29
|
-
* @returns The ratio now in force for the model.
|
|
30
34
|
*/
|
|
31
35
|
export declare function calibrate(supports: Capabilities, body: OpenAI.ChatCompletionCreateParamsStreaming, promptTokens: number): number;
|
|
32
36
|
/** Forgets every reading, so the next request is sized at `CHARS_PER_TOKEN` again. */
|
package/dist/calibration.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { scoped } from
|
|
3
|
-
import { CHARS_PER_TOKEN } from
|
|
1
|
+
import { getOrCreate } from './guards.js';
|
|
2
|
+
import { scoped } from './scope.js';
|
|
3
|
+
import { CHARS_PER_TOKEN, requestChars, toolsChars } from './tokens.js';
|
|
4
|
+
import { PartType } from './wire.js';
|
|
4
5
|
/**
|
|
5
6
|
* How many characters a token is worth on one model, learned from what its endpoint reports.
|
|
6
7
|
*
|
|
@@ -34,53 +35,59 @@ const readings = scoped(() => new WeakMap());
|
|
|
34
35
|
* The characters per token to size a request to this model with, `CHARS_PER_TOKEN` until a turn
|
|
35
36
|
* has reported one.
|
|
36
37
|
*
|
|
38
|
+
* @param supports - The endpoint, as `capabilitiesFor` hands it over.
|
|
39
|
+
* @param model - The name the endpoint knows the model as, as it goes in the body.
|
|
40
|
+
* @returns The highest of the readings held for the model in the current runtime, or
|
|
41
|
+
* `CHARS_PER_TOKEN` where it holds none.
|
|
42
|
+
*
|
|
43
|
+
* @remarks
|
|
37
44
|
* The highest of the model's last few readings rather than their mean. The estimate guards a
|
|
38
45
|
* window, and `estimateTokens` says which side of wrong that should be on: a count that comes out
|
|
39
46
|
* high refuses a run that would have fit, one that comes out low only costs the round trip the
|
|
40
47
|
* guard was saving. The highest ratio is the lowest count, and the last few rather than all of
|
|
41
48
|
* them because a run's transcript grows by appending, so the latest requests are the best
|
|
42
49
|
* likeness of the next.
|
|
43
|
-
*
|
|
44
|
-
* @param supports The endpoint, as `capabilitiesFor` hands it over.
|
|
45
|
-
* @param model The name the endpoint knows the model as, as it goes in the body.
|
|
46
50
|
*/
|
|
47
51
|
export function charsPerTokenFor(supports, model) {
|
|
48
52
|
const known = readings().get(supports)?.get(model);
|
|
49
53
|
return known?.length ? Math.max(...known) : CHARS_PER_TOKEN;
|
|
50
54
|
}
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Whether any message carries a part whose tokens its characters do not count.
|
|
57
|
+
*
|
|
58
|
+
* @param messages - A request's messages.
|
|
59
|
+
* @returns True where some message's content is an array holding a part that is neither text nor
|
|
60
|
+
* a refusal. Content that is a string never counts.
|
|
61
|
+
*/
|
|
62
|
+
const hasMedia = (messages) => messages.some(({ content }) => Array.isArray(content) && content.some((part) => part.type !== PartType.Text && part.type !== PartType.Refusal));
|
|
54
63
|
/**
|
|
55
64
|
* Takes one reading from a request that was answered, so the next one to this model is sized by it.
|
|
56
65
|
*
|
|
66
|
+
* @param supports - The endpoint the request went to.
|
|
67
|
+
* @param body - The request as it was last sent, which names the model.
|
|
68
|
+
* @param promptTokens - The prompt count the endpoint reported for it. Zero or less is no report.
|
|
69
|
+
* @returns The ratio now in force for the model.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
57
72
|
* `runTurn` calls it after every turn whose prompt was reported, so a caller using that has
|
|
58
73
|
* nothing to do. A request carrying an image or audio is not read: a vision model charges a
|
|
59
74
|
* picture hundreds of tokens its characters say nothing about. Neither is a reading outside what a
|
|
60
75
|
* tokenizer could produce, which is a miscount and not a tokenizer.
|
|
61
|
-
*
|
|
62
|
-
* @param supports The endpoint the request went to.
|
|
63
|
-
* @param body The request as it was last sent, which names the model.
|
|
64
|
-
* @param promptTokens The prompt count the endpoint reported for it. Zero or less is no report.
|
|
65
|
-
* @returns The ratio now in force for the model.
|
|
66
76
|
*/
|
|
67
77
|
export function calibrate(supports, body, promptTokens) {
|
|
68
|
-
if (!(promptTokens > 0) || hasMedia(body.messages))
|
|
78
|
+
if (!(promptTokens > 0) || hasMedia(body.messages)) {
|
|
69
79
|
return charsPerTokenFor(supports, body.model);
|
|
80
|
+
}
|
|
70
81
|
const ratio = (requestChars(body) + toolsChars(body.tools ?? [])) / promptTokens;
|
|
71
82
|
if (ratio < PLAUSIBLE.least || ratio > PLAUSIBLE.most) {
|
|
72
83
|
return charsPerTokenFor(supports, body.model);
|
|
73
84
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
models = new Map();
|
|
77
|
-
readings().set(supports, models);
|
|
78
|
-
}
|
|
79
|
-
const known = models.get(body.model) ?? [];
|
|
85
|
+
const models = getOrCreate(readings(), supports, () => new Map());
|
|
86
|
+
const known = getOrCreate(models, body.model, () => []);
|
|
80
87
|
known.push(ratio);
|
|
81
|
-
if (known.length > READINGS)
|
|
88
|
+
if (known.length > READINGS) {
|
|
82
89
|
known.shift();
|
|
83
|
-
|
|
90
|
+
}
|
|
84
91
|
return charsPerTokenFor(supports, body.model);
|
|
85
92
|
}
|
|
86
93
|
/** Forgets every reading, so the next request is sized at `CHARS_PER_TOKEN` again. */
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EndpointIdentity } from './config.ts';
|
|
2
|
+
import type { Produced } from './stream.ts';
|
|
2
3
|
/**
|
|
3
4
|
* What an endpoint turned out not to support, and answering it when it says so.
|
|
4
5
|
*
|
|
@@ -39,6 +40,7 @@ export interface Capabilities {
|
|
|
39
40
|
* When this entry was opened, as epoch milliseconds: first contact with the endpoint in this
|
|
40
41
|
* process, or the age an imported snapshot gave it. What `expireCapabilities` measures.
|
|
41
42
|
*
|
|
43
|
+
* @remarks
|
|
42
44
|
* Not when a flag latched. A flag that latches at all almost always does so on the first
|
|
43
45
|
* request or two, and an entry that latched nothing has nothing to expire, so the difference
|
|
44
46
|
* costs at most one retried field somewhat earlier than it was due — which is the direction to
|
|
@@ -51,6 +53,7 @@ export interface Capabilities {
|
|
|
51
53
|
* What one model on that endpoint turned out not to support. All start optimistic and only ever
|
|
52
54
|
* latch off, the same as the endpoint's own.
|
|
53
55
|
*
|
|
56
|
+
* @remarks
|
|
54
57
|
* These arrive through the same channel as the endpoint's — an error string on a chat
|
|
55
58
|
* completion — which is why they are negotiated by the same loop rather than a second one. What
|
|
56
59
|
* makes them the model's is that the answer differs between two models the same key reaches.
|
|
@@ -65,6 +68,7 @@ export interface ModelCapabilities {
|
|
|
65
68
|
* Spells its ceiling `max_tokens`. The reasoning models want `max_completion_tokens` instead,
|
|
66
69
|
* and they are exactly the models anyone sets an effort on.
|
|
67
70
|
*
|
|
71
|
+
* @remarks
|
|
68
72
|
* Read it as `=== false` rather than for truthiness. This is the one flag whose two answers are
|
|
69
73
|
* both a field to send, so a caller that named no model — and was told that changes nothing —
|
|
70
74
|
* gets `undefined` here and, on a truthiness test, sends `max_completion_tokens` to a server
|
|
@@ -81,6 +85,7 @@ export interface ModelCapabilities {
|
|
|
81
85
|
* builder leaves out of what `extraBody` asks for. Only ever grows, which is this set's way of
|
|
82
86
|
* latching off.
|
|
83
87
|
*
|
|
88
|
+
* @remarks
|
|
84
89
|
* Only the fields a caller offered as droppable reach it (see `NegotiateOptions.droppable`),
|
|
85
90
|
* because a name read out of an error string is not otherwise something to stop sending: a
|
|
86
91
|
* refusal naming `messages` is a broken request, not a field the model can do without.
|
|
@@ -97,6 +102,7 @@ export interface ModelCapabilities {
|
|
|
97
102
|
* Efforts this model refused by value rather than by field — a request that named `none` on a
|
|
98
103
|
* model whose list starts at `minimal`. Only ever grows, which is this set's way of latching.
|
|
99
104
|
*
|
|
105
|
+
* @remarks
|
|
100
106
|
* Separate from `reasoningEffort` because the two refusals mean opposite things: that one says
|
|
101
107
|
* the model cannot reason and the field must go, this one says it reasons and was handed an
|
|
102
108
|
* effort off a list this package does not know. Dropping the field there would run at the
|
|
@@ -104,7 +110,7 @@ export interface ModelCapabilities {
|
|
|
104
110
|
*/
|
|
105
111
|
refusedEfforts: Set<string>;
|
|
106
112
|
/**
|
|
107
|
-
* The efforts a refusal published as this model's, in
|
|
113
|
+
* The efforts a refusal published as this model's, in the order it gave them, filtered to the ones
|
|
108
114
|
* `EFFORT_LADDER` can place. Absent until a refusal lists them, and a model that lists nothing
|
|
109
115
|
* is walked up the ladder a rung per refusal instead.
|
|
110
116
|
*/
|
|
@@ -125,6 +131,7 @@ export type ModelFlag = {
|
|
|
125
131
|
/**
|
|
126
132
|
* A model's on/off flags as it starts out, every one optimistic.
|
|
127
133
|
*
|
|
134
|
+
* @remarks
|
|
128
135
|
* A record over every boolean on `ModelCapabilities`, so a flag added there does not compile until
|
|
129
136
|
* it is listed here — and this is the list a snapshot is exported, imported and judged empty by,
|
|
130
137
|
* where each of those used to name the flags again and one could be missed.
|
|
@@ -133,58 +140,103 @@ export declare const OPTIMISTIC_MODEL: Readonly<Record<ModelFlag, true>>;
|
|
|
133
140
|
/** The names of those flags, for a caller that reads or latches each in turn. */
|
|
134
141
|
export declare const MODEL_FLAGS: ModelFlag[];
|
|
135
142
|
/**
|
|
136
|
-
* What
|
|
137
|
-
* latches off stays off.
|
|
143
|
+
* What each endpoint cannot do, remembered for the life of the process.
|
|
138
144
|
*
|
|
139
|
-
* @
|
|
145
|
+
* @remarks
|
|
146
|
+
* Keyed by `endpointId` — `endpointKey` hashed, so a snapshot holds no key — because these are
|
|
147
|
+
* facts about the server on the other end and not about this one. A llama.cpp box that cannot
|
|
148
|
+
* compile a grammar and a cloud API that can are both reachable from one settings row over its
|
|
149
|
+
* lifetime — an operator retargets it from Ollama this afternoon to OpenAI this evening — and the
|
|
150
|
+
* first one's refusal must not quietly strip pattern/format from the second one's requests, or
|
|
151
|
+
* silently cost it its token counts, for the rest of the process. Bounded by the number of
|
|
152
|
+
* endpoints ever configured, which is a settings row's worth.
|
|
153
|
+
*
|
|
154
|
+
* The API key is part of that identity, the same as it is for the client pool and the model
|
|
155
|
+
* listings. A router — LiteLLM, OpenRouter, a gateway with several boxes behind it — is free to
|
|
156
|
+
* send two keys to two different backends, and then what one of them refused is not a fact about
|
|
157
|
+
* the other. Keyed on the URL alone the first caller through the gateway latched for everyone
|
|
158
|
+
* behind it, including the `models` map underneath, which is the level where two keys through
|
|
159
|
+
* one host are most likely to differ at all.
|
|
160
|
+
*/
|
|
161
|
+
/**
|
|
162
|
+
* Hears one line of operator text: what was given up on, what is being waited out, what was chosen.
|
|
163
|
+
*
|
|
164
|
+
* @remarks
|
|
165
|
+
* One name for it because the same listener is handed down from the loop through a turn to
|
|
166
|
+
* `negotiate` and across to every side task, and each had spelled the signature out.
|
|
167
|
+
*/
|
|
168
|
+
export type OnNotice = (message: string) => void;
|
|
169
|
+
/**
|
|
170
|
+
* What this endpoint is known not to support.
|
|
171
|
+
*
|
|
172
|
+
* @param baseUrl - Where the endpoint is. The two flags on it are per-server; what is per-model
|
|
140
173
|
* hangs off `models`, which `modelCapabilitiesFor` reads.
|
|
141
|
-
* @param apiKey The rest of the endpoint's identity. Optional, because it changes nothing for
|
|
174
|
+
* @param [apiKey] - The rest of the endpoint's identity. Optional, because it changes nothing for
|
|
142
175
|
* the ordinary case of one key per base URL and a caller with one need not thread it through;
|
|
143
176
|
* absent reads as `NO_KEY`, exactly as it does in `getClient`, so an endpoint with no key and
|
|
144
177
|
* one that passes `undefined` share an entry rather than holding two.
|
|
178
|
+
* @returns The endpoint's live entry, made with both flags on and no models the first time it is
|
|
179
|
+
* asked for.
|
|
180
|
+
*
|
|
181
|
+
* @remarks
|
|
182
|
+
* The same object every time, so what `negotiate` latches off stays off.
|
|
145
183
|
*/
|
|
146
184
|
export declare function capabilitiesFor(baseUrl: string, apiKey?: string): Capabilities;
|
|
147
185
|
/**
|
|
148
186
|
* What this model on this endpoint is known not to support. The same object every time, so what
|
|
149
187
|
* `negotiate` latches off stays off.
|
|
150
188
|
*
|
|
189
|
+
* @param supports - The endpoint's own, as `capabilitiesFor` hands it over.
|
|
190
|
+
* @param model - The name the endpoint knows the model as — whatever goes in the request body,
|
|
191
|
+
* since that is the only name the refusal is about.
|
|
192
|
+
* @returns The model's live entry under `supports.models`, made with every flag on and nothing
|
|
193
|
+
* refused the first time it is asked for.
|
|
194
|
+
*
|
|
195
|
+
* @remarks
|
|
151
196
|
* Nested under the endpoint rather than keyed by name alone, because `gpt-4o` at OpenAI and
|
|
152
197
|
* `gpt-4o` behind a proxy need not be the same weights — and a proxy is free to answer to a name
|
|
153
198
|
* it does not really serve. One that refused a reasoning effort must not speak for the other.
|
|
154
199
|
* Bounded by the models actually asked for on that endpoint, which is what a dropdown holds.
|
|
155
|
-
*
|
|
156
|
-
* @param supports The endpoint's own, as `capabilitiesFor` hands it over.
|
|
157
|
-
* @param model The name the endpoint knows the model as — whatever goes in the request body,
|
|
158
|
-
* since that is the only name the refusal is about.
|
|
159
200
|
*/
|
|
160
201
|
export declare function modelCapabilitiesFor(supports: Capabilities, model: string): ModelCapabilities;
|
|
161
|
-
/**
|
|
202
|
+
/**
|
|
203
|
+
* Every endpoint's capabilities by `endpointId`, the live objects, for `exportCapabilities`.
|
|
204
|
+
*
|
|
205
|
+
* @returns The map itself rather than a copy, read-only by type alone: what is latched or forgotten
|
|
206
|
+
* afterwards shows through it.
|
|
207
|
+
*/
|
|
162
208
|
export declare const knownCapabilities: () => ReadonlyMap<string, Capabilities>;
|
|
163
209
|
/**
|
|
164
210
|
* The capabilities of the endpoint with this `endpointId`, created optimistic if unseen — the way
|
|
165
211
|
* `importCapabilities` reaches an endpoint it has only a digest for.
|
|
212
|
+
*
|
|
213
|
+
* @param id - The digest `endpointId` gives. Not checked: any string opens an entry under itself.
|
|
214
|
+
* @returns The live entry, the same object `capabilitiesFor` hands over for that endpoint.
|
|
166
215
|
*/
|
|
167
216
|
export declare function capabilitiesById(id: string): Capabilities;
|
|
168
217
|
/**
|
|
169
218
|
* Forgets what one endpoint refused, or every endpoint's when told none.
|
|
170
219
|
*
|
|
220
|
+
* @param [endpoint] - Whose to forget, by the same identity `capabilitiesFor` takes. Absent clears
|
|
221
|
+
* every endpoint, which is what tests and `resetAll` mean by it.
|
|
222
|
+
* @returns Whether there was anything to forget.
|
|
223
|
+
*
|
|
224
|
+
* @remarks
|
|
171
225
|
* A latch never unlatches on its own, so a server upgraded behind the same URL — a newer
|
|
172
226
|
* llama.cpp that compiles the grammar, a proxy that has learned `stream_options` — keeps being
|
|
173
227
|
* sent the downgraded request for the life of the process. This is the seam for a consumer that
|
|
174
228
|
* *knows* it changed: a settings row saved, a health check that reads a new build string, an
|
|
175
229
|
* operator pressing a button. See `expireCapabilities` for the case where nobody knows.
|
|
176
|
-
*
|
|
177
|
-
* @param endpoint Whose to forget, by the same identity `capabilitiesFor` takes. Absent clears
|
|
178
|
-
* every endpoint, which is what tests and `resetAll` mean by it.
|
|
179
|
-
* @returns Whether there was anything to forget.
|
|
180
230
|
*/
|
|
181
|
-
export declare function resetCapabilities(endpoint?:
|
|
182
|
-
baseUrl: string;
|
|
183
|
-
apiKey?: string;
|
|
184
|
-
}): boolean;
|
|
231
|
+
export declare function resetCapabilities(endpoint?: EndpointIdentity): boolean;
|
|
185
232
|
/**
|
|
186
233
|
* Forgets every endpoint whose entry is older than this, so the next request finds out again.
|
|
187
234
|
*
|
|
235
|
+
* @param maxAgeMs - How old an entry may be. Zero or less expires everything.
|
|
236
|
+
* @param [now] - The clock, for tests.
|
|
237
|
+
* @returns How many endpoints were forgotten.
|
|
238
|
+
*
|
|
239
|
+
* @remarks
|
|
188
240
|
* The other half of the problem `resetCapabilities` solves: a server upgraded behind the same URL
|
|
189
241
|
* with nobody to notice. What an expiry costs is one round trip per endpoint and model — the next
|
|
190
242
|
* request carries the field again, and a server that still refuses it refuses it once and
|
|
@@ -194,15 +246,16 @@ export declare function resetCapabilities(endpoint?: {
|
|
|
194
246
|
*
|
|
195
247
|
* Nothing calls this on a timer. When to sweep is the consumer's, the same way how stale a
|
|
196
248
|
* snapshot is too stale is, and a sweep costs a walk of one settings row's worth of entries.
|
|
197
|
-
*
|
|
198
|
-
* @param maxAgeMs How old an entry may be. Zero or less expires everything.
|
|
199
|
-
* @param now The clock, for tests.
|
|
200
|
-
* @returns How many endpoints were forgotten.
|
|
201
249
|
*/
|
|
202
250
|
export declare function expireCapabilities(maxAgeMs: number, now?: number): number;
|
|
251
|
+
/** The setting that asks for no `reasoning_effort` field at all. Ours, and never sent. */
|
|
252
|
+
export declare const EFFORT_OFF: 'off';
|
|
253
|
+
/** The lowest effort the wire has a word for, which is what a side task asks for. */
|
|
254
|
+
export declare const EFFORT_NONE: 'none';
|
|
203
255
|
/**
|
|
204
256
|
* The efforts this package can place, cheapest first. A substitution only ever walks *up* it.
|
|
205
257
|
*
|
|
258
|
+
* @remarks
|
|
206
259
|
* Not a list of what any model takes — `medium` is refused by a model whose list is
|
|
207
260
|
* `minimal, low, high`, and `xhigh` is real and deliberately absent. It is the order the values
|
|
208
261
|
* OpenAI has shipped stand in, which is all a step needs to know. A value not on it cannot be
|
|
@@ -210,37 +263,45 @@ export declare function expireCapabilities(maxAgeMs: number, now?: number): numb
|
|
|
210
263
|
* refused `xhigh` to `high` would quietly answer a question with less deliberation than whoever
|
|
211
264
|
* typed it asked for, where stepping up from `none` to `minimal` only costs tokens and says so.
|
|
212
265
|
*/
|
|
213
|
-
export declare const EFFORT_LADDER: readonly ["none",
|
|
266
|
+
export declare const EFFORT_LADDER: readonly ["none", 'minimal', 'low', 'medium', 'high'];
|
|
214
267
|
/**
|
|
215
268
|
* What to actually put in `reasoning_effort` for a model that has refused the value asked for.
|
|
216
269
|
*
|
|
270
|
+
* @param refused - What the model has refused, as `negotiate` hands it over. Absent is a model that
|
|
271
|
+
* has refused nothing.
|
|
272
|
+
* @param asked - What the config asks for. `"off"` and absent mean no effort.
|
|
273
|
+
* @returns The value for the field, or the empty string for no field. `asked` itself, as written,
|
|
274
|
+
* where the model has not refused it — and where it has but there is no rung left to step to.
|
|
275
|
+
*
|
|
276
|
+
* @remarks
|
|
217
277
|
* The caller's own value, until this model has said that value is not one of its own; then the
|
|
218
278
|
* cheapest it will take that is at least as much deliberation. A model that takes no effort at
|
|
219
279
|
* all, and an absent or `"off"` setting, both answer the empty string, which is the body
|
|
220
280
|
* builders' signal to send no field.
|
|
221
|
-
*
|
|
222
|
-
* @param refused What the model has refused, as `negotiate` hands it over. Absent is a model that
|
|
223
|
-
* has refused nothing.
|
|
224
|
-
* @param asked What the config asks for. `"off"` and absent mean no effort.
|
|
225
281
|
*/
|
|
226
282
|
export declare function effortFor(refused: ModelCapabilities | undefined, asked: string | undefined): string;
|
|
227
283
|
/**
|
|
228
284
|
* The reply ceiling and the temperature as this model takes them, to spread into a request body.
|
|
229
285
|
*
|
|
286
|
+
* @param refused - What the model has refused, as `negotiate` hands it over. Absent is a model that
|
|
287
|
+
* has refused nothing.
|
|
288
|
+
* @param maxTokens - The ceiling. Zero or less sends none and leaves it to the server: a zero sent
|
|
289
|
+
* as `max_tokens: 0` asks for an empty reply.
|
|
290
|
+
* @param temperature - What to sample at, where the model takes one that was picked for it.
|
|
291
|
+
* @returns A fresh object holding the ceiling under one of its two names, or under neither, and
|
|
292
|
+
* `temperature` unless the model refused ours.
|
|
293
|
+
*
|
|
294
|
+
* @remarks
|
|
230
295
|
* The reasoning models want the ceiling spelled the other way, and one that will only run at the
|
|
231
296
|
* temperature it was built with is sent none. Both are tested `=== false`, so a caller that named
|
|
232
297
|
* no model sends what one that has refused nothing is sent; see `ModelCapabilities.legacyTokenLimit`.
|
|
233
|
-
*
|
|
234
|
-
* @param refused What the model has refused, as `negotiate` hands it over. Absent is a model that
|
|
235
|
-
* has refused nothing.
|
|
236
|
-
* @param maxTokens The ceiling. Zero or less sends none and leaves it to the server: a zero sent
|
|
237
|
-
* as `max_tokens: 0` asks for an empty reply.
|
|
238
|
-
* @param temperature What to sample at, where the model takes one that was picked for it.
|
|
239
298
|
*/
|
|
240
299
|
export declare const ceilingAndTemperature: (refused: ModelCapabilities | undefined, maxTokens: number, temperature: number) => {
|
|
241
300
|
max_completion_tokens: number;
|
|
301
|
+
max_tokens?: undefined;
|
|
242
302
|
temperature?: number | undefined;
|
|
243
303
|
} | {
|
|
304
|
+
max_completion_tokens?: undefined;
|
|
244
305
|
max_tokens: number;
|
|
245
306
|
temperature?: number | undefined;
|
|
246
307
|
} | {
|
|
@@ -251,6 +312,7 @@ export interface NegotiateOptions {
|
|
|
251
312
|
/**
|
|
252
313
|
* The flag `send` will be given, for a caller that has to read it after `negotiate` returns.
|
|
253
314
|
*
|
|
315
|
+
* @remarks
|
|
254
316
|
* An outer retry loop needs it: nothing is retried once the server has started answering, and
|
|
255
317
|
* by the time a rejected promise is in hand the turn is over. Callers without one can leave
|
|
256
318
|
* this out and take the flag from `send`'s second argument, which is the same object.
|
|
@@ -259,6 +321,7 @@ export interface NegotiateOptions {
|
|
|
259
321
|
/**
|
|
260
322
|
* Told what was given up on, for a watcher who would otherwise see an unexplained pause.
|
|
261
323
|
*
|
|
324
|
+
* @remarks
|
|
262
325
|
* Each message opens with the thing that refused, so a reader tells the two levels apart
|
|
263
326
|
* without parsing: `server` for the endpoint's own, and the model's own name — as `model` was
|
|
264
327
|
* given it — for the three that are the model's. That matters because these latch for the
|
|
@@ -267,10 +330,11 @@ export interface NegotiateOptions {
|
|
|
267
330
|
* line for every model on the endpoint, and the operator who later asks why the setting still
|
|
268
331
|
* reads `high` has no way to tell which one it was about.
|
|
269
332
|
*/
|
|
270
|
-
onNotice?:
|
|
333
|
+
onNotice?: OnNotice;
|
|
271
334
|
/**
|
|
272
335
|
* Which model this request is for, by the name the endpoint knows it as.
|
|
273
336
|
*
|
|
337
|
+
* @remarks
|
|
274
338
|
* Given one, the refusals that are about the model rather than the server are answered too,
|
|
275
339
|
* and `send` is handed what that model has already refused. Left out, nothing changes — which
|
|
276
340
|
* is the point of it being here rather than a third positional argument: a caller with one
|
|
@@ -282,6 +346,7 @@ export interface NegotiateOptions {
|
|
|
282
346
|
* them — what `extraBody` added, ordinarily. Such a name is latched into the model's
|
|
283
347
|
* `refusedFields` and the request is sent again, which `send` is expected to build without it.
|
|
284
348
|
*
|
|
349
|
+
* @remarks
|
|
285
350
|
* Opt-in by name, because the answer is to stop sending the field, and a name out of an error
|
|
286
351
|
* string that `send` does not know how to leave out would only be refused again. Needs `model`,
|
|
287
352
|
* since the latch is the model's.
|
|
@@ -293,6 +358,17 @@ export interface NegotiateOptions {
|
|
|
293
358
|
* request can do without. Returns once the endpoint has answered, or throws if the refusal is
|
|
294
359
|
* not one of ours.
|
|
295
360
|
*
|
|
361
|
+
* @typeParam T - What `send` resolves, which is handed back as it came.
|
|
362
|
+
* @param supports - What this endpoint has already refused. Latched off further as it refuses more.
|
|
363
|
+
* @param send - Builds and sends the request. Called again per downgrade, never once tokens
|
|
364
|
+
* have arrived. Its third argument is what the named model has refused, absent when no model
|
|
365
|
+
* was named.
|
|
366
|
+
* @param [options] - `produced` for a caller with its own retry budget, `onNotice` for a watcher,
|
|
367
|
+
* `model` to negotiate the model's refusals alongside the endpoint's.
|
|
368
|
+
* @returns What the first `send` to succeed resolved. A rejection is `send`'s own error, rethrown
|
|
369
|
+
* as it was caught.
|
|
370
|
+
*
|
|
371
|
+
* @remarks
|
|
296
372
|
* A loop rather than one retry. A server that has heard of neither `stream_options` nor a
|
|
297
373
|
* grammar keyword complains about them one at a time, and answering only the first leaves the
|
|
298
374
|
* second to fail the request — so the first run against such an endpoint is spent discovering
|
|
@@ -314,12 +390,5 @@ export interface NegotiateOptions {
|
|
|
314
390
|
* ever one flag in a turn — the same box `streamTurn` sets and the re-send below reads — and a
|
|
315
391
|
* caller that passed it to only one of the two got a turn that had already streamed tokens sent
|
|
316
392
|
* again, silently, with the watcher seeing every one of them twice.
|
|
317
|
-
*
|
|
318
|
-
* @param supports What this endpoint has already refused. Latched off further as it refuses more.
|
|
319
|
-
* @param send Builds and sends the request. Called again per downgrade, never once tokens
|
|
320
|
-
* have arrived. Its third argument is what the named model has refused, absent when no model
|
|
321
|
-
* was named.
|
|
322
|
-
* @param options `produced` for a caller with its own retry budget, `onNotice` for a watcher,
|
|
323
|
-
* `model` to negotiate the model's refusals alongside the endpoint's.
|
|
324
393
|
*/
|
|
325
394
|
export declare function negotiate<T>(supports: Capabilities, send: (supports: Capabilities, produced: Produced, model: ModelCapabilities | undefined) => Promise<T>, { produced, onNotice, model: name, droppable }?: NegotiateOptions): Promise<T>;
|