@framers/agentos 0.5.1 → 0.5.3
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/dist/memory/retrieval/typed-network/TypedNetworkObserver.d.ts +53 -7
- package/dist/memory/retrieval/typed-network/TypedNetworkObserver.d.ts.map +1 -1
- package/dist/memory/retrieval/typed-network/TypedNetworkObserver.js +143 -18
- package/dist/memory/retrieval/typed-network/TypedNetworkObserver.js.map +1 -1
- package/dist/memory/retrieval/typed-network/prompts/extraction-schema.d.ts +56 -23
- package/dist/memory/retrieval/typed-network/prompts/extraction-schema.d.ts.map +1 -1
- package/dist/memory/retrieval/typed-network/prompts/extraction-schema.js +50 -10
- package/dist/memory/retrieval/typed-network/prompts/extraction-schema.js.map +1 -1
- package/dist/memory-router/MemoryRouter.d.ts +85 -1
- package/dist/memory-router/MemoryRouter.d.ts.map +1 -1
- package/dist/memory-router/MemoryRouter.js +88 -1
- package/dist/memory-router/MemoryRouter.js.map +1 -1
- package/dist/memory-router/dispatcher.d.ts +39 -1
- package/dist/memory-router/dispatcher.d.ts.map +1 -1
- package/dist/memory-router/dispatcher.js +9 -1
- package/dist/memory-router/dispatcher.js.map +1 -1
- package/dist/memory-router/index.d.ts +7 -5
- package/dist/memory-router/index.d.ts.map +1 -1
- package/dist/memory-router/index.js +7 -2
- package/dist/memory-router/index.js.map +1 -1
- package/dist/memory-router/retrieval-config.d.ts +147 -0
- package/dist/memory-router/retrieval-config.d.ts.map +1 -0
- package/dist/memory-router/retrieval-config.js +268 -0
- package/dist/memory-router/retrieval-config.js.map +1 -0
- package/dist/memory-router/routing-tables.d.ts +112 -0
- package/dist/memory-router/routing-tables.d.ts.map +1 -1
- package/dist/memory-router/routing-tables.js +113 -0
- package/dist/memory-router/routing-tables.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @file TypedNetworkObserver.ts
|
|
3
3
|
* @description LLM-driven extractor that turns a conversation block
|
|
4
4
|
* into 0+ {@link TypedFact}s. Wraps the 6-step extraction prompt and
|
|
5
|
-
* the zod
|
|
5
|
+
* the tolerant zod parsing of the LLM's structured-output response.
|
|
6
6
|
*
|
|
7
7
|
* Production wiring: a typical caller constructs the observer once per
|
|
8
8
|
* pipeline (re-using the same `gpt-5-mini` adapter), then invokes
|
|
@@ -10,6 +10,30 @@
|
|
|
10
10
|
* are then upserted into a {@link TypedNetworkStore} and embedded by
|
|
11
11
|
* the host's {@link IEmbeddingManager}.
|
|
12
12
|
*
|
|
13
|
+
* **Tolerance design (Phase 4c smoke fix):** the parser accepts the
|
|
14
|
+
* common deviations gpt-5-mini emits at scale, rather than throwing on
|
|
15
|
+
* any deviation:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Code-fence stripping**: triple-backtick fences (with or without
|
|
18
|
+
* language tag) are removed before JSON parse.
|
|
19
|
+
* 2. **Top-level array auto-wrap**: a bare `[fact, fact]` is wrapped
|
|
20
|
+
* as `{facts: [...]}` before schema validation.
|
|
21
|
+
* 3. **Per-fact tolerance**: facts are validated one at a time via
|
|
22
|
+
* `TypedExtractionFactSchema.safeParse`. Bad facts are dropped
|
|
23
|
+
* silently; good facts in the same response are kept.
|
|
24
|
+
* 4. **Schema-level defaults**: `temporal`, `participants`,
|
|
25
|
+
* `reasoning_markers`, and `entities` default to sensible empties
|
|
26
|
+
* when the LLM omits them. `bank` is uppercase-coerced. See
|
|
27
|
+
* {@link TypedExtractionFactSchema} for the full tolerance surface.
|
|
28
|
+
* 5. **Retry-on-outer-failure**: if the catastrophic outer parse
|
|
29
|
+
* fails (invalid JSON, primitive value, neither array nor object
|
|
30
|
+
* with `facts`), the extractor retries once with the validation
|
|
31
|
+
* error appended to the user prompt. Implements spec section 6's
|
|
32
|
+
* retry path that was specified but never shipped.
|
|
33
|
+
*
|
|
34
|
+
* The extract method NEVER throws on extractable input; persistent
|
|
35
|
+
* outer failure returns `[]` so the caller can continue ingest.
|
|
36
|
+
*
|
|
13
37
|
* @module @framers/agentos/memory/retrieval/typed-network/TypedNetworkObserver
|
|
14
38
|
*/
|
|
15
39
|
import type { TypedFact } from './types.js';
|
|
@@ -38,6 +62,14 @@ export interface TypedNetworkObserverOptions {
|
|
|
38
62
|
maxTokens?: number;
|
|
39
63
|
/** Temperature. Default 0 for deterministic extraction. */
|
|
40
64
|
temperature?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Per-attempt request timeout in milliseconds. When the underlying
|
|
67
|
+
* `llm.invoke()` does not resolve within this window the attempt is
|
|
68
|
+
* abandoned and the observer falls through to the retry path. Used
|
|
69
|
+
* to prevent stale TCP sockets / hung OpenAI requests from
|
|
70
|
+
* deadlocking long-running ingest pipelines. Default 30 000 ms (30 s).
|
|
71
|
+
*/
|
|
72
|
+
timeoutMs?: number;
|
|
41
73
|
}
|
|
42
74
|
/**
|
|
43
75
|
* The 6-step extractor. Stateless aside from its constructor options;
|
|
@@ -47,21 +79,35 @@ export declare class TypedNetworkObserver {
|
|
|
47
79
|
private readonly llm;
|
|
48
80
|
private readonly maxTokens;
|
|
49
81
|
private readonly temperature;
|
|
82
|
+
private readonly timeoutMs;
|
|
50
83
|
constructor(options: TypedNetworkObserverOptions);
|
|
51
84
|
/**
|
|
52
|
-
* Extract typed facts from a conversation block.
|
|
53
|
-
*
|
|
54
|
-
* IDs of the form
|
|
55
|
-
*
|
|
85
|
+
* Extract typed facts from a conversation block.
|
|
86
|
+
*
|
|
87
|
+
* Resulting facts have stable IDs of the form
|
|
88
|
+
* `<sessionId>-fact-<index>`, where `<index>` is the sequential
|
|
89
|
+
* POST-DROP position so dropped facts produce contiguous IDs in the
|
|
90
|
+
* returned array.
|
|
91
|
+
*
|
|
92
|
+
* **Never throws on extractable input.** Catastrophic outer parse
|
|
93
|
+
* failures (invalid JSON, primitive value, missing facts key) get
|
|
94
|
+
* one retry; persistent failure returns `[]`. Bad individual facts
|
|
95
|
+
* are dropped silently via per-fact `safeParse`.
|
|
56
96
|
*
|
|
57
97
|
* @param sessionText - Full conversation text. Will be wrapped in
|
|
58
98
|
* the user prompt's delimiters automatically.
|
|
59
99
|
* @param sessionId - Stable identifier used to namespace the
|
|
60
100
|
* resulting fact IDs.
|
|
61
101
|
* @returns Array of {@link TypedFact}s, possibly empty.
|
|
62
|
-
* @throws ZodError if the LLM output fails schema validation.
|
|
63
|
-
* @throws SyntaxError if the LLM output is not valid JSON.
|
|
64
102
|
*/
|
|
65
103
|
extract(sessionText: string, sessionId: string): Promise<TypedFact[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Run `this.llm.invoke()` with a per-attempt timeout. Throws an
|
|
106
|
+
* `Error('TypedNetworkObserver: extraction timed out after Nms')`
|
|
107
|
+
* when the timer fires before the LLM responds. The timer is cleared
|
|
108
|
+
* on resolution to avoid leaking pending timeouts into subsequent
|
|
109
|
+
* extractions.
|
|
110
|
+
*/
|
|
111
|
+
private invokeWithTimeout;
|
|
66
112
|
}
|
|
67
113
|
//# sourceMappingURL=TypedNetworkObserver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypedNetworkObserver.d.ts","sourceRoot":"","sources":["../../../../src/memory/retrieval/typed-network/TypedNetworkObserver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"TypedNetworkObserver.d.ts","sourceRoot":"","sources":["../../../../src/memory/retrieval/typed-network/TypedNetworkObserver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAOH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,IAAI,EAAE;QACX,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,2DAA2D;IAC3D,GAAG,EAAE,mBAAmB,CAAC;IACzB,4GAA4G;IAC5G,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AASD;;;GAGG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAsB;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,EAAE,2BAA2B;IAOhD;;;;;;;;;;;;;;;;;;OAkBG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAuE3E;;;;;;OAMG;YACW,iBAAiB;CAuBhC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @file TypedNetworkObserver.ts
|
|
3
3
|
* @description LLM-driven extractor that turns a conversation block
|
|
4
4
|
* into 0+ {@link TypedFact}s. Wraps the 6-step extraction prompt and
|
|
5
|
-
* the zod
|
|
5
|
+
* the tolerant zod parsing of the LLM's structured-output response.
|
|
6
6
|
*
|
|
7
7
|
* Production wiring: a typical caller constructs the observer once per
|
|
8
8
|
* pipeline (re-using the same `gpt-5-mini` adapter), then invokes
|
|
@@ -10,10 +10,40 @@
|
|
|
10
10
|
* are then upserted into a {@link TypedNetworkStore} and embedded by
|
|
11
11
|
* the host's {@link IEmbeddingManager}.
|
|
12
12
|
*
|
|
13
|
+
* **Tolerance design (Phase 4c smoke fix):** the parser accepts the
|
|
14
|
+
* common deviations gpt-5-mini emits at scale, rather than throwing on
|
|
15
|
+
* any deviation:
|
|
16
|
+
*
|
|
17
|
+
* 1. **Code-fence stripping**: triple-backtick fences (with or without
|
|
18
|
+
* language tag) are removed before JSON parse.
|
|
19
|
+
* 2. **Top-level array auto-wrap**: a bare `[fact, fact]` is wrapped
|
|
20
|
+
* as `{facts: [...]}` before schema validation.
|
|
21
|
+
* 3. **Per-fact tolerance**: facts are validated one at a time via
|
|
22
|
+
* `TypedExtractionFactSchema.safeParse`. Bad facts are dropped
|
|
23
|
+
* silently; good facts in the same response are kept.
|
|
24
|
+
* 4. **Schema-level defaults**: `temporal`, `participants`,
|
|
25
|
+
* `reasoning_markers`, and `entities` default to sensible empties
|
|
26
|
+
* when the LLM omits them. `bank` is uppercase-coerced. See
|
|
27
|
+
* {@link TypedExtractionFactSchema} for the full tolerance surface.
|
|
28
|
+
* 5. **Retry-on-outer-failure**: if the catastrophic outer parse
|
|
29
|
+
* fails (invalid JSON, primitive value, neither array nor object
|
|
30
|
+
* with `facts`), the extractor retries once with the validation
|
|
31
|
+
* error appended to the user prompt. Implements spec section 6's
|
|
32
|
+
* retry path that was specified but never shipped.
|
|
33
|
+
*
|
|
34
|
+
* The extract method NEVER throws on extractable input; persistent
|
|
35
|
+
* outer failure returns `[]` so the caller can continue ingest.
|
|
36
|
+
*
|
|
13
37
|
* @module @framers/agentos/memory/retrieval/typed-network/TypedNetworkObserver
|
|
14
38
|
*/
|
|
15
|
-
import {
|
|
39
|
+
import { TypedExtractionFactSchema } from './prompts/extraction-schema.js';
|
|
16
40
|
import { TYPED_EXTRACTION_SYSTEM_PROMPT, buildExtractionUserPrompt, } from './prompts/extraction-prompt.js';
|
|
41
|
+
/**
|
|
42
|
+
* Maximum total LLM invocations per `extract` call. The first attempt
|
|
43
|
+
* uses the base prompt; the second appends the validation error from
|
|
44
|
+
* the first attempt for the model to self-correct against.
|
|
45
|
+
*/
|
|
46
|
+
const MAX_ATTEMPTS = 2;
|
|
17
47
|
/**
|
|
18
48
|
* The 6-step extractor. Stateless aside from its constructor options;
|
|
19
49
|
* safe to share across concurrent extractions.
|
|
@@ -23,35 +53,129 @@ export class TypedNetworkObserver {
|
|
|
23
53
|
this.llm = options.llm;
|
|
24
54
|
this.maxTokens = options.maxTokens ?? 4096;
|
|
25
55
|
this.temperature = options.temperature ?? 0;
|
|
56
|
+
this.timeoutMs = options.timeoutMs ?? 30000;
|
|
26
57
|
}
|
|
27
58
|
/**
|
|
28
|
-
* Extract typed facts from a conversation block.
|
|
29
|
-
*
|
|
30
|
-
* IDs of the form
|
|
31
|
-
*
|
|
59
|
+
* Extract typed facts from a conversation block.
|
|
60
|
+
*
|
|
61
|
+
* Resulting facts have stable IDs of the form
|
|
62
|
+
* `<sessionId>-fact-<index>`, where `<index>` is the sequential
|
|
63
|
+
* POST-DROP position so dropped facts produce contiguous IDs in the
|
|
64
|
+
* returned array.
|
|
65
|
+
*
|
|
66
|
+
* **Never throws on extractable input.** Catastrophic outer parse
|
|
67
|
+
* failures (invalid JSON, primitive value, missing facts key) get
|
|
68
|
+
* one retry; persistent failure returns `[]`. Bad individual facts
|
|
69
|
+
* are dropped silently via per-fact `safeParse`.
|
|
32
70
|
*
|
|
33
71
|
* @param sessionText - Full conversation text. Will be wrapped in
|
|
34
72
|
* the user prompt's delimiters automatically.
|
|
35
73
|
* @param sessionId - Stable identifier used to namespace the
|
|
36
74
|
* resulting fact IDs.
|
|
37
75
|
* @returns Array of {@link TypedFact}s, possibly empty.
|
|
38
|
-
* @throws ZodError if the LLM output fails schema validation.
|
|
39
|
-
* @throws SyntaxError if the LLM output is not valid JSON.
|
|
40
76
|
*/
|
|
41
77
|
async extract(sessionText, sessionId) {
|
|
42
|
-
const
|
|
78
|
+
const baseUserPrompt = buildExtractionUserPrompt(sessionText);
|
|
79
|
+
let lastValidationError = null;
|
|
80
|
+
for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
81
|
+
// First attempt uses the bare prompt; retry appends the
|
|
82
|
+
// validation error so the model can self-correct.
|
|
83
|
+
const userPrompt = lastValidationError === null
|
|
84
|
+
? baseUserPrompt
|
|
85
|
+
: `${baseUserPrompt}\n\nThe previous response failed validation: ${lastValidationError}\nReturn JSON matching the schema strictly. Do not add commentary.`;
|
|
86
|
+
// Race the underlying invoke against a per-attempt timeout. A
|
|
87
|
+
// hung TCP socket / unresponsive provider would otherwise
|
|
88
|
+
// deadlock long-running ingest pipelines — at concurrency=1 a
|
|
89
|
+
// single hung request stalls every subsequent session forever.
|
|
90
|
+
// The timeout fires from the agentos side without requiring the
|
|
91
|
+
// adapter to surface AbortSignal support; the underlying request
|
|
92
|
+
// is abandoned (its socket leaks until GC / process exit) but
|
|
93
|
+
// the observer moves to its retry path.
|
|
94
|
+
let raw;
|
|
95
|
+
try {
|
|
96
|
+
raw = await this.invokeWithTimeout(userPrompt);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
lastValidationError = err instanceof Error ? err.message : String(err);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const stripped = stripCodeFence(raw);
|
|
103
|
+
// Parse JSON. SyntaxError captures bad-JSON outer failures into
|
|
104
|
+
// the retry path.
|
|
105
|
+
let json;
|
|
106
|
+
try {
|
|
107
|
+
json = JSON.parse(stripped);
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
lastValidationError = err instanceof Error ? err.message : String(err);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
// Auto-wrap top-level array. gpt-5-mini frequently emits a bare
|
|
114
|
+
// facts array instead of `{facts: [...]}`; this recovers the
|
|
115
|
+
// most common deviation.
|
|
116
|
+
const container = Array.isArray(json) ? { facts: json } : json;
|
|
117
|
+
// Outer-shape validation. We accept any object with a `facts`
|
|
118
|
+
// array; per-fact validation runs in `extractFactsFromContainer`.
|
|
119
|
+
if (typeof container !== 'object' ||
|
|
120
|
+
container === null ||
|
|
121
|
+
!('facts' in container) ||
|
|
122
|
+
!Array.isArray(container.facts)) {
|
|
123
|
+
lastValidationError =
|
|
124
|
+
'expected JSON object with a "facts" array; got unexpected outer shape';
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
return extractFactsFromContainer(container.facts, sessionId);
|
|
128
|
+
}
|
|
129
|
+
// Both attempts failed at the outer layer; return empty rather
|
|
130
|
+
// than throwing so the caller can continue ingest. The caller is
|
|
131
|
+
// responsible for downstream "no typed facts in this session"
|
|
132
|
+
// semantics.
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Run `this.llm.invoke()` with a per-attempt timeout. Throws an
|
|
137
|
+
* `Error('TypedNetworkObserver: extraction timed out after Nms')`
|
|
138
|
+
* when the timer fires before the LLM responds. The timer is cleared
|
|
139
|
+
* on resolution to avoid leaking pending timeouts into subsequent
|
|
140
|
+
* extractions.
|
|
141
|
+
*/
|
|
142
|
+
async invokeWithTimeout(userPrompt) {
|
|
143
|
+
let timeoutHandle = null;
|
|
144
|
+
const invokePromise = this.llm.invoke({
|
|
43
145
|
system: TYPED_EXTRACTION_SYSTEM_PROMPT,
|
|
44
|
-
user:
|
|
146
|
+
user: userPrompt,
|
|
45
147
|
maxTokens: this.maxTokens,
|
|
46
148
|
temperature: this.temperature,
|
|
47
149
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
150
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
151
|
+
timeoutHandle = setTimeout(() => {
|
|
152
|
+
reject(new Error(`TypedNetworkObserver: extraction timed out after ${this.timeoutMs}ms`));
|
|
153
|
+
}, this.timeoutMs);
|
|
154
|
+
});
|
|
155
|
+
try {
|
|
156
|
+
return await Promise.race([invokePromise, timeoutPromise]);
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
if (timeoutHandle !== null)
|
|
160
|
+
clearTimeout(timeoutHandle);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Run per-fact tolerance over a candidate array. Returns only the
|
|
166
|
+
* facts that pass {@link TypedExtractionFactSchema} validation;
|
|
167
|
+
* silently drops the rest. IDs are sequential post-drop indices to
|
|
168
|
+
* keep the output array contiguously addressable.
|
|
169
|
+
*/
|
|
170
|
+
function extractFactsFromContainer(candidates, sessionId) {
|
|
171
|
+
const facts = [];
|
|
172
|
+
for (const candidate of candidates) {
|
|
173
|
+
const result = TypedExtractionFactSchema.safeParse(candidate);
|
|
174
|
+
if (!result.success)
|
|
175
|
+
continue;
|
|
176
|
+
const f = result.data;
|
|
177
|
+
facts.push({
|
|
178
|
+
id: `${sessionId}-fact-${facts.length}`,
|
|
55
179
|
bank: f.bank,
|
|
56
180
|
text: f.text,
|
|
57
181
|
embedding: [],
|
|
@@ -60,8 +184,9 @@ export class TypedNetworkObserver {
|
|
|
60
184
|
reasoningMarkers: f.reasoning_markers,
|
|
61
185
|
entities: f.entities,
|
|
62
186
|
confidence: f.confidence,
|
|
63
|
-
})
|
|
187
|
+
});
|
|
64
188
|
}
|
|
189
|
+
return facts;
|
|
65
190
|
}
|
|
66
191
|
/**
|
|
67
192
|
* Strip leading/trailing markdown code fences. Tolerates triple-backtick
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TypedNetworkObserver.js","sourceRoot":"","sources":["../../../../src/memory/retrieval/typed-network/TypedNetworkObserver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"TypedNetworkObserver.js","sourceRoot":"","sources":["../../../../src/memory/retrieval/typed-network/TypedNetworkObserver.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,59 +8,92 @@
|
|
|
8
8
|
* schema's snake_case shape to the camelCase TypedFact at construction
|
|
9
9
|
* time.
|
|
10
10
|
*
|
|
11
|
+
* **Tolerance design (Phase 4c smoke fix):** the schema accepts the
|
|
12
|
+
* common deviations gpt-5-mini emits at scale, rather than throwing on
|
|
13
|
+
* any deviation:
|
|
14
|
+
*
|
|
15
|
+
* - `bank` is preprocessed to uppercase before enum validation. The
|
|
16
|
+
* prompt asks for uppercase; if the model emits lowercase, the
|
|
17
|
+
* coercion recovers the fact instead of dropping it.
|
|
18
|
+
* - `temporal.mention` is optional and defaults to empty string. The
|
|
19
|
+
* model sometimes omits it when it cannot infer a mention timestamp.
|
|
20
|
+
* Downstream {@link rankByTemporalOverlap} already handles empty
|
|
21
|
+
* mentions gracefully (falls back to interval endpoints).
|
|
22
|
+
* - `temporal` itself defaults to `{mention: ''}`. The model sometimes
|
|
23
|
+
* omits the temporal block entirely on non-temporal facts.
|
|
24
|
+
* - `participants`, `reasoning_markers`, `entities` default to `[]`.
|
|
25
|
+
* The model frequently emits the fact without these keys when no
|
|
26
|
+
* participants/entities/markers apply.
|
|
27
|
+
*
|
|
28
|
+
* Per-fact failures (text below minimum length, bank not in
|
|
29
|
+
* WORLD/EXPERIENCE/OPINION/OBSERVATION after uppercase coercion,
|
|
30
|
+
* confidence outside [0, 1]) still cause the INDIVIDUAL fact to drop.
|
|
31
|
+
* The {@link TypedNetworkObserver} validates
|
|
32
|
+
* facts one by one (`safeParse` per fact) and keeps the valid ones.
|
|
33
|
+
*
|
|
11
34
|
* @module @framers/agentos/memory/retrieval/typed-network/prompts/extraction-schema
|
|
12
35
|
*/
|
|
13
36
|
import { z } from 'zod';
|
|
14
37
|
/**
|
|
15
38
|
* Schema for one extracted fact, matching the LLM's expected output.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
39
|
+
*
|
|
40
|
+
* Defaults applied when the LLM omits fields:
|
|
41
|
+
* - `temporal.mention`: `''` (downstream tolerates empty mention)
|
|
42
|
+
* - `participants`: `[]`
|
|
43
|
+
* - `reasoning_markers`: `[]`
|
|
44
|
+
* - `entities`: `[]`
|
|
45
|
+
* - `confidence`: `1.0`
|
|
46
|
+
*
|
|
47
|
+
* `bank` is uppercase-coerced before enum validation so a lowercase
|
|
48
|
+
* model output (e.g. `'world'`) passes as `'WORLD'`.
|
|
18
49
|
*/
|
|
19
50
|
export declare const TypedExtractionFactSchema: z.ZodObject<{
|
|
20
51
|
text: z.ZodString;
|
|
21
|
-
bank: z.ZodEnum<{
|
|
52
|
+
bank: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
|
|
22
53
|
WORLD: "WORLD";
|
|
23
54
|
EXPERIENCE: "EXPERIENCE";
|
|
24
55
|
OPINION: "OPINION";
|
|
25
56
|
OBSERVATION: "OBSERVATION";
|
|
26
|
-
}
|
|
27
|
-
temporal: z.ZodObject<{
|
|
57
|
+
}>>;
|
|
58
|
+
temporal: z.ZodDefault<z.ZodObject<{
|
|
28
59
|
start: z.ZodOptional<z.ZodString>;
|
|
29
60
|
end: z.ZodOptional<z.ZodString>;
|
|
30
|
-
mention: z.ZodString
|
|
31
|
-
}, z.core.$strip>;
|
|
32
|
-
participants: z.ZodArray<z.ZodObject<{
|
|
33
|
-
name: z.ZodString;
|
|
34
|
-
role: z.ZodString;
|
|
61
|
+
mention: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
35
62
|
}, z.core.$strip>>;
|
|
36
|
-
|
|
37
|
-
|
|
63
|
+
participants: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
64
|
+
name: z.ZodString;
|
|
65
|
+
role: z.ZodDefault<z.ZodString>;
|
|
66
|
+
}, z.core.$strip>>>;
|
|
67
|
+
reasoning_markers: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
68
|
+
entities: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
38
69
|
confidence: z.ZodDefault<z.ZodNumber>;
|
|
39
70
|
}, z.core.$strip>;
|
|
40
71
|
/**
|
|
41
72
|
* Top-level schema. Wraps the fact array under a `facts` key so the
|
|
42
|
-
* LLM has a stable structural anchor to emit against.
|
|
73
|
+
* LLM has a stable structural anchor to emit against. The
|
|
74
|
+
* {@link TypedNetworkObserver} additionally tolerates a top-level
|
|
75
|
+
* array (no `facts` key) by auto-wrapping it before this schema runs.
|
|
43
76
|
*/
|
|
44
77
|
export declare const TypedExtractionSchema: z.ZodObject<{
|
|
45
78
|
facts: z.ZodArray<z.ZodObject<{
|
|
46
79
|
text: z.ZodString;
|
|
47
|
-
bank: z.ZodEnum<{
|
|
80
|
+
bank: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodEnum<{
|
|
48
81
|
WORLD: "WORLD";
|
|
49
82
|
EXPERIENCE: "EXPERIENCE";
|
|
50
83
|
OPINION: "OPINION";
|
|
51
84
|
OBSERVATION: "OBSERVATION";
|
|
52
|
-
}
|
|
53
|
-
temporal: z.ZodObject<{
|
|
85
|
+
}>>;
|
|
86
|
+
temporal: z.ZodDefault<z.ZodObject<{
|
|
54
87
|
start: z.ZodOptional<z.ZodString>;
|
|
55
88
|
end: z.ZodOptional<z.ZodString>;
|
|
56
|
-
mention: z.ZodString
|
|
57
|
-
}, z.core.$strip>;
|
|
58
|
-
participants: z.ZodArray<z.ZodObject<{
|
|
59
|
-
name: z.ZodString;
|
|
60
|
-
role: z.ZodString;
|
|
89
|
+
mention: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
61
90
|
}, z.core.$strip>>;
|
|
62
|
-
|
|
63
|
-
|
|
91
|
+
participants: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
92
|
+
name: z.ZodString;
|
|
93
|
+
role: z.ZodDefault<z.ZodString>;
|
|
94
|
+
}, z.core.$strip>>>;
|
|
95
|
+
reasoning_markers: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
96
|
+
entities: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
64
97
|
confidence: z.ZodDefault<z.ZodNumber>;
|
|
65
98
|
}, z.core.$strip>>;
|
|
66
99
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction-schema.d.ts","sourceRoot":"","sources":["../../../../../src/memory/retrieval/typed-network/prompts/extraction-schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"extraction-schema.d.ts","sourceRoot":"","sources":["../../../../../src/memory/retrieval/typed-network/prompts/extraction-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;iBAwBpC,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;iBAEhC,CAAC;AAEH,mEAAmE;AACnE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAC1E,qEAAqE;AACrE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}
|
|
@@ -8,30 +8,70 @@
|
|
|
8
8
|
* schema's snake_case shape to the camelCase TypedFact at construction
|
|
9
9
|
* time.
|
|
10
10
|
*
|
|
11
|
+
* **Tolerance design (Phase 4c smoke fix):** the schema accepts the
|
|
12
|
+
* common deviations gpt-5-mini emits at scale, rather than throwing on
|
|
13
|
+
* any deviation:
|
|
14
|
+
*
|
|
15
|
+
* - `bank` is preprocessed to uppercase before enum validation. The
|
|
16
|
+
* prompt asks for uppercase; if the model emits lowercase, the
|
|
17
|
+
* coercion recovers the fact instead of dropping it.
|
|
18
|
+
* - `temporal.mention` is optional and defaults to empty string. The
|
|
19
|
+
* model sometimes omits it when it cannot infer a mention timestamp.
|
|
20
|
+
* Downstream {@link rankByTemporalOverlap} already handles empty
|
|
21
|
+
* mentions gracefully (falls back to interval endpoints).
|
|
22
|
+
* - `temporal` itself defaults to `{mention: ''}`. The model sometimes
|
|
23
|
+
* omits the temporal block entirely on non-temporal facts.
|
|
24
|
+
* - `participants`, `reasoning_markers`, `entities` default to `[]`.
|
|
25
|
+
* The model frequently emits the fact without these keys when no
|
|
26
|
+
* participants/entities/markers apply.
|
|
27
|
+
*
|
|
28
|
+
* Per-fact failures (text below minimum length, bank not in
|
|
29
|
+
* WORLD/EXPERIENCE/OPINION/OBSERVATION after uppercase coercion,
|
|
30
|
+
* confidence outside [0, 1]) still cause the INDIVIDUAL fact to drop.
|
|
31
|
+
* The {@link TypedNetworkObserver} validates
|
|
32
|
+
* facts one by one (`safeParse` per fact) and keeps the valid ones.
|
|
33
|
+
*
|
|
11
34
|
* @module @framers/agentos/memory/retrieval/typed-network/prompts/extraction-schema
|
|
12
35
|
*/
|
|
13
36
|
import { z } from 'zod';
|
|
14
37
|
/**
|
|
15
38
|
* Schema for one extracted fact, matching the LLM's expected output.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
39
|
+
*
|
|
40
|
+
* Defaults applied when the LLM omits fields:
|
|
41
|
+
* - `temporal.mention`: `''` (downstream tolerates empty mention)
|
|
42
|
+
* - `participants`: `[]`
|
|
43
|
+
* - `reasoning_markers`: `[]`
|
|
44
|
+
* - `entities`: `[]`
|
|
45
|
+
* - `confidence`: `1.0`
|
|
46
|
+
*
|
|
47
|
+
* `bank` is uppercase-coerced before enum validation so a lowercase
|
|
48
|
+
* model output (e.g. `'world'`) passes as `'WORLD'`.
|
|
18
49
|
*/
|
|
19
50
|
export const TypedExtractionFactSchema = z.object({
|
|
20
51
|
text: z.string().min(1),
|
|
21
|
-
bank: z.enum(['WORLD', 'EXPERIENCE', 'OPINION', 'OBSERVATION']),
|
|
22
|
-
temporal: z
|
|
52
|
+
bank: z.preprocess((v) => (typeof v === 'string' ? v.toUpperCase() : v), z.enum(['WORLD', 'EXPERIENCE', 'OPINION', 'OBSERVATION'])),
|
|
53
|
+
temporal: z
|
|
54
|
+
.object({
|
|
23
55
|
start: z.string().optional(),
|
|
24
56
|
end: z.string().optional(),
|
|
25
|
-
mention: z.string(),
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
57
|
+
mention: z.string().optional().default(''),
|
|
58
|
+
})
|
|
59
|
+
.default({ mention: '' }),
|
|
60
|
+
participants: z
|
|
61
|
+
.array(z.object({
|
|
62
|
+
name: z.string(),
|
|
63
|
+
role: z.string().default(''),
|
|
64
|
+
}))
|
|
65
|
+
.default([]),
|
|
66
|
+
reasoning_markers: z.array(z.string()).default([]),
|
|
67
|
+
entities: z.array(z.string()).default([]),
|
|
30
68
|
confidence: z.number().min(0).max(1).default(1.0),
|
|
31
69
|
});
|
|
32
70
|
/**
|
|
33
71
|
* Top-level schema. Wraps the fact array under a `facts` key so the
|
|
34
|
-
* LLM has a stable structural anchor to emit against.
|
|
72
|
+
* LLM has a stable structural anchor to emit against. The
|
|
73
|
+
* {@link TypedNetworkObserver} additionally tolerates a top-level
|
|
74
|
+
* array (no `facts` key) by auto-wrapping it before this schema runs.
|
|
35
75
|
*/
|
|
36
76
|
export const TypedExtractionSchema = z.object({
|
|
37
77
|
facts: z.array(TypedExtractionFactSchema),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction-schema.js","sourceRoot":"","sources":["../../../../../src/memory/retrieval/typed-network/prompts/extraction-schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"extraction-schema.js","sourceRoot":"","sources":["../../../../../src/memory/retrieval/typed-network/prompts/extraction-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,CAAC,CAAC,UAAU,CAChB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EACpD,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAC1D;IACD,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC;QACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC1B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;KAC3C,CAAC;SACD,OAAO,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC3B,YAAY,EAAE,CAAC;SACZ,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;QAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;KAC7B,CAAC,CACH;SACA,OAAO,CAAC,EAAE,CAAC;IACd,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAClD,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACzC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;CAClD,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,yBAAyB,CAAC;CAC1C,CAAC,CAAC"}
|