@agent-native/core 0.52.0 → 0.53.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/README.md +41 -95
- package/blueprints/action/crud.md +98 -0
- package/blueprints/channel/discord.md +74 -0
- package/blueprints/provider/stripe.md +87 -0
- package/blueprints/sandbox/docker.md +78 -0
- package/dist/action.d.ts +24 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +4 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/observational-memory/compactor.d.ts +43 -0
- package/dist/agent/observational-memory/compactor.d.ts.map +1 -0
- package/dist/agent/observational-memory/compactor.js +50 -0
- package/dist/agent/observational-memory/compactor.js.map +1 -0
- package/dist/agent/observational-memory/config.d.ts +37 -0
- package/dist/agent/observational-memory/config.d.ts.map +1 -0
- package/dist/agent/observational-memory/config.js +48 -0
- package/dist/agent/observational-memory/config.js.map +1 -0
- package/dist/agent/observational-memory/index.d.ts +26 -0
- package/dist/agent/observational-memory/index.d.ts.map +1 -0
- package/dist/agent/observational-memory/index.js +25 -0
- package/dist/agent/observational-memory/index.js.map +1 -0
- package/dist/agent/observational-memory/internal-run.d.ts +37 -0
- package/dist/agent/observational-memory/internal-run.d.ts.map +1 -0
- package/dist/agent/observational-memory/internal-run.js +59 -0
- package/dist/agent/observational-memory/internal-run.js.map +1 -0
- package/dist/agent/observational-memory/message-text.d.ts +13 -0
- package/dist/agent/observational-memory/message-text.d.ts.map +1 -0
- package/dist/agent/observational-memory/message-text.js +46 -0
- package/dist/agent/observational-memory/message-text.js.map +1 -0
- package/dist/agent/observational-memory/migrations.d.ts +13 -0
- package/dist/agent/observational-memory/migrations.d.ts.map +1 -0
- package/dist/agent/observational-memory/migrations.js +43 -0
- package/dist/agent/observational-memory/migrations.js.map +1 -0
- package/dist/agent/observational-memory/observer.d.ts +37 -0
- package/dist/agent/observational-memory/observer.d.ts.map +1 -0
- package/dist/agent/observational-memory/observer.js +82 -0
- package/dist/agent/observational-memory/observer.js.map +1 -0
- package/dist/agent/observational-memory/plugin.d.ts +16 -0
- package/dist/agent/observational-memory/plugin.d.ts.map +1 -0
- package/dist/agent/observational-memory/plugin.js +26 -0
- package/dist/agent/observational-memory/plugin.js.map +1 -0
- package/dist/agent/observational-memory/prompts.d.ts +27 -0
- package/dist/agent/observational-memory/prompts.d.ts.map +1 -0
- package/dist/agent/observational-memory/prompts.js +42 -0
- package/dist/agent/observational-memory/prompts.js.map +1 -0
- package/dist/agent/observational-memory/read.d.ts +47 -0
- package/dist/agent/observational-memory/read.d.ts.map +1 -0
- package/dist/agent/observational-memory/read.js +99 -0
- package/dist/agent/observational-memory/read.js.map +1 -0
- package/dist/agent/observational-memory/reflector.d.ts +31 -0
- package/dist/agent/observational-memory/reflector.d.ts.map +1 -0
- package/dist/agent/observational-memory/reflector.js +76 -0
- package/dist/agent/observational-memory/reflector.js.map +1 -0
- package/dist/agent/observational-memory/schema.d.ts +267 -0
- package/dist/agent/observational-memory/schema.d.ts.map +1 -0
- package/dist/agent/observational-memory/schema.js +48 -0
- package/dist/agent/observational-memory/schema.js.map +1 -0
- package/dist/agent/observational-memory/store.d.ts +52 -0
- package/dist/agent/observational-memory/store.d.ts.map +1 -0
- package/dist/agent/observational-memory/store.js +197 -0
- package/dist/agent/observational-memory/store.js.map +1 -0
- package/dist/agent/observational-memory/types.d.ts +61 -0
- package/dist/agent/observational-memory/types.d.ts.map +1 -0
- package/dist/agent/observational-memory/types.js +9 -0
- package/dist/agent/observational-memory/types.js.map +1 -0
- package/dist/agent/production-agent.d.ts +15 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +240 -1
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +49 -0
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-store.d.ts +17 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +55 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/runtime-context.d.ts +30 -0
- package/dist/agent/runtime-context.d.ts.map +1 -1
- package/dist/agent/runtime-context.js +54 -1
- package/dist/agent/runtime-context.js.map +1 -1
- package/dist/agent/tool-call-journal.d.ts +101 -0
- package/dist/agent/tool-call-journal.d.ts.map +1 -0
- package/dist/agent/tool-call-journal.js +214 -0
- package/dist/agent/tool-call-journal.js.map +1 -0
- package/dist/agent/types.d.ts +24 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/add.d.ts +109 -0
- package/dist/cli/add.d.ts.map +1 -0
- package/dist/cli/add.js +352 -0
- package/dist/cli/add.js.map +1 -0
- package/dist/cli/connect.d.ts +2 -2
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +92 -24
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/eval.d.ts +17 -0
- package/dist/cli/eval.d.ts.map +1 -0
- package/dist/cli/eval.js +121 -0
- package/dist/cli/eval.js.map +1 -0
- package/dist/cli/index.js +44 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +11 -5
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/plan-local.d.ts +66 -5
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +495 -19
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts +2 -2
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +70 -59
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +118 -92
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +16 -0
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +20 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +32 -7
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +13 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +21 -0
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/db/client.d.ts +4 -2
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +6 -4
- package/dist/db/client.js.map +1 -1
- package/dist/deploy/route-discovery.d.ts.map +1 -1
- package/dist/deploy/route-discovery.js +1 -0
- package/dist/deploy/route-discovery.js.map +1 -1
- package/dist/eval/agent-runner.d.ts +63 -0
- package/dist/eval/agent-runner.d.ts.map +1 -0
- package/dist/eval/agent-runner.js +142 -0
- package/dist/eval/agent-runner.js.map +1 -0
- package/dist/eval/define-eval.d.ts +29 -0
- package/dist/eval/define-eval.d.ts.map +1 -0
- package/dist/eval/define-eval.js +43 -0
- package/dist/eval/define-eval.js.map +1 -0
- package/dist/eval/index.d.ts +18 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +17 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/report.d.ts +8 -0
- package/dist/eval/report.d.ts.map +1 -0
- package/dist/eval/report.js +44 -0
- package/dist/eval/report.js.map +1 -0
- package/dist/eval/runner.d.ts +67 -0
- package/dist/eval/runner.d.ts.map +1 -0
- package/dist/eval/runner.js +256 -0
- package/dist/eval/runner.js.map +1 -0
- package/dist/eval/scorer.d.ts +83 -0
- package/dist/eval/scorer.d.ts.map +1 -0
- package/dist/eval/scorer.js +195 -0
- package/dist/eval/scorer.js.map +1 -0
- package/dist/eval/types.d.ts +162 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +20 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +100 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/observability/tracing.d.ts +73 -0
- package/dist/observability/tracing.d.ts.map +1 -0
- package/dist/observability/tracing.js +126 -0
- package/dist/observability/tracing.js.map +1 -0
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +4 -1
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +10 -3
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +4 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +9 -0
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +118 -110
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-teams.d.ts +62 -0
- package/dist/server/agent-teams.d.ts.map +1 -1
- package/dist/server/agent-teams.js +99 -2
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +7 -4
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +2 -0
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +33 -1
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +10 -0
- package/dist/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
- package/docs/content/agent-teams.md +32 -0
- package/docs/content/blueprint-installer.md +73 -0
- package/docs/content/evals.md +141 -0
- package/docs/content/pr-visual-recap.md +7 -4
- package/docs/content/sandbox-adapters.md +134 -0
- package/docs/content/template-plan.md +20 -8
- package/package.json +5 -1
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +10 -0
- package/src/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +20 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read API for Observational Memory.
|
|
3
|
+
*
|
|
4
|
+
* `buildObservationalContext` assembles the three tiers — reflections (highest
|
|
5
|
+
* level) + observations (dense) + the recent raw message tail — into a single
|
|
6
|
+
* structure ready to fold into a prompt. It is intentionally NOT wired into
|
|
7
|
+
* production-agent.ts here; see the exported seam note below and the package
|
|
8
|
+
* barrel export so the wire-up is one call later.
|
|
9
|
+
*
|
|
10
|
+
* Token-cheap by construction: a long thread is represented by its compacted
|
|
11
|
+
* tiers plus only the last N raw turns, instead of the entire transcript.
|
|
12
|
+
*/
|
|
13
|
+
import { resolveObservationalMemoryConfig, } from "./config.js";
|
|
14
|
+
import { listObservationalMemory } from "./store.js";
|
|
15
|
+
import { countWindowTokens } from "./message-text.js";
|
|
16
|
+
function sumTokens(entries) {
|
|
17
|
+
return entries.reduce((acc, entry) => acc + (entry.tokenEstimate || 0), 0);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* SEAM (deferred wire-up): build the three-tier Observational Memory context
|
|
21
|
+
* for a thread. The returned tiers are ready to be injected into the turn's
|
|
22
|
+
* prompt assembly.
|
|
23
|
+
*
|
|
24
|
+
* TODO(charlie-merge): inject buildObservationalContext output into the turn
|
|
25
|
+
* context assembly in production-agent.ts once the lazy-skill context changes
|
|
26
|
+
* land. The intended shape: replace the older raw-message prefix (everything
|
|
27
|
+
* before `recentMessages`) with the `reflections` + `observations` text, keep
|
|
28
|
+
* `recentMessages` verbatim, and prepend a short "Observational Memory" system
|
|
29
|
+
* section. This module deliberately does not edit production-agent.ts.
|
|
30
|
+
*/
|
|
31
|
+
/** True when this thread has at least one persisted observation or reflection. */
|
|
32
|
+
export function hasObservationalMemory(context) {
|
|
33
|
+
return context.reflections.length > 0 || context.observations.length > 0;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Serialize the reflections + observations tiers into a single, clearly
|
|
37
|
+
* delimited prompt block. The recent-raw-message tail is NOT serialized here —
|
|
38
|
+
* it stays as verbatim engine messages — so this block represents only the
|
|
39
|
+
* compacted older history that replaces the raw prefix.
|
|
40
|
+
*
|
|
41
|
+
* Returns an empty string when there is nothing compacted yet, so callers can
|
|
42
|
+
* cheaply skip injection for short threads.
|
|
43
|
+
*/
|
|
44
|
+
export function serializeObservationalMemoryBlock(context) {
|
|
45
|
+
if (!hasObservationalMemory(context))
|
|
46
|
+
return "";
|
|
47
|
+
const sections = [];
|
|
48
|
+
sections.push("[Observational Memory] The earlier part of this long conversation has been " +
|
|
49
|
+
"compacted into the dated reflections and observations below. Treat these " +
|
|
50
|
+
"as an authoritative record of what already happened — do not redo " +
|
|
51
|
+
"completed work, and trust the recorded decisions, names, dates, and " +
|
|
52
|
+
"status. The most recent turns follow verbatim after this block.");
|
|
53
|
+
if (context.reflections.length > 0) {
|
|
54
|
+
sections.push("## Reflections (highest-level)\n" +
|
|
55
|
+
context.reflections.map((entry) => entry.text).join("\n\n"));
|
|
56
|
+
}
|
|
57
|
+
if (context.observations.length > 0) {
|
|
58
|
+
sections.push("## Observations (dense, dated)\n" +
|
|
59
|
+
context.observations.map((entry) => entry.text).join("\n\n"));
|
|
60
|
+
}
|
|
61
|
+
return sections.join("\n\n");
|
|
62
|
+
}
|
|
63
|
+
export async function buildObservationalContext(options) {
|
|
64
|
+
const config = resolveObservationalMemoryConfig(options.config);
|
|
65
|
+
const owner = {
|
|
66
|
+
ownerEmail: options.ownerEmail,
|
|
67
|
+
orgId: options.orgId ?? null,
|
|
68
|
+
};
|
|
69
|
+
const [reflections, observations] = await Promise.all([
|
|
70
|
+
listObservationalMemory({
|
|
71
|
+
...owner,
|
|
72
|
+
threadId: options.threadId,
|
|
73
|
+
tier: "reflection",
|
|
74
|
+
}),
|
|
75
|
+
listObservationalMemory({
|
|
76
|
+
...owner,
|
|
77
|
+
threadId: options.threadId,
|
|
78
|
+
tier: "observation",
|
|
79
|
+
}),
|
|
80
|
+
]);
|
|
81
|
+
const recentCount = Math.max(0, config.recentRawMessageCount);
|
|
82
|
+
const recentMessages = recentCount > 0 ? options.messages.slice(-recentCount) : [];
|
|
83
|
+
const recentTokens = await countWindowTokens(recentMessages);
|
|
84
|
+
const reflectionTokens = sumTokens(reflections);
|
|
85
|
+
const observationTokens = sumTokens(observations);
|
|
86
|
+
return {
|
|
87
|
+
threadId: options.threadId,
|
|
88
|
+
reflections,
|
|
89
|
+
observations,
|
|
90
|
+
recentMessages,
|
|
91
|
+
tokens: {
|
|
92
|
+
reflections: reflectionTokens,
|
|
93
|
+
observations: observationTokens,
|
|
94
|
+
recentMessages: recentTokens,
|
|
95
|
+
total: reflectionTokens + observationTokens + recentTokens,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/agent/observational-memory/read.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Read API for Observational Memory.\n *\n * `buildObservationalContext` assembles the three tiers — reflections (highest\n * level) + observations (dense) + the recent raw message tail — into a single\n * structure ready to fold into a prompt. It is intentionally NOT wired into\n * production-agent.ts here; see the exported seam note below and the package\n * barrel export so the wire-up is one call later.\n *\n * Token-cheap by construction: a long thread is represented by its compacted\n * tiers plus only the last N raw turns, instead of the entire transcript.\n */\n\nimport type { EngineMessage } from \"../engine/types.js\";\nimport {\n resolveObservationalMemoryConfig,\n type ObservationalMemoryConfig,\n} from \"./config.js\";\nimport { listObservationalMemory } from \"./store.js\";\nimport { countWindowTokens } from \"./message-text.js\";\nimport type {\n ObservationalContext,\n ObservationalMemoryEntry,\n ObservationalMemoryOwner,\n} from \"./types.js\";\n\nexport interface BuildObservationalContextOptions extends ObservationalMemoryOwner {\n threadId: string;\n /** The full, ordered thread messages — the recent tail is taken from here. */\n messages: EngineMessage[];\n config?: Partial<ObservationalMemoryConfig>;\n}\n\nfunction sumTokens(entries: ObservationalMemoryEntry[]): number {\n return entries.reduce((acc, entry) => acc + (entry.tokenEstimate || 0), 0);\n}\n\n/**\n * SEAM (deferred wire-up): build the three-tier Observational Memory context\n * for a thread. The returned tiers are ready to be injected into the turn's\n * prompt assembly.\n *\n * TODO(charlie-merge): inject buildObservationalContext output into the turn\n * context assembly in production-agent.ts once the lazy-skill context changes\n * land. The intended shape: replace the older raw-message prefix (everything\n * before `recentMessages`) with the `reflections` + `observations` text, keep\n * `recentMessages` verbatim, and prepend a short \"Observational Memory\" system\n * section. This module deliberately does not edit production-agent.ts.\n */\n/** True when this thread has at least one persisted observation or reflection. */\nexport function hasObservationalMemory(context: ObservationalContext): boolean {\n return context.reflections.length > 0 || context.observations.length > 0;\n}\n\n/**\n * Serialize the reflections + observations tiers into a single, clearly\n * delimited prompt block. The recent-raw-message tail is NOT serialized here —\n * it stays as verbatim engine messages — so this block represents only the\n * compacted older history that replaces the raw prefix.\n *\n * Returns an empty string when there is nothing compacted yet, so callers can\n * cheaply skip injection for short threads.\n */\nexport function serializeObservationalMemoryBlock(\n context: ObservationalContext,\n): string {\n if (!hasObservationalMemory(context)) return \"\";\n const sections: string[] = [];\n sections.push(\n \"[Observational Memory] The earlier part of this long conversation has been \" +\n \"compacted into the dated reflections and observations below. Treat these \" +\n \"as an authoritative record of what already happened — do not redo \" +\n \"completed work, and trust the recorded decisions, names, dates, and \" +\n \"status. The most recent turns follow verbatim after this block.\",\n );\n if (context.reflections.length > 0) {\n sections.push(\n \"## Reflections (highest-level)\\n\" +\n context.reflections.map((entry) => entry.text).join(\"\\n\\n\"),\n );\n }\n if (context.observations.length > 0) {\n sections.push(\n \"## Observations (dense, dated)\\n\" +\n context.observations.map((entry) => entry.text).join(\"\\n\\n\"),\n );\n }\n return sections.join(\"\\n\\n\");\n}\n\nexport async function buildObservationalContext(\n options: BuildObservationalContextOptions,\n): Promise<ObservationalContext> {\n const config = resolveObservationalMemoryConfig(options.config);\n const owner: ObservationalMemoryOwner = {\n ownerEmail: options.ownerEmail,\n orgId: options.orgId ?? null,\n };\n\n const [reflections, observations] = await Promise.all([\n listObservationalMemory({\n ...owner,\n threadId: options.threadId,\n tier: \"reflection\",\n }),\n listObservationalMemory({\n ...owner,\n threadId: options.threadId,\n tier: \"observation\",\n }),\n ]);\n\n const recentCount = Math.max(0, config.recentRawMessageCount);\n const recentMessages =\n recentCount > 0 ? options.messages.slice(-recentCount) : [];\n\n const recentTokens = await countWindowTokens(recentMessages);\n const reflectionTokens = sumTokens(reflections);\n const observationTokens = sumTokens(observations);\n\n return {\n threadId: options.threadId,\n reflections,\n observations,\n recentMessages,\n tokens: {\n reflections: reflectionTokens,\n observations: observationTokens,\n recentMessages: recentTokens,\n total: reflectionTokens + observationTokens + recentTokens,\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Reflector.
|
|
3
|
+
*
|
|
4
|
+
* When the persisted observation log itself exceeds the reflection token
|
|
5
|
+
* threshold, the Reflector runs ONE internal (tool-less) agent call to condense
|
|
6
|
+
* the observations into higher-level reflections, and persists a
|
|
7
|
+
* `tier: "reflection"` entry. Observations are kept (they remain the dense
|
|
8
|
+
* mid-tier); the reflection sits above them.
|
|
9
|
+
*/
|
|
10
|
+
import { type ObservationalMemoryConfig } from "./config.js";
|
|
11
|
+
import { type InternalAgentRunFn } from "./internal-run.js";
|
|
12
|
+
import type { ObservationalMemoryEntry, ObservationalMemoryOwner } from "./types.js";
|
|
13
|
+
export interface RunReflectorOptions extends ObservationalMemoryOwner {
|
|
14
|
+
threadId: string;
|
|
15
|
+
config?: Partial<ObservationalMemoryConfig>;
|
|
16
|
+
/** Internal-run seam — defaults to the real one; injected in tests. */
|
|
17
|
+
runInternal?: InternalAgentRunFn;
|
|
18
|
+
}
|
|
19
|
+
export interface RunReflectorResult {
|
|
20
|
+
/** True when a reflection was produced and persisted. */
|
|
21
|
+
reflected: boolean;
|
|
22
|
+
entry?: ObservationalMemoryEntry;
|
|
23
|
+
/** Tokens in the observation log that was considered. */
|
|
24
|
+
observationLogTokens: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Condense the observation log into a reflection IF it exceeds the token
|
|
28
|
+
* threshold; otherwise no-op.
|
|
29
|
+
*/
|
|
30
|
+
export declare function runReflector(options: RunReflectorOptions): Promise<RunReflectorResult>;
|
|
31
|
+
//# sourceMappingURL=reflector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflector.d.ts","sourceRoot":"","sources":["../../../src/agent/observational-memory/reflector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,aAAa,CAAC;AAMrB,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EACV,wBAAwB,EACxB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,mBAAoB,SAAQ,wBAAwB;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC5C,uEAAuE;IACvE,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,wBAAwB,CAAC;IACjC,yDAAyD;IACzD,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CAmE7B"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Reflector.
|
|
3
|
+
*
|
|
4
|
+
* When the persisted observation log itself exceeds the reflection token
|
|
5
|
+
* threshold, the Reflector runs ONE internal (tool-less) agent call to condense
|
|
6
|
+
* the observations into higher-level reflections, and persists a
|
|
7
|
+
* `tier: "reflection"` entry. Observations are kept (they remain the dense
|
|
8
|
+
* mid-tier); the reflection sits above them.
|
|
9
|
+
*/
|
|
10
|
+
import { countTextTokens } from "../context-xray/tokenize.js";
|
|
11
|
+
import { resolveObservationalMemoryConfig, } from "./config.js";
|
|
12
|
+
import { getObservationLogTokens, insertObservationalMemory, listObservationalMemory, } from "./store.js";
|
|
13
|
+
import { runInternalAgentCall, } from "./internal-run.js";
|
|
14
|
+
import { REFLECTOR_SYSTEM_PROMPT, buildReflectorPrompt } from "./prompts.js";
|
|
15
|
+
/**
|
|
16
|
+
* Condense the observation log into a reflection IF it exceeds the token
|
|
17
|
+
* threshold; otherwise no-op.
|
|
18
|
+
*/
|
|
19
|
+
export async function runReflector(options) {
|
|
20
|
+
const config = resolveObservationalMemoryConfig(options.config);
|
|
21
|
+
const owner = {
|
|
22
|
+
ownerEmail: options.ownerEmail,
|
|
23
|
+
orgId: options.orgId ?? null,
|
|
24
|
+
};
|
|
25
|
+
const observationLogTokens = await getObservationLogTokens({
|
|
26
|
+
...owner,
|
|
27
|
+
threadId: options.threadId,
|
|
28
|
+
});
|
|
29
|
+
if (observationLogTokens < config.reflectionTokenThreshold) {
|
|
30
|
+
return { reflected: false, observationLogTokens };
|
|
31
|
+
}
|
|
32
|
+
const observations = await listObservationalMemory({
|
|
33
|
+
...owner,
|
|
34
|
+
threadId: options.threadId,
|
|
35
|
+
tier: "observation",
|
|
36
|
+
});
|
|
37
|
+
if (observations.length === 0) {
|
|
38
|
+
return { reflected: false, observationLogTokens };
|
|
39
|
+
}
|
|
40
|
+
const observationsText = observations.map((entry) => entry.text).join("\n\n");
|
|
41
|
+
const priorReflections = (await listObservationalMemory({
|
|
42
|
+
...owner,
|
|
43
|
+
threadId: options.threadId,
|
|
44
|
+
tier: "reflection",
|
|
45
|
+
}))
|
|
46
|
+
.map((entry) => entry.text)
|
|
47
|
+
.join("\n\n");
|
|
48
|
+
const run = options.runInternal ?? runInternalAgentCall;
|
|
49
|
+
const reflectionText = await run({
|
|
50
|
+
systemPrompt: REFLECTOR_SYSTEM_PROMPT,
|
|
51
|
+
prompt: buildReflectorPrompt({
|
|
52
|
+
threadId: options.threadId,
|
|
53
|
+
observationsText,
|
|
54
|
+
priorReflections,
|
|
55
|
+
}),
|
|
56
|
+
maxOutputTokens: config.reflectionMaxOutputTokens,
|
|
57
|
+
});
|
|
58
|
+
if (!reflectionText.trim()) {
|
|
59
|
+
return { reflected: false, observationLogTokens };
|
|
60
|
+
}
|
|
61
|
+
const { tokens: tokenEstimate } = await countTextTokens(reflectionText);
|
|
62
|
+
const sourceStart = observations[0]?.sourceStartIndex ?? null;
|
|
63
|
+
const sourceEnd = observations[observations.length - 1]?.sourceEndIndex ?? null;
|
|
64
|
+
const entry = await insertObservationalMemory({
|
|
65
|
+
...owner,
|
|
66
|
+
threadId: options.threadId,
|
|
67
|
+
tier: "reflection",
|
|
68
|
+
text: reflectionText,
|
|
69
|
+
tokenEstimate,
|
|
70
|
+
sourceStartIndex: sourceStart,
|
|
71
|
+
sourceEndIndex: sourceEnd,
|
|
72
|
+
sourceMessageCount: observations.length,
|
|
73
|
+
});
|
|
74
|
+
return { reflected: true, entry, observationLogTokens };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=reflector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflector.js","sourceRoot":"","sources":["../../../src/agent/observational-memory/reflector.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Reflector.\n *\n * When the persisted observation log itself exceeds the reflection token\n * threshold, the Reflector runs ONE internal (tool-less) agent call to condense\n * the observations into higher-level reflections, and persists a\n * `tier: \"reflection\"` entry. Observations are kept (they remain the dense\n * mid-tier); the reflection sits above them.\n */\n\nimport { countTextTokens } from \"../context-xray/tokenize.js\";\nimport {\n resolveObservationalMemoryConfig,\n type ObservationalMemoryConfig,\n} from \"./config.js\";\nimport {\n getObservationLogTokens,\n insertObservationalMemory,\n listObservationalMemory,\n} from \"./store.js\";\nimport {\n runInternalAgentCall,\n type InternalAgentRunFn,\n} from \"./internal-run.js\";\nimport { REFLECTOR_SYSTEM_PROMPT, buildReflectorPrompt } from \"./prompts.js\";\nimport type {\n ObservationalMemoryEntry,\n ObservationalMemoryOwner,\n} from \"./types.js\";\n\nexport interface RunReflectorOptions extends ObservationalMemoryOwner {\n threadId: string;\n config?: Partial<ObservationalMemoryConfig>;\n /** Internal-run seam — defaults to the real one; injected in tests. */\n runInternal?: InternalAgentRunFn;\n}\n\nexport interface RunReflectorResult {\n /** True when a reflection was produced and persisted. */\n reflected: boolean;\n entry?: ObservationalMemoryEntry;\n /** Tokens in the observation log that was considered. */\n observationLogTokens: number;\n}\n\n/**\n * Condense the observation log into a reflection IF it exceeds the token\n * threshold; otherwise no-op.\n */\nexport async function runReflector(\n options: RunReflectorOptions,\n): Promise<RunReflectorResult> {\n const config = resolveObservationalMemoryConfig(options.config);\n const owner: ObservationalMemoryOwner = {\n ownerEmail: options.ownerEmail,\n orgId: options.orgId ?? null,\n };\n\n const observationLogTokens = await getObservationLogTokens({\n ...owner,\n threadId: options.threadId,\n });\n if (observationLogTokens < config.reflectionTokenThreshold) {\n return { reflected: false, observationLogTokens };\n }\n\n const observations = await listObservationalMemory({\n ...owner,\n threadId: options.threadId,\n tier: \"observation\",\n });\n if (observations.length === 0) {\n return { reflected: false, observationLogTokens };\n }\n const observationsText = observations.map((entry) => entry.text).join(\"\\n\\n\");\n\n const priorReflections = (\n await listObservationalMemory({\n ...owner,\n threadId: options.threadId,\n tier: \"reflection\",\n })\n )\n .map((entry) => entry.text)\n .join(\"\\n\\n\");\n\n const run = options.runInternal ?? runInternalAgentCall;\n const reflectionText = await run({\n systemPrompt: REFLECTOR_SYSTEM_PROMPT,\n prompt: buildReflectorPrompt({\n threadId: options.threadId,\n observationsText,\n priorReflections,\n }),\n maxOutputTokens: config.reflectionMaxOutputTokens,\n });\n\n if (!reflectionText.trim()) {\n return { reflected: false, observationLogTokens };\n }\n\n const { tokens: tokenEstimate } = await countTextTokens(reflectionText);\n const sourceStart = observations[0]?.sourceStartIndex ?? null;\n const sourceEnd =\n observations[observations.length - 1]?.sourceEndIndex ?? null;\n\n const entry = await insertObservationalMemory({\n ...owner,\n threadId: options.threadId,\n tier: \"reflection\",\n text: reflectionText,\n tokenEstimate,\n sourceStartIndex: sourceStart,\n sourceEndIndex: sourceEnd,\n sourceMessageCount: observations.length,\n });\n\n return { reflected: true, entry, observationLogTokens };\n}\n"]}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observational Memory (OM) entries.
|
|
3
|
+
*
|
|
4
|
+
* A long-running agent thread is compacted in the background into a dated,
|
|
5
|
+
* three-tier context so it costs far fewer tokens and stays prompt-cache
|
|
6
|
+
* stable:
|
|
7
|
+
*
|
|
8
|
+
* recent raw messages → dense "observations" → higher-level "reflections"
|
|
9
|
+
*
|
|
10
|
+
* Each row is ONE compaction artifact for a thread:
|
|
11
|
+
*
|
|
12
|
+
* - `tier = "observation"` — a dense, dated digest of a contiguous range of
|
|
13
|
+
* thread messages (task status, names, dates, decisions preserved). Produced
|
|
14
|
+
* by the Observer once a thread's unobserved messages exceed a token
|
|
15
|
+
* threshold.
|
|
16
|
+
* - `tier = "reflection"` — a higher-level condensation OVER observations,
|
|
17
|
+
* produced by the Reflector once the observation log itself grows past its
|
|
18
|
+
* own threshold.
|
|
19
|
+
*
|
|
20
|
+
* The table is ownable (scoped reads/writes via `accessFilter`/`assertAccess`
|
|
21
|
+
* per the `security` skill) and dialect-agnostic (Drizzle helpers from
|
|
22
|
+
* `db/schema`, never raw SQLite types). The companion migrations live in
|
|
23
|
+
* `./migrations.ts` and are additive-only.
|
|
24
|
+
*/
|
|
25
|
+
export declare const observationalMemory: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
26
|
+
name: "observational_memory";
|
|
27
|
+
schema: undefined;
|
|
28
|
+
columns: {
|
|
29
|
+
ownerEmail: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
30
|
+
name: "owner_email";
|
|
31
|
+
tableName: "observational_memory";
|
|
32
|
+
dataType: "string";
|
|
33
|
+
columnType: "SQLiteText";
|
|
34
|
+
data: string;
|
|
35
|
+
driverParam: string;
|
|
36
|
+
notNull: true;
|
|
37
|
+
hasDefault: true;
|
|
38
|
+
isPrimaryKey: false;
|
|
39
|
+
isAutoincrement: false;
|
|
40
|
+
hasRuntimeDefault: false;
|
|
41
|
+
enumValues: [string, ...string[]];
|
|
42
|
+
baseColumn: never;
|
|
43
|
+
identity: undefined;
|
|
44
|
+
generated: undefined;
|
|
45
|
+
}, {}, {
|
|
46
|
+
length: number | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
orgId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
49
|
+
name: "org_id";
|
|
50
|
+
tableName: "observational_memory";
|
|
51
|
+
dataType: "string";
|
|
52
|
+
columnType: "SQLiteText";
|
|
53
|
+
data: string;
|
|
54
|
+
driverParam: string;
|
|
55
|
+
notNull: false;
|
|
56
|
+
hasDefault: false;
|
|
57
|
+
isPrimaryKey: false;
|
|
58
|
+
isAutoincrement: false;
|
|
59
|
+
hasRuntimeDefault: false;
|
|
60
|
+
enumValues: [string, ...string[]];
|
|
61
|
+
baseColumn: never;
|
|
62
|
+
identity: undefined;
|
|
63
|
+
generated: undefined;
|
|
64
|
+
}, {}, {
|
|
65
|
+
length: number | undefined;
|
|
66
|
+
}>;
|
|
67
|
+
visibility: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
68
|
+
name: "visibility";
|
|
69
|
+
tableName: "observational_memory";
|
|
70
|
+
dataType: "string";
|
|
71
|
+
columnType: "SQLiteText";
|
|
72
|
+
data: "org" | "private" | "public";
|
|
73
|
+
driverParam: string;
|
|
74
|
+
notNull: true;
|
|
75
|
+
hasDefault: true;
|
|
76
|
+
isPrimaryKey: false;
|
|
77
|
+
isAutoincrement: false;
|
|
78
|
+
hasRuntimeDefault: false;
|
|
79
|
+
enumValues: ["private", "org", "public"];
|
|
80
|
+
baseColumn: never;
|
|
81
|
+
identity: undefined;
|
|
82
|
+
generated: undefined;
|
|
83
|
+
}, {}, {
|
|
84
|
+
length: number | undefined;
|
|
85
|
+
}>;
|
|
86
|
+
id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
87
|
+
name: "id";
|
|
88
|
+
tableName: "observational_memory";
|
|
89
|
+
dataType: "string";
|
|
90
|
+
columnType: "SQLiteText";
|
|
91
|
+
data: string;
|
|
92
|
+
driverParam: string;
|
|
93
|
+
notNull: true;
|
|
94
|
+
hasDefault: false;
|
|
95
|
+
isPrimaryKey: true;
|
|
96
|
+
isAutoincrement: false;
|
|
97
|
+
hasRuntimeDefault: false;
|
|
98
|
+
enumValues: [string, ...string[]];
|
|
99
|
+
baseColumn: never;
|
|
100
|
+
identity: undefined;
|
|
101
|
+
generated: undefined;
|
|
102
|
+
}, {}, {
|
|
103
|
+
length: number | undefined;
|
|
104
|
+
}>;
|
|
105
|
+
threadId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
106
|
+
name: "thread_id";
|
|
107
|
+
tableName: "observational_memory";
|
|
108
|
+
dataType: "string";
|
|
109
|
+
columnType: "SQLiteText";
|
|
110
|
+
data: string;
|
|
111
|
+
driverParam: string;
|
|
112
|
+
notNull: true;
|
|
113
|
+
hasDefault: false;
|
|
114
|
+
isPrimaryKey: false;
|
|
115
|
+
isAutoincrement: false;
|
|
116
|
+
hasRuntimeDefault: false;
|
|
117
|
+
enumValues: [string, ...string[]];
|
|
118
|
+
baseColumn: never;
|
|
119
|
+
identity: undefined;
|
|
120
|
+
generated: undefined;
|
|
121
|
+
}, {}, {
|
|
122
|
+
length: number | undefined;
|
|
123
|
+
}>;
|
|
124
|
+
tier: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
125
|
+
name: "tier";
|
|
126
|
+
tableName: "observational_memory";
|
|
127
|
+
dataType: "string";
|
|
128
|
+
columnType: "SQLiteText";
|
|
129
|
+
data: "observation" | "reflection";
|
|
130
|
+
driverParam: string;
|
|
131
|
+
notNull: true;
|
|
132
|
+
hasDefault: false;
|
|
133
|
+
isPrimaryKey: false;
|
|
134
|
+
isAutoincrement: false;
|
|
135
|
+
hasRuntimeDefault: false;
|
|
136
|
+
enumValues: ["observation", "reflection"];
|
|
137
|
+
baseColumn: never;
|
|
138
|
+
identity: undefined;
|
|
139
|
+
generated: undefined;
|
|
140
|
+
}, {}, {
|
|
141
|
+
length: number | undefined;
|
|
142
|
+
}>;
|
|
143
|
+
text: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
144
|
+
name: "text";
|
|
145
|
+
tableName: "observational_memory";
|
|
146
|
+
dataType: "string";
|
|
147
|
+
columnType: "SQLiteText";
|
|
148
|
+
data: string;
|
|
149
|
+
driverParam: string;
|
|
150
|
+
notNull: true;
|
|
151
|
+
hasDefault: false;
|
|
152
|
+
isPrimaryKey: false;
|
|
153
|
+
isAutoincrement: false;
|
|
154
|
+
hasRuntimeDefault: false;
|
|
155
|
+
enumValues: [string, ...string[]];
|
|
156
|
+
baseColumn: never;
|
|
157
|
+
identity: undefined;
|
|
158
|
+
generated: undefined;
|
|
159
|
+
}, {}, {
|
|
160
|
+
length: number | undefined;
|
|
161
|
+
}>;
|
|
162
|
+
tokenEstimate: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
163
|
+
name: "token_estimate";
|
|
164
|
+
tableName: "observational_memory";
|
|
165
|
+
dataType: "number";
|
|
166
|
+
columnType: "SQLiteInteger";
|
|
167
|
+
data: number;
|
|
168
|
+
driverParam: number;
|
|
169
|
+
notNull: true;
|
|
170
|
+
hasDefault: true;
|
|
171
|
+
isPrimaryKey: false;
|
|
172
|
+
isAutoincrement: false;
|
|
173
|
+
hasRuntimeDefault: false;
|
|
174
|
+
enumValues: undefined;
|
|
175
|
+
baseColumn: never;
|
|
176
|
+
identity: undefined;
|
|
177
|
+
generated: undefined;
|
|
178
|
+
}, {}, {}>;
|
|
179
|
+
sourceStartIndex: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
180
|
+
name: "source_start_index";
|
|
181
|
+
tableName: "observational_memory";
|
|
182
|
+
dataType: "number";
|
|
183
|
+
columnType: "SQLiteInteger";
|
|
184
|
+
data: number;
|
|
185
|
+
driverParam: number;
|
|
186
|
+
notNull: false;
|
|
187
|
+
hasDefault: false;
|
|
188
|
+
isPrimaryKey: false;
|
|
189
|
+
isAutoincrement: false;
|
|
190
|
+
hasRuntimeDefault: false;
|
|
191
|
+
enumValues: undefined;
|
|
192
|
+
baseColumn: never;
|
|
193
|
+
identity: undefined;
|
|
194
|
+
generated: undefined;
|
|
195
|
+
}, {}, {}>;
|
|
196
|
+
sourceEndIndex: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
197
|
+
name: "source_end_index";
|
|
198
|
+
tableName: "observational_memory";
|
|
199
|
+
dataType: "number";
|
|
200
|
+
columnType: "SQLiteInteger";
|
|
201
|
+
data: number;
|
|
202
|
+
driverParam: number;
|
|
203
|
+
notNull: false;
|
|
204
|
+
hasDefault: false;
|
|
205
|
+
isPrimaryKey: false;
|
|
206
|
+
isAutoincrement: false;
|
|
207
|
+
hasRuntimeDefault: false;
|
|
208
|
+
enumValues: undefined;
|
|
209
|
+
baseColumn: never;
|
|
210
|
+
identity: undefined;
|
|
211
|
+
generated: undefined;
|
|
212
|
+
}, {}, {}>;
|
|
213
|
+
sourceMessageCount: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
214
|
+
name: "source_message_count";
|
|
215
|
+
tableName: "observational_memory";
|
|
216
|
+
dataType: "number";
|
|
217
|
+
columnType: "SQLiteInteger";
|
|
218
|
+
data: number;
|
|
219
|
+
driverParam: number;
|
|
220
|
+
notNull: true;
|
|
221
|
+
hasDefault: true;
|
|
222
|
+
isPrimaryKey: false;
|
|
223
|
+
isAutoincrement: false;
|
|
224
|
+
hasRuntimeDefault: false;
|
|
225
|
+
enumValues: undefined;
|
|
226
|
+
baseColumn: never;
|
|
227
|
+
identity: undefined;
|
|
228
|
+
generated: undefined;
|
|
229
|
+
}, {}, {}>;
|
|
230
|
+
createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
231
|
+
name: "created_at";
|
|
232
|
+
tableName: "observational_memory";
|
|
233
|
+
dataType: "number";
|
|
234
|
+
columnType: "SQLiteInteger";
|
|
235
|
+
data: number;
|
|
236
|
+
driverParam: number;
|
|
237
|
+
notNull: true;
|
|
238
|
+
hasDefault: false;
|
|
239
|
+
isPrimaryKey: false;
|
|
240
|
+
isAutoincrement: false;
|
|
241
|
+
hasRuntimeDefault: false;
|
|
242
|
+
enumValues: undefined;
|
|
243
|
+
baseColumn: never;
|
|
244
|
+
identity: undefined;
|
|
245
|
+
generated: undefined;
|
|
246
|
+
}, {}, {}>;
|
|
247
|
+
updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
248
|
+
name: "updated_at";
|
|
249
|
+
tableName: "observational_memory";
|
|
250
|
+
dataType: "number";
|
|
251
|
+
columnType: "SQLiteInteger";
|
|
252
|
+
data: number;
|
|
253
|
+
driverParam: number;
|
|
254
|
+
notNull: true;
|
|
255
|
+
hasDefault: false;
|
|
256
|
+
isPrimaryKey: false;
|
|
257
|
+
isAutoincrement: false;
|
|
258
|
+
hasRuntimeDefault: false;
|
|
259
|
+
enumValues: undefined;
|
|
260
|
+
baseColumn: never;
|
|
261
|
+
identity: undefined;
|
|
262
|
+
generated: undefined;
|
|
263
|
+
}, {}, {}>;
|
|
264
|
+
};
|
|
265
|
+
dialect: "sqlite";
|
|
266
|
+
}>;
|
|
267
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/agent/observational-memory/schema.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB9B,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { table, text, integer, ownableColumns } from "../../db/schema.js";
|
|
2
|
+
/**
|
|
3
|
+
* Observational Memory (OM) entries.
|
|
4
|
+
*
|
|
5
|
+
* A long-running agent thread is compacted in the background into a dated,
|
|
6
|
+
* three-tier context so it costs far fewer tokens and stays prompt-cache
|
|
7
|
+
* stable:
|
|
8
|
+
*
|
|
9
|
+
* recent raw messages → dense "observations" → higher-level "reflections"
|
|
10
|
+
*
|
|
11
|
+
* Each row is ONE compaction artifact for a thread:
|
|
12
|
+
*
|
|
13
|
+
* - `tier = "observation"` — a dense, dated digest of a contiguous range of
|
|
14
|
+
* thread messages (task status, names, dates, decisions preserved). Produced
|
|
15
|
+
* by the Observer once a thread's unobserved messages exceed a token
|
|
16
|
+
* threshold.
|
|
17
|
+
* - `tier = "reflection"` — a higher-level condensation OVER observations,
|
|
18
|
+
* produced by the Reflector once the observation log itself grows past its
|
|
19
|
+
* own threshold.
|
|
20
|
+
*
|
|
21
|
+
* The table is ownable (scoped reads/writes via `accessFilter`/`assertAccess`
|
|
22
|
+
* per the `security` skill) and dialect-agnostic (Drizzle helpers from
|
|
23
|
+
* `db/schema`, never raw SQLite types). The companion migrations live in
|
|
24
|
+
* `./migrations.ts` and are additive-only.
|
|
25
|
+
*/
|
|
26
|
+
export const observationalMemory = table("observational_memory", {
|
|
27
|
+
id: text("id").primaryKey(),
|
|
28
|
+
threadId: text("thread_id").notNull(),
|
|
29
|
+
/** Which tier this entry belongs to. */
|
|
30
|
+
tier: text("tier", { enum: ["observation", "reflection"] }).notNull(),
|
|
31
|
+
/** The dated, compacted text content of this entry. */
|
|
32
|
+
text: text("text").notNull(),
|
|
33
|
+
/** Estimated token count of `text` (used for the reflection threshold). */
|
|
34
|
+
tokenEstimate: integer("token_estimate").notNull().default(0),
|
|
35
|
+
/**
|
|
36
|
+
* Inclusive index range of the source thread messages this entry summarizes.
|
|
37
|
+
* For observations these are indices into the flattened thread-message array;
|
|
38
|
+
* for reflections they span the observation indices that were folded.
|
|
39
|
+
*/
|
|
40
|
+
sourceStartIndex: integer("source_start_index"),
|
|
41
|
+
sourceEndIndex: integer("source_end_index"),
|
|
42
|
+
/** How many source messages/observations this entry covers. */
|
|
43
|
+
sourceMessageCount: integer("source_message_count").notNull().default(0),
|
|
44
|
+
createdAt: integer("created_at").notNull(),
|
|
45
|
+
updatedAt: integer("updated_at").notNull(),
|
|
46
|
+
...ownableColumns(),
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/agent/observational-memory/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC,sBAAsB,EAAE;IAC/D,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;IAC3B,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE;IACrC,wCAAwC;IACxC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,aAAa,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE;IACrE,uDAAuD;IACvD,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;IAC5B,2EAA2E;IAC3E,aAAa,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7D;;;;OAIG;IACH,gBAAgB,EAAE,OAAO,CAAC,oBAAoB,CAAC;IAC/C,cAAc,EAAE,OAAO,CAAC,kBAAkB,CAAC;IAC3C,+DAA+D;IAC/D,kBAAkB,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACxE,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAC1C,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAC1C,GAAG,cAAc,EAAE;CACpB,CAAC,CAAC","sourcesContent":["import { table, text, integer, ownableColumns } from \"../../db/schema.js\";\n\n/**\n * Observational Memory (OM) entries.\n *\n * A long-running agent thread is compacted in the background into a dated,\n * three-tier context so it costs far fewer tokens and stays prompt-cache\n * stable:\n *\n * recent raw messages → dense \"observations\" → higher-level \"reflections\"\n *\n * Each row is ONE compaction artifact for a thread:\n *\n * - `tier = \"observation\"` — a dense, dated digest of a contiguous range of\n * thread messages (task status, names, dates, decisions preserved). Produced\n * by the Observer once a thread's unobserved messages exceed a token\n * threshold.\n * - `tier = \"reflection\"` — a higher-level condensation OVER observations,\n * produced by the Reflector once the observation log itself grows past its\n * own threshold.\n *\n * The table is ownable (scoped reads/writes via `accessFilter`/`assertAccess`\n * per the `security` skill) and dialect-agnostic (Drizzle helpers from\n * `db/schema`, never raw SQLite types). The companion migrations live in\n * `./migrations.ts` and are additive-only.\n */\nexport const observationalMemory = table(\"observational_memory\", {\n id: text(\"id\").primaryKey(),\n threadId: text(\"thread_id\").notNull(),\n /** Which tier this entry belongs to. */\n tier: text(\"tier\", { enum: [\"observation\", \"reflection\"] }).notNull(),\n /** The dated, compacted text content of this entry. */\n text: text(\"text\").notNull(),\n /** Estimated token count of `text` (used for the reflection threshold). */\n tokenEstimate: integer(\"token_estimate\").notNull().default(0),\n /**\n * Inclusive index range of the source thread messages this entry summarizes.\n * For observations these are indices into the flattened thread-message array;\n * for reflections they span the observation indices that were folded.\n */\n sourceStartIndex: integer(\"source_start_index\"),\n sourceEndIndex: integer(\"source_end_index\"),\n /** How many source messages/observations this entry covers. */\n sourceMessageCount: integer(\"source_message_count\").notNull().default(0),\n createdAt: integer(\"created_at\").notNull(),\n updatedAt: integer(\"updated_at\").notNull(),\n ...ownableColumns(),\n});\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence for Observational Memory entries.
|
|
3
|
+
*
|
|
4
|
+
* Owner-scoped throughout: every read and write takes an `ownerEmail` and the
|
|
5
|
+
* SQL always filters by it, so the ownable table is never read or written
|
|
6
|
+
* cross-owner (per the `security` skill). Dialect-agnostic — only `getDbExec()`
|
|
7
|
+
* and parameterized SQL, never raw SQLite/Postgres types or string interpolation
|
|
8
|
+
* of user data.
|
|
9
|
+
*
|
|
10
|
+
* `ensureTable()` lazily creates the table on first use (the same belt-and-
|
|
11
|
+
* suspenders pattern as `chat-threads/store.ts`), so OM works in tests and at
|
|
12
|
+
* runtime even before the migration plugin is registered.
|
|
13
|
+
*/
|
|
14
|
+
import type { ObservationalMemoryEntry, ObservationalMemoryOwner, ObservationalMemoryTier } from "./types.js";
|
|
15
|
+
/** Reset the cached ensureTable promise — test-only seam. */
|
|
16
|
+
export declare function __resetObservationalMemoryTableCache(): void;
|
|
17
|
+
export interface InsertObservationalMemoryInput extends ObservationalMemoryOwner {
|
|
18
|
+
threadId: string;
|
|
19
|
+
tier: ObservationalMemoryTier;
|
|
20
|
+
text: string;
|
|
21
|
+
tokenEstimate: number;
|
|
22
|
+
sourceStartIndex?: number | null;
|
|
23
|
+
sourceEndIndex?: number | null;
|
|
24
|
+
sourceMessageCount?: number;
|
|
25
|
+
visibility?: "private" | "org" | "public";
|
|
26
|
+
}
|
|
27
|
+
/** Insert one OM entry, returning the persisted row. */
|
|
28
|
+
export declare function insertObservationalMemory(input: InsertObservationalMemoryInput): Promise<ObservationalMemoryEntry>;
|
|
29
|
+
export interface ListObservationalMemoryOptions extends ObservationalMemoryOwner {
|
|
30
|
+
threadId: string;
|
|
31
|
+
/** When set, only entries of this tier are returned. */
|
|
32
|
+
tier?: ObservationalMemoryTier;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* List a thread's OM entries for an owner, oldest → newest. Always
|
|
36
|
+
* owner-scoped; `org_id` is matched too when supplied so org-visible rows
|
|
37
|
+
* don't leak across orgs.
|
|
38
|
+
*/
|
|
39
|
+
export declare function listObservationalMemory(options: ListObservationalMemoryOptions): Promise<ObservationalMemoryEntry[]>;
|
|
40
|
+
/**
|
|
41
|
+
* The highest source-message index already folded into an observation for this
|
|
42
|
+
* thread/owner, or -1 if none. The Observer uses this to know which messages
|
|
43
|
+
* are still unobserved.
|
|
44
|
+
*/
|
|
45
|
+
export declare function getObservedThroughIndex(options: ObservationalMemoryOwner & {
|
|
46
|
+
threadId: string;
|
|
47
|
+
}): Promise<number>;
|
|
48
|
+
/** Sum the token estimates of a thread's observation entries for an owner. */
|
|
49
|
+
export declare function getObservationLogTokens(options: ObservationalMemoryOwner & {
|
|
50
|
+
threadId: string;
|
|
51
|
+
}): Promise<number>;
|
|
52
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/agent/observational-memory/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EACV,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AA0CpB,6DAA6D;AAC7D,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAqDD,MAAM,WAAW,8BAA+B,SAAQ,wBAAwB;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,uBAAuB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAC;CAC3C;AAED,wDAAwD;AACxD,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,wBAAwB,CAAC,CAyCnC;AAED,MAAM,WAAW,8BAA+B,SAAQ,wBAAwB;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,IAAI,CAAC,EAAE,uBAAuB,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAiBrC;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,wBAAwB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvD,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,8EAA8E;AAC9E,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,wBAAwB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GACvD,OAAO,CAAC,MAAM,CAAC,CAcjB"}
|