@zenera/neo 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +178 -0
  3. package/dist/agent.d.ts +66 -0
  4. package/dist/agent.js +97 -0
  5. package/dist/architecture.d.ts +74 -0
  6. package/dist/architecture.js +105 -0
  7. package/dist/embedding.d.ts +60 -0
  8. package/dist/embedding.js +21 -0
  9. package/dist/embeddings/gemini.d.ts +24 -0
  10. package/dist/embeddings/gemini.js +71 -0
  11. package/dist/embeddings/index.d.ts +4 -0
  12. package/dist/embeddings/index.js +4 -0
  13. package/dist/embeddings/openai.d.ts +18 -0
  14. package/dist/embeddings/openai.js +27 -0
  15. package/dist/embeddings/openrouter.d.ts +21 -0
  16. package/dist/embeddings/openrouter.js +54 -0
  17. package/dist/events.d.ts +144 -0
  18. package/dist/events.js +110 -0
  19. package/dist/ids.d.ts +14 -0
  20. package/dist/ids.js +33 -0
  21. package/dist/index.d.ts +25 -0
  22. package/dist/index.js +25 -0
  23. package/dist/inspect/client.d.ts +2 -0
  24. package/dist/inspect/client.js +1326 -0
  25. package/dist/inspect/css.d.ts +2 -0
  26. package/dist/inspect/css.js +164 -0
  27. package/dist/inspect/index.d.ts +9 -0
  28. package/dist/inspect/index.js +12 -0
  29. package/dist/inspect/page.d.ts +3 -0
  30. package/dist/inspect/page.js +93 -0
  31. package/dist/inspect/report.d.ts +54 -0
  32. package/dist/inspect/report.js +62 -0
  33. package/dist/kernel.d.ts +178 -0
  34. package/dist/kernel.js +929 -0
  35. package/dist/memory-stores/factory.d.ts +15 -0
  36. package/dist/memory-stores/factory.js +29 -0
  37. package/dist/memory-stores/file.d.ts +37 -0
  38. package/dist/memory-stores/file.js +174 -0
  39. package/dist/memory-stores/in-memory.d.ts +17 -0
  40. package/dist/memory-stores/in-memory.js +80 -0
  41. package/dist/memory-stores/index.d.ts +4 -0
  42. package/dist/memory-stores/index.js +5 -0
  43. package/dist/memory.d.ts +115 -0
  44. package/dist/memory.js +213 -0
  45. package/dist/model.d.ts +25 -0
  46. package/dist/model.js +2 -0
  47. package/dist/models/anthropic.d.ts +36 -0
  48. package/dist/models/anthropic.js +293 -0
  49. package/dist/models/factory.d.ts +202 -0
  50. package/dist/models/factory.js +533 -0
  51. package/dist/models/gemini.d.ts +45 -0
  52. package/dist/models/gemini.js +368 -0
  53. package/dist/models/index.d.ts +7 -0
  54. package/dist/models/index.js +7 -0
  55. package/dist/models/openai-chat.d.ts +19 -0
  56. package/dist/models/openai-chat.js +203 -0
  57. package/dist/models/openai-responses.d.ts +31 -0
  58. package/dist/models/openai-responses.js +258 -0
  59. package/dist/models/openrouter.d.ts +44 -0
  60. package/dist/models/openrouter.js +230 -0
  61. package/dist/payload-stores/factory.d.ts +15 -0
  62. package/dist/payload-stores/factory.js +30 -0
  63. package/dist/payload-stores/file.d.ts +29 -0
  64. package/dist/payload-stores/file.js +112 -0
  65. package/dist/payload-stores/in-memory.d.ts +17 -0
  66. package/dist/payload-stores/in-memory.js +40 -0
  67. package/dist/payload-stores/index.d.ts +4 -0
  68. package/dist/payload-stores/index.js +5 -0
  69. package/dist/payload.d.ts +89 -0
  70. package/dist/payload.js +181 -0
  71. package/dist/project/config.d.ts +302 -0
  72. package/dist/project/config.js +290 -0
  73. package/dist/project/index.d.ts +4 -0
  74. package/dist/project/index.js +4 -0
  75. package/dist/project/load.d.ts +142 -0
  76. package/dist/project/load.js +430 -0
  77. package/dist/project/refs.d.ts +23 -0
  78. package/dist/project/refs.js +70 -0
  79. package/dist/prompt.d.ts +66 -0
  80. package/dist/prompt.js +62 -0
  81. package/dist/runner.d.ts +103 -0
  82. package/dist/runner.js +537 -0
  83. package/dist/services.d.ts +23 -0
  84. package/dist/services.js +44 -0
  85. package/dist/skill-providers/factory.d.ts +16 -0
  86. package/dist/skill-providers/factory.js +26 -0
  87. package/dist/skill-providers/file.d.ts +44 -0
  88. package/dist/skill-providers/file.js +209 -0
  89. package/dist/skill-providers/index.d.ts +4 -0
  90. package/dist/skill-providers/index.js +5 -0
  91. package/dist/skill-providers/static.d.ts +13 -0
  92. package/dist/skill-providers/static.js +47 -0
  93. package/dist/skills.d.ts +102 -0
  94. package/dist/skills.js +232 -0
  95. package/dist/state.d.ts +86 -0
  96. package/dist/state.js +49 -0
  97. package/dist/tools/exa.d.ts +23 -0
  98. package/dist/tools/exa.js +389 -0
  99. package/dist/tools/index.d.ts +4 -0
  100. package/dist/tools/index.js +6 -0
  101. package/dist/tools/sandbox.d.ts +172 -0
  102. package/dist/tools/sandbox.js +602 -0
  103. package/dist/tools/workspace.d.ts +53 -0
  104. package/dist/tools/workspace.js +1034 -0
  105. package/dist/trajectory.d.ts +213 -0
  106. package/dist/trajectory.js +232 -0
  107. package/dist/types.d.ts +195 -0
  108. package/dist/types.js +134 -0
  109. package/package.json +98 -0
@@ -0,0 +1,112 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { hash, previewOf } from "../payload.js";
5
+ // ---------------------------------------------------------------------------
6
+ // Filesystem-backed payload store
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * A content address is the only thing that ever becomes a path segment, so it
10
+ * is validated before it touches the filesystem: addresses arrive from
11
+ * deserialized state, which may come from an untrusted bundle.
12
+ */
13
+ const ADDRESS = /^[0-9a-f]{64}$/;
14
+ /**
15
+ * Same contract as the in-memory store, on disk. Content addressing does the
16
+ * hard part: writes are write-once and therefore idempotent under retry and
17
+ * replay, and two processes racing on the same blob produce identical bytes.
18
+ */
19
+ export class FilePayloadStore {
20
+ id;
21
+ #dir;
22
+ #concurrency;
23
+ #verify;
24
+ constructor(opts) {
25
+ const o = typeof opts === 'string' ? { dir: opts } : opts;
26
+ this.#dir = resolve(o.dir);
27
+ this.id = o.id ?? 'file';
28
+ this.#concurrency = Math.max(1, o.concurrency ?? 32);
29
+ this.#verify = o.verify ?? false;
30
+ }
31
+ get dir() {
32
+ return this.#dir;
33
+ }
34
+ async put(value) {
35
+ const sha256 = hash(value);
36
+ const path = this.#path(sha256);
37
+ if (!(await exists(path))) {
38
+ await mkdir(dirname(path), { recursive: true });
39
+ // Write elsewhere then rename: a reader never observes a partial
40
+ // blob, and a crash leaves at worst an orphaned temp file.
41
+ const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;
42
+ await writeFile(tmp, value, 'utf8');
43
+ try {
44
+ await rename(tmp, path);
45
+ }
46
+ catch (err) {
47
+ await rm(tmp, { force: true });
48
+ throw err;
49
+ }
50
+ }
51
+ return {
52
+ store: this.id,
53
+ sha256,
54
+ size: Buffer.byteLength(value),
55
+ preview: previewOf(value),
56
+ };
57
+ }
58
+ async get(p) {
59
+ return this.#read(p.sha256);
60
+ }
61
+ async getMany(ps) {
62
+ return mapPool(ps, this.#concurrency, (p) => this.#read(p.sha256));
63
+ }
64
+ /** Two levels of fan-out keep any single directory small. */
65
+ #path(sha256) {
66
+ if (!ADDRESS.test(sha256)) {
67
+ throw new Error(`invalid payload address: ${JSON.stringify(sha256)}`);
68
+ }
69
+ return join(this.#dir, sha256.slice(0, 2), sha256.slice(2, 4), sha256);
70
+ }
71
+ async #read(sha256) {
72
+ const path = this.#path(sha256);
73
+ let value;
74
+ try {
75
+ value = await readFile(path, 'utf8');
76
+ }
77
+ catch (err) {
78
+ if (err.code === 'ENOENT') {
79
+ throw new Error(`payload not found in store "${this.id}": ${sha256}`);
80
+ }
81
+ throw err;
82
+ }
83
+ if (this.#verify && hash(value) !== sha256) {
84
+ throw new Error(`payload corrupted in store "${this.id}": ${sha256}`);
85
+ }
86
+ return value;
87
+ }
88
+ }
89
+ async function exists(path) {
90
+ try {
91
+ await stat(path);
92
+ return true;
93
+ }
94
+ catch (err) {
95
+ if (err.code === 'ENOENT') {
96
+ return false;
97
+ }
98
+ throw err;
99
+ }
100
+ }
101
+ async function mapPool(items, limit, fn) {
102
+ const out = new Array(items.length);
103
+ let next = 0;
104
+ const worker = async () => {
105
+ for (let i = next++; i < items.length; i = next++) {
106
+ out[i] = await fn(items[i]);
107
+ }
108
+ };
109
+ await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
110
+ return out;
111
+ }
112
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1,17 @@
1
+ import { type Payload, type PayloadStore } from '../payload.ts';
2
+ /**
3
+ * The zero-I/O backend, and the one `Services` falls back to. Content-addressed
4
+ * and therefore write-once: putting existing content is a no-op returning the
5
+ * same reference, which makes writes idempotent under retry and replay for
6
+ * free.
7
+ */
8
+ export declare class InMemoryPayloadStore implements PayloadStore {
9
+ #private;
10
+ readonly id: string;
11
+ constructor(id?: string);
12
+ put(value: string): Promise<Payload>;
13
+ get(p: Payload): Promise<string>;
14
+ getMany(ps: Payload[]): Promise<string[]>;
15
+ get size(): number;
16
+ }
17
+ //# sourceMappingURL=in-memory.d.ts.map
@@ -0,0 +1,40 @@
1
+ import { hash, previewOf } from "../payload.js";
2
+ /**
3
+ * The zero-I/O backend, and the one `Services` falls back to. Content-addressed
4
+ * and therefore write-once: putting existing content is a no-op returning the
5
+ * same reference, which makes writes idempotent under retry and replay for
6
+ * free.
7
+ */
8
+ export class InMemoryPayloadStore {
9
+ id;
10
+ #blobs = new Map();
11
+ constructor(id = 'mem') {
12
+ this.id = id;
13
+ }
14
+ async put(value) {
15
+ const sha256 = hash(value);
16
+ if (!this.#blobs.has(sha256)) {
17
+ this.#blobs.set(sha256, value);
18
+ }
19
+ return {
20
+ store: this.id,
21
+ sha256,
22
+ size: Buffer.byteLength(value),
23
+ preview: previewOf(value),
24
+ };
25
+ }
26
+ async get(p) {
27
+ const v = this.#blobs.get(p.sha256);
28
+ if (v === undefined) {
29
+ throw new Error(`payload not found in store "${this.id}": ${p.sha256}`);
30
+ }
31
+ return v;
32
+ }
33
+ async getMany(ps) {
34
+ return Promise.all(ps.map((p) => this.get(p)));
35
+ }
36
+ get size() {
37
+ return this.#blobs.size;
38
+ }
39
+ }
40
+ //# sourceMappingURL=in-memory.js.map
@@ -0,0 +1,4 @@
1
+ export * from './factory.ts';
2
+ export * from './file.ts';
3
+ export * from './in-memory.ts';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ // Backends for the `PayloadStore` contract in `../payload.ts`.
2
+ export * from "./factory.js";
3
+ export * from "./file.js";
4
+ export * from "./in-memory.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,89 @@
1
+ /**
2
+ * A content-addressed reference. Uniform (never inline) so a state stays
3
+ * O(number of nodes) in size no matter how much data flowed through the run,
4
+ * which is what makes checkpointing every step affordable.
5
+ */
6
+ export interface Payload {
7
+ /** store id, e.g. 's3://bucket' or 'mem' */
8
+ store: string;
9
+ /** content address — also the key */
10
+ sha256: string;
11
+ /** bytes, for budgeting without fetching */
12
+ size: number;
13
+ /** first ~200 chars, for logs, UIs and debugging */
14
+ preview?: string;
15
+ }
16
+ export declare const PREVIEW_LEN = 200;
17
+ export declare function hash(value: string): string;
18
+ export declare function previewOf(value: string): string | undefined;
19
+ export declare function isPayload(v: unknown): v is Payload;
20
+ export interface PayloadStore {
21
+ readonly id: string;
22
+ put(value: string): Promise<Payload>;
23
+ get(p: Payload): Promise<string>;
24
+ /** one round trip for a whole projection */
25
+ getMany(ps: Payload[]): Promise<string[]>;
26
+ }
27
+ /**
28
+ * Fans a projection out over the stores it references and caches results.
29
+ * Because payloads are content-addressed, a growing trajectory re-projects its
30
+ * unchanged prefix with exact cache hits — repeated projection is cheap.
31
+ */
32
+ export declare class PayloadResolver {
33
+ #private;
34
+ constructor(def: PayloadStore, maxCacheBytes?: number);
35
+ register(store: PayloadStore): this;
36
+ get defaultStore(): PayloadStore;
37
+ store(id: string): PayloadStore;
38
+ put(value: string, store?: PayloadStore): Promise<Payload>;
39
+ get(p: Payload): Promise<string>;
40
+ /**
41
+ * Batched resolution keyed by content address: duplicates collapse, and one
42
+ * store round trip covers a whole projection.
43
+ */
44
+ getMany(ps: Payload[]): Promise<Map<string, string>>;
45
+ }
46
+ /** Every payload reachable from an arbitrary JSON value, deduped by address. */
47
+ export declare function collectPayloads(value: unknown, into?: Map<string, Payload>): Payload[];
48
+ /**
49
+ * A run made whole: a state plus every blob it points at.
50
+ *
51
+ * On its own an `AgentState` is a graph of references — meaningless without
52
+ * the stores those references name, which may be a bucket the reader cannot
53
+ * reach or an in-memory store that died with its process. A bundle closes
54
+ * that gap, so it is the unit for anything crossing a machine, a process or a
55
+ * trust boundary: test fixtures, bug reports, archival, handing a run to
56
+ * another service.
57
+ *
58
+ * Plain JSON by design — `JSON.stringify` it, and `importRun` rehydrates it
59
+ * against whatever store the reader has. Note the two halves are indexed
60
+ * differently on purpose: `state` keeps full `Payload` refs (store id, size,
61
+ * preview) because it is still a working state, while `blobs` is keyed by
62
+ * content address alone, which both drops the origin store (an imported run
63
+ * belongs to its new one) and dedupes for free — content repeated across
64
+ * steps or fork branches is carried once.
65
+ */
66
+ export interface RunBundle {
67
+ /** typically an `AgentState`, but any payload-bearing JSON works */
68
+ state: unknown;
69
+ /** sha256 → content; deduped by construction */
70
+ blobs: Record<string, string>;
71
+ }
72
+ /**
73
+ * Self-containment on demand: one portable artifact for tests, bug reports and
74
+ * archival. A fork tree needs no special handling — branch nodes live in the
75
+ * one trajectory, so their payloads are already reachable.
76
+ */
77
+ export declare function exportRun(state: unknown, payloads: PayloadResolver): Promise<RunBundle>;
78
+ /**
79
+ * Writes a bundle's blobs into the target store and rewrites every reference
80
+ * to point at it, so an imported run resolves locally.
81
+ *
82
+ * It re-`put`s rather than inserting under the bundle's keys, which keeps the
83
+ * contract at `PayloadStore` (any backend works, not just the in-memory one)
84
+ * and means nothing has to trust those keys: the store re-derives the address
85
+ * from the bytes, so a tampered blob lands under its true address and leaves a
86
+ * dangling reference that fails loudly instead of poisoning the store.
87
+ */
88
+ export declare function importRun<T>(bundle: RunBundle, store: PayloadStore): Promise<T>;
89
+ //# sourceMappingURL=payload.d.ts.map
@@ -0,0 +1,181 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const PREVIEW_LEN = 200;
3
+ export function hash(value) {
4
+ return createHash('sha256').update(value, 'utf8').digest('hex');
5
+ }
6
+ export function previewOf(value) {
7
+ return value ? value.slice(0, PREVIEW_LEN) : undefined;
8
+ }
9
+ export function isPayload(v) {
10
+ if (v === null || typeof v !== 'object') {
11
+ return false;
12
+ }
13
+ const p = v;
14
+ return (typeof p.store === 'string' && typeof p.sha256 === 'string' && typeof p.size === 'number');
15
+ }
16
+ /**
17
+ * Fans a projection out over the stores it references and caches results.
18
+ * Because payloads are content-addressed, a growing trajectory re-projects its
19
+ * unchanged prefix with exact cache hits — repeated projection is cheap.
20
+ */
21
+ export class PayloadResolver {
22
+ #stores = new Map();
23
+ #cache = new Map();
24
+ #maxCacheBytes;
25
+ #cacheBytes = 0;
26
+ #default;
27
+ constructor(def, maxCacheBytes = 8 << 20) {
28
+ this.#default = def;
29
+ this.#maxCacheBytes = maxCacheBytes;
30
+ this.register(def);
31
+ }
32
+ register(store) {
33
+ this.#stores.set(store.id, store);
34
+ return this;
35
+ }
36
+ get defaultStore() {
37
+ return this.#default;
38
+ }
39
+ store(id) {
40
+ const s = this.#stores.get(id);
41
+ if (!s) {
42
+ throw new Error(`unknown payload store: ${id} (known: ${[...this.#stores.keys()]})`);
43
+ }
44
+ return s;
45
+ }
46
+ async put(value, store = this.#default) {
47
+ const p = await store.put(value);
48
+ this.#remember(p.sha256, value);
49
+ return p;
50
+ }
51
+ async get(p) {
52
+ const cached = this.#cache.get(p.sha256);
53
+ if (cached !== undefined) {
54
+ return cached;
55
+ }
56
+ const value = await this.store(p.store).get(p);
57
+ this.#remember(p.sha256, value);
58
+ return value;
59
+ }
60
+ /**
61
+ * Batched resolution keyed by content address: duplicates collapse, and one
62
+ * store round trip covers a whole projection.
63
+ */
64
+ async getMany(ps) {
65
+ const out = new Map();
66
+ const missing = new Map();
67
+ for (const p of ps) {
68
+ if (out.has(p.sha256)) {
69
+ continue;
70
+ }
71
+ const cached = this.#cache.get(p.sha256);
72
+ if (cached !== undefined) {
73
+ out.set(p.sha256, cached);
74
+ continue;
75
+ }
76
+ const byStore = missing.get(p.store) ?? [];
77
+ if (!byStore.some((q) => q.sha256 === p.sha256)) {
78
+ byStore.push(p);
79
+ }
80
+ missing.set(p.store, byStore);
81
+ }
82
+ await Promise.all([...missing].map(async ([storeId, refs]) => {
83
+ const values = await this.store(storeId).getMany(refs);
84
+ refs.forEach((ref, i) => {
85
+ const value = values[i] ?? '';
86
+ out.set(ref.sha256, value);
87
+ this.#remember(ref.sha256, value);
88
+ });
89
+ }));
90
+ return out;
91
+ }
92
+ #remember(sha256, value) {
93
+ if (this.#cache.has(sha256)) {
94
+ return;
95
+ }
96
+ this.#cache.set(sha256, value);
97
+ this.#cacheBytes += value.length;
98
+ // Insertion-ordered Map == FIFO eviction, good enough for a prefix-heavy
99
+ // access pattern where the hot entries are re-inserted on every miss.
100
+ for (const [key, val] of this.#cache) {
101
+ if (this.#cacheBytes <= this.#maxCacheBytes) {
102
+ break;
103
+ }
104
+ if (key === sha256) {
105
+ continue;
106
+ }
107
+ this.#cache.delete(key);
108
+ this.#cacheBytes -= val.length;
109
+ }
110
+ }
111
+ }
112
+ // ---------------------------------------------------------------------------
113
+ // Deep payload traversal — export/import and GC accounting
114
+ // ---------------------------------------------------------------------------
115
+ /** Every payload reachable from an arbitrary JSON value, deduped by address. */
116
+ export function collectPayloads(value, into = new Map()) {
117
+ if (Array.isArray(value)) {
118
+ for (const v of value) {
119
+ collectPayloads(v, into);
120
+ }
121
+ }
122
+ else if (value !== null && typeof value === 'object') {
123
+ if (isPayload(value)) {
124
+ into.set(value.sha256, value);
125
+ return [...into.values()];
126
+ }
127
+ for (const v of Object.values(value)) {
128
+ collectPayloads(v, into);
129
+ }
130
+ }
131
+ return [...into.values()];
132
+ }
133
+ /**
134
+ * Self-containment on demand: one portable artifact for tests, bug reports and
135
+ * archival. A fork tree needs no special handling — branch nodes live in the
136
+ * one trajectory, so their payloads are already reachable.
137
+ */
138
+ export async function exportRun(state, payloads) {
139
+ const refs = collectPayloads(state);
140
+ const values = await payloads.getMany(refs);
141
+ const blobs = {};
142
+ for (const p of refs) {
143
+ blobs[p.sha256] = values.get(p.sha256) ?? '';
144
+ }
145
+ return { state, blobs };
146
+ }
147
+ /** Bounded fan-out: a bundle can hold thousands of blobs, a store has limits. */
148
+ const IMPORT_CONCURRENCY = 32;
149
+ /**
150
+ * Writes a bundle's blobs into the target store and rewrites every reference
151
+ * to point at it, so an imported run resolves locally.
152
+ *
153
+ * It re-`put`s rather than inserting under the bundle's keys, which keeps the
154
+ * contract at `PayloadStore` (any backend works, not just the in-memory one)
155
+ * and means nothing has to trust those keys: the store re-derives the address
156
+ * from the bytes, so a tampered blob lands under its true address and leaves a
157
+ * dangling reference that fails loudly instead of poisoning the store.
158
+ */
159
+ export async function importRun(bundle, store) {
160
+ const values = Object.values(bundle.blobs);
161
+ for (let i = 0; i < values.length; i += IMPORT_CONCURRENCY) {
162
+ await Promise.all(values.slice(i, i + IMPORT_CONCURRENCY).map((v) => store.put(v)));
163
+ }
164
+ return rewriteStore(structuredClone(bundle.state), store.id);
165
+ }
166
+ function rewriteStore(value, storeId) {
167
+ if (Array.isArray(value)) {
168
+ value.forEach((v) => rewriteStore(v, storeId));
169
+ }
170
+ else if (value !== null && typeof value === 'object') {
171
+ if (isPayload(value)) {
172
+ value.store = storeId;
173
+ return value;
174
+ }
175
+ for (const v of Object.values(value)) {
176
+ rewriteStore(v, storeId);
177
+ }
178
+ }
179
+ return value;
180
+ }
181
+ //# sourceMappingURL=payload.js.map