@tangleai/context 0.21.1 → 0.25.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.
@@ -1,12 +1,38 @@
1
1
  /**
2
- * Path-discriminated RFC 6902 operations. Provider decoding uses this same
3
- * schema in non-strict mode; local validation remains authoritative.
4
- * @param {{ maxOps?: number }} [options]
5
- * @returns {any}
2
+ * The refinement patch: a deliberately small subset of RFC 6902.
3
+ *
4
+ * A model that has finished a run is asked what it learned. The unsafe
5
+ * answer is a rewritten prompt or a restated set of memories — a
6
+ * rewrite is unreviewable, unbounded, and a model asked to restate what
7
+ * it remembers will drift it. The safe answer is a PATCH: small enough
8
+ * to read, addressed enough to audit, and reversible with a snapshot.
9
+ *
10
+ * Three restrictions, and each one exists because the alternative fails
11
+ * on the tier this package targets:
12
+ *
13
+ * - **`path` is a pattern, not a free string.** It matches exactly the
14
+ * supplemental subtree — append or replace a memory, append or
15
+ * replace a skill, append one progress entry — and nothing else. The
16
+ * base system prompt is not merely undocumented as a target, it is
17
+ * unaddressable: it is not in the document a refinement is applied
18
+ * to, and no path that could reach it matches this pattern. That is
19
+ * D5 asserted rather than described.
20
+ * - **`op` is three verbs.** `move`, `copy` and `test` are legal RFC
21
+ * 6902 and useless here; every one of them is another shape a small
22
+ * model can get subtly wrong, and none of them expresses anything
23
+ * `add`/`replace`/`remove` cannot.
24
+ * - **The number of operations is capped.** A refinement is meant to be
25
+ * a few evidence-backed updates. A patch of forty operations is a
26
+ * rewrite wearing a patch's clothes, and it is also the shape that
27
+ * makes a repair round useless — the model cannot tell which of forty
28
+ * operations the error came from.
29
+ *
30
+ * `value` carries no `id` and no `at` on purpose. Identity and time are
31
+ * the ledger's to mint: a model that could choose an id could overwrite
32
+ * a record it never read, and a model that could choose a timestamp
33
+ * could put a memory in front of one that came later — the recency
34
+ * ordering everything downstream depends on is not the model's to set.
6
35
  */
7
- export function refinementPatchSchema(options?: {
8
- maxOps?: number;
9
- }): any;
10
36
  /**
11
37
  * Where a refinement may write. Anchored, and read as: append or address
12
38
  * one memory, append or address one skill, append one progress entry.
@@ -16,20 +42,28 @@ export function refinementPatchSchema(options?: {
16
42
  * a memory is revised by replacing it whole, with fresh evidence, so
17
43
  * that every stored record was validated as a whole exactly once.
18
44
  */
19
- export const REFINEMENT_PATH_PATTERN: "^(/memories/(-|[0-9]+)|/skills/(-|[0-9]+)|/goal/progress/-)$";
45
+ export declare const REFINEMENT_PATH_PATTERN = "^(/memories/(-|[0-9]+)|/skills/(-|[0-9]+)|/goal/progress/-)$";
20
46
  /** The default cap on operations per refinement. */
21
- export const DEFAULT_MAX_OPS: 6;
22
- export namespace MEMORY_PROPOSAL_SCHEMA {
23
- let type: string;
24
- namespace properties {
25
- namespace text {
26
- let type_1: string;
27
- export { type_1 as type };
28
- export let minLength: number;
29
- export let description: string;
30
- }
31
- namespace evidence {
32
- let anyOf: ({
47
+ export declare const DEFAULT_MAX_OPS = 6;
48
+ /**
49
+ * A proposed memory. `evidence` is required here AND by the ledger's own
50
+ * schema — the same requirement twice, on purpose: this copy is what
51
+ * constrains decoding (a model generating against it tends to write the
52
+ * evidence rather than be corrected into it), and the ledger's copy is
53
+ * what makes the rule true even for a patch that never went near a
54
+ * model. It is the mechanism that stops a refinement laundering a
55
+ * hallucination into durable state.
56
+ */
57
+ export declare const MEMORY_PROPOSAL_SCHEMA: {
58
+ type: string;
59
+ properties: {
60
+ text: {
61
+ type: string;
62
+ minLength: number;
63
+ description: string;
64
+ };
65
+ evidence: {
66
+ anyOf: ({
33
67
  type: "object";
34
68
  properties: Record<string, object>;
35
69
  required: string[];
@@ -38,92 +72,72 @@ export namespace MEMORY_PROPOSAL_SCHEMA {
38
72
  type: string;
39
73
  minLength: number;
40
74
  })[];
41
- }
42
- namespace tags {
43
- let type_2: string;
44
- export { type_2 as type };
45
- export namespace items {
46
- let type_3: string;
47
- export { type_3 as type };
48
- let minLength_1: number;
49
- export { minLength_1 as minLength };
50
- }
51
- }
52
- }
53
- let required: string[];
54
- let additionalProperties: boolean;
55
- }
56
- export namespace SKILL_PROPOSAL_SCHEMA {
57
- let type_4: string;
58
- export { type_4 as type };
59
- export namespace properties_1 {
60
- namespace name {
61
- let type_5: string;
62
- export { type_5 as type };
63
- let minLength_2: number;
64
- export { minLength_2 as minLength };
65
- }
66
- namespace when {
67
- let type_6: string;
68
- export { type_6 as type };
69
- let minLength_3: number;
70
- export { minLength_3 as minLength };
71
- let description_1: string;
72
- export { description_1 as description };
73
- }
74
- namespace instructions {
75
- let type_7: string;
76
- export { type_7 as type };
77
- let minLength_4: number;
78
- export { minLength_4 as minLength };
79
- let description_2: string;
80
- export { description_2 as description };
81
- }
82
- namespace tools {
83
- let type_8: string;
84
- export { type_8 as type };
85
- export namespace items_1 {
86
- let type_9: string;
87
- export { type_9 as type };
88
- let minLength_5: number;
89
- export { minLength_5 as minLength };
90
- }
91
- export { items_1 as items };
92
- }
93
- }
94
- export { properties_1 as properties };
95
- let required_1: string[];
96
- export { required_1 as required };
97
- let additionalProperties_1: boolean;
98
- export { additionalProperties_1 as additionalProperties };
99
- }
100
- export namespace PROGRESS_PROPOSAL_SCHEMA {
101
- let type_10: string;
102
- export { type_10 as type };
103
- export namespace properties_2 {
104
- export namespace note {
105
- let type_11: string;
106
- export { type_11 as type };
107
- let minLength_6: number;
108
- export { minLength_6 as minLength };
109
- let description_3: string;
110
- export { description_3 as description };
111
- }
112
- export namespace evidence_1 {
113
- let type_12: string;
114
- export { type_12 as type };
115
- let minLength_7: number;
116
- export { minLength_7 as minLength };
117
- let description_4: string;
118
- export { description_4 as description };
119
- }
120
- export { evidence_1 as evidence };
121
- }
122
- export { properties_2 as properties };
123
- let required_2: string[];
124
- export { required_2 as required };
125
- let additionalProperties_2: boolean;
126
- export { additionalProperties_2 as additionalProperties };
127
- }
75
+ };
76
+ tags: {
77
+ type: string;
78
+ items: {
79
+ type: string;
80
+ minLength: number;
81
+ };
82
+ };
83
+ };
84
+ required: string[];
85
+ additionalProperties: boolean;
86
+ };
87
+ /** A proposed skill: when it applies, what to do, which tools it needs. */
88
+ export declare const SKILL_PROPOSAL_SCHEMA: {
89
+ type: string;
90
+ properties: {
91
+ name: {
92
+ type: string;
93
+ minLength: number;
94
+ };
95
+ when: {
96
+ type: string;
97
+ minLength: number;
98
+ description: string;
99
+ };
100
+ instructions: {
101
+ type: string;
102
+ minLength: number;
103
+ description: string;
104
+ };
105
+ tools: {
106
+ type: string;
107
+ items: {
108
+ type: string;
109
+ minLength: number;
110
+ };
111
+ };
112
+ };
113
+ required: string[];
114
+ additionalProperties: boolean;
115
+ };
116
+ /** A proposed progress entry against the active goal. */
117
+ export declare const PROGRESS_PROPOSAL_SCHEMA: {
118
+ type: string;
119
+ properties: {
120
+ note: {
121
+ type: string;
122
+ minLength: number;
123
+ description: string;
124
+ };
125
+ evidence: {
126
+ type: string;
127
+ minLength: number;
128
+ description: string;
129
+ };
130
+ };
131
+ required: string[];
132
+ additionalProperties: boolean;
133
+ };
134
+ /**
135
+ * Path-discriminated RFC 6902 operations. Provider decoding uses this same
136
+ * schema in non-strict mode; local validation remains authoritative.
137
+ * @param [options]
138
+ */
139
+ export declare function refinementPatchSchema(options?: {
140
+ maxOps?: number;
141
+ }): any;
128
142
  /** The full schema used for handwritten and generated proposals alike. */
129
- export const REFINEMENT_PATCH_SCHEMA: any;
143
+ export declare const REFINEMENT_PATCH_SCHEMA: any;
@@ -1,4 +1,3 @@
1
- //@ts-check
2
1
  /**
3
2
  * The refinement patch: a deliberately small subset of RFC 6902.
4
3
  *
@@ -34,9 +33,7 @@
34
33
  * could put a memory in front of one that came later — the recency
35
34
  * ordering everything downstream depends on is not the model's to set.
36
35
  */
37
-
38
- import { CLAIM_EVIDENCE_SCHEMA } from './evidence.js';
39
-
36
+ import { CLAIM_EVIDENCE_SCHEMA } from "./evidence.js";
40
37
  /**
41
38
  * Where a refinement may write. Anchored, and read as: append or address
42
39
  * one memory, append or address one skill, append one progress entry.
@@ -46,12 +43,9 @@ import { CLAIM_EVIDENCE_SCHEMA } from './evidence.js';
46
43
  * a memory is revised by replacing it whole, with fresh evidence, so
47
44
  * that every stored record was validated as a whole exactly once.
48
45
  */
49
- export const REFINEMENT_PATH_PATTERN =
50
- '^(/memories/(-|[0-9]+)|/skills/(-|[0-9]+)|/goal/progress/-)$';
51
-
46
+ export const REFINEMENT_PATH_PATTERN = '^(/memories/(-|[0-9]+)|/skills/(-|[0-9]+)|/goal/progress/-)$';
52
47
  /** The default cap on operations per refinement. */
53
48
  export const DEFAULT_MAX_OPS = 6;
54
-
55
49
  /**
56
50
  * A proposed memory. `evidence` is required here AND by the ledger's own
57
51
  * schema — the same requirement twice, on purpose: this copy is what
@@ -62,74 +56,75 @@ export const DEFAULT_MAX_OPS = 6;
62
56
  * hallucination into durable state.
63
57
  */
64
58
  export const MEMORY_PROPOSAL_SCHEMA = {
65
- type: 'object',
66
- properties: {
67
- text: { type: 'string', minLength: 1, description: 'The fact worth carrying, in one sentence.' },
68
- evidence: { anyOf: [{ type: 'string', minLength: 1 }, CLAIM_EVIDENCE_SCHEMA] },
69
- tags: { type: 'array', items: { type: 'string', minLength: 1 } },
70
- },
71
- required: ['text', 'evidence'],
72
- additionalProperties: false,
59
+ type: 'object',
60
+ properties: {
61
+ text: { type: 'string', minLength: 1, description: 'The fact worth carrying, in one sentence.' },
62
+ evidence: { anyOf: [{ type: 'string', minLength: 1 }, CLAIM_EVIDENCE_SCHEMA] },
63
+ tags: { type: 'array', items: { type: 'string', minLength: 1 } },
64
+ },
65
+ required: ['text', 'evidence'],
66
+ additionalProperties: false,
73
67
  };
74
-
75
68
  /** A proposed skill: when it applies, what to do, which tools it needs. */
76
69
  export const SKILL_PROPOSAL_SCHEMA = {
77
- type: 'object',
78
- properties: {
79
- name: { type: 'string', minLength: 1 },
80
- when: { type: 'string', minLength: 1, description: 'The situation this recipe applies to.' },
81
- instructions: { type: 'string', minLength: 1, description: 'The steps, concretely.' },
82
- tools: { type: 'array', items: { type: 'string', minLength: 1 } },
83
- },
84
- required: ['name', 'when', 'instructions'],
85
- additionalProperties: false,
70
+ type: 'object',
71
+ properties: {
72
+ name: { type: 'string', minLength: 1 },
73
+ when: { type: 'string', minLength: 1, description: 'The situation this recipe applies to.' },
74
+ instructions: { type: 'string', minLength: 1, description: 'The steps, concretely.' },
75
+ tools: { type: 'array', items: { type: 'string', minLength: 1 } },
76
+ },
77
+ required: ['name', 'when', 'instructions'],
78
+ additionalProperties: false,
86
79
  };
87
-
88
80
  /** A proposed progress entry against the active goal. */
89
81
  export const PROGRESS_PROPOSAL_SCHEMA = {
90
- type: 'object',
91
- properties: {
92
- note: { type: 'string', minLength: 1, description: 'What was done or established.' },
93
- evidence: { type: 'string', minLength: 1, description: 'What in the run establishes it.' },
94
- },
95
- required: ['note', 'evidence'],
96
- additionalProperties: false,
82
+ type: 'object',
83
+ properties: {
84
+ note: { type: 'string', minLength: 1, description: 'What was done or established.' },
85
+ evidence: { type: 'string', minLength: 1, description: 'What in the run establishes it.' },
86
+ },
87
+ required: ['note', 'evidence'],
88
+ additionalProperties: false,
97
89
  };
98
-
99
90
  /**
100
91
  * Path-discriminated RFC 6902 operations. Provider decoding uses this same
101
92
  * schema in non-strict mode; local validation remains authoritative.
102
- * @param {{ maxOps?: number }} [options]
103
- * @returns {any}
93
+ * @param [options]
104
94
  */
105
95
  export function refinementPatchSchema(options = {}) {
106
- const maxOps = options.maxOps ?? DEFAULT_MAX_OPS;
107
- if (!Number.isSafeInteger(maxOps) || maxOps < 0)
108
- throw new TypeError('maxOps must be a non-negative safe integer');
109
- const branch = (op, pattern, value) => ({
110
- type: 'object',
111
- properties: { op: { enum: op }, path: { type: 'string', pattern },
112
- ...(value ? { value } : {}) },
113
- required: value ? ['op', 'path', 'value'] : ['op', 'path'],
114
- additionalProperties: false,
115
- });
116
- const index = '(0|[1-9][0-9]*)';
117
- return {
118
- $id: 'https://jarenjs.github.io/schemas/ai/refinement-patch.json',
119
- title: 'Refinement patch',
120
- type: 'array', maxItems: maxOps,
121
- $defs: { memory: MEMORY_PROPOSAL_SCHEMA, skill: SKILL_PROPOSAL_SCHEMA,
122
- progress: PROGRESS_PROPOSAL_SCHEMA },
123
- items: { oneOf: [
124
- ...[['memories', 'memory'], ['skills', 'skill']].flatMap(([path, kind]) => [
125
- branch(['add'], `^/${path}/(-|${index})$`, { $ref: `#/$defs/${kind}` }),
126
- branch(['replace'], `^/${path}/${index}$`, { $ref: `#/$defs/${kind}` }),
127
- branch(['remove'], `^/${path}/${index}$`, null),
128
- ]),
129
- branch(['add'], '^/goal/progress/-$', { $ref: '#/$defs/progress' }),
130
- ] },
131
- };
96
+ const maxOps = options.maxOps ?? DEFAULT_MAX_OPS;
97
+ if (!Number.isSafeInteger(maxOps) || maxOps < 0)
98
+ throw new TypeError('maxOps must be a non-negative safe integer');
99
+ const branch = (op, pattern, value) => ({
100
+ type: 'object',
101
+ properties: {
102
+ op: { enum: op }, path: { type: 'string', pattern },
103
+ ...(value ? { value } : {})
104
+ },
105
+ required: value ? ['op', 'path', 'value'] : ['op', 'path'],
106
+ additionalProperties: false,
107
+ });
108
+ const index = '(0|[1-9][0-9]*)';
109
+ return {
110
+ $id: 'https://jarenjs.github.io/schemas/ai/refinement-patch.json',
111
+ title: 'Refinement patch',
112
+ type: 'array', maxItems: maxOps,
113
+ $defs: {
114
+ memory: MEMORY_PROPOSAL_SCHEMA, skill: SKILL_PROPOSAL_SCHEMA,
115
+ progress: PROGRESS_PROPOSAL_SCHEMA
116
+ },
117
+ items: {
118
+ oneOf: [
119
+ ...[['memories', 'memory'], ['skills', 'skill']].flatMap(([path, kind]) => [
120
+ branch(['add'], `^/${path}/(-|${index})$`, { $ref: `#/$defs/${kind}` }),
121
+ branch(['replace'], `^/${path}/${index}$`, { $ref: `#/$defs/${kind}` }),
122
+ branch(['remove'], `^/${path}/${index}$`, null),
123
+ ]),
124
+ branch(['add'], '^/goal/progress/-$', { $ref: '#/$defs/progress' }),
125
+ ]
126
+ },
127
+ };
132
128
  }
133
-
134
129
  /** The full schema used for handwritten and generated proposals alike. */
135
130
  export const REFINEMENT_PATCH_SCHEMA = refinementPatchSchema();
@@ -70,17 +70,12 @@
70
70
  * copies: a caller that mutates what it stored — or what it read —
71
71
  * cannot reach inside the ledger.
72
72
  *
73
- * @param {Map<string, string>} [backing] - an existing map to adopt
74
- * @returns {{ get: (key: string) => Promise<any>,
75
- * set: (key: string, value: any) => Promise<void>,
76
- * delete: (key: string) => Promise<void>,
77
- * keys: (prefix?: string) => Promise<string[]>,
78
- * mutate: import('./transaction.js').StorageMutation }}
73
+ * @param [backing] - an existing map to adopt
79
74
  */
80
- export function createMemoryStorage(backing?: Map<string, string>): {
75
+ export declare function createMemoryStorage(backing?: Map<string, string>): {
81
76
  get: (key: string) => Promise<any>;
82
77
  set: (key: string, value: any) => Promise<void>;
83
78
  delete: (key: string) => Promise<void>;
84
79
  keys: (prefix?: string) => Promise<string[]>;
85
- mutate: import("./transaction.js").StorageMutation;
80
+ mutate: import('./transaction.ts').StorageMutation;
86
81
  };
@@ -1,4 +1,3 @@
1
- //@ts-check
2
1
  /**
3
2
  * The in-memory storage adapter: the ledger's default, and the reason
4
3
  * `createLedger()` works with no arguments at all.
@@ -58,7 +57,6 @@
58
57
  * `via: 'sweep'` — which is why the in-memory adapter below does not
59
58
  * grow it.
60
59
  */
61
-
62
60
  /**
63
61
  * Create an in-memory adapter with JSON-value semantics: every value is
64
62
  * serialized on the way in and parsed on the way out, so what survives
@@ -72,47 +70,47 @@
72
70
  * copies: a caller that mutates what it stored — or what it read —
73
71
  * cannot reach inside the ledger.
74
72
  *
75
- * @param {Map<string, string>} [backing] - an existing map to adopt
76
- * @returns {{ get: (key: string) => Promise<any>,
77
- * set: (key: string, value: any) => Promise<void>,
78
- * delete: (key: string) => Promise<void>,
79
- * keys: (prefix?: string) => Promise<string[]>,
80
- * mutate: import('./transaction.js').StorageMutation }}
73
+ * @param [backing] - an existing map to adopt
81
74
  */
82
75
  export function createMemoryStorage(backing = new Map()) {
83
- return {
84
- mutate: async (prefix, transform) => {
85
- const matches = (key) => typeof prefix === 'string' ? key.startsWith(prefix)
86
- : (prefix.keys ?? []).includes(key) || (prefix.prefixes ?? []).some((part) => key.startsWith(part));
87
- // No await between read and publication: even separate adapters sharing
88
- // this map observe one complete mutation. Serialize every value first.
89
- const current = Object.fromEntries([...backing].filter(([key]) => matches(key))
90
- .sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)
91
- .map(([key, raw]) => [key, JSON.parse(raw)]));
92
- const outcome = transform(current);
93
- if (!outcome || typeof outcome.then === 'function') throw new TypeError('mutate callback must be synchronous');
94
- if (outcome.next !== undefined) {
95
- const entries = Object.entries(outcome.next).map(([key, value]) => {
96
- if (!matches(key)) throw new TypeError('mutation escaped its namespace');
97
- return [key, JSON.stringify(value)];
98
- });
99
- for (const key of backing.keys()) if (matches(key)) backing.delete(key);
100
- for (const [key, raw] of entries) backing.set(key, raw);
101
- }
102
- return outcome.result;
103
- },
104
- get: async (key) => {
105
- const raw = backing.get(key);
106
- return raw === undefined ? undefined : JSON.parse(raw);
107
- },
108
- set: async (key, value) => {
109
- backing.set(key, JSON.stringify(value));
110
- },
111
- delete: async (key) => {
112
- backing.delete(key);
113
- },
114
- keys: async (prefix = '') => [...backing.keys()]
115
- .filter((key) => key.startsWith(prefix))
116
- .sort(),
117
- };
76
+ return {
77
+ mutate: async (prefix, transform) => {
78
+ const matches = (key) => typeof prefix === 'string' ? key.startsWith(prefix)
79
+ : (prefix.keys ?? []).includes(key) || (prefix.prefixes ?? []).some((part) => key.startsWith(part));
80
+ // No await between read and publication: even separate adapters sharing
81
+ // this map observe one complete mutation. Serialize every value first.
82
+ const current = Object.fromEntries([...backing].filter(([key]) => matches(key))
83
+ .sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)
84
+ .map(([key, raw]) => [key, JSON.parse(raw)]));
85
+ const outcome = transform(current);
86
+ if (!outcome || typeof outcome.then === 'function')
87
+ throw new TypeError('mutate callback must be synchronous');
88
+ if (outcome.next !== undefined) {
89
+ const entries = Object.entries(outcome.next).map(([key, value]) => {
90
+ if (!matches(key))
91
+ throw new TypeError('mutation escaped its namespace');
92
+ return [key, JSON.stringify(value)];
93
+ });
94
+ for (const key of backing.keys())
95
+ if (matches(key))
96
+ backing.delete(key);
97
+ for (const [key, raw] of entries)
98
+ backing.set(key, raw);
99
+ }
100
+ return outcome.result;
101
+ },
102
+ get: async (key) => {
103
+ const raw = backing.get(key);
104
+ return raw === undefined ? undefined : JSON.parse(raw);
105
+ },
106
+ set: async (key, value) => {
107
+ backing.set(key, JSON.stringify(value));
108
+ },
109
+ delete: async (key) => {
110
+ backing.delete(key);
111
+ },
112
+ keys: async (prefix = '') => [...backing.keys()]
113
+ .filter((key) => key.startsWith(prefix))
114
+ .sort(),
115
+ };
118
116
  }
@@ -3,10 +3,9 @@
3
3
  * slot that swallows errors cannot promise durability; status says unverified.
4
4
  * Web Locks serialize tabs using the same slot name. Without them the adapter
5
5
  * explicitly exposes only the four-method, single-writer contract.
6
- * @param {{ read: () => any, write: (data: any) => any, key?: string, reliable?: boolean }} slot
7
- * @param {{ locks?: any, name?: string, singleWriter?: boolean }} [options]
6
+ * @param [options]
8
7
  */
9
- export function createSlotLedgerStorage(slot: {
8
+ export declare function createSlotLedgerStorage(slot: {
10
9
  read: () => any;
11
10
  write: (data: any) => any;
12
11
  key?: string;
@@ -26,5 +25,5 @@ export function createSlotLedgerStorage(slot: {
26
25
  set: (key: any, value: any) => Promise<any>;
27
26
  delete: (key: any) => Promise<any>;
28
27
  keys: (prefix?: string) => Promise<string[]>;
29
- mutate?: (prefix: any, transform: any) => Promise<any>;
28
+ mutate?: ((prefix: any, transform: any) => Promise<any>) | undefined;
30
29
  };