@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.
Files changed (90) hide show
  1. package/README.md +3 -3
  2. package/dist/agent.d.ts +8 -7
  3. package/dist/agent.js +15 -8
  4. package/dist/architecture.d.ts +7 -5
  5. package/dist/architecture.js +20 -12
  6. package/dist/embedding.d.ts +20 -1
  7. package/dist/embedding.js +3 -2
  8. package/dist/embeddings/fanout.d.ts +51 -0
  9. package/dist/embeddings/fanout.js +76 -0
  10. package/dist/embeddings/gemini.d.ts +3 -10
  11. package/dist/embeddings/gemini.js +46 -30
  12. package/dist/embeddings/index.d.ts +3 -0
  13. package/dist/embeddings/index.js +3 -0
  14. package/dist/embeddings/limiter.d.ts +36 -0
  15. package/dist/embeddings/limiter.js +182 -0
  16. package/dist/embeddings/openai.d.ts +3 -2
  17. package/dist/embeddings/openai.js +54 -13
  18. package/dist/embeddings/openrouter.d.ts +2 -1
  19. package/dist/embeddings/openrouter.js +52 -23
  20. package/dist/embeddings/rate-limit.d.ts +16 -0
  21. package/dist/embeddings/rate-limit.js +131 -0
  22. package/dist/failure.d.ts +82 -0
  23. package/dist/failure.js +323 -0
  24. package/dist/index.d.ts +13 -2
  25. package/dist/index.js +13 -2
  26. package/dist/inspect/client.d.ts +1 -1
  27. package/dist/inspect/client.js +42 -26
  28. package/dist/kernel.d.ts +1 -1
  29. package/dist/kernel.js +40 -23
  30. package/dist/memory/files.d.ts +24 -0
  31. package/dist/memory/files.js +85 -0
  32. package/dist/memory/graph.d.ts +56 -0
  33. package/dist/memory/graph.js +159 -0
  34. package/dist/memory/index.d.ts +93 -0
  35. package/dist/memory/index.js +357 -0
  36. package/dist/memory/instructions.d.ts +15 -0
  37. package/dist/memory/instructions.js +103 -0
  38. package/dist/memory/page.d.ts +8 -0
  39. package/dist/memory/page.js +797 -0
  40. package/dist/memory/recall.d.ts +35 -0
  41. package/dist/memory/recall.js +161 -0
  42. package/dist/memory/render.d.ts +10 -0
  43. package/dist/memory/render.js +228 -0
  44. package/dist/memory/report.d.ts +57 -0
  45. package/dist/memory/report.js +113 -0
  46. package/dist/memory/store.d.ts +49 -0
  47. package/dist/memory/store.js +226 -0
  48. package/dist/memory/tools.d.ts +11 -0
  49. package/dist/memory/tools.js +310 -0
  50. package/dist/memory/types.d.ts +192 -0
  51. package/dist/memory/types.js +105 -0
  52. package/dist/memory/vectors.d.ts +29 -0
  53. package/dist/memory/vectors.js +152 -0
  54. package/dist/models/anthropic.d.ts +2 -1
  55. package/dist/models/anthropic.js +11 -4
  56. package/dist/models/factory.d.ts +15 -0
  57. package/dist/models/factory.js +49 -10
  58. package/dist/models/gemini.d.ts +2 -1
  59. package/dist/models/gemini.js +8 -3
  60. package/dist/models/openai-chat.d.ts +2 -1
  61. package/dist/models/openai-chat.js +10 -5
  62. package/dist/models/openai-responses.d.ts +2 -1
  63. package/dist/models/openai-responses.js +22 -7
  64. package/dist/models/openrouter.d.ts +2 -1
  65. package/dist/models/openrouter.js +14 -6
  66. package/dist/project/config.d.ts +55 -3
  67. package/dist/project/config.js +76 -1
  68. package/dist/project/index.d.ts +2 -2
  69. package/dist/project/index.js +1 -1
  70. package/dist/project/load.d.ts +16 -2
  71. package/dist/project/load.js +67 -1
  72. package/dist/runner.d.ts +4 -2
  73. package/dist/runner.js +29 -30
  74. package/dist/services.d.ts +23 -6
  75. package/dist/services.js +25 -15
  76. package/dist/tools/workspace.js +195 -17
  77. package/dist/trajectory.d.ts +14 -12
  78. package/dist/types.d.ts +5 -5
  79. package/dist/types.js +3 -3
  80. package/package.json +2 -5
  81. package/dist/memory-stores/factory.d.ts +0 -15
  82. package/dist/memory-stores/factory.js +0 -29
  83. package/dist/memory-stores/file.d.ts +0 -37
  84. package/dist/memory-stores/file.js +0 -174
  85. package/dist/memory-stores/in-memory.d.ts +0 -17
  86. package/dist/memory-stores/in-memory.js +0 -80
  87. package/dist/memory-stores/index.d.ts +0 -4
  88. package/dist/memory-stores/index.js +0 -5
  89. package/dist/memory.d.ts +0 -115
  90. package/dist/memory.js +0 -213
@@ -0,0 +1,323 @@
1
+ import { classify, isAbort, statusOf } from "./embeddings/rate-limit.js";
2
+ export const callSites = (model, provider) => (doing, api) => ({ doing, api, model, provider });
3
+ const ONCE = { attempts: 1, elapsedMs: 0 };
4
+ /** A provider call that failed, with the call it was. */
5
+ export class ProviderError extends Error {
6
+ site;
7
+ /** the vendor's own sentence, unwrapped out of whatever it arrived in */
8
+ detail;
9
+ /** the HTTP status, wherever the SDK or the body left it */
10
+ status;
11
+ attempts;
12
+ elapsedMs;
13
+ chunks;
14
+ constructor(site, detail, status, cause, tried = ONCE) {
15
+ super(`${site.doing} failed — ${where(site)}: ${detail}${trailer(tried)}`, { cause });
16
+ this.name = 'ProviderError';
17
+ this.site = site;
18
+ this.detail = detail;
19
+ this.status = status;
20
+ this.attempts = tried.attempts;
21
+ this.elapsedMs = tried.elapsedMs;
22
+ this.chunks = tried.chunks;
23
+ }
24
+ }
25
+ /**
26
+ * What the failure cost, when that is worth a person's attention. A call that
27
+ * failed at once and was never retried spent nothing worth reporting, and the
28
+ * message is long already.
29
+ */
30
+ function trailer(tried) {
31
+ const said = [];
32
+ if (tried.attempts > 1) {
33
+ said.push(`${tried.attempts} attempts`);
34
+ }
35
+ if (tried.elapsedMs >= 1_000) {
36
+ said.push(`${(tried.elapsedMs / 1000).toFixed(1)}s`);
37
+ }
38
+ if (tried.chunks) {
39
+ // Says why it was not retried, which is the first thing asked of a
40
+ // connection that dropped.
41
+ const many = tried.chunks === 1 ? '' : 's';
42
+ said.push(`${tried.chunks} chunk${many} in, too late to retry`);
43
+ }
44
+ return said.length ? ` [after ${said.join(', ')}]` : '';
45
+ }
46
+ const where = (site) => `${site.provider ? `${site.provider} ` : ''}${site.api}, model "${site.model}"`;
47
+ /** Runs one provider call, and makes sure a refusal says what it refused. */
48
+ export async function called(site, run) {
49
+ const started = Date.now();
50
+ try {
51
+ return await run();
52
+ }
53
+ catch (err) {
54
+ // The SDK's own retries are inside this: an OpenAI or Vertex client
55
+ // gives up only after four of them, so the elapsed time is the only
56
+ // report of what the wait was spent on.
57
+ throw failed(site, err, { attempts: 1, elapsedMs: Date.now() - started });
58
+ }
59
+ }
60
+ /**
61
+ * Attempts to reopen a stream that broke before it said anything, and the pause
62
+ * before each. Short on purpose: the client's own backoff has already been
63
+ * spent getting the request accepted, and a body that dies on an accepted
64
+ * connection is usually a dropped socket rather than a busy server.
65
+ */
66
+ const REOPEN = 2;
67
+ const REOPEN_BACKOFF_MS = 300;
68
+ /**
69
+ * The same for a response body: an HTTP error, and every mid-stream failure,
70
+ * arrives while the stream is being read — long after the call that opened it
71
+ * returned successfully. None of the SDKs retry that: their backoff wraps the
72
+ * request, and by the time a body is being consumed the request has succeeded.
73
+ *
74
+ * So this does, but only while nothing has come out of it. A connection reset
75
+ * before the first chunk is indistinguishable from one that never opened, and
76
+ * reopening is invisible to the caller. One chunk later it is not: the deltas
77
+ * have been delivered, a second stream would repeat them, and the failure has
78
+ * to be reported instead.
79
+ */
80
+ export async function* reading(site, source, reopen) {
81
+ const started = Date.now();
82
+ let stream = source;
83
+ let chunks = 0;
84
+ for (let attempt = 1;; attempt++) {
85
+ try {
86
+ for await (const item of stream) {
87
+ chunks++;
88
+ yield item;
89
+ }
90
+ return;
91
+ }
92
+ catch (err) {
93
+ const again = reopen &&
94
+ chunks === 0 &&
95
+ attempt <= REOPEN &&
96
+ !isAbort(err) &&
97
+ classify(err) !== 'fatal';
98
+ if (!again) {
99
+ throw failed(site, err, {
100
+ attempts: attempt,
101
+ elapsedMs: Date.now() - started,
102
+ chunks,
103
+ });
104
+ }
105
+ await sleep(REOPEN_BACKOFF_MS * attempt);
106
+ stream = await reopen();
107
+ }
108
+ }
109
+ }
110
+ const sleep = (ms) => new Promise((done) => setTimeout(done, ms));
111
+ /** Names for "the caller stopped waiting", which are not the provider's doing. */
112
+ const INTERRUPTED = new Set(['AbortError', 'TimeoutError']);
113
+ /** The error to throw in place of `err`, which may be `err` itself. */
114
+ export function failed(site, err, tried = ONCE) {
115
+ // An abort is the caller's own decision and a deadline is the caller's own
116
+ // clock. Both are recognised by name upstream, so neither is rewritten.
117
+ const name = err?.name;
118
+ if (err instanceof ProviderError ||
119
+ isAbort(err) ||
120
+ (typeof name === 'string' && INTERRUPTED.has(name))) {
121
+ return err;
122
+ }
123
+ const { detail, status } = explain(err);
124
+ return new ProviderError(site, detail, status, err, tried);
125
+ }
126
+ /** Bodies nest at most this deep before the unwrapping is the bug. */
127
+ const MAX_UNWRAP = 4;
128
+ /** Words that name a category of failure without naming the failure. */
129
+ const OPAQUE = /^(fetch failed|failed to fetch|terminated|internal error)\.?$/i;
130
+ /** Longer than this is a document, not a sentence. */
131
+ const MAX_DETAIL = 500;
132
+ /**
133
+ * The sentence a vendor buried, and the status it came with. Exported because
134
+ * it is useful anywhere a raw provider error has to be shown to someone.
135
+ */
136
+ export function explain(err) {
137
+ let status = statusOf(err);
138
+ let code;
139
+ let about;
140
+ let text = messageOf(err);
141
+ // Unwrapping once is not enough — Google's body holds a body — and
142
+ // unwrapping until it stops is a loop waiting for a self-quoting error.
143
+ for (let depth = 0; depth < MAX_UNWRAP; depth++) {
144
+ const said = body(text);
145
+ if (!said) {
146
+ break;
147
+ }
148
+ // The innermost wins: the outer layer says `Bad Request`, the inner one
149
+ // says which argument was invalid.
150
+ status = said.status ?? status;
151
+ code = said.code ?? code;
152
+ about = said.about ?? about;
153
+ text = said.message;
154
+ }
155
+ code ??= symbolOf(err);
156
+ // A failure raised from inside a stream has no HTTP status to carry: the
157
+ // response was a 200 and the refusal arrived as an event in it. The vendor's
158
+ // own word for what went wrong is the only thing left to classify on, and
159
+ // everything downstream — the retry limiter, the CLI's liveness probe —
160
+ // classifies on the status.
161
+ status ??= code ? STATUS.get(code.toLowerCase()) : undefined;
162
+ // `Request contains an invalid argument` names no argument. The vendor's
163
+ // `details` are where the field that was wrong is, when it is anywhere.
164
+ text = collapse(about ? `${text.trim()} — ${about}` : text);
165
+ if (!text || OPAQUE.test(text)) {
166
+ // `fetch failed` is undici's word for DNS, refused, TLS and timeout
167
+ // alike; the reason is only ever in the cause.
168
+ const because = blamed(err, text);
169
+ text = because ? (text ? `${text} — ${because}` : because) : text;
170
+ }
171
+ return { detail: mark(text || String(err), status, code), status };
172
+ }
173
+ const messageOf = (err) => err instanceof Error ? err.message : typeof err === 'string' ? err : String(err);
174
+ /** The vendor's word for the kind of refusal, off the error object itself. */
175
+ function symbolOf(err) {
176
+ for (const link of chain(err)) {
177
+ for (const key of ['code', 'type']) {
178
+ const said = link[key];
179
+ if (typeof said === 'string' && said) {
180
+ return said;
181
+ }
182
+ }
183
+ }
184
+ return undefined;
185
+ }
186
+ /** The error and everything it blames, guarded against a self-referential cause. */
187
+ function* chain(err) {
188
+ const seen = new Set();
189
+ for (let at = err; at && typeof at === 'object' && !seen.has(at); at = cause(at)) {
190
+ seen.add(at);
191
+ yield at;
192
+ }
193
+ }
194
+ const cause = (err) => err.cause;
195
+ /**
196
+ * What a symbolic refusal would have been as an HTTP status, for the vendors
197
+ * that omit one. Only the unambiguous ones: a guess here is a retry decision.
198
+ */
199
+ const STATUS = new Map([
200
+ ['invalid_request_error', 400],
201
+ ['invalid_argument', 400],
202
+ ['context_length_exceeded', 400],
203
+ ['authentication_error', 401],
204
+ ['unauthenticated', 401],
205
+ ['permission_error', 403],
206
+ ['permission_denied', 403],
207
+ ['not_found_error', 404],
208
+ ['not_found', 404],
209
+ ['rate_limit_error', 429],
210
+ ['rate_limit_exceeded', 429],
211
+ ['resource_exhausted', 429],
212
+ ['api_error', 500],
213
+ ['internal', 500],
214
+ ['unavailable', 503],
215
+ ['overloaded_error', 529],
216
+ ]);
217
+ /** A JSON error body, wherever the message happens to begin with one. */
218
+ function body(text) {
219
+ const start = text.indexOf('{');
220
+ if (start === -1) {
221
+ return undefined;
222
+ }
223
+ let parsed;
224
+ try {
225
+ parsed = JSON.parse(text.slice(start));
226
+ }
227
+ catch {
228
+ // Not JSON, or a body cut short. What is already in hand is the answer.
229
+ return undefined;
230
+ }
231
+ const root = parsed;
232
+ const error = root?.error ?? root;
233
+ if (typeof error === 'string') {
234
+ return { message: error };
235
+ }
236
+ if (!error || typeof error !== 'object') {
237
+ return undefined;
238
+ }
239
+ const said = error;
240
+ if (typeof said.message !== 'string') {
241
+ return undefined;
242
+ }
243
+ return {
244
+ message: said.message,
245
+ // `code` is the status on Google and a symbol on OpenAI; `status` is
246
+ // the other way round. Which is which is decided by the type, not by
247
+ // the vendor. `type` is where OpenAI and Anthropic keep the kind.
248
+ status: typeof said.code === 'number' ? said.code : undefined,
249
+ code: typeof said.status === 'string'
250
+ ? said.status
251
+ : typeof said.code === 'string'
252
+ ? said.code
253
+ : typeof said.type === 'string'
254
+ ? said.type
255
+ : undefined,
256
+ about: aboutOf(said.details) ?? (typeof said.param === 'string' ? said.param : undefined),
257
+ };
258
+ }
259
+ /** Names of the field a `google.rpc` detail is about, and of what was wrong with it. */
260
+ const VIOLATION = ['field', 'description', 'reason', 'detail', 'message'];
261
+ /**
262
+ * What a vendor's `details` array says, flattened to one clause.
263
+ *
264
+ * This is where a 400 keeps the part a person needs: the top-level message is
265
+ * `Request contains an invalid argument`, and `fieldViolations[0].field` is the
266
+ * argument. The shapes are `google.rpc.BadRequest`, `ErrorInfo` and `DebugInfo`
267
+ * — read by the field names they have in common rather than by `@type`, since
268
+ * a detail nobody anticipated is still worth printing.
269
+ */
270
+ function aboutOf(details) {
271
+ if (!Array.isArray(details)) {
272
+ return undefined;
273
+ }
274
+ const clauses = [];
275
+ for (const entry of details.flatMap(violations)) {
276
+ if (!entry || typeof entry !== 'object') {
277
+ continue;
278
+ }
279
+ const said = entry;
280
+ const parts = VIOLATION.map((key) => said[key]).filter((v) => typeof v === 'string' && v.length > 0);
281
+ if (parts.length) {
282
+ clauses.push(parts.join(': '));
283
+ }
284
+ }
285
+ return clauses.length ? clauses.join('; ') : undefined;
286
+ }
287
+ /** A detail entry, or the violations inside it when it carries a list of them. */
288
+ function violations(entry) {
289
+ const list = entry?.fieldViolations;
290
+ return Array.isArray(list) ? list : [entry];
291
+ }
292
+ /** One line, however many the vendor sent, and never a whole document. */
293
+ function collapse(text) {
294
+ const flat = text.replace(/\s+/g, ' ').trim();
295
+ return flat.length > MAX_DETAIL ? `${flat.slice(0, MAX_DETAIL)}…` : flat;
296
+ }
297
+ /** What an opaque failure blames, from the first cause that says something else. */
298
+ function blamed(err, said) {
299
+ const seen = new Set();
300
+ let at = err?.cause;
301
+ while (at && typeof at === 'object' && !seen.has(at)) {
302
+ seen.add(at);
303
+ const link = at;
304
+ const message = collapse(typeof link.message === 'string' ? link.message : '');
305
+ if (message && message !== said) {
306
+ return typeof link.code === 'string' ? `${message} (${link.code})` : message;
307
+ }
308
+ at = link.cause;
309
+ }
310
+ return undefined;
311
+ }
312
+ /** Appends the status and the vendor's symbol, unless the sentence has them. */
313
+ function mark(text, status, code) {
314
+ const marks = [];
315
+ if (status !== undefined && !text.includes(String(status))) {
316
+ marks.push(String(status));
317
+ }
318
+ if (code && !text.toLowerCase().includes(code.toLowerCase())) {
319
+ marks.push(code);
320
+ }
321
+ return marks.length ? `${text} (${marks.join(' ')})` : text;
322
+ }
323
+ //# sourceMappingURL=failure.js.map
package/dist/index.d.ts CHANGED
@@ -3,11 +3,22 @@ export * from './architecture.ts';
3
3
  export * from './embedding.ts';
4
4
  export * from './embeddings/index.ts';
5
5
  export * from './events.ts';
6
+ export * from './failure.ts';
6
7
  export * from './ids.ts';
7
8
  export * from './inspect/index.ts';
8
9
  export * as Kernel from './kernel.ts';
9
- export * from './memory-stores/index.ts';
10
- export * from './memory.ts';
10
+ export * from './memory/files.ts';
11
+ export * from './memory/graph.ts';
12
+ export * from './memory/index.ts';
13
+ export * from './memory/instructions.ts';
14
+ export * from './memory/page.ts';
15
+ export * from './memory/recall.ts';
16
+ export * from './memory/render.ts';
17
+ export * from './memory/report.ts';
18
+ export * from './memory/store.ts';
19
+ export * from './memory/tools.ts';
20
+ export * from './memory/types.ts';
21
+ export * from './memory/vectors.ts';
11
22
  export * from './model.ts';
12
23
  export * from './models/index.ts';
13
24
  export * from './payload-stores/index.ts';
package/dist/index.js CHANGED
@@ -3,11 +3,22 @@ export * from "./architecture.js";
3
3
  export * from "./embedding.js";
4
4
  export * from "./embeddings/index.js";
5
5
  export * from "./events.js";
6
+ export * from "./failure.js";
6
7
  export * from "./ids.js";
7
8
  export * from "./inspect/index.js";
8
9
  export * as Kernel from "./kernel.js";
9
- export * from "./memory-stores/index.js";
10
- export * from "./memory.js";
10
+ export * from "./memory/files.js";
11
+ export * from "./memory/graph.js";
12
+ export * from "./memory/index.js";
13
+ export * from "./memory/instructions.js";
14
+ export * from "./memory/page.js";
15
+ export * from "./memory/recall.js";
16
+ export * from "./memory/render.js";
17
+ export * from "./memory/report.js";
18
+ export * from "./memory/store.js";
19
+ export * from "./memory/tools.js";
20
+ export * from "./memory/types.js";
21
+ export * from "./memory/vectors.js";
11
22
  export * from "./model.js";
12
23
  export * from "./models/index.js";
13
24
  export * from "./payload-stores/index.js";