@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.
package/src/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- export type ProgramRunResult = import("./program-result.js").ProgramRunResult;
2
- export type ProgramAnswer = import("./program-result.js").ProgramAnswer;
3
- export type ProgramStepReport = import("./program-result.js").ProgramStepReport;
4
- export type ProgramDiagnostic = import("./program-result.js").ProgramDiagnostic;
5
- export { createProgramSession, questionFingerprint, DEFAULT_REUSE_THRESHOLD } from "./program-session.js";
6
- export { createToolbox, registerModelContext } from "./toolbox.js";
7
- export { createAgent, transcriptText } from "./agent.js";
8
- export { compileProgram, programGate, createProgramRunner, createProgramAuthor, ProgramError, PROGRAM_EXAMPLE, readProgramAnswer } from "./program.js";
9
- export { createLongHorizonAgent, createBudgetAccount, createTrajectory, resolveDepth, childScope, MAX_DEPTH, DEFAULT_DEPTH } from "./recursive.js";
10
- export { createRefiner, describeTrajectory } from "./refine.js";
11
- export { PROGRAM_SCHEMA, programSchema, PROGRAM_OPS, MAX_STEPS, MAX_PROGRAM_CHARS, NAME_PATTERN } from "./schemas/program.js";
1
+ /** agents: public AI mechanisms over injected Jaren foundations. */
2
+ export { createProgramSession, questionFingerprint, DEFAULT_REUSE_THRESHOLD } from './program-session.ts';
3
+ export { createToolbox, registerModelContext } from './toolbox.ts';
4
+ export { createAgent, transcriptText } from './agent.ts';
5
+ export { compileProgram, programGate, createProgramRunner, createProgramAuthor, ProgramError, PROGRAM_EXAMPLE, readProgramAnswer } from './program.ts';
6
+ export { createLongHorizonAgent, createBudgetAccount, createTrajectory, resolveDepth, childScope, MAX_DEPTH, DEFAULT_DEPTH } from './recursive.ts';
7
+ export { createRefiner, describeTrajectory } from './refine.ts';
8
+ export { PROGRAM_SCHEMA, programSchema, PROGRAM_OPS, MAX_STEPS, MAX_PROGRAM_CHARS, NAME_PATTERN } from './schemas/program.ts';
9
+ export type ProgramRunResult = import('./program-result.ts').ProgramRunResult;
10
+ export type ProgramAnswer = import('./program-result.ts').ProgramAnswer;
11
+ export type ProgramStepReport = import('./program-result.ts').ProgramStepReport;
12
+ export type ProgramDiagnostic = import('./program-result.ts').ProgramDiagnostic;
package/src/index.js CHANGED
@@ -1,13 +1,8 @@
1
- //@ts-check
2
1
  /** agents: public AI mechanisms over injected Jaren foundations. */
3
- export { createProgramSession, questionFingerprint, DEFAULT_REUSE_THRESHOLD } from './program-session.js';
4
- export { createToolbox, registerModelContext } from './toolbox.js';
5
- export { createAgent, transcriptText } from './agent.js';
6
- export { compileProgram, programGate, createProgramRunner, createProgramAuthor, ProgramError, PROGRAM_EXAMPLE, readProgramAnswer } from './program.js';
7
- export { createLongHorizonAgent, createBudgetAccount, createTrajectory, resolveDepth, childScope, MAX_DEPTH, DEFAULT_DEPTH } from './recursive.js';
8
- export { createRefiner, describeTrajectory } from './refine.js';
9
- export { PROGRAM_SCHEMA, programSchema, PROGRAM_OPS, MAX_STEPS, MAX_PROGRAM_CHARS, NAME_PATTERN } from './schemas/program.js';
10
- /** @typedef {import('./program-result.js').ProgramRunResult} ProgramRunResult */
11
- /** @typedef {import('./program-result.js').ProgramAnswer} ProgramAnswer */
12
- /** @typedef {import('./program-result.js').ProgramStepReport} ProgramStepReport */
13
- /** @typedef {import('./program-result.js').ProgramDiagnostic} ProgramDiagnostic */
2
+ export { createProgramSession, questionFingerprint, DEFAULT_REUSE_THRESHOLD } from "./program-session.js";
3
+ export { createToolbox, registerModelContext } from "./toolbox.js";
4
+ export { createAgent, transcriptText } from "./agent.js";
5
+ export { compileProgram, programGate, createProgramRunner, createProgramAuthor, ProgramError, PROGRAM_EXAMPLE, readProgramAnswer } from "./program.js";
6
+ export { createLongHorizonAgent, createBudgetAccount, createTrajectory, resolveDepth, childScope, MAX_DEPTH, DEFAULT_DEPTH } from "./recursive.js";
7
+ export { createRefiner, describeTrajectory } from "./refine.js";
8
+ export { PROGRAM_SCHEMA, programSchema, PROGRAM_OPS, MAX_STEPS, MAX_PROGRAM_CHARS, NAME_PATTERN } from "./schemas/program.js";
@@ -1,32 +1,10 @@
1
1
  /** Public program results and bounded access to their stored answers. */
2
- /** @typedef {{ slot: string, size: number, text: string, truncated: boolean }} ProgramAnswer */
3
- /** @typedef {{ code: string, docPath: string, message: string }} ProgramDiagnostic */
4
- /** @typedef {(
5
- * { op: 'chunk', as: string, count: number, family: string } |
6
- * { op: 'grep', as: string, total: number, slots: number, size: number } |
7
- * { op: 'select', as: string, size: number, count?: number } |
8
- * { op: 'stat' | 'peek', as: string, size: number } |
9
- * { op: 'map', as: string, subcalls: number, failed: number, concurrency: number,
10
- * skipped?: number, note?: string, stopped?: string } |
11
- * { op: 'reduce', as: string, over: number, size: number }
12
- * )} ProgramStepReport */
13
- /** @typedef {{ ran: number, steps: ProgramStepReport[], subcalls: number,
14
- * failed: number, concurrency: number, ms: number }} ProgramRunMetrics */
15
- /** @typedef {ProgramRunMetrics & (
16
- * { ok: true, answer: ProgramAnswer, error?: never, errors?: never, stopped?: never } |
17
- * { ok: false, answer: null, error: string, errors?: ProgramDiagnostic[], stopped?: string }
18
- * )} ProgramRunResult */
19
2
  /**
20
3
  * Read a complete answer through the owning environment's scoped ledger.
21
4
  * Check metadata before loading content, then check its actual length as well.
22
5
  * A missing, resized or oversized slot is a refusal, never a parsed preview.
23
- * @param {{ ledger: { getSlot: (name: string) => Promise<{ size: number } | null>,
24
- * readSlot: (name: string) => Promise<unknown> } }} environment
25
- * @param {ProgramAnswer} answer
26
- * @param {{ maxChars: number }} options
27
- * @returns {Promise<{ ok: true, answer: ProgramAnswer } | { ok: false, error: string }>}
28
6
  */
29
- export function readProgramAnswer(environment: {
7
+ export declare function readProgramAnswer(environment: {
30
8
  ledger: {
31
9
  getSlot: (name: string) => Promise<{
32
10
  size: number;
@@ -54,27 +32,27 @@ export type ProgramDiagnostic = {
54
32
  message: string;
55
33
  };
56
34
  export type ProgramStepReport = ({
57
- op: "chunk";
35
+ op: 'chunk';
58
36
  as: string;
59
37
  count: number;
60
38
  family: string;
61
39
  } | {
62
- op: "grep";
40
+ op: 'grep';
63
41
  as: string;
64
42
  total: number;
65
43
  slots: number;
66
44
  size: number;
67
45
  } | {
68
- op: "select";
46
+ op: 'select';
69
47
  as: string;
70
48
  size: number;
71
49
  count?: number;
72
50
  } | {
73
- op: "stat" | "peek";
51
+ op: 'stat' | 'peek';
74
52
  as: string;
75
53
  size: number;
76
54
  } | {
77
- op: "map";
55
+ op: 'map';
78
56
  as: string;
79
57
  subcalls: number;
80
58
  failed: number;
@@ -83,7 +61,7 @@ export type ProgramStepReport = ({
83
61
  note?: string;
84
62
  stopped?: string;
85
63
  } | {
86
- op: "reduce";
64
+ op: 'reduce';
87
65
  as: string;
88
66
  over: number;
89
67
  size: number;
@@ -1,48 +1,24 @@
1
- //@ts-check
2
1
  /** Public program results and bounded access to their stored answers. */
3
-
4
- /** @typedef {{ slot: string, size: number, text: string, truncated: boolean }} ProgramAnswer */
5
- /** @typedef {{ code: string, docPath: string, message: string }} ProgramDiagnostic */
6
- /** @typedef {(
7
- * { op: 'chunk', as: string, count: number, family: string } |
8
- * { op: 'grep', as: string, total: number, slots: number, size: number } |
9
- * { op: 'select', as: string, size: number, count?: number } |
10
- * { op: 'stat' | 'peek', as: string, size: number } |
11
- * { op: 'map', as: string, subcalls: number, failed: number, concurrency: number,
12
- * skipped?: number, note?: string, stopped?: string } |
13
- * { op: 'reduce', as: string, over: number, size: number }
14
- * )} ProgramStepReport */
15
- /** @typedef {{ ran: number, steps: ProgramStepReport[], subcalls: number,
16
- * failed: number, concurrency: number, ms: number }} ProgramRunMetrics */
17
- /** @typedef {ProgramRunMetrics & (
18
- * { ok: true, answer: ProgramAnswer, error?: never, errors?: never, stopped?: never } |
19
- * { ok: false, answer: null, error: string, errors?: ProgramDiagnostic[], stopped?: string }
20
- * )} ProgramRunResult */
21
-
22
2
  /**
23
3
  * Read a complete answer through the owning environment's scoped ledger.
24
4
  * Check metadata before loading content, then check its actual length as well.
25
5
  * A missing, resized or oversized slot is a refusal, never a parsed preview.
26
- * @param {{ ledger: { getSlot: (name: string) => Promise<{ size: number } | null>,
27
- * readSlot: (name: string) => Promise<unknown> } }} environment
28
- * @param {ProgramAnswer} answer
29
- * @param {{ maxChars: number }} options
30
- * @returns {Promise<{ ok: true, answer: ProgramAnswer } | { ok: false, error: string }>}
31
6
  */
32
7
  export async function readProgramAnswer(environment, answer, options) {
33
- const maxChars = options.maxChars;
34
- if (!Number.isSafeInteger(maxChars) || maxChars < 1)
35
- throw new RangeError('maxChars must be a positive safe integer');
36
- if (!answer || typeof answer.slot !== 'string' || !Number.isSafeInteger(answer.size) || answer.size < 0)
37
- return { ok: false, error: 'the program answer has invalid slot metadata' };
38
- if (answer.size > maxChars)
39
- return { ok: false, error: `the program answer exceeds the ${maxChars} character limit` };
40
- const slot = await environment.ledger.getSlot(answer.slot);
41
- if (slot === null) return { ok: false, error: `no answer slot '${answer.slot}'` };
42
- if (slot.size !== answer.size)
43
- return { ok: false, error: `answer slot '${answer.slot}' changed size since the program ran` };
44
- const raw = await environment.ledger.readSlot(answer.slot);
45
- if (typeof raw !== 'string' || raw.length !== answer.size || raw.length > maxChars)
46
- return { ok: false, error: `answer slot '${answer.slot}' no longer matches its bounded size` };
47
- return { ok: true, answer: { slot: answer.slot, size: raw.length, text: raw, truncated: false } };
8
+ const maxChars = options.maxChars;
9
+ if (!Number.isSafeInteger(maxChars) || maxChars < 1)
10
+ throw new RangeError('maxChars must be a positive safe integer');
11
+ if (!answer || typeof answer.slot !== 'string' || !Number.isSafeInteger(answer.size) || answer.size < 0)
12
+ return { ok: false, error: 'the program answer has invalid slot metadata' };
13
+ if (answer.size > maxChars)
14
+ return { ok: false, error: `the program answer exceeds the ${maxChars} character limit` };
15
+ const slot = await environment.ledger.getSlot(answer.slot);
16
+ if (slot === null)
17
+ return { ok: false, error: `no answer slot '${answer.slot}'` };
18
+ if (slot.size !== answer.size)
19
+ return { ok: false, error: `answer slot '${answer.slot}' changed size since the program ran` };
20
+ const raw = await environment.ledger.readSlot(answer.slot);
21
+ if (typeof raw !== 'string' || raw.length !== answer.size || raw.length > maxChars)
22
+ return { ok: false, error: `answer slot '${answer.slot}' no longer matches its bounded size` };
23
+ return { ok: true, answer: { slot: answer.slot, size: raw.length, text: raw, truncated: false } };
48
24
  }
@@ -1,18 +1,14 @@
1
+ /** The fixture frontier requires an outcome checker; hosts must remeasure other embedders. */
2
+ export declare const DEFAULT_REUSE_THRESHOLD = 0.9;
1
3
  /** Hash the exact question; case and whitespace may be meaningful inside record keys.
2
- * @param {string} question */
3
- export function questionFingerprint(question: string): Promise<string>;
4
+ * @param question */
5
+ export declare function questionFingerprint(question: string): Promise<string>;
4
6
  /** Compose author and runner with one fresh fallback and append-only failure evidence.
5
7
  * `check` is required when reuse is enabled, including the first successful stored run.
6
8
  * `accept` proves suitability before a paraphrase executes; an identical fingerprint
7
9
  * under the same host environment identity needs no separate suitability hook.
8
- * @param {{ environment: any, client?: any, compileQuery?: any, createStructuredOutput?: any,
9
- * querySchema?: any, maxRepairs?: number, system?: string, recursive?: boolean,
10
- * analyzeQuery?: any, annotateTypes?: any, selectModel?: any, limits?: any, onRoute?: any,
11
- * depth?: number, account?: any, maxSubcalls?: number, maxConcurrentSubcalls?: number,
12
- * reuse?: { environmentId: string, schemaVersion: string, threshold?: number,
13
- * tools?: string[], embedder?: any, check: (context: any) => any,
14
- * accept?: (context: any) => any }, author?: any, runner?: any }} options */
15
- export function createProgramSession(options: {
10
+ * @param options */
11
+ export declare function createProgramSession(options: {
16
12
  environment: any;
17
13
  client?: any;
18
14
  compileQuery?: any;
@@ -42,7 +38,5 @@ export function createProgramSession(options: {
42
38
  author?: any;
43
39
  runner?: any;
44
40
  }): {
45
- run(question: any, hooks?: {}): Promise<any>;
41
+ run(question: any, hooks?: Record<string, any>): Promise<any>;
46
42
  };
47
- /** The fixture frontier requires an outcome checker; hosts must remeasure other embedders. */
48
- export const DEFAULT_REUSE_THRESHOLD: 0.9;
@@ -1,121 +1,143 @@
1
- //@ts-check
2
1
  /** Verified, opt-in reuse. Retrieval proposes; the host and current compiler decide. */
3
- import { createProgramAuthor, createProgramRunner, programGate } from './program.js';
2
+ import { createProgramAuthor, createProgramRunner, programGate } from "./program.js";
4
3
  import { checkOutcome } from '@jarenjs/core/check';
5
-
6
4
  /** The fixture frontier requires an outcome checker; hosts must remeasure other embedders. */
7
5
  export const DEFAULT_REUSE_THRESHOLD = 0.9;
8
-
9
6
  /** Hash the exact question; case and whitespace may be meaningful inside record keys.
10
- * @param {string} question */
7
+ * @param question */
11
8
  export async function questionFingerprint(question) {
12
- const bytes = new TextEncoder().encode(question);
13
- const hash = await globalThis.crypto.subtle.digest('SHA-256', bytes);
14
- return Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, '0')).join('');
9
+ const bytes = new TextEncoder().encode(question);
10
+ const hash = await globalThis.crypto.subtle.digest('SHA-256', bytes);
11
+ return Array.from(new Uint8Array(hash), (byte) => byte.toString(16).padStart(2, '0')).join('');
15
12
  }
16
-
17
13
  /** Compose author and runner with one fresh fallback and append-only failure evidence.
18
14
  * `check` is required when reuse is enabled, including the first successful stored run.
19
15
  * `accept` proves suitability before a paraphrase executes; an identical fingerprint
20
16
  * under the same host environment identity needs no separate suitability hook.
21
- * @param {{ environment: any, client?: any, compileQuery?: any, createStructuredOutput?: any,
22
- * querySchema?: any, maxRepairs?: number, system?: string, recursive?: boolean,
23
- * analyzeQuery?: any, annotateTypes?: any, selectModel?: any, limits?: any, onRoute?: any,
24
- * depth?: number, account?: any, maxSubcalls?: number, maxConcurrentSubcalls?: number,
25
- * reuse?: { environmentId: string, schemaVersion: string, threshold?: number,
26
- * tools?: string[], embedder?: any, check: (context: any) => any,
27
- * accept?: (context: any) => any }, author?: any, runner?: any }} options */
17
+ * @param options */
28
18
  export function createProgramSession(options) {
29
- const author = options.author ?? createProgramAuthor(options);
30
- const runner = options.runner ?? createProgramRunner(options);
31
- const policy = options.reuse;
32
- if (policy !== undefined && (typeof policy.check !== 'function'
33
- || !policy.environmentId || !policy.schemaVersion))
34
- throw new TypeError('program reuse needs environmentId, schemaVersion and an outcome check');
35
- const threshold = policy?.threshold ?? DEFAULT_REUSE_THRESHOLD;
36
- if (!Number.isFinite(threshold) || threshold < -1 || threshold > 1)
37
- throw new TypeError('reuse threshold must be finite and between -1 and 1');
38
- const ledger = options.environment.ledger;
39
-
40
- return {
41
- async run(question, hooks = {}) {
42
- const events = [];
43
- const fingerprint = policy ? await questionFingerprint(question) : null;
44
- const tools = [...(policy?.tools ?? [])].sort();
45
- let candidate = null;
46
- let attempts = 0;
47
- const failed = async (skill, reason) => {
48
- events.push({ kind: 'rejected', skill: skill.id, reason });
49
- const evidence = await ledger.addMemory({ text: `Program reuse failed: ${reason}`,
50
- evidence: `skill:${skill.id}; question:${fingerprint}`, tags: ['program-reuse-failure'] });
51
- if (evidence.error) events.push({ kind: 'storage-error', operation: 'failure-evidence' });
52
- };
53
- if (policy && !hooks.signal?.aborted) {
54
- const recalled = await ledger.recallSkills({ near: question, limit: 5, minScore: threshold });
55
- events.push({ kind: 'retrieval', error: recalled.error ?? null });
56
- for (const [index, skill] of (recalled.skills ?? []).entries()) {
57
- const stored = skill.program;
58
- if (!stored) continue;
59
- const reason = stored.version !== 1 || stored.schemaVersion !== policy.schemaVersion ? 'schema-drift'
60
- : stored.environmentId !== policy.environmentId ? 'environment-drift'
61
- : JSON.stringify([...skill.tools].sort()) !== JSON.stringify(tools) ? 'tool-drift'
62
- : stored.checked !== true ? 'missing-success' : null;
63
- if (reason) { await failed(skill, reason); continue; }
64
- // A returned metadata record is mutable in some storage adapters. Validate
65
- // and compile it again rather than trusting a past compiler or cached closure.
66
- const names = (await ledger.listSlots()).map((slot) => slot.name);
67
- const gate = programGate({ compileQuery: options.compileQuery, known: names,
68
- recursive: options.recursive, analyzeQuery: options.analyzeQuery, annotateTypes: options.annotateTypes })(stored.document);
69
- if (gate !== true) { await failed(skill, 'compile-gate'); continue; }
70
- let suitable = stored.fingerprint === fingerprint;
71
- if (!suitable && policy.accept) {
72
- try { suitable = await policy.accept({ question, skill, score: recalled.scores[index] }) === true; }
73
- catch { suitable = false; }
74
- }
75
- if (!suitable) { await failed(skill, 'unsuitable'); continue; }
76
- candidate = skill;
77
- break;
78
- }
79
- }
80
- if (candidate) {
81
- const result = await runner.run(candidate.program.document, hooks);
82
- let accepted = false;
83
- if (result.ok) {
84
- try { accepted = checkOutcome(await policy.check({ question, result, reused: true })).valid; }
85
- catch { /* A checker exception is a failed reuse, never implicit success. */ }
86
- }
87
- if (accepted) {
88
- events.push({ kind: 'reused', skill: candidate.id });
89
- return { ...result, program: candidate.program.document, reuse: { reused: true, authorCalls: 0, fallback: false, events } };
90
- }
91
- await failed(candidate, result.ok ? 'wrong-outcome' : 'execution-failed');
92
- }
93
- if (hooks.signal?.aborted) return { ok: false, stopped: 'aborted', reuse: { reused: false, authorCalls: 0, events } };
94
- const authored = await author.author(question, hooks);
95
- attempts += authored.attempts ?? 1;
96
- const reuse = { reused: false, authorCalls: attempts, fallback: candidate !== null || events.some((event) => event.kind === 'rejected'), events };
97
- if (authored.value === undefined) return { ok: false, errors: authored.errors, reuse };
98
- const result = await runner.run(authored.value, hooks);
99
- if (!policy || !result.ok) return { ...result, program: authored.value, reuse };
100
- let checked = false;
101
- try { checked = checkOutcome(await policy.check({ question, result, reused: false })).valid; }
102
- catch { /* A failed fresh check ends this request; fallback never loops. */ }
103
- if (!checked) return { ...result, ok: false, error: 'fresh program failed outcome check', reuse };
104
- let pair = {};
105
- if (policy.embedder) {
106
- try {
107
- const [vector] = await policy.embedder.embed([question], { signal: hooks.signal });
108
- pair = { embedding: Array.from(vector), embeddedBy: { model: policy.embedder.model, dims: policy.embedder.dims } };
109
- }
110
- catch { events.push({ kind: 'embedding-failed' }); }
111
- }
112
- const saved = await ledger.addSkill({ name: 'Verified program', when: question,
113
- instructions: 'Run the verified program after checking its requirements.', tools, ...pair,
114
- program: { version: 1, question, fingerprint, environmentId: policy.environmentId,
115
- schemaVersion: policy.schemaVersion, document: authored.value,
116
- evidence: `outcome-check:${fingerprint}`, checked: true } });
117
- events.push(saved.error ? { kind: 'storage-error', operation: 'successful-program' } : { kind: 'stored', skill: saved.id });
118
- return { ...result, program: authored.value, reuse };
119
- },
120
- };
19
+ const author = options.author ?? createProgramAuthor({ ...options, client: options.client, createStructuredOutput: options.createStructuredOutput });
20
+ const runner = options.runner ?? createProgramRunner(options);
21
+ const policy = options.reuse;
22
+ if (policy !== undefined && (typeof policy.check !== 'function'
23
+ || !policy.environmentId || !policy.schemaVersion))
24
+ throw new TypeError('program reuse needs environmentId, schemaVersion and an outcome check');
25
+ const threshold = policy?.threshold ?? DEFAULT_REUSE_THRESHOLD;
26
+ if (!Number.isFinite(threshold) || threshold < -1 || threshold > 1)
27
+ throw new TypeError('reuse threshold must be finite and between -1 and 1');
28
+ const ledger = options.environment.ledger;
29
+ return {
30
+ async run(question, hooks = {}) {
31
+ const events = [];
32
+ const fingerprint = policy ? await questionFingerprint(question) : null;
33
+ const tools = [...(policy?.tools ?? [])].sort();
34
+ let candidate = null;
35
+ let attempts = 0;
36
+ const failed = async (skill, reason) => {
37
+ events.push({ kind: 'rejected', skill: skill.id, reason });
38
+ const evidence = await ledger.addMemory({
39
+ text: `Program reuse failed: ${reason}`,
40
+ evidence: `skill:${skill.id}; question:${fingerprint}`, tags: ['program-reuse-failure']
41
+ });
42
+ if (evidence.error)
43
+ events.push({ kind: 'storage-error', operation: 'failure-evidence' });
44
+ };
45
+ if (policy && !hooks.signal?.aborted) {
46
+ const recalled = await ledger.recallSkills({ near: question, limit: 5, minScore: threshold });
47
+ events.push({ kind: 'retrieval', error: recalled.error ?? null });
48
+ for (const [index, skill] of (recalled.skills ?? []).entries()) {
49
+ const stored = skill.program;
50
+ if (!stored)
51
+ continue;
52
+ const reason = stored.version !== 1 || stored.schemaVersion !== policy.schemaVersion ? 'schema-drift'
53
+ : stored.environmentId !== policy.environmentId ? 'environment-drift'
54
+ : JSON.stringify([...skill.tools].sort()) !== JSON.stringify(tools) ? 'tool-drift'
55
+ : stored.checked !== true ? 'missing-success' : null;
56
+ if (reason) {
57
+ await failed(skill, reason);
58
+ continue;
59
+ }
60
+ // A returned metadata record is mutable in some storage adapters. Validate
61
+ // and compile it again rather than trusting a past compiler or cached closure.
62
+ const names = (await ledger.listSlots()).map((slot) => slot.name);
63
+ const gate = programGate({
64
+ compileQuery: options.compileQuery, known: names,
65
+ recursive: options.recursive, analyzeQuery: options.analyzeQuery, annotateTypes: options.annotateTypes
66
+ })(stored.document);
67
+ if (gate !== true) {
68
+ await failed(skill, 'compile-gate');
69
+ continue;
70
+ }
71
+ let suitable = stored.fingerprint === fingerprint;
72
+ if (!suitable && policy.accept) {
73
+ try {
74
+ suitable = await policy.accept({ question, skill, score: recalled.scores[index] }) === true;
75
+ }
76
+ catch {
77
+ suitable = false;
78
+ }
79
+ }
80
+ if (!suitable) {
81
+ await failed(skill, 'unsuitable');
82
+ continue;
83
+ }
84
+ candidate = skill;
85
+ break;
86
+ }
87
+ }
88
+ if (candidate) {
89
+ const result = await runner.run(candidate.program.document, hooks);
90
+ let accepted = false;
91
+ if (result.ok) {
92
+ try {
93
+ accepted = checkOutcome(await policy.check({ question, result, reused: true })).valid;
94
+ }
95
+ catch { /* A checker exception is a failed reuse, never implicit success. */ }
96
+ }
97
+ if (accepted) {
98
+ events.push({ kind: 'reused', skill: candidate.id });
99
+ return { ...result, program: candidate.program.document, reuse: { reused: true, authorCalls: 0, fallback: false, events } };
100
+ }
101
+ await failed(candidate, result.ok ? 'wrong-outcome' : 'execution-failed');
102
+ }
103
+ if (hooks.signal?.aborted)
104
+ return { ok: false, stopped: 'aborted', reuse: { reused: false, authorCalls: 0, events } };
105
+ const authored = await author.author(question, hooks);
106
+ attempts += authored.attempts ?? 1;
107
+ const reuse = { reused: false, authorCalls: attempts, fallback: candidate !== null || events.some((event) => event.kind === 'rejected'), events };
108
+ if (authored.value === undefined)
109
+ return { ok: false, errors: authored.errors, reuse };
110
+ const result = await runner.run(authored.value, hooks);
111
+ if (!policy || !result.ok)
112
+ return { ...result, program: authored.value, reuse };
113
+ let checked = false;
114
+ try {
115
+ checked = checkOutcome(await policy.check({ question, result, reused: false })).valid;
116
+ }
117
+ catch { /* A failed fresh check ends this request; fallback never loops. */ }
118
+ if (!checked)
119
+ return { ...result, ok: false, error: 'fresh program failed outcome check', reuse };
120
+ let pair = {};
121
+ if (policy.embedder) {
122
+ try {
123
+ const [vector] = await policy.embedder.embed([question], { signal: hooks.signal });
124
+ pair = { embedding: Array.from(vector), embeddedBy: { model: policy.embedder.model, dims: policy.embedder.dims } };
125
+ }
126
+ catch {
127
+ events.push({ kind: 'embedding-failed' });
128
+ }
129
+ }
130
+ const saved = await ledger.addSkill({
131
+ name: 'Verified program', when: question,
132
+ instructions: 'Run the verified program after checking its requirements.', tools, ...pair,
133
+ program: {
134
+ version: 1, question, fingerprint, environmentId: policy.environmentId,
135
+ schemaVersion: policy.schemaVersion, document: authored.value,
136
+ evidence: `outcome-check:${fingerprint}`, checked: true
137
+ }
138
+ });
139
+ events.push(saved.error ? { kind: 'storage-error', operation: 'successful-program' } : { kind: 'stored', skill: saved.id });
140
+ return { ...result, program: authored.value, reuse };
141
+ },
142
+ };
121
143
  }
@@ -1,21 +1,21 @@
1
+ /** Recursive answers carry the same envelope as map elements. Query engines stay injected. */
2
+ export declare const RECURSIVE_ITEM_SCHEMA: {
3
+ type: string;
4
+ properties: {
5
+ slot: {
6
+ type: string;
7
+ };
8
+ value: {};
9
+ };
10
+ required: string[];
11
+ };
1
12
  /** Query singleton normalization: empty sequence, one item, or several items.
2
- * @param {any} value */
3
- export function recursiveItems(value: any): any[];
13
+ * @param value */
14
+ export declare function recursiveItems(value: any): any[] | null;
4
15
  /** Conservatively prove a declared item/sequence schema. Unknown schema keywords
5
16
  * never manufacture required properties. Runtime validation enforces the full declaration.
6
- * @param {any} schema @param {boolean} [item] @returns {boolean} */
7
- export function recursiveSchema(schema: any, item?: boolean): boolean;
17
+ * @param schema @param [item] @returns */
18
+ export declare function recursiveSchema(schema: any, item?: boolean): boolean;
8
19
  /** Three-valued structural proof over the existing annotated query AST.
9
- * @param {any} node @param {boolean} [item] @returns {'compatible'|'incompatible'|'unknown'} */
10
- export function recursiveShape(node: any, item?: boolean): "compatible" | "incompatible" | "unknown";
11
- export namespace RECURSIVE_ITEM_SCHEMA {
12
- let type: string;
13
- namespace properties {
14
- namespace slot {
15
- let type_1: string;
16
- export { type_1 as type };
17
- }
18
- let value: {};
19
- }
20
- let required: string[];
21
- }
20
+ * @param node @param [item] @returns */
21
+ export declare function recursiveShape(node: any, item?: boolean): 'compatible' | 'incompatible' | 'unknown';