@zenera/neo 1.1.10 → 1.1.12
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 +3 -3
- package/dist/agent.d.ts +8 -7
- package/dist/agent.js +15 -8
- package/dist/architecture.d.ts +7 -5
- package/dist/architecture.js +20 -12
- package/dist/embedding.d.ts +20 -1
- package/dist/embedding.js +3 -2
- package/dist/embeddings/fanout.d.ts +51 -0
- package/dist/embeddings/fanout.js +76 -0
- package/dist/embeddings/gemini.d.ts +3 -10
- package/dist/embeddings/gemini.js +46 -30
- package/dist/embeddings/index.d.ts +3 -0
- package/dist/embeddings/index.js +3 -0
- package/dist/embeddings/limiter.d.ts +36 -0
- package/dist/embeddings/limiter.js +182 -0
- package/dist/embeddings/openai.d.ts +3 -2
- package/dist/embeddings/openai.js +54 -13
- package/dist/embeddings/openrouter.d.ts +2 -1
- package/dist/embeddings/openrouter.js +52 -23
- package/dist/embeddings/rate-limit.d.ts +16 -0
- package/dist/embeddings/rate-limit.js +131 -0
- package/dist/failure.d.ts +82 -0
- package/dist/failure.js +323 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.js +13 -2
- package/dist/inspect/client.d.ts +1 -1
- package/dist/inspect/client.js +42 -26
- package/dist/kernel.d.ts +1 -1
- package/dist/kernel.js +40 -23
- package/dist/memory/files.d.ts +24 -0
- package/dist/memory/files.js +85 -0
- package/dist/memory/graph.d.ts +56 -0
- package/dist/memory/graph.js +159 -0
- package/dist/memory/index.d.ts +93 -0
- package/dist/memory/index.js +357 -0
- package/dist/memory/instructions.d.ts +15 -0
- package/dist/memory/instructions.js +103 -0
- package/dist/memory/page.d.ts +8 -0
- package/dist/memory/page.js +797 -0
- package/dist/memory/recall.d.ts +35 -0
- package/dist/memory/recall.js +161 -0
- package/dist/memory/render.d.ts +10 -0
- package/dist/memory/render.js +228 -0
- package/dist/memory/report.d.ts +57 -0
- package/dist/memory/report.js +113 -0
- package/dist/memory/store.d.ts +49 -0
- package/dist/memory/store.js +226 -0
- package/dist/memory/tools.d.ts +11 -0
- package/dist/memory/tools.js +310 -0
- package/dist/memory/types.d.ts +192 -0
- package/dist/memory/types.js +105 -0
- package/dist/memory/vectors.d.ts +29 -0
- package/dist/memory/vectors.js +152 -0
- package/dist/models/anthropic.d.ts +2 -1
- package/dist/models/anthropic.js +11 -4
- package/dist/models/factory.d.ts +15 -0
- package/dist/models/factory.js +49 -10
- package/dist/models/gemini.d.ts +2 -1
- package/dist/models/gemini.js +8 -3
- package/dist/models/openai-chat.d.ts +2 -1
- package/dist/models/openai-chat.js +10 -5
- package/dist/models/openai-responses.d.ts +2 -1
- package/dist/models/openai-responses.js +22 -7
- package/dist/models/openrouter.d.ts +2 -1
- package/dist/models/openrouter.js +14 -6
- package/dist/project/config.d.ts +55 -3
- package/dist/project/config.js +76 -1
- package/dist/project/index.d.ts +2 -2
- package/dist/project/index.js +1 -1
- package/dist/project/load.d.ts +16 -2
- package/dist/project/load.js +67 -1
- package/dist/runner.d.ts +4 -2
- package/dist/runner.js +29 -30
- package/dist/services.d.ts +23 -6
- package/dist/services.js +25 -15
- package/dist/tools/workspace.js +195 -17
- package/dist/trajectory.d.ts +14 -12
- package/dist/types.d.ts +5 -5
- package/dist/types.js +3 -3
- package/package.json +2 -5
- package/dist/memory-stores/factory.d.ts +0 -15
- package/dist/memory-stores/factory.js +0 -29
- package/dist/memory-stores/file.d.ts +0 -37
- package/dist/memory-stores/file.js +0 -174
- package/dist/memory-stores/in-memory.d.ts +0 -17
- package/dist/memory-stores/in-memory.js +0 -80
- package/dist/memory-stores/index.d.ts +0 -4
- package/dist/memory-stores/index.js +0 -5
- package/dist/memory.d.ts +0 -115
- package/dist/memory.js +0 -213
package/dist/models/factory.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { GeminiEmbedder } from "../embeddings/gemini.js";
|
|
4
|
+
import { DEFAULT_START, RateLimiter } from "../embeddings/limiter.js";
|
|
4
5
|
import { OpenAIEmbedder } from "../embeddings/openai.js";
|
|
5
6
|
import { OpenRouterEmbedder } from "../embeddings/openrouter.js";
|
|
6
7
|
import { AnthropicModel } from "./anthropic.js";
|
|
@@ -159,6 +160,7 @@ function expand(value, where) {
|
|
|
159
160
|
export class ModelRegistry {
|
|
160
161
|
#providers = new Map();
|
|
161
162
|
#clients = new Map();
|
|
163
|
+
#limiters = new Map();
|
|
162
164
|
#default = 'openai';
|
|
163
165
|
/** Declares (or replaces) a provider. Nothing is contacted until it is used. */
|
|
164
166
|
provider(name, spec = {}) {
|
|
@@ -170,6 +172,7 @@ export class ModelRegistry {
|
|
|
170
172
|
// Re-declaring after a client was handed out would otherwise leave the
|
|
171
173
|
// old credentials in service for the rest of the process.
|
|
172
174
|
this.#clients.delete(name);
|
|
175
|
+
this.#limiters.delete(name);
|
|
173
176
|
return this;
|
|
174
177
|
}
|
|
175
178
|
/** Names the provider a bare model id belongs to. */
|
|
@@ -201,6 +204,27 @@ export class ModelRegistry {
|
|
|
201
204
|
this.#clients.set(name, built);
|
|
202
205
|
return built;
|
|
203
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* The pacing shared by every embedder on a provider, so that what one of
|
|
209
|
+
* them learns from a 429 the others do not have to learn again — and so
|
|
210
|
+
* that two of them cannot each ramp up to the full limit against one key.
|
|
211
|
+
*/
|
|
212
|
+
#limiter(name) {
|
|
213
|
+
const existing = this.#limiters.get(name);
|
|
214
|
+
if (existing) {
|
|
215
|
+
return existing;
|
|
216
|
+
}
|
|
217
|
+
const spec = this.#providers.get(name);
|
|
218
|
+
const built = new RateLimiter({
|
|
219
|
+
max: spec?.concurrency,
|
|
220
|
+
start: spec?.concurrency === undefined
|
|
221
|
+
? undefined
|
|
222
|
+
: Math.min(spec.concurrency, DEFAULT_START),
|
|
223
|
+
maxRetries: spec?.maxRetries,
|
|
224
|
+
});
|
|
225
|
+
this.#limiters.set(name, built);
|
|
226
|
+
return built;
|
|
227
|
+
}
|
|
204
228
|
/** Turns a shorthand or a spec into a `Model`. */
|
|
205
229
|
model(ref) {
|
|
206
230
|
const spec = typeof ref === 'string' ? this.parse(ref) : ref;
|
|
@@ -213,6 +237,10 @@ export class ModelRegistry {
|
|
|
213
237
|
// silently ignore them.
|
|
214
238
|
const client = spec.client ??
|
|
215
239
|
(hasCredentials(spec) ? buildClient(name, kind, spec, provider) : this.client(name));
|
|
240
|
+
// The *resolved* name, not `spec.provider`: a bare ref carries none,
|
|
241
|
+
// and a failure that cannot say which connection refused it is the
|
|
242
|
+
// thing this is here to prevent.
|
|
243
|
+
const options = { ...spec, provider: name };
|
|
216
244
|
// Every protocol but OpenAI's has exactly one API, so naming one is a
|
|
217
245
|
// mistake worth reporting rather than a field to ignore.
|
|
218
246
|
if (defaults.protocol !== 'openai') {
|
|
@@ -221,11 +249,11 @@ export class ModelRegistry {
|
|
|
221
249
|
}
|
|
222
250
|
switch (defaults.protocol) {
|
|
223
251
|
case 'anthropic':
|
|
224
|
-
return new AnthropicModel(spec.model, client,
|
|
252
|
+
return new AnthropicModel(spec.model, client, options);
|
|
225
253
|
case 'gemini':
|
|
226
|
-
return new GeminiModel(spec.model, client,
|
|
254
|
+
return new GeminiModel(spec.model, client, options);
|
|
227
255
|
case 'openrouter':
|
|
228
|
-
return new OpenRouterModel(spec.model, client,
|
|
256
|
+
return new OpenRouterModel(spec.model, client, options);
|
|
229
257
|
}
|
|
230
258
|
}
|
|
231
259
|
const api = spec.api ?? defaults.apis[0];
|
|
@@ -234,8 +262,8 @@ export class ModelRegistry {
|
|
|
234
262
|
`(supported: ${defaults.apis.join(', ')})`);
|
|
235
263
|
}
|
|
236
264
|
return api === 'responses'
|
|
237
|
-
? new OpenAIResponsesModel(spec.model, client,
|
|
238
|
-
: new OpenAIModel(spec.model, client,
|
|
265
|
+
? new OpenAIResponsesModel(spec.model, client, options)
|
|
266
|
+
: new OpenAIModel(spec.model, client, options);
|
|
239
267
|
}
|
|
240
268
|
/**
|
|
241
269
|
* Turns a shorthand or a spec into an `Embedder`, over the same providers
|
|
@@ -243,19 +271,26 @@ export class ModelRegistry {
|
|
|
243
271
|
* generates and embeds without being mentioned twice.
|
|
244
272
|
*/
|
|
245
273
|
embedder(ref) {
|
|
246
|
-
const spec = typeof ref === 'string' ? this
|
|
274
|
+
const spec = typeof ref === 'string' ? this.parseEmbedding(ref) : ref;
|
|
247
275
|
const name = spec.provider ?? this.#default;
|
|
248
276
|
const provider = this.#spec(name);
|
|
249
277
|
const kind = this.kindOf(name);
|
|
250
278
|
const client = spec.client ??
|
|
251
279
|
(hasCredentials(spec) ? buildClient(name, kind, spec, provider) : this.client(name));
|
|
280
|
+
// Inline credentials are a different connection, and so a different
|
|
281
|
+
// budget: they get pacing of their own rather than the provider's.
|
|
282
|
+
const options = {
|
|
283
|
+
...spec,
|
|
284
|
+
provider: name,
|
|
285
|
+
limiter: spec.limiter ?? (hasCredentials(spec) ? undefined : this.#limiter(name)),
|
|
286
|
+
};
|
|
252
287
|
switch (KINDS[kind].protocol) {
|
|
253
288
|
case 'openai':
|
|
254
|
-
return new OpenAIEmbedder(spec.model, client,
|
|
289
|
+
return new OpenAIEmbedder(spec.model, client, options);
|
|
255
290
|
case 'gemini':
|
|
256
|
-
return new GeminiEmbedder(spec.model, client,
|
|
291
|
+
return new GeminiEmbedder(spec.model, client, options);
|
|
257
292
|
case 'openrouter':
|
|
258
|
-
return new OpenRouterEmbedder(spec.model, client,
|
|
293
|
+
return new OpenRouterEmbedder(spec.model, client, options);
|
|
259
294
|
case 'anthropic':
|
|
260
295
|
// Not an omission to be filled in later: Anthropic publishes no
|
|
261
296
|
// embeddings API at all, and points at third parties instead.
|
|
@@ -318,7 +353,11 @@ export class ModelRegistry {
|
|
|
318
353
|
}
|
|
319
354
|
return { provider, api, model };
|
|
320
355
|
}
|
|
321
|
-
|
|
356
|
+
/**
|
|
357
|
+
* Splits `[provider:]model` into the spec it stands for, so a caller holding
|
|
358
|
+
* a shorthand can still set the knobs a shorthand has no room for.
|
|
359
|
+
*/
|
|
360
|
+
parseEmbedding(ref) {
|
|
322
361
|
const { provider, api, model } = this.parse(ref);
|
|
323
362
|
if (api) {
|
|
324
363
|
throw new TypeError(`"${ref}": embeddings have one api, so "${api}" means nothing here`);
|
package/dist/models/gemini.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GoogleGenAI } from '@google/genai';
|
|
2
2
|
import type { StreamDelta } from '../events.ts';
|
|
3
|
+
import { type ProviderNamed } from '../failure.ts';
|
|
3
4
|
import type { Model, ModelRequest, ModelResponse } from '../model.ts';
|
|
4
5
|
/** The coarse dial Gemini 3 takes in place of a token budget. */
|
|
5
6
|
export type GeminiThinkingLevel = 'minimal' | 'low' | 'medium' | 'high';
|
|
@@ -11,7 +12,7 @@ export type GeminiThinkingLevel = 'minimal' | 'low' | 'medium' | 'high';
|
|
|
11
12
|
* 3 takes a coarse `thinkingLevel`, and passing the wrong one is an API error
|
|
12
13
|
* rather than something this adapter can paper over.
|
|
13
14
|
*/
|
|
14
|
-
export interface GeminiModelOptions {
|
|
15
|
+
export interface GeminiModelOptions extends ProviderNamed {
|
|
15
16
|
/** hard cap on output tokens; the model's own default applies when unset */
|
|
16
17
|
maxTokens?: number;
|
|
17
18
|
/** 2.5-era budget, in tokens: `0` disables thinking, `-1` lets the model decide */
|
package/dist/models/gemini.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { callSites, called, reading } from "../failure.js";
|
|
1
2
|
import { zeroUsage, } from "../types.js";
|
|
2
3
|
/**
|
|
3
4
|
* Google's `ThinkingLevel` is a *string* enum, so its members are just their
|
|
@@ -40,14 +41,16 @@ export class GeminiModel {
|
|
|
40
41
|
id;
|
|
41
42
|
#client;
|
|
42
43
|
#options;
|
|
44
|
+
#site;
|
|
43
45
|
#nextId = 0;
|
|
44
46
|
constructor(id, client, options = {}) {
|
|
45
47
|
this.id = id;
|
|
46
48
|
this.#client = client;
|
|
47
49
|
this.#options = options;
|
|
50
|
+
this.#site = callSites(id, options.provider);
|
|
48
51
|
}
|
|
49
52
|
async generate(req) {
|
|
50
|
-
const res = await this.#client.models.generateContent(this.#params(req));
|
|
53
|
+
const res = await called(this.#site('llm generation', 'models.generateContent'), () => this.#client.models.generateContent(this.#params(req)));
|
|
51
54
|
const read = emptyRead();
|
|
52
55
|
for (const part of candidateParts(res)) {
|
|
53
56
|
this.#readPart(part, read);
|
|
@@ -55,10 +58,12 @@ export class GeminiModel {
|
|
|
55
58
|
return this.#finish(read, res);
|
|
56
59
|
}
|
|
57
60
|
async stream(req, onDelta) {
|
|
58
|
-
const
|
|
61
|
+
const site = this.#site('llm streaming', 'models.generateContentStream');
|
|
62
|
+
const open = () => this.#client.models.generateContentStream(this.#params(req));
|
|
63
|
+
const stream = await called(site, open);
|
|
59
64
|
const read = emptyRead();
|
|
60
65
|
let last;
|
|
61
|
-
for await (const chunk of stream) {
|
|
66
|
+
for await (const chunk of reading(site, stream, open)) {
|
|
62
67
|
last = chunk;
|
|
63
68
|
for (const part of candidateParts(chunk)) {
|
|
64
69
|
this.#readPart(part, read, onDelta);
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type OpenAI from 'openai';
|
|
2
2
|
import type { StreamDelta } from '../events.ts';
|
|
3
|
+
import { type ProviderNamed } from '../failure.ts';
|
|
3
4
|
import type { Model, ModelRequest, ModelResponse } from '../model.ts';
|
|
4
5
|
/**
|
|
5
6
|
* Provider-specific knobs. Reasoning effort is deliberately *not* part of
|
|
6
7
|
* `ModelRequest`: every provider spells it differently (and most models ignore
|
|
7
8
|
* it), so it belongs to the concrete adapter rather than the `Model` contract.
|
|
8
9
|
*/
|
|
9
|
-
export interface OpenAIModelOptions {
|
|
10
|
+
export interface OpenAIModelOptions extends ProviderNamed {
|
|
10
11
|
reasoningEffort?: OpenAI.ReasoningEffort;
|
|
11
12
|
}
|
|
12
13
|
export declare class OpenAIModel implements Model {
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
var _a;
|
|
2
|
+
import { callSites, called, reading } from "../failure.js";
|
|
2
3
|
import { zeroUsage } from "../types.js";
|
|
4
|
+
/** The SDK call these methods make, named as it is named in a failure. */
|
|
5
|
+
const API = 'chat.completions.create';
|
|
3
6
|
// ---------------------------------------------------------------------------
|
|
4
7
|
// OpenAI chat-completions adapter
|
|
5
8
|
// ---------------------------------------------------------------------------
|
|
@@ -20,15 +23,15 @@ export class OpenAIModel {
|
|
|
20
23
|
id;
|
|
21
24
|
#client;
|
|
22
25
|
#reasoningEffort;
|
|
26
|
+
#site;
|
|
23
27
|
constructor(id, client, options = {}) {
|
|
24
28
|
this.id = id;
|
|
25
29
|
this.#client = client;
|
|
26
30
|
this.#reasoningEffort = options.reasoningEffort;
|
|
31
|
+
this.#site = callSites(id, options.provider);
|
|
27
32
|
}
|
|
28
33
|
async generate(req) {
|
|
29
|
-
const res = await this.#client.chat.completions.create(this.#params(req), {
|
|
30
|
-
signal: req.signal,
|
|
31
|
-
});
|
|
34
|
+
const res = await called(this.#site('llm generation', API), () => this.#client.chat.completions.create(this.#params(req), { signal: req.signal }));
|
|
32
35
|
const choice = res.choices[0];
|
|
33
36
|
const message = choice?.message;
|
|
34
37
|
return {
|
|
@@ -42,7 +45,9 @@ export class OpenAIModel {
|
|
|
42
45
|
};
|
|
43
46
|
}
|
|
44
47
|
async stream(req, onDelta) {
|
|
45
|
-
const
|
|
48
|
+
const site = this.#site('llm streaming', API);
|
|
49
|
+
const open = () => this.#client.chat.completions.create({ ...this.#params(req), stream: true, stream_options: { include_usage: true } }, { signal: req.signal });
|
|
50
|
+
const stream = await called(site, open);
|
|
46
51
|
let text = '';
|
|
47
52
|
let thinking = '';
|
|
48
53
|
let usage;
|
|
@@ -50,7 +55,7 @@ export class OpenAIModel {
|
|
|
50
55
|
// Tool calls arrive as deltas keyed by index, with the id and name in the
|
|
51
56
|
// first fragment and arguments trickling in afterwards.
|
|
52
57
|
const calls = new Map();
|
|
53
|
-
for await (const chunk of stream) {
|
|
58
|
+
for await (const chunk of reading(site, stream, open)) {
|
|
54
59
|
if (chunk.usage) {
|
|
55
60
|
usage = toUsage(chunk.usage);
|
|
56
61
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type OpenAI from 'openai';
|
|
2
2
|
import type { StreamDelta } from '../events.ts';
|
|
3
|
+
import { type ProviderNamed } from '../failure.ts';
|
|
3
4
|
import type { Model, ModelRequest, ModelResponse } from '../model.ts';
|
|
4
5
|
/**
|
|
5
6
|
* Provider-specific knobs, mirroring `OpenAIModelOptions` but expressed the way
|
|
6
7
|
* the responses API spells them.
|
|
7
8
|
*/
|
|
8
|
-
export interface OpenAIResponsesModelOptions {
|
|
9
|
+
export interface OpenAIResponsesModelOptions extends ProviderNamed {
|
|
9
10
|
reasoningEffort?: OpenAI.ReasoningEffort;
|
|
10
11
|
/** ask the model for a reasoning summary — the only reasoning text this API exposes */
|
|
11
12
|
reasoningSummary?: 'auto' | 'concise' | 'detailed';
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
var _a;
|
|
2
|
+
import { callSites, called, failed, reading, } from "../failure.js";
|
|
2
3
|
import { zeroUsage } from "../types.js";
|
|
4
|
+
/** The SDK call these methods make, named as it is named in a failure. */
|
|
5
|
+
const API = 'responses.create';
|
|
3
6
|
/**
|
|
4
7
|
* Same `Model` contract as `OpenAIModel`, over `/v1/responses` instead of
|
|
5
8
|
* `/v1/chat/completions`. Reasoning models are the reason to prefer it: effort
|
|
@@ -11,17 +14,17 @@ export class OpenAIResponsesModel {
|
|
|
11
14
|
#reasoningEffort;
|
|
12
15
|
#reasoningSummary;
|
|
13
16
|
#store;
|
|
17
|
+
#site;
|
|
14
18
|
constructor(id, client, options = {}) {
|
|
15
19
|
this.id = id;
|
|
16
20
|
this.#client = client;
|
|
17
21
|
this.#reasoningEffort = options.reasoningEffort;
|
|
18
22
|
this.#reasoningSummary = options.reasoningSummary;
|
|
19
23
|
this.#store = options.store ?? false;
|
|
24
|
+
this.#site = callSites(id, options.provider);
|
|
20
25
|
}
|
|
21
26
|
async generate(req) {
|
|
22
|
-
const res = await this.#client.responses.create(this.#params(req), {
|
|
23
|
-
signal: req.signal,
|
|
24
|
-
});
|
|
27
|
+
const res = await called(this.#site('llm generation', API), () => this.#client.responses.create(this.#params(req), { signal: req.signal }));
|
|
25
28
|
const toolCalls = readToolCalls(res.output);
|
|
26
29
|
return {
|
|
27
30
|
text: readText(res.output),
|
|
@@ -32,7 +35,11 @@ export class OpenAIResponsesModel {
|
|
|
32
35
|
};
|
|
33
36
|
}
|
|
34
37
|
async stream(req, onDelta) {
|
|
35
|
-
const
|
|
38
|
+
const site = this.#site('llm streaming', API);
|
|
39
|
+
const open = () => this.#client.responses.create({ ...this.#params(req), stream: true }, {
|
|
40
|
+
signal: req.signal,
|
|
41
|
+
});
|
|
42
|
+
const stream = await called(site, open);
|
|
36
43
|
let text = '';
|
|
37
44
|
let thinking = '';
|
|
38
45
|
let final;
|
|
@@ -40,7 +47,7 @@ export class OpenAIResponsesModel {
|
|
|
40
47
|
// every delta event carries — that is the only stable key while the
|
|
41
48
|
// items are still being assembled.
|
|
42
49
|
const calls = new Map();
|
|
43
|
-
for await (const event of stream) {
|
|
50
|
+
for await (const event of reading(site, stream, open)) {
|
|
44
51
|
// Some models/gateways emit `response.reasoning.delta`, which the
|
|
45
52
|
// SDK does not carry in its event union, so it is matched before
|
|
46
53
|
// the typed switch.
|
|
@@ -103,9 +110,17 @@ export class OpenAIResponsesModel {
|
|
|
103
110
|
}
|
|
104
111
|
break;
|
|
105
112
|
}
|
|
106
|
-
case 'response.completed':
|
|
107
|
-
case 'response.incomplete':
|
|
108
113
|
case 'response.failed': {
|
|
114
|
+
// The request was accepted, so the refusal arrives as an
|
|
115
|
+
// event in a 200 rather than as a status. Returning it as a
|
|
116
|
+
// response would make it an empty answer.
|
|
117
|
+
const said = event.response.error;
|
|
118
|
+
throw failed(site, Object.assign(new Error(said?.message ?? 'the response failed'), {
|
|
119
|
+
code: said?.code,
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
case 'response.completed':
|
|
123
|
+
case 'response.incomplete': {
|
|
109
124
|
final = event.response;
|
|
110
125
|
break;
|
|
111
126
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { OpenRouter } from '@openrouter/sdk';
|
|
2
2
|
import type { ChatRequestPlugin, ProviderPreferences } from '@openrouter/sdk/models';
|
|
3
3
|
import type { StreamDelta } from '../events.ts';
|
|
4
|
+
import { type ProviderNamed } from '../failure.ts';
|
|
4
5
|
import type { Model, ModelRequest, ModelResponse } from '../model.ts';
|
|
5
6
|
/**
|
|
6
7
|
* Which failures the SDK's backoff applies to: rate limits, request timeouts,
|
|
@@ -21,7 +22,7 @@ export declare const RETRY_STATUS_CODES: string[];
|
|
|
21
22
|
*/
|
|
22
23
|
export type OpenRouterEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;
|
|
23
24
|
/** Provider-specific knobs. */
|
|
24
|
-
export interface OpenRouterModelOptions {
|
|
25
|
+
export interface OpenRouterModelOptions extends ProviderNamed {
|
|
25
26
|
reasoningEffort?: OpenRouterEffort;
|
|
26
27
|
/** ask for a reasoning summary from models that expose one */
|
|
27
28
|
reasoningSummary?: 'auto' | 'concise' | 'detailed';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var _a;
|
|
2
|
+
import { callSites, called, reading } from "../failure.js";
|
|
2
3
|
import { zeroUsage } from "../types.js";
|
|
3
4
|
// ---------------------------------------------------------------------------
|
|
4
5
|
// OpenRouter adapter
|
|
@@ -72,13 +73,15 @@ export class OpenRouterModel {
|
|
|
72
73
|
id;
|
|
73
74
|
#client;
|
|
74
75
|
#options;
|
|
76
|
+
#site;
|
|
75
77
|
constructor(id, client, options = {}) {
|
|
76
78
|
this.id = id;
|
|
77
79
|
this.#client = client;
|
|
78
80
|
this.#options = options;
|
|
81
|
+
this.#site = callSites(id, options.provider);
|
|
79
82
|
}
|
|
80
83
|
async generate(req) {
|
|
81
|
-
const res = await this.#send(req, false);
|
|
84
|
+
const res = await called(this.#site('llm generation', 'chat.send'), () => this.#send(req, false));
|
|
82
85
|
// Both overloads are declared to return the same union, so the narrowing
|
|
83
86
|
// the `stream` flag implies has to be done here.
|
|
84
87
|
if (Symbol.asyncIterator in res) {
|
|
@@ -99,10 +102,15 @@ export class OpenRouterModel {
|
|
|
99
102
|
};
|
|
100
103
|
}
|
|
101
104
|
async stream(req, onDelta) {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
const site = this.#site('llm streaming', 'chat.send');
|
|
106
|
+
const open = async () => {
|
|
107
|
+
const res = await this.#send(req, true);
|
|
108
|
+
if (!(Symbol.asyncIterator in res)) {
|
|
109
|
+
throw new Error(`model "${this.id}": asked for a stream, got one completion`);
|
|
110
|
+
}
|
|
111
|
+
return res;
|
|
112
|
+
};
|
|
113
|
+
const res = await called(site, open);
|
|
106
114
|
let text = '';
|
|
107
115
|
let thinking = '';
|
|
108
116
|
let usage;
|
|
@@ -110,7 +118,7 @@ export class OpenRouterModel {
|
|
|
110
118
|
// Tool calls arrive as deltas keyed by index, with the id and name in the
|
|
111
119
|
// first fragment and arguments trickling in afterwards.
|
|
112
120
|
const calls = new Map();
|
|
113
|
-
for await (const chunk of res) {
|
|
121
|
+
for await (const chunk of reading(site, res, open)) {
|
|
114
122
|
// An upstream failure mid-stream arrives as a chunk on a 200, so it
|
|
115
123
|
// has to be raised here or the turn ends early and looks complete.
|
|
116
124
|
if (chunk.error) {
|
package/dist/project/config.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ declare const provider: z.ZodObject<{
|
|
|
18
18
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
19
19
|
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
20
20
|
maxRetries: z.ZodOptional<z.ZodInt>;
|
|
21
|
+
concurrency: z.ZodOptional<z.ZodInt>;
|
|
21
22
|
apiKey: z.ZodOptional<z.ZodString>;
|
|
22
23
|
apiKeyEnv: z.ZodOptional<z.ZodString>;
|
|
23
24
|
baseURL: z.ZodOptional<z.ZodString>;
|
|
@@ -47,10 +48,10 @@ declare const modelSpec: z.ZodObject<{
|
|
|
47
48
|
thinkingBudgetTokens: z.ZodOptional<z.ZodInt>;
|
|
48
49
|
thinkingBudget: z.ZodOptional<z.ZodInt>;
|
|
49
50
|
thinkingLevel: z.ZodOptional<z.ZodEnum<{
|
|
50
|
-
minimal: "minimal";
|
|
51
51
|
low: "low";
|
|
52
52
|
medium: "medium";
|
|
53
53
|
high: "high";
|
|
54
|
+
minimal: "minimal";
|
|
54
55
|
}>>;
|
|
55
56
|
includeThoughts: z.ZodOptional<z.ZodBoolean>;
|
|
56
57
|
routing: z.ZodOptional<z.ZodObject<{
|
|
@@ -93,6 +94,7 @@ declare const embeddingSpec: z.ZodObject<{
|
|
|
93
94
|
dimensions: z.ZodOptional<z.ZodInt>;
|
|
94
95
|
title: z.ZodOptional<z.ZodString>;
|
|
95
96
|
maxBatch: z.ZodOptional<z.ZodInt>;
|
|
97
|
+
maxBatchTokens: z.ZodOptional<z.ZodInt>;
|
|
96
98
|
routing: z.ZodOptional<z.ZodObject<{
|
|
97
99
|
order: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
98
100
|
only: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -112,6 +114,34 @@ declare const embeddingSpec: z.ZodObject<{
|
|
|
112
114
|
baseURL: z.ZodOptional<z.ZodString>;
|
|
113
115
|
baseURLEnv: z.ZodOptional<z.ZodString>;
|
|
114
116
|
}, z.core.$strict>;
|
|
117
|
+
/**
|
|
118
|
+
* What an agent may do with the project's one memory graph, and which slice of
|
|
119
|
+
* it it can see. Both lists are audience labels; `'*'` is the public slice and
|
|
120
|
+
* is always readable, so `sees` can only ever widen from there.
|
|
121
|
+
*
|
|
122
|
+
* `sees` and `writes` are here and not in any tool schema on purpose: an agent
|
|
123
|
+
* that could name its own audience could read another agent's slice just by
|
|
124
|
+
* asking for it.
|
|
125
|
+
*/
|
|
126
|
+
declare const memoryBinding: z.ZodObject<{
|
|
127
|
+
access: z.ZodDefault<z.ZodEnum<{
|
|
128
|
+
read: "read";
|
|
129
|
+
"read-write": "read-write";
|
|
130
|
+
full: "full";
|
|
131
|
+
}>>;
|
|
132
|
+
sees: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
133
|
+
writes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
134
|
+
autoRecall: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
135
|
+
limit: z.ZodDefault<z.ZodInt>;
|
|
136
|
+
}, z.core.$strict>]>>;
|
|
137
|
+
}, z.core.$strict>;
|
|
138
|
+
/** Where the project's memory lives, and what vectorises it. */
|
|
139
|
+
declare const memoryConfig: z.ZodObject<{
|
|
140
|
+
dir: z.ZodDefault<z.ZodString>;
|
|
141
|
+
embedding: z.ZodOptional<z.ZodString>;
|
|
142
|
+
kinds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
143
|
+
relations: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
144
|
+
}, z.core.$strict>;
|
|
115
145
|
/**
|
|
116
146
|
* A Dockerfile to build instead of an image to pull, for the ordinary case the
|
|
117
147
|
* `image:` key cannot serve: a project that needs two runtimes, or a pinned
|
|
@@ -161,6 +191,7 @@ export declare const projectSchema: z.ZodObject<{
|
|
|
161
191
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
162
192
|
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
163
193
|
maxRetries: z.ZodOptional<z.ZodInt>;
|
|
194
|
+
concurrency: z.ZodOptional<z.ZodInt>;
|
|
164
195
|
apiKey: z.ZodOptional<z.ZodString>;
|
|
165
196
|
apiKeyEnv: z.ZodOptional<z.ZodString>;
|
|
166
197
|
baseURL: z.ZodOptional<z.ZodString>;
|
|
@@ -185,10 +216,10 @@ export declare const projectSchema: z.ZodObject<{
|
|
|
185
216
|
thinkingBudgetTokens: z.ZodOptional<z.ZodInt>;
|
|
186
217
|
thinkingBudget: z.ZodOptional<z.ZodInt>;
|
|
187
218
|
thinkingLevel: z.ZodOptional<z.ZodEnum<{
|
|
188
|
-
minimal: "minimal";
|
|
189
219
|
low: "low";
|
|
190
220
|
medium: "medium";
|
|
191
221
|
high: "high";
|
|
222
|
+
minimal: "minimal";
|
|
192
223
|
}>>;
|
|
193
224
|
includeThoughts: z.ZodOptional<z.ZodBoolean>;
|
|
194
225
|
routing: z.ZodOptional<z.ZodObject<{
|
|
@@ -226,6 +257,7 @@ export declare const projectSchema: z.ZodObject<{
|
|
|
226
257
|
dimensions: z.ZodOptional<z.ZodInt>;
|
|
227
258
|
title: z.ZodOptional<z.ZodString>;
|
|
228
259
|
maxBatch: z.ZodOptional<z.ZodInt>;
|
|
260
|
+
maxBatchTokens: z.ZodOptional<z.ZodInt>;
|
|
229
261
|
routing: z.ZodOptional<z.ZodObject<{
|
|
230
262
|
order: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
231
263
|
only: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -268,6 +300,12 @@ export declare const projectSchema: z.ZodObject<{
|
|
|
268
300
|
env: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
269
301
|
keys: z.ZodOptional<z.ZodBoolean>;
|
|
270
302
|
}, z.core.$strict>>;
|
|
303
|
+
memory: z.ZodOptional<z.ZodObject<{
|
|
304
|
+
dir: z.ZodDefault<z.ZodString>;
|
|
305
|
+
embedding: z.ZodOptional<z.ZodString>;
|
|
306
|
+
kinds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
307
|
+
relations: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
308
|
+
}, z.core.$strict>>;
|
|
271
309
|
agents: z.ZodArray<z.ZodObject<{
|
|
272
310
|
name: z.ZodString;
|
|
273
311
|
description: z.ZodOptional<z.ZodString>;
|
|
@@ -278,8 +316,8 @@ export declare const projectSchema: z.ZodObject<{
|
|
|
278
316
|
skills: z.ZodOptional<z.ZodObject<{
|
|
279
317
|
provider: z.ZodOptional<z.ZodString>;
|
|
280
318
|
discovery: z.ZodDefault<z.ZodEnum<{
|
|
281
|
-
search: "search";
|
|
282
319
|
none: "none";
|
|
320
|
+
search: "search";
|
|
283
321
|
index: "index";
|
|
284
322
|
}>>;
|
|
285
323
|
allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -290,6 +328,18 @@ export declare const projectSchema: z.ZodObject<{
|
|
|
290
328
|
agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
291
329
|
maxBranches: z.ZodOptional<z.ZodInt>;
|
|
292
330
|
}, z.core.$strict>]>>;
|
|
331
|
+
memory: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodObject<{
|
|
332
|
+
access: z.ZodDefault<z.ZodEnum<{
|
|
333
|
+
read: "read";
|
|
334
|
+
"read-write": "read-write";
|
|
335
|
+
full: "full";
|
|
336
|
+
}>>;
|
|
337
|
+
sees: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
338
|
+
writes: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
339
|
+
autoRecall: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
340
|
+
limit: z.ZodDefault<z.ZodInt>;
|
|
341
|
+
}, z.core.$strict>]>>;
|
|
342
|
+
}, z.core.$strict>>>>;
|
|
293
343
|
sandbox: z.ZodOptional<z.ZodObject<{
|
|
294
344
|
image: z.ZodOptional<z.ZodString>;
|
|
295
345
|
build: z.ZodOptional<z.ZodObject<{
|
|
@@ -320,6 +370,8 @@ export type ModelConfig = z.infer<typeof modelSpec>;
|
|
|
320
370
|
export type EmbeddingConfig = z.infer<typeof embeddingSpec>;
|
|
321
371
|
export type SandboxConfig = z.infer<typeof sandbox>;
|
|
322
372
|
export type SandboxBuildConfig = z.infer<typeof build>;
|
|
373
|
+
export type MemoryConfig = z.infer<typeof memoryConfig>;
|
|
374
|
+
export type MemoryBindingConfig = z.infer<typeof memoryBinding>;
|
|
323
375
|
/**
|
|
324
376
|
* Re-renders a zod failure as `agents.yaml: agents[1].skills.discovery — …`.
|
|
325
377
|
*
|
package/dist/project/config.js
CHANGED
|
@@ -46,6 +46,13 @@ const provider = z
|
|
|
46
46
|
headers: z.record(z.string().min(1), z.string()).optional(),
|
|
47
47
|
timeoutMs: z.number().positive().optional(),
|
|
48
48
|
maxRetries: z.int().nonnegative().optional(),
|
|
49
|
+
/**
|
|
50
|
+
* Ceiling on embedding requests in flight against this connection. The
|
|
51
|
+
* working number is discovered from the provider's own refusals; this
|
|
52
|
+
* only caps how high that may climb, for a key shared with something
|
|
53
|
+
* else that also needs quota.
|
|
54
|
+
*/
|
|
55
|
+
concurrency: z.int().positive().optional(),
|
|
49
56
|
})
|
|
50
57
|
.strict();
|
|
51
58
|
/**
|
|
@@ -120,8 +127,13 @@ const embeddingSpec = z
|
|
|
120
127
|
dimensions: z.int().positive().optional(),
|
|
121
128
|
/** gemini only: a document title the retrieval task type takes into account */
|
|
122
129
|
title: z.string().min(1).optional(),
|
|
123
|
-
/**
|
|
130
|
+
/**
|
|
131
|
+
* Ceilings on how a batch is split into requests. Both default to what
|
|
132
|
+
* the model is known to accept, so setting them is for a gateway whose
|
|
133
|
+
* caps are not the vendor's.
|
|
134
|
+
*/
|
|
124
135
|
maxBatch: z.int().positive().optional(),
|
|
136
|
+
maxBatchTokens: z.int().positive().optional(),
|
|
125
137
|
/** openrouter only: who serves the request */
|
|
126
138
|
routing: routing.optional(),
|
|
127
139
|
})
|
|
@@ -156,6 +168,52 @@ const forkBinding = z
|
|
|
156
168
|
maxBranches: z.int().min(2).optional(),
|
|
157
169
|
})
|
|
158
170
|
.strict();
|
|
171
|
+
/**
|
|
172
|
+
* What an agent may do with the project's one memory graph, and which slice of
|
|
173
|
+
* it it can see. Both lists are audience labels; `'*'` is the public slice and
|
|
174
|
+
* is always readable, so `sees` can only ever widen from there.
|
|
175
|
+
*
|
|
176
|
+
* `sees` and `writes` are here and not in any tool schema on purpose: an agent
|
|
177
|
+
* that could name its own audience could read another agent's slice just by
|
|
178
|
+
* asking for it.
|
|
179
|
+
*/
|
|
180
|
+
const memoryBinding = z
|
|
181
|
+
.object({
|
|
182
|
+
access: z.enum(['read', 'read-write', 'full']).default('read-write'),
|
|
183
|
+
/** audience labels this agent may read, on top of the public slice */
|
|
184
|
+
sees: z.array(name).optional(),
|
|
185
|
+
/** labels it may put on what it writes */
|
|
186
|
+
writes: z.array(name).optional(),
|
|
187
|
+
/**
|
|
188
|
+
* Recall before a turn that follows new user input, rather than before
|
|
189
|
+
* every call: recalling on every turn costs tokens and defeats prompt
|
|
190
|
+
* caching for a marginal gain. `false` leaves the agent the tools and
|
|
191
|
+
* lets it decide when to look.
|
|
192
|
+
*/
|
|
193
|
+
autoRecall: z
|
|
194
|
+
.union([z.boolean(), z.object({ limit: z.int().positive().default(5) }).strict()])
|
|
195
|
+
.optional(),
|
|
196
|
+
})
|
|
197
|
+
.strict();
|
|
198
|
+
/** Where the project's memory lives, and what vectorises it. */
|
|
199
|
+
const memoryConfig = z
|
|
200
|
+
.object({
|
|
201
|
+
/** relative to the project root */
|
|
202
|
+
dir: z.string().min(1).default('memory'),
|
|
203
|
+
/**
|
|
204
|
+
* A name from `embeddings:`. Without one, recall ranks by term overlap
|
|
205
|
+
* — which works, but only finds the words the agent happened to reuse.
|
|
206
|
+
*/
|
|
207
|
+
embedding: modelRef.optional(),
|
|
208
|
+
/**
|
|
209
|
+
* Closed vocabularies. Absent means the built-in sets, which is almost
|
|
210
|
+
* always right: a kind nothing else understands is a kind no other
|
|
211
|
+
* agent can search for.
|
|
212
|
+
*/
|
|
213
|
+
kinds: z.array(name).min(1).optional(),
|
|
214
|
+
relations: z.array(name).min(1).optional(),
|
|
215
|
+
})
|
|
216
|
+
.strict();
|
|
159
217
|
/**
|
|
160
218
|
* The container command-line tools run in.
|
|
161
219
|
*
|
|
@@ -263,6 +321,17 @@ const agent = z
|
|
|
263
321
|
skills: skillsBinding.optional(),
|
|
264
322
|
/** parallel sub-agents; `true` is the unrestricted form */
|
|
265
323
|
fork: z.union([z.boolean(), forkBinding]).optional(),
|
|
324
|
+
/**
|
|
325
|
+
* The shared memory graph. `true` is the whole feature working the
|
|
326
|
+
* obvious way — read and write, with auto-recall on.
|
|
327
|
+
*
|
|
328
|
+
* Normalised before validation rather than unioned with a boolean, so
|
|
329
|
+
* that a misspelled key inside the block is reported as
|
|
330
|
+
* `agents[0].memory.scope` instead of collapsing to "invalid input".
|
|
331
|
+
*/
|
|
332
|
+
memory: z
|
|
333
|
+
.preprocess((v) => (typeof v === 'boolean' ? (v ? {} : undefined) : v), memoryBinding.optional())
|
|
334
|
+
.optional(),
|
|
266
335
|
/**
|
|
267
336
|
* Overrides on the project's sandbox. An agent that overrides nothing
|
|
268
337
|
* shares the container with everyone else, which is what a hand-off
|
|
@@ -304,6 +373,12 @@ export const projectSchema = z
|
|
|
304
373
|
assets: z.string().min(1).optional(),
|
|
305
374
|
/** the container `run_command` and friends execute in */
|
|
306
375
|
sandbox: sandbox.optional(),
|
|
376
|
+
/**
|
|
377
|
+
* The one graph every agent's `memory:` binding is a view onto. Declare
|
|
378
|
+
* it to choose where it lives or what embeds it; an agent that opts in
|
|
379
|
+
* without this block gets the defaults.
|
|
380
|
+
*/
|
|
381
|
+
memory: memoryConfig.optional(),
|
|
307
382
|
agents: z.array(agent).min(1),
|
|
308
383
|
})
|
|
309
384
|
.strict();
|
package/dist/project/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { parseConfig, projectSchema, type AgentConfig, type EmbeddingConfig, type ModelConfig, type ProjectConfig, type ProviderConfig, type SandboxBuildConfig, type SandboxConfig, } from './config.ts';
|
|
2
|
-
export { AgentProject, assetsDir, loadProject, projectRegistry, readProjectConfig, skillDirs, skillMounts, type ProjectOptions, type ProjectSource, } from './load.ts';
|
|
1
|
+
export { parseConfig, projectSchema, type AgentConfig, type EmbeddingConfig, type MemoryBindingConfig, type MemoryConfig, type ModelConfig, type ProjectConfig, type ProviderConfig, type SandboxBuildConfig, type SandboxConfig, } from './config.ts';
|
|
2
|
+
export { AgentProject, assetsDir, loadProject, memoryDir, projectRegistry, readProjectConfig, skillDirs, skillMounts, type ProjectOptions, type ProjectSource, } from './load.ts';
|
|
3
3
|
export { projectDir, projectFile, projectPath, projectRoot } from './refs.ts';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|