@tangleai/agents 0.21.1 → 0.24.1

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.
@@ -1,53 +1,60 @@
1
- //@ts-check
2
1
  /** Recursive answers carry the same envelope as map elements. Query engines stay injected. */
3
2
  export const RECURSIVE_ITEM_SCHEMA = {
4
- type: 'object', properties: { slot: { type: 'string' }, value: {} }, required: ['slot', 'value'],
3
+ type: 'object', properties: { slot: { type: 'string' }, value: {} }, required: ['slot', 'value'],
5
4
  };
6
-
7
5
  /** Query singleton normalization: empty sequence, one item, or several items.
8
- * @param {any} value */
6
+ * @param value */
9
7
  export function recursiveItems(value) {
10
- const items = value === null ? [] : Array.isArray(value) ? value : [value];
11
- return items.every((item) => item !== null && typeof item === 'object' && !Array.isArray(item)
12
- && typeof item.slot === 'string' && Object.hasOwn(item, 'value')) ? items : null;
8
+ const items = value === null ? [] : Array.isArray(value) ? value : [value];
9
+ return items.every((item) => item !== null && typeof item === 'object' && !Array.isArray(item)
10
+ && typeof item.slot === 'string' && Object.hasOwn(item, 'value')) ? items : null;
13
11
  }
14
-
15
12
  /** Conservatively prove a declared item/sequence schema. Unknown schema keywords
16
13
  * never manufacture required properties. Runtime validation enforces the full declaration.
17
- * @param {any} schema @param {boolean} [item] @returns {boolean} */
14
+ * @param schema @param [item] @returns */
18
15
  export function recursiveSchema(schema, item = false) {
19
- if (!schema || typeof schema !== 'object') return false;
20
- if (schema.type === 'array') return !item && recursiveSchema(schema.items, true);
21
- if (schema.anyOf) return schema.anyOf.every((branch) => recursiveSchema(branch, item));
22
- return schema.type === 'object' && schema.required?.includes('slot')
23
- && schema.required?.includes('value') && schema.properties?.slot?.type === 'string';
16
+ if (!schema || typeof schema !== 'object')
17
+ return false;
18
+ if (schema.type === 'array')
19
+ return !item && recursiveSchema(schema.items, true);
20
+ if (schema.anyOf)
21
+ return schema.anyOf.every((branch) => recursiveSchema(branch, item));
22
+ return schema.type === 'object' && schema.required?.includes('slot')
23
+ && schema.required?.includes('value') && schema.properties?.slot?.type === 'string';
24
24
  }
25
-
26
25
  /** Three-valued structural proof over the existing annotated query AST.
27
- * @param {any} node @param {boolean} [item] @returns {'compatible'|'incompatible'|'unknown'} */
26
+ * @param node @param [item] @returns */
28
27
  export function recursiveShape(node, item = false) {
29
- if (!node) return 'unknown';
30
- if (node.kind === 'let') return recursiveShape(node.ret, item);
31
- if (node.kind === 'flwor') {
32
- const output = recursiveShape(node.ret, node.fold ? item : true);
33
- if (!node.fold) return output;
34
- const initial = recursiveShape(node.fold.expr, item);
35
- return initial === output ? output : 'unknown';
36
- }
37
- if (node.kind === 'array') {
38
- if (item) return 'incompatible';
39
- const shapes = node.elements.map((element) => recursiveShape(element, true));
40
- return shapes.includes('incompatible') ? 'incompatible' : shapes.includes('unknown') ? 'unknown' : 'compatible';
41
- }
42
- if (node.kind === 'literal') return (item && (Array.isArray(node.value) || node.value === null))
43
- || recursiveItems(node.value) === null ? 'incompatible' : 'compatible';
44
- if (node.kind === 'object') {
45
- const slot = node.entries.find((entry) => entry.name === 'slot')?.expr;
46
- const value = node.entries.find((entry) => entry.name === 'value');
47
- if (!slot || !value) return 'incompatible';
48
- if (slot.type?.type === 'string' && slot.type.optional === false) return 'compatible';
49
- return !slot.type || slot.type.type === 'unknown' ? 'unknown' : 'incompatible';
50
- }
51
- if (node.type?.type && !['unknown', 'object', 'array'].includes(node.type.type)) return 'incompatible';
52
- return 'unknown';
28
+ if (!node)
29
+ return 'unknown';
30
+ if (node.kind === 'let')
31
+ return recursiveShape(node.ret, item);
32
+ if (node.kind === 'flwor') {
33
+ const output = recursiveShape(node.ret, node.fold ? item : true);
34
+ if (!node.fold)
35
+ return output;
36
+ const initial = recursiveShape(node.fold.expr, item);
37
+ return initial === output ? output : 'unknown';
38
+ }
39
+ if (node.kind === 'array') {
40
+ if (item)
41
+ return 'incompatible';
42
+ const shapes = node.elements.map((element) => recursiveShape(element, true));
43
+ return shapes.includes('incompatible') ? 'incompatible' : shapes.includes('unknown') ? 'unknown' : 'compatible';
44
+ }
45
+ if (node.kind === 'literal')
46
+ return (item && (Array.isArray(node.value) || node.value === null))
47
+ || recursiveItems(node.value) === null ? 'incompatible' : 'compatible';
48
+ if (node.kind === 'object') {
49
+ const slot = node.entries.find((entry) => entry.name === 'slot')?.expr;
50
+ const value = node.entries.find((entry) => entry.name === 'value');
51
+ if (!slot || !value)
52
+ return 'incompatible';
53
+ if (slot.type?.type === 'string' && slot.type.optional === false)
54
+ return 'compatible';
55
+ return !slot.type || slot.type.type === 'unknown' ? 'unknown' : 'incompatible';
56
+ }
57
+ if (node.type?.type && !['unknown', 'object', 'array'].includes(node.type.type))
58
+ return 'incompatible';
59
+ return 'unknown';
53
60
  }
package/src/program.d.ts CHANGED
@@ -1,3 +1,92 @@
1
+ /**
2
+ * The action language: compile it, then run it.
3
+ *
4
+ * HORIZON_06 put the corpus outside the context and gave the root a
5
+ * digest instead. That fixed what the model *sees*; this file fixes what
6
+ * it can *do*. The model authors a small program naming slots and
7
+ * operations, the program is compiled before anything runs, and the
8
+ * harness executes it — fanning model sub-calls out over the pieces in
9
+ * parallel and writing every result back to a slot.
10
+ *
11
+ * Why this closes the pairwise question. A relation over every record
12
+ * needs every record, and no summariser and no `recall` can put forty
13
+ * rounds into a budget they were cut to fit. A program does not have to:
14
+ * `map` visits all forty pieces, each sub-call reads one of them, and
15
+ * `reduce` computes over the forty small results. The root never sees
16
+ * any of it — it sees a plan going out and one slot's metadata coming
17
+ * back — so the request stays the same size whether the corpus is ten
18
+ * kilobytes or ten megabytes.
19
+ *
20
+ * Four rules hold without exception:
21
+ *
22
+ * - **A program that does not compile never runs.** `run` compiles
23
+ * first and returns the compile errors; no step has executed and no
24
+ * slot has been written when it does. The errors are coded and
25
+ * `docPath`'d into the program document, which is the error class
26
+ * this package's field notes say small models actually repair.
27
+ * - **`map` is the only step that calls a model** — so `maxSubcalls`
28
+ * and `maxConcurrentSubcalls` are the whole cost model, and one place
29
+ * threads the `AbortSignal`.
30
+ * - **A sub-call failure is a result, not a crash.** It lands as
31
+ * `{ error }` in its own result slot and the map completes, exactly
32
+ * as the toolbox never throws for content-level problems. A map whose
33
+ * sub-calls all failed is a finished map with forty recorded errors.
34
+ * - **Nothing bulk comes back.** Every step reports metadata; the one
35
+ * place content returns to the caller is the final `answer` step, and
36
+ * it is capped.
37
+ *
38
+ * **The decision this file exists to record** (asked once per reader, so
39
+ * it is answered here): why not register an async `$llm` operator into
40
+ * the JSLT registry and let a stylesheet call a model inline? Because
41
+ * `@jarenjs/core`'s operators are pure synchronous functions and the
42
+ * query/JSLT evaluators are synchronous by construction. Making them
43
+ * async to accommodate one caller would change an engine every other
44
+ * package in the suite depends on — a `queryJson` that returned a
45
+ * promise would break `@jarenjs/db`'s pushdown, `@jarenjs/md`'s
46
+ * directives and `@jarenjs/app`'s state derivation, all to save this
47
+ * package a `map` step. So the division is fixed: **the program selects
48
+ * (pure, synchronous, compiled) and the harness awaits (async, bounded,
49
+ * cancellable).** `map` is the seam between the two halves, and it is
50
+ * the only one.
51
+ */
52
+ import { CodedError } from '@jarenjs/core/errors';
53
+ export { readProgramAnswer } from './program-result.ts';
54
+ /**
55
+ * A program that will not compile.
56
+ *
57
+ * Thrown, unlike `refine.ts`'s AI01xx records, because this is a
58
+ * COMPILER and the suite's compilers throw coded errors with a
59
+ * `docPath` — which is what makes the documented two-line gate adapter
60
+ * (`try { compile(doc) } catch (e) { … }`) work here exactly as it does
61
+ * for a query, a stylesheet or a flow machine. {@link programGate} is
62
+ * that adapter, so a caller never writes it.
63
+ *
64
+ * The codes:
65
+ *
66
+ * AI0200 — the document is not a program
67
+ * AI0201 — a step reads a name nothing produced
68
+ * AI0202 — a name is bound twice
69
+ * AI0203 — the last step is not `answer`, or there is more than one
70
+ * AI0204 — a `reduce` reads something that is not a `map`
71
+ * AI0205 — the program is longer than its cap
72
+ * AI0206 — a step needs the query seam and none is wired
73
+ * AI0207 — a step reading ONE slot was given a family of pieces
74
+ * AI0208 — a recursive result has an incompatible or unknown envelope
75
+ * AI0209 — a runtime result violates its declared recursive shape
76
+ *
77
+ * A query that does not compile keeps the QUERY engine's own code
78
+ * (`JQ0002`, …) and its pointer is rebased onto the program document,
79
+ * so the model is told which step and which member — the same posture
80
+ * `refine.ts` takes with the patch engine's codes.
81
+ */
82
+ export declare class ProgramError extends CodedError {
83
+ /**
84
+ * @param code - 'AI0200' … 'AI0209'
85
+ * @param reason - the bare reason
86
+ * @param [docPath] - JSON Pointer into the program document
87
+ */
88
+ constructor(code: string, reason: string, docPath?: string);
89
+ }
1
90
  /**
2
91
  * Compile a program document.
3
92
  *
@@ -7,9 +96,8 @@
7
96
  * model, so a compile is cheap enough to run on every authored candidate
8
97
  * — which is exactly what makes it usable as a decoding gate.
9
98
  *
10
- * @param {any} doc - the program document
11
- * @param {{ compileQuery?: ((document: any) => (data: any) => any) | null,
12
- * known?: Iterable<string>, recursive?: boolean, analyzeQuery?: any, annotateTypes?: any }} [options]
99
+ * @param doc - the program document
100
+ * @param [options]
13
101
  * - `compileQuery` is the D3 seam. Absent, a program using `select` or
14
102
  * `reduce` is refused with AI0206 rather than half-compiled.
15
103
  * - `known` is what the environment already holds. Given, a `from`
@@ -18,11 +106,10 @@
18
106
  * reason a compile gate catches what a schema cannot. Absent, only
19
107
  * bindings are resolved: nothing else can be checked without an
20
108
  * environment, and inventing an error would be worse than saying so.
21
- * @returns {{ steps: any[], answer: { from: string, chars: number },
22
- * bindings: string[], chars: number }}
109
+ * @returns
23
110
  * @throws {ProgramError}
24
111
  */
25
- export function compileProgram(doc: any, options?: {
112
+ export declare function compileProgram(doc: any, options?: {
26
113
  compileQuery?: ((document: any) => (data: any) => any) | null;
27
114
  known?: Iterable<string>;
28
115
  recursive?: boolean;
@@ -43,10 +130,9 @@ export function compileProgram(doc: any, options?: {
43
130
  * One implementation of "does this program compile", used by the
44
131
  * authoring path and by the runner, so a program that authored cleanly
45
132
  * cannot fail differently when it runs.
46
- * @param {{ compileQuery?: any, known?: Iterable<string>, recursive?: boolean, analyzeQuery?: any, annotateTypes?: any }} [options]
47
- * @returns {(doc: any) => true | { valid: false, errors: any[] }}
133
+ * @param [options]
48
134
  */
49
- export function programGate(options?: {
135
+ export declare function programGate(options?: {
50
136
  compileQuery?: any;
51
137
  known?: Iterable<string>;
52
138
  recursive?: boolean;
@@ -59,17 +145,6 @@ export function programGate(options?: {
59
145
  /**
60
146
  * Create a runner over an environment.
61
147
  *
62
- * @param {{ environment: any,
63
- * client?: { complete: (request: any) => Promise<any> },
64
- * compileQuery?: any,
65
- * recursive?: boolean, analyzeQuery?: any, annotateTypes?: any,
66
- * selectModel?: any, limits?: any, onRoute?: any, depth?: number,
67
- * model?: string,
68
- * maxSubcalls?: number, maxConcurrentSubcalls?: number,
69
- * subcallChars?: number, maxReduceChars?: number,
70
- * sequential?: boolean,
71
- * subcall?: (name: string, prompt: string, signal?: AbortSignal, index?: number) => Promise<any>,
72
- * account?: { reserve: Function, settle: Function, stop: () => string | null } }} options
73
148
  * - `client` is only needed by `map`; a program without one is a
74
149
  * perfectly good program (chunk / grep / select / stat / answer are
75
150
  * model-free), and running a `map` without a client is a stated
@@ -86,9 +161,8 @@ export function programGate(options?: {
86
161
  * - `account` is a budget shared with everything else in the run,
87
162
  * including other depths. Checked before each sub-call and charged
88
163
  * by it, so a tree cannot outspend the sum of its branches.
89
- * @returns {{ run: (doc: any, hooks?: { signal?: AbortSignal }) => Promise<ProgramRunResult> }}
90
164
  */
91
- export function createProgramRunner(options: {
165
+ export declare function createProgramRunner(options: {
92
166
  environment: any;
93
167
  client?: {
94
168
  complete: (request: any) => Promise<any>;
@@ -118,6 +192,48 @@ export function createProgramRunner(options: {
118
192
  signal?: AbortSignal;
119
193
  }) => Promise<ProgramRunResult>;
120
194
  };
195
+ /** The example, so a test can compile it. Exported for exactly that:
196
+ * the prompt's correctness is a property worth a gate. */
197
+ export declare const PROGRAM_EXAMPLE: {
198
+ steps: ({
199
+ op: string;
200
+ from: string;
201
+ as: string;
202
+ strategy: string;
203
+ size: number;
204
+ prompt?: undefined;
205
+ query?: undefined;
206
+ } | {
207
+ op: string;
208
+ from: string;
209
+ as: string;
210
+ prompt: string;
211
+ strategy?: undefined;
212
+ size?: undefined;
213
+ query?: undefined;
214
+ } | {
215
+ op: string;
216
+ from: string;
217
+ as: string;
218
+ query: {
219
+ $for: {
220
+ r: string;
221
+ };
222
+ $return: string;
223
+ };
224
+ strategy?: undefined;
225
+ size?: undefined;
226
+ prompt?: undefined;
227
+ } | {
228
+ op: string;
229
+ from: string;
230
+ as?: undefined;
231
+ strategy?: undefined;
232
+ size?: undefined;
233
+ prompt?: undefined;
234
+ query?: undefined;
235
+ })[];
236
+ };
121
237
  /**
122
238
  * Author a program with a model, gated on the compiler.
123
239
  *
@@ -127,20 +243,14 @@ export function createProgramRunner(options: {
127
243
  * decoding, the compile gate constrains meaning, and a rejected
128
244
  * candidate goes back with its code and its pointer.
129
245
  *
130
- * @param {{ client: any, environment: any, compileQuery?: any,
131
- * recursive?: boolean, analyzeQuery?: any, annotateTypes?: any,
132
- * selectModel?: any, limits?: any, onRoute?: any, depth?: number, account?: any,
133
- * createStructuredOutput: (options: any) => { generate: Function },
134
- * querySchema?: any, maxRepairs?: number, system?: string }} options
135
246
  * - `createStructuredOutput` is injected rather than imported so a
136
247
  * caller can wrap it (a probe counting attempts, a cache); the
137
248
  * package's own is the obvious argument.
138
249
  * - `querySchema` is the published query grammar. Given, `select` and
139
250
  * `reduce` are shape-constrained too and it is registered as a
140
251
  * `$ref`; absent, the compile gate carries it alone (D3).
141
- * @returns {{ author: (question: string, hooks?: { signal?: AbortSignal }) => Promise<any> }}
142
252
  */
143
- export function createProgramAuthor(options: {
253
+ export declare function createProgramAuthor(options: {
144
254
  client: any;
145
255
  environment: any;
146
256
  compileQuery?: any;
@@ -163,82 +273,4 @@ export function createProgramAuthor(options: {
163
273
  signal?: AbortSignal;
164
274
  }) => Promise<any>;
165
275
  };
166
- export { readProgramAnswer } from "./program-result.js";
167
- /**
168
- * A program that will not compile.
169
- *
170
- * Thrown, unlike `refine.js`'s AI01xx records, because this is a
171
- * COMPILER and the suite's compilers throw coded errors with a
172
- * `docPath` — which is what makes the documented two-line gate adapter
173
- * (`try { compile(doc) } catch (e) { … }`) work here exactly as it does
174
- * for a query, a stylesheet or a flow machine. {@link programGate} is
175
- * that adapter, so a caller never writes it.
176
- *
177
- * The codes:
178
- *
179
- * AI0200 — the document is not a program
180
- * AI0201 — a step reads a name nothing produced
181
- * AI0202 — a name is bound twice
182
- * AI0203 — the last step is not `answer`, or there is more than one
183
- * AI0204 — a `reduce` reads something that is not a `map`
184
- * AI0205 — the program is longer than its cap
185
- * AI0206 — a step needs the query seam and none is wired
186
- * AI0207 — a step reading ONE slot was given a family of pieces
187
- * AI0208 — a recursive result has an incompatible or unknown envelope
188
- * AI0209 — a runtime result violates its declared recursive shape
189
- *
190
- * A query that does not compile keeps the QUERY engine's own code
191
- * (`JQ0002`, …) and its pointer is rebased onto the program document,
192
- * so the model is told which step and which member — the same posture
193
- * `refine.js` takes with the patch engine's codes.
194
- */
195
- export class ProgramError extends CodedError {
196
- /**
197
- * @param {string} code - 'AI0200' … 'AI0209'
198
- * @param {string} reason - the bare reason
199
- * @param {string} [docPath] - JSON Pointer into the program document
200
- */
201
- constructor(code: string, reason: string, docPath?: string);
202
- }
203
- export namespace PROGRAM_EXAMPLE {
204
- let steps: ({
205
- op: string;
206
- from: string;
207
- as: string;
208
- strategy: string;
209
- size: number;
210
- prompt?: undefined;
211
- query?: undefined;
212
- } | {
213
- op: string;
214
- from: string;
215
- as: string;
216
- prompt: string;
217
- strategy?: undefined;
218
- size?: undefined;
219
- query?: undefined;
220
- } | {
221
- op: string;
222
- from: string;
223
- as: string;
224
- query: {
225
- $for: {
226
- r: string;
227
- };
228
- $return: string;
229
- };
230
- strategy?: undefined;
231
- size?: undefined;
232
- prompt?: undefined;
233
- } | {
234
- op: string;
235
- from: string;
236
- as?: undefined;
237
- strategy?: undefined;
238
- size?: undefined;
239
- prompt?: undefined;
240
- query?: undefined;
241
- })[];
242
- }
243
- export type ProgramRunResult = import("./program-result.js").ProgramRunResult;
244
- import { CodedError } from '@jarenjs/core/errors';
276
+ export type ProgramRunResult = import('./program-result.ts').ProgramRunResult;