@corenel/harness 0.6.0 → 0.7.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.
- package/dist/core/factFile.d.ts +14 -4
- package/dist/core/factFile.d.ts.map +1 -1
- package/dist/core/factFile.js +34 -13
- package/dist/core/factFile.js.map +1 -1
- package/dist/dag/executeNode.d.ts +4 -1
- package/dist/dag/executeNode.d.ts.map +1 -1
- package/dist/dag/executeNode.js +19 -5
- package/dist/dag/executeNode.js.map +1 -1
- package/dist/memory/bm25.d.ts +20 -0
- package/dist/memory/bm25.d.ts.map +1 -0
- package/dist/memory/bm25.js +73 -0
- package/dist/memory/bm25.js.map +1 -0
- package/dist/memory/manifest.d.ts +62 -0
- package/dist/memory/manifest.d.ts.map +1 -0
- package/dist/memory/manifest.js +54 -0
- package/dist/memory/manifest.js.map +1 -0
- package/dist/memory/store.d.ts +61 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +386 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/tier.d.ts +38 -0
- package/dist/memory/tier.d.ts.map +1 -0
- package/dist/memory/tier.js +52 -0
- package/dist/memory/tier.js.map +1 -0
- package/dist/prompts/config.d.ts +52 -3
- package/dist/prompts/config.d.ts.map +1 -1
- package/dist/prompts/config.js +175 -16
- package/dist/prompts/config.js.map +1 -1
- package/dist/prompts/host.d.ts +19 -0
- package/dist/prompts/host.d.ts.map +1 -1
- package/dist/prompts/host.js.map +1 -1
- package/dist/prompts/library/defaults.generated.d.ts.map +1 -1
- package/dist/prompts/library/defaults.generated.js +16 -0
- package/dist/prompts/library/defaults.generated.js.map +1 -1
- package/dist/prompts/syncConfig.d.ts +52 -0
- package/dist/prompts/syncConfig.d.ts.map +1 -0
- package/dist/prompts/syncConfig.js +132 -0
- package/dist/prompts/syncConfig.js.map +1 -0
- package/dist/sidecar/host.d.ts +56 -2
- package/dist/sidecar/host.d.ts.map +1 -1
- package/dist/sidecar/host.js +152 -1
- package/dist/sidecar/host.js.map +1 -1
- package/dist/sidecar/server.d.ts +130 -1
- package/dist/sidecar/server.d.ts.map +1 -1
- package/dist/sidecar/server.js +205 -5
- package/dist/sidecar/server.js.map +1 -1
- package/dist/tools/builtins.d.ts +2 -0
- package/dist/tools/builtins.d.ts.map +1 -1
- package/dist/tools/builtins.js +63 -14
- package/dist/tools/builtins.js.map +1 -1
- package/dist/tools/namespaces.d.ts +22 -4
- package/dist/tools/namespaces.d.ts.map +1 -1
- package/dist/tools/namespaces.js +49 -8
- package/dist/tools/namespaces.js.map +1 -1
- package/package.json +2 -2
package/dist/core/factFile.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import { type MemoryType } from '@corenel/protocol';
|
|
2
|
+
export type { MemoryType };
|
|
3
|
+
/** A body longer than this is refused: one fact must not be able to consume a
|
|
4
|
+
* whole plane's core budget. */
|
|
5
|
+
export declare const BODY_CAP_CHARS = 2000;
|
|
1
6
|
/** One remembered fact, as stored. */
|
|
2
7
|
export interface Fact {
|
|
3
8
|
slug: string;
|
|
4
9
|
description: string;
|
|
10
|
+
type: MemoryType;
|
|
5
11
|
tags: string[];
|
|
6
12
|
createdAt: number;
|
|
13
|
+
updatedAt: number;
|
|
7
14
|
text: string;
|
|
8
15
|
/** The scope the model asked for when it saved. RECORDED, NOT ROUTED, for a
|
|
9
16
|
* per-agent store — an agent's memory is its own folder, so there is nothing
|
|
@@ -14,11 +21,14 @@ export interface Fact {
|
|
|
14
21
|
/** The index file an agent maintains for itself. Never listed as a fact. */
|
|
15
22
|
export declare const FACT_INDEX = "MEMORY.md";
|
|
16
23
|
/** Kebab slug from arbitrary text: lowercase, alphanumerics and dashes, trimmed,
|
|
17
|
-
* capped. Empty input -> 'note'.
|
|
24
|
+
* capped. Empty input -> 'note'.
|
|
25
|
+
*
|
|
26
|
+
* MUST be idempotent (slugify(slugify(x)) === slugify(x)) -- assertName in
|
|
27
|
+
* memory/store.ts rejects a name that doesn't survive a round-trip. The dash
|
|
28
|
+
* trim runs a SECOND time, after the length cap: cutting at 48 chars can land
|
|
29
|
+
* mid-run of separators (e.g. right on a word boundary), leaving a trailing
|
|
30
|
+
* dash that a bare `.slice()` before the trim would miss. */
|
|
18
31
|
export declare function slugify(text: string): string;
|
|
19
|
-
/** `base`, or `base-2`, `base-3` ... until one is free. A save must never
|
|
20
|
-
* silently replace an unrelated memory (spec §3.2). */
|
|
21
|
-
export declare function uniqueSlug(base: string, taken: ReadonlySet<string>): string;
|
|
22
32
|
export declare function renderFact(f: Fact): string;
|
|
23
33
|
export declare function parseFact(slug: string, raw: string): Fact;
|
|
24
34
|
export declare function factIndexLine(f: Fact): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factFile.d.ts","sourceRoot":"","sources":["../../core/factFile.ts"],"names":[],"mappings":"AAWA,sCAAsC;AACtC,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb;;;0EAGsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4EAA4E;AAC5E,eAAO,MAAM,UAAU,cAAc,CAAC;AAEtC;
|
|
1
|
+
{"version":3,"file":"factFile.d.ts","sourceRoot":"","sources":["../../core/factFile.ts"],"names":[],"mappings":"AAWA,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAClE,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B;gCACgC;AAChC,eAAO,MAAM,cAAc,OAAO,CAAC;AAMnC,sCAAsC;AACtC,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb;;;0EAGsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,4EAA4E;AAC5E,eAAO,MAAM,UAAU,cAAc,CAAC;AAEtC;;;;;;;6DAO6D;AAC7D,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG5C;AAUD,wBAAgB,UAAU,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAO1C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CA6BzD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAE7C"}
|
package/dist/core/factFile.js
CHANGED
|
@@ -8,30 +8,41 @@
|
|
|
8
8
|
* Lives in core/ beside budget.ts and pricing.ts: no imports, no DOM, no node —
|
|
9
9
|
* the browser and the daemon both build providers on it.
|
|
10
10
|
*/
|
|
11
|
+
import { MEMORY_TYPES } from '@corenel/protocol';
|
|
12
|
+
/** A body longer than this is refused: one fact must not be able to consume a
|
|
13
|
+
* whole plane's core budget. */
|
|
14
|
+
export const BODY_CAP_CHARS = 2000;
|
|
15
|
+
function asType(raw) {
|
|
16
|
+
return MEMORY_TYPES.includes(raw) ? raw : null;
|
|
17
|
+
}
|
|
11
18
|
/** The index file an agent maintains for itself. Never listed as a fact. */
|
|
12
19
|
export const FACT_INDEX = 'MEMORY.md';
|
|
13
20
|
/** Kebab slug from arbitrary text: lowercase, alphanumerics and dashes, trimmed,
|
|
14
|
-
* capped. Empty input -> 'note'.
|
|
21
|
+
* capped. Empty input -> 'note'.
|
|
22
|
+
*
|
|
23
|
+
* MUST be idempotent (slugify(slugify(x)) === slugify(x)) -- assertName in
|
|
24
|
+
* memory/store.ts rejects a name that doesn't survive a round-trip. The dash
|
|
25
|
+
* trim runs a SECOND time, after the length cap: cutting at 48 chars can land
|
|
26
|
+
* mid-run of separators (e.g. right on a word boundary), leaving a trailing
|
|
27
|
+
* dash that a bare `.slice()` before the trim would miss. */
|
|
15
28
|
export function slugify(text) {
|
|
16
|
-
const s = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48);
|
|
29
|
+
const s = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 48).replace(/^-+|-+$/g, '');
|
|
17
30
|
return s || 'note';
|
|
18
31
|
}
|
|
19
|
-
/**
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
while (taken.has(`${base}-${i}`))
|
|
26
|
-
i++;
|
|
27
|
-
return `${base}-${i}`;
|
|
32
|
+
/** Collapse CR/LF to a single space. `name` and `description` are interpolated
|
|
33
|
+
* directly into a frontmatter block; either one carrying a real newline could
|
|
34
|
+
* inject an extra frontmatter line (e.g. a forged `type:`) into the fact a
|
|
35
|
+
* model just asked to save. */
|
|
36
|
+
function oneLine(s) {
|
|
37
|
+
return s.replace(/[\r\n]+/g, ' ');
|
|
28
38
|
}
|
|
29
39
|
export function renderFact(f) {
|
|
30
40
|
const tagList = f.tags.length ? `[${f.tags.join(', ')}]` : '[]';
|
|
31
41
|
// The scope line is omitted when empty so this renders byte-identically to
|
|
32
42
|
// what shared memory wrote before the extraction.
|
|
33
43
|
const scopeLine = f.scope ? `scope: ${f.scope}\n` : '';
|
|
34
|
-
return `---\nname: ${f.slug}\ndescription: ${f.description}\
|
|
44
|
+
return `---\nname: ${oneLine(f.slug)}\ndescription: ${oneLine(f.description)}\ntype: ${f.type}\ntags: ${tagList}\n`
|
|
45
|
+
+ `createdAt: ${f.createdAt}\nupdatedAt: ${f.updatedAt}\n${scopeLine}---\n${f.text}\n`;
|
|
35
46
|
}
|
|
36
47
|
export function parseFact(slug, raw) {
|
|
37
48
|
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(raw);
|
|
@@ -44,11 +55,21 @@ export function parseFact(slug, raw) {
|
|
|
44
55
|
const description = field('description') || body.split('\n')[0] || slug;
|
|
45
56
|
const tagsRaw = field('tags').replace(/^\[|\]$/g, '').trim();
|
|
46
57
|
const tags = tagsRaw ? tagsRaw.split(',').map((t) => t.trim()).filter(Boolean) : [];
|
|
58
|
+
const createdAt = Number(field('createdAt')) || 0;
|
|
59
|
+
/* An old file has no `type`. Fall back to a tag that names one -- the only
|
|
60
|
+
* signal such a file carries -- and then to 'project', the safe default: it
|
|
61
|
+
* takes the lower tier weight, so a guess never pins a fact into core. */
|
|
62
|
+
const type = asType(field('type')) ?? tags.map(asType).find((t) => t !== null) ?? 'project';
|
|
63
|
+
/* No `updatedAt` means the file was never revised: it was last written when
|
|
64
|
+
* it was created. */
|
|
65
|
+
const updatedAt = Number(field('updatedAt')) || createdAt;
|
|
47
66
|
return {
|
|
48
67
|
slug,
|
|
49
68
|
description,
|
|
69
|
+
type,
|
|
50
70
|
tags,
|
|
51
|
-
createdAt
|
|
71
|
+
createdAt,
|
|
72
|
+
updatedAt,
|
|
52
73
|
text: body,
|
|
53
74
|
scope: field('scope'),
|
|
54
75
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factFile.js","sourceRoot":"","sources":["../../core/factFile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"factFile.js","sourceRoot":"","sources":["../../core/factFile.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,7 +25,10 @@ export interface RunNodeDeps {
|
|
|
25
25
|
/** Read-biased default tool set for a node with no explicit allowlist (§4). No
|
|
26
26
|
* mutating tools, so a delegated node never writes unless its allowlist opts in. */
|
|
27
27
|
export declare const READ_BIASED_TOOLS: string[];
|
|
28
|
-
|
|
28
|
+
/** What a delegated sub-agent is told about its situation. It cannot see the
|
|
29
|
+
* parent conversation, so this is the whole of it. From the config workspace
|
|
30
|
+
* so a user can retune how delegation behaves. */
|
|
31
|
+
export declare const subagentSystem: () => Promise<string>;
|
|
29
32
|
/** Resolve the node's effective tool list: allowlist (or read-biased default),
|
|
30
33
|
* with spawn_* tools dropped when this context can't spawn (the depth cap). */
|
|
31
34
|
export declare function resolveTools(all: AgentTool[], allow: string[] | undefined, ctx: ToolContext): AgentTool[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executeNode.d.ts","sourceRoot":"","sources":["../../dag/executeNode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"executeNode.d.ts","sourceRoot":"","sources":["../../dag/executeNode.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAIjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,KAAK,EACV,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,iBAAiB,EAC7D,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAC/C,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEjE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAC;IACf,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;CACjC;AAED;;0CAE0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;oFACoF;AACpF,eAAO,MAAM,iBAAiB,UAI7B,CAAC;AAEF;;kDAEkD;AAClD,eAAO,MAAM,cAAc,QAAO,OAAO,CAAC,MAAM,CAAmD,CAAC;AAEpG;+EAC+E;AAC/E,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,SAAS,EAAE,CAKzG;AAED;mFACmF;AACnF,wBAAsB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAWrG;AAED;gEACgE;AAChE,wBAAsB,OAAO,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAiC5F;AAED;oEACoE;AACpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAExG"}
|
package/dist/dag/executeNode.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/* DAG node executor — the executor layer of docs/SUBAGENT-DAG-CONTRACT.md.
|
|
2
|
+
*
|
|
3
|
+
* runNode() runs ONE graph node = one runAgent call with a FRESH message history
|
|
4
|
+
* (the isolation that keeps a node's work out of the rest of the graph's context
|
|
5
|
+
* windows). It composes the task (literal `task`, or a Nunjucks `promptTemplate`
|
|
6
|
+
* bound to upstream `inputs`, or a fan-in concat), resolves the node's tool
|
|
7
|
+
* allowlist (read-biased by default), runs the loop, and emits the node-tagged
|
|
8
|
+
* NodeEvent stream the canvas consumes.
|
|
9
|
+
*
|
|
10
|
+
* This is also the in-worker primitive behind the spawn_agent tool (Phase 1/2):
|
|
11
|
+
* the worker's makeSpawn wraps runNode. The shapes the canvas binds to
|
|
12
|
+
* (NodeOutput / NodeEvent) live in ./types and are REUSED here, not redefined;
|
|
13
|
+
* the executor-only shapes (NodeSpec / NodeRunRequest / deps) live here. */
|
|
14
|
+
import { compileConfigTemplate } from '../prompts/index.js';
|
|
1
15
|
import { runAgent } from '../core/loop.js';
|
|
2
16
|
import { compilePrompt } from '../promptCompiler.js';
|
|
3
17
|
/** Read-biased default tool set for a node with no explicit allowlist (§4). No
|
|
@@ -7,10 +21,10 @@ export const READ_BIASED_TOOLS = [
|
|
|
7
21
|
'read_file', 'list_files', 'search_files', 'stat_file',
|
|
8
22
|
'recall_result', 'recall_memory', 'kv_get',
|
|
9
23
|
];
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
24
|
+
/** What a delegated sub-agent is told about its situation. It cannot see the
|
|
25
|
+
* parent conversation, so this is the whole of it. From the config workspace
|
|
26
|
+
* so a user can retune how delegation behaves. */
|
|
27
|
+
export const subagentSystem = () => compileConfigTemplate('agent/subagent.md', {});
|
|
14
28
|
/** Resolve the node's effective tool list: allowlist (or read-biased default),
|
|
15
29
|
* with spawn_* tools dropped when this context can't spawn (the depth cap). */
|
|
16
30
|
export function resolveTools(all, allow, ctx) {
|
|
@@ -48,7 +62,7 @@ export async function runNode(req, deps) {
|
|
|
48
62
|
const result = await runAgent({
|
|
49
63
|
client: deps.client,
|
|
50
64
|
model: node.model || deps.defaultModel,
|
|
51
|
-
system: node.system || deps.defaultSystem ||
|
|
65
|
+
system: node.system || deps.defaultSystem || await subagentSystem(),
|
|
52
66
|
messages,
|
|
53
67
|
tools,
|
|
54
68
|
toolCtx: deps.toolCtx,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executeNode.js","sourceRoot":"","sources":["../../dag/executeNode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"executeNode.js","sourceRoot":"","sources":["../../dag/executeNode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Lowercase, split on non-alphanumerics, drop stopwords and single characters. */
|
|
2
|
+
export declare function tokenize(text: string): string[];
|
|
3
|
+
/** The per-fact map the manifest stores: term -> count. */
|
|
4
|
+
export declare function termFrequencies(text: string): Record<string, number>;
|
|
5
|
+
export interface Bm25Doc {
|
|
6
|
+
id: string;
|
|
7
|
+
tf: Record<string, number>;
|
|
8
|
+
/** Total token count of the document (sum of tf values). */
|
|
9
|
+
length: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Rank `docs` against `query`, best first, dropping documents that match no
|
|
13
|
+
* query term at all. A zero-score document is not a weak answer, it is a
|
|
14
|
+
* non-answer: returning it would put unrelated memories in front of the model.
|
|
15
|
+
*/
|
|
16
|
+
export declare function rankBm25(docs: Bm25Doc[], query: string, limit: number): {
|
|
17
|
+
id: string;
|
|
18
|
+
score: number;
|
|
19
|
+
}[];
|
|
20
|
+
//# sourceMappingURL=bm25.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bm25.d.ts","sourceRoot":"","sources":["../../memory/bm25.ts"],"names":[],"mappings":"AAyBA,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAK/C;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIpE;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CA4BvG"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/* BM25 over pre-computed term frequencies.
|
|
2
|
+
*
|
|
3
|
+
* Pure, and deliberately free of every app type: it takes ids and frequency
|
|
4
|
+
* maps, so the store can rank without reading a single fact body. Term
|
|
5
|
+
* frequencies are computed once at write time and live in the manifest; the
|
|
6
|
+
* corpus statistics (document frequency, average length) are derived here on
|
|
7
|
+
* each call, which costs one pass over a few hundred small objects.
|
|
8
|
+
*
|
|
9
|
+
* Rewritten from the shape of Marshal's packages/harness/src/memory/bm25.ts;
|
|
10
|
+
* no code is shared because that module is node-flavoured and this one must run
|
|
11
|
+
* in a browser worker. */
|
|
12
|
+
const K1 = 1.2;
|
|
13
|
+
const B = 0.75;
|
|
14
|
+
/* Words that carry no signal in a short factual note. Kept small on purpose: a
|
|
15
|
+
* long stoplist starts eating real query terms (a memory about "the state dir"
|
|
16
|
+
* is about a state dir). */
|
|
17
|
+
const STOPWORDS = new Set([
|
|
18
|
+
'a', 'an', 'and', 'are', 'as', 'at', 'be', 'but', 'by', 'do', 'for', 'from', 'how',
|
|
19
|
+
'i', 'if', 'in', 'is', 'it', 'me', 'my', 'no', 'not', 'of', 'on', 'or', 'our', 'so',
|
|
20
|
+
'that', 'the', 'their', 'then', 'there', 'they', 'this', 'to', 'was', 'we', 'were',
|
|
21
|
+
'what', 'when', 'where', 'which', 'who', 'why', 'will', 'with', 'you', 'your',
|
|
22
|
+
]);
|
|
23
|
+
/** Lowercase, split on non-alphanumerics, drop stopwords and single characters. */
|
|
24
|
+
export function tokenize(text) {
|
|
25
|
+
return (text || '')
|
|
26
|
+
.toLowerCase()
|
|
27
|
+
.split(/[^a-z0-9]+/)
|
|
28
|
+
.filter((t) => t.length > 1 && !STOPWORDS.has(t));
|
|
29
|
+
}
|
|
30
|
+
/** The per-fact map the manifest stores: term -> count. */
|
|
31
|
+
export function termFrequencies(text) {
|
|
32
|
+
const out = {};
|
|
33
|
+
for (const t of tokenize(text))
|
|
34
|
+
out[t] = (out[t] ?? 0) + 1;
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Rank `docs` against `query`, best first, dropping documents that match no
|
|
39
|
+
* query term at all. A zero-score document is not a weak answer, it is a
|
|
40
|
+
* non-answer: returning it would put unrelated memories in front of the model.
|
|
41
|
+
*/
|
|
42
|
+
export function rankBm25(docs, query, limit) {
|
|
43
|
+
const terms = tokenize(query);
|
|
44
|
+
if (!terms.length || !docs.length)
|
|
45
|
+
return [];
|
|
46
|
+
const n = docs.length;
|
|
47
|
+
const avgLen = docs.reduce((sum, d) => sum + d.length, 0) / n || 1;
|
|
48
|
+
const df = new Map();
|
|
49
|
+
for (const term of new Set(terms)) {
|
|
50
|
+
let count = 0;
|
|
51
|
+
for (const d of docs)
|
|
52
|
+
if (d.tf[term])
|
|
53
|
+
count += 1;
|
|
54
|
+
df.set(term, count);
|
|
55
|
+
}
|
|
56
|
+
const scored = [];
|
|
57
|
+
for (const d of docs) {
|
|
58
|
+
let score = 0;
|
|
59
|
+
for (const term of terms) {
|
|
60
|
+
const f = d.tf[term];
|
|
61
|
+
if (!f)
|
|
62
|
+
continue;
|
|
63
|
+
/* The +1 inside the log keeps idf non-negative: a term in EVERY document
|
|
64
|
+
* scores ~0 rather than going negative and actively penalising a match. */
|
|
65
|
+
const idf = Math.log(1 + (n - (df.get(term) ?? 0) + 0.5) / ((df.get(term) ?? 0) + 0.5));
|
|
66
|
+
score += idf * ((f * (K1 + 1)) / (f + K1 * (1 - B + (B * d.length) / avgLen)));
|
|
67
|
+
}
|
|
68
|
+
if (score > 0)
|
|
69
|
+
scored.push({ id: d.id, score });
|
|
70
|
+
}
|
|
71
|
+
return scored.sort((a, b) => b.score - a.score || a.id.localeCompare(b.id)).slice(0, limit);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=bm25.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bm25.js","sourceRoot":"","sources":["../../memory/bm25.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { MemoryType } from '../core/factFile';
|
|
2
|
+
import type { Tier } from './tier';
|
|
3
|
+
export declare const MANIFEST_FILE = "memory.json";
|
|
4
|
+
export declare const MANIFEST_VERSION = 1;
|
|
5
|
+
export interface ManifestEntry {
|
|
6
|
+
type: MemoryType;
|
|
7
|
+
/** Copy of the fact's description, so listing and rendering need no body reads. */
|
|
8
|
+
description: string;
|
|
9
|
+
/**
|
|
10
|
+
* CHEAP drift check: size and mtime as the directory listing reported them
|
|
11
|
+
* when this entry was indexed. A content hash would be exact, but obtaining
|
|
12
|
+
* one means READING every file -- precisely the cost this manifest exists to
|
|
13
|
+
* avoid. MemoryFileService (the browser's store) reports no mtime at all, so
|
|
14
|
+
* in the browser this is size alone.
|
|
15
|
+
*/
|
|
16
|
+
sig: string;
|
|
17
|
+
/** EXACT check: hash of the body as last indexed. Verified only when a body is
|
|
18
|
+
* read for some other reason, which is what catches an edit that kept the
|
|
19
|
+
* same size. */
|
|
20
|
+
hash: string;
|
|
21
|
+
created: number;
|
|
22
|
+
updated: number;
|
|
23
|
+
tier: Tier;
|
|
24
|
+
recallCount: number;
|
|
25
|
+
lastRecalledAt?: number;
|
|
26
|
+
/** Term frequencies over name + description + body, computed at write time. */
|
|
27
|
+
tf: Record<string, number>;
|
|
28
|
+
/** Estimated prompt cost, from estimateFactTokens. */
|
|
29
|
+
tokens: number;
|
|
30
|
+
}
|
|
31
|
+
export interface Manifest {
|
|
32
|
+
version: number;
|
|
33
|
+
facts: Record<string, ManifestEntry>;
|
|
34
|
+
}
|
|
35
|
+
export declare function emptyManifest(): Manifest;
|
|
36
|
+
export declare function renderManifest(m: Manifest): string;
|
|
37
|
+
/** Never throws: a corrupt or future-versioned manifest reads as empty, and the
|
|
38
|
+
* store rebuilds it from the files that are actually there. */
|
|
39
|
+
export declare function parseManifest(raw: string): Manifest;
|
|
40
|
+
/** The listing-cheap signature. Empty mtime is normal in the browser. */
|
|
41
|
+
export declare function fileSignature(size: number, mtime?: number): string;
|
|
42
|
+
/** Stable 32-bit FNV-1a, hex. Same function the config workspace uses for its
|
|
43
|
+
* baselines -- cheap, sync, and only ever compared to itself. */
|
|
44
|
+
export declare function hashContent(s: string): string;
|
|
45
|
+
export interface ReconcilePlan {
|
|
46
|
+
/** Facts whose .md must be read and re-indexed (new, or changed size/mtime). */
|
|
47
|
+
reindex: string[];
|
|
48
|
+
/** Manifest entries whose .md is gone. */
|
|
49
|
+
drop: string[];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* What the store must do to agree with the disk.
|
|
53
|
+
*
|
|
54
|
+
* The point is the NEGATIVE space: a fact whose hash matches is not re-read.
|
|
55
|
+
* With a few hundred facts on a sidecar, re-reading everything on every load is
|
|
56
|
+
* the difference between a usable store and a slow one.
|
|
57
|
+
*/
|
|
58
|
+
export declare function planReconcile(m: Manifest, onDisk: {
|
|
59
|
+
name: string;
|
|
60
|
+
sig: string;
|
|
61
|
+
}[]): ReconcilePlan;
|
|
62
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../memory/manifest.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAC3C,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;oBAEgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACtC;AAED,wBAAgB,aAAa,IAAI,QAAQ,CAExC;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAElD;AAED;+DAC+D;AAC/D,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAQnD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;iEACiE;AACjE,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,aAAa,CASjG"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export const MANIFEST_FILE = 'memory.json';
|
|
2
|
+
export const MANIFEST_VERSION = 1;
|
|
3
|
+
export function emptyManifest() {
|
|
4
|
+
return { version: MANIFEST_VERSION, facts: {} };
|
|
5
|
+
}
|
|
6
|
+
export function renderManifest(m) {
|
|
7
|
+
return JSON.stringify(m, null, 2);
|
|
8
|
+
}
|
|
9
|
+
/** Never throws: a corrupt or future-versioned manifest reads as empty, and the
|
|
10
|
+
* store rebuilds it from the files that are actually there. */
|
|
11
|
+
export function parseManifest(raw) {
|
|
12
|
+
try {
|
|
13
|
+
const j = JSON.parse(raw);
|
|
14
|
+
if (!j || j.version !== MANIFEST_VERSION || typeof j.facts !== 'object' || j.facts === null || Array.isArray(j.facts))
|
|
15
|
+
return emptyManifest();
|
|
16
|
+
return { version: MANIFEST_VERSION, facts: j.facts };
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return emptyManifest();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** The listing-cheap signature. Empty mtime is normal in the browser. */
|
|
23
|
+
export function fileSignature(size, mtime) {
|
|
24
|
+
return `${size}:${mtime ?? ''}`;
|
|
25
|
+
}
|
|
26
|
+
/** Stable 32-bit FNV-1a, hex. Same function the config workspace uses for its
|
|
27
|
+
* baselines -- cheap, sync, and only ever compared to itself. */
|
|
28
|
+
export function hashContent(s) {
|
|
29
|
+
let h = 0x811c9dc5;
|
|
30
|
+
for (let i = 0; i < s.length; i++) {
|
|
31
|
+
h ^= s.charCodeAt(i);
|
|
32
|
+
h = Math.imul(h, 0x01000193);
|
|
33
|
+
}
|
|
34
|
+
return (h >>> 0).toString(16);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* What the store must do to agree with the disk.
|
|
38
|
+
*
|
|
39
|
+
* The point is the NEGATIVE space: a fact whose hash matches is not re-read.
|
|
40
|
+
* With a few hundred facts on a sidecar, re-reading everything on every load is
|
|
41
|
+
* the difference between a usable store and a slow one.
|
|
42
|
+
*/
|
|
43
|
+
export function planReconcile(m, onDisk) {
|
|
44
|
+
const reindex = [];
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
for (const f of onDisk) {
|
|
47
|
+
seen.add(f.name);
|
|
48
|
+
if (m.facts[f.name]?.sig !== f.sig)
|
|
49
|
+
reindex.push(f.name);
|
|
50
|
+
}
|
|
51
|
+
const drop = Object.keys(m.facts).filter((name) => !seen.has(name));
|
|
52
|
+
return { reindex, drop };
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../memory/manifest.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;AAC3C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAkClC,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,CAAW;IACxC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACpC,CAAC;AAED;+DAC+D;AAC/D,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAC;QAC/C,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,gBAAgB,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,OAAO,aAAa,EAAE,CAAC;QAC9I,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC,KAAsC,EAAE,CAAC;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAc;IACxD,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;AAClC,CAAC;AAED;iEACiE;AACjE,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAAC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAAC,CAAC;IAC1F,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC;AASD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,CAAW,EAAE,MAAuC;IAChF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type FileService } from '@corenel/protocol';
|
|
2
|
+
import { type MemoryType } from '../core/factFile';
|
|
3
|
+
import { type Tier } from './tier';
|
|
4
|
+
export interface StoredFact {
|
|
5
|
+
name: string;
|
|
6
|
+
type: MemoryType;
|
|
7
|
+
description: string;
|
|
8
|
+
body: string;
|
|
9
|
+
created: number;
|
|
10
|
+
updated: number;
|
|
11
|
+
tier: Tier;
|
|
12
|
+
/** The BM25 score this fact matched a query with. Set only by `recall()` --
|
|
13
|
+
* `read()`, `list()` and `core()` don't rank against a query, so they leave
|
|
14
|
+
* it undefined. A cross-plane caller (the app's router) needs this to merge
|
|
15
|
+
* two planes' hits by relevance rather than by which plane happened to be
|
|
16
|
+
* asked first. */
|
|
17
|
+
score?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface SaveInput {
|
|
20
|
+
name: string;
|
|
21
|
+
type: MemoryType;
|
|
22
|
+
description: string;
|
|
23
|
+
body: string;
|
|
24
|
+
}
|
|
25
|
+
export interface CoreBlock {
|
|
26
|
+
facts: StoredFact[];
|
|
27
|
+
archivedCount: number;
|
|
28
|
+
}
|
|
29
|
+
export interface RankedCandidate {
|
|
30
|
+
name: string;
|
|
31
|
+
score: number;
|
|
32
|
+
}
|
|
33
|
+
export interface FactStore {
|
|
34
|
+
save(input: SaveInput): Promise<StoredFact>;
|
|
35
|
+
read(name: string): Promise<StoredFact | null>;
|
|
36
|
+
recall(query: string, limit?: number): Promise<StoredFact[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Rank facts against a query WITHOUT marking any of them recalled -- a pure
|
|
39
|
+
* read, like core(). For a caller that will merge candidates across several
|
|
40
|
+
* stores before deciding what the model actually sees (fileMemory.ts's
|
|
41
|
+
* cross-plane recall), ranking every plane's candidates first and marking
|
|
42
|
+
* only the final winners (via hydrateRecalled) is the only way a fact that
|
|
43
|
+
* gets sliced away in that merge is not still recorded as used.
|
|
44
|
+
*/
|
|
45
|
+
rankCandidates(query: string, limit?: number): Promise<RankedCandidate[]>;
|
|
46
|
+
/**
|
|
47
|
+
* Load bodies for exactly these names and record a recall against each --
|
|
48
|
+
* the "used" half of recall(), split out so a caller can apply it only to
|
|
49
|
+
* the facts it actually returns. Names not in the manifest are skipped.
|
|
50
|
+
*/
|
|
51
|
+
hydrateRecalled(names: string[]): Promise<StoredFact[]>;
|
|
52
|
+
list(limit?: number): Promise<StoredFact[]>;
|
|
53
|
+
forget(name: string): Promise<void>;
|
|
54
|
+
/** Core facts plus how many are archived -- everything injection needs, and
|
|
55
|
+
* nothing it could write with. */
|
|
56
|
+
core(): Promise<CoreBlock>;
|
|
57
|
+
}
|
|
58
|
+
type GetFiles = () => FileService | null | Promise<FileService | null>;
|
|
59
|
+
export declare function makeFactStore(getFiles: GetFiles, root: string): FactStore;
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../memory/store.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EACuD,KAAK,UAAU,EAC5E,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAoC,KAAK,IAAI,EAAE,MAAM,QAAQ,CAAC;AAgBrE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,IAAI,CAAC;IACX;;;;sBAIkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AAEhE,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC/C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC7D;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAC1E;;;;OAIG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5C,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC;sCACkC;IAClC,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;CAC5B;AAED,KAAK,QAAQ,GAAG,MAAM,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;AAqBvE,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAgVzE"}
|