agents 0.12.4 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/{agent-tool-types-CM_50fcV.d.ts → agent-tool-types-Dn9n-3SI.d.ts} +234 -85
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-BylX6WXG.d.ts → agent-tools-B1ttU-pq.d.ts} +2 -2
- package/dist/agent-tools-BAdX1vdI.js.map +1 -1
- package/dist/agent-tools.d.ts +1 -1
- package/dist/agent-tools.js.map +1 -1
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-chat-v5-migration.js.map +1 -1
- package/dist/ai-react.js.map +1 -1
- package/dist/ai-types.js.map +1 -1
- package/dist/browser/ai.js +1 -1
- package/dist/browser/ai.js.map +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/tanstack-ai.js +1 -1
- package/dist/browser/tanstack-ai.js.map +1 -1
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat/index.js.map +1 -1
- package/dist/{classPrivateFieldGet2-CS51BNGR.js → classPrivateFieldGet2-Evpt0SEr.js} +5 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/client-D1kFXo80.js.map +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js.map +1 -1
- package/dist/codemode/ai.js.map +1 -1
- package/dist/{compaction-helpers-bYvP1o2S.d.ts → compaction-helpers-DAe-xiVY.d.ts} +33 -15
- package/dist/compaction-helpers-DvcZnvQ1.js.map +1 -1
- package/dist/email.d.ts +1 -1
- package/dist/email.js.map +1 -1
- package/dist/experimental/memory/session/index.d.ts +247 -34
- package/dist/experimental/memory/session/index.js +540 -135
- package/dist/experimental/memory/session/index.js.map +1 -1
- package/dist/experimental/memory/utils/index.d.ts +1 -1
- package/dist/experimental/memory/utils/index.js.map +1 -1
- package/dist/experimental/webmcp.js.map +1 -1
- package/dist/index.d.ts +71 -57
- package/dist/index.js +583 -45
- package/dist/index.js.map +1 -1
- package/dist/internal_context.js.map +1 -1
- package/dist/mcp/client.d.ts +12 -12
- package/dist/mcp/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/index.d.ts +40 -40
- package/dist/mcp/index.js +21 -45
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/x402.js.map +1 -1
- package/dist/observability/index.js.map +1 -1
- package/dist/react.d.ts +3 -3
- package/dist/react.js.map +1 -1
- package/dist/retries.js.map +1 -1
- package/dist/schedule.js.map +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/{shared-DzJYHisH.js → shared-CiKaIK4h.js} +4 -5
- package/dist/{shared-DzJYHisH.js.map → shared-CiKaIK4h.js.map} +1 -1
- package/dist/sub-routing.d.ts +6 -6
- package/dist/sub-routing.js.map +1 -1
- package/dist/tool-output-truncation-CH-khbZ3.js.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.js.map +1 -1
- package/dist/vite.js.map +1 -1
- package/dist/workflow-types.js.map +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/experimental/memory/session/search.ts","../../../../src/experimental/memory/session/skills.ts","../../../../src/experimental/memory/session/context.ts","../../../../src/experimental/memory/session/providers/agent.ts","../../../../src/experimental/memory/session/providers/agent-context.ts","../../../../src/experimental/memory/session/session.ts","../../../../src/experimental/memory/session/manager.ts"],"sourcesContent":["/**\n * Search Provider — full-text searchable context blocks.\n *\n * Extends ContextProvider with `search()` for querying indexed content\n * and a keyed `set()` for indexing individual entries.\n *\n * Duck-typed: if a provider has a `search` method, it's a SearchProvider.\n */\n\nimport type { ContextProvider } from \"./context\";\nimport type { SqlProvider } from \"./providers/agent\";\n\n/**\n * Storage interface for searchable context.\n *\n * - `get()` returns a summary of indexed content (rendered into system prompt)\n * - `search(query)` full-text search (via search_context tool)\n * - `set(key, content)` indexes content under a key (via set_context tool)\n */\nexport interface SearchProvider extends ContextProvider {\n search(query: string): Promise<string | null>;\n set?(key: string, content: string): Promise<void>;\n}\n\n/**\n * Check if a provider is a SearchProvider (has a `search` method).\n */\nexport function isSearchProvider(\n provider: unknown\n): provider is SearchProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"search\" in provider &&\n typeof (provider as SearchProvider).search === \"function\"\n );\n}\n\n// ── Agent Search Provider (DO SQLite FTS5) ─────────────────────────\n\n/**\n * SearchProvider backed by Durable Object SQLite with FTS5.\n *\n * - `get()` returns a count of indexed entries\n * - `search(query)` full-text search using FTS5\n * - `set(key, content)` indexes or replaces content under a key\n *\n * Each instance uses a namespaced FTS5 table to avoid collisions\n * with the session message search.\n *\n * @example\n * ```ts\n * Session.create(this)\n * .withContext(\"knowledge\", {\n * provider: new AgentSearchProvider(this)\n * })\n * ```\n */\nexport class AgentSearchProvider implements SearchProvider {\n private agent: SqlProvider;\n private label = \"\";\n private initialized = false;\n\n constructor(agent: SqlProvider) {\n this.agent = agent;\n }\n\n init(label: string): void {\n this.label = label;\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_search_entries (\n label TEXT NOT NULL,\n key TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (label, key)\n )\n `;\n this.agent.sql`\n CREATE VIRTUAL TABLE IF NOT EXISTS cf_agents_search_fts\n USING fts5(\n label UNINDEXED,\n key UNINDEXED,\n content,\n tokenize='porter unicode61'\n )\n `;\n this.initialized = true;\n }\n\n async get(): Promise<string | null> {\n this.ensureTable();\n const rows = this.agent.sql<{ count: number }>`\n SELECT COUNT(*) as count FROM cf_agents_search_entries\n WHERE label = ${this.label}\n `;\n const count = rows[0]?.count ?? 0;\n if (count === 0) return null;\n\n const keys = this.agent.sql<{ key: string }>`\n SELECT key FROM cf_agents_search_entries\n WHERE label = ${this.label}\n ORDER BY updated_at DESC\n LIMIT 20\n `;\n const listing = keys.map((r) => `- ${r.key}`).join(\"\\n\");\n return `${count} entries indexed. Recent:\\n${listing}`;\n }\n\n async search(query: string): Promise<string | null> {\n this.ensureTable();\n // Quote each word individually to prevent FTS5 syntax injection\n // while preserving implicit AND between terms\n const sanitized = query\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => `\"${w.replace(/\"/g, '\"\"')}\"`)\n .join(\" \");\n if (!sanitized) return null;\n try {\n const rows = this.agent.sql<{\n key: string;\n content: string;\n }>`\n SELECT f.key, f.content\n FROM cf_agents_search_fts f\n WHERE cf_agents_search_fts MATCH ${sanitized}\n AND f.label = ${this.label}\n ORDER BY rank\n LIMIT 10\n `;\n if (rows.length === 0) return null;\n return rows.map((r) => `[${r.key}]\\n${r.content}`).join(\"\\n\\n\");\n } catch {\n // Malformed FTS query\n return null;\n }\n }\n\n async set(key: string, content: string): Promise<void> {\n this.ensureTable();\n\n // Delete old FTS entry if exists\n this.deleteFTS(key);\n\n // Upsert the entry\n this.agent.sql`\n INSERT INTO cf_agents_search_entries (label, key, content)\n VALUES (${this.label}, ${key}, ${content})\n ON CONFLICT(label, key) DO UPDATE SET\n content = ${content},\n updated_at = CURRENT_TIMESTAMP\n `;\n\n // Index in FTS\n this.agent.sql`\n INSERT INTO cf_agents_search_fts (label, key, content)\n VALUES (${this.label}, ${key}, ${content})\n `;\n }\n\n private deleteFTS(key: string): void {\n const rows = this.agent.sql<{ rowid: number }>`\n SELECT rowid FROM cf_agents_search_fts\n WHERE key = ${key} AND label = ${this.label}\n `;\n for (const row of rows) {\n this.agent\n .sql`DELETE FROM cf_agents_search_fts WHERE rowid = ${row.rowid}`;\n }\n }\n}\n","/**\n * Skill Provider — on-demand keyed document collections.\n *\n * Extends ContextProvider with `load()` for on-demand content fetching\n * and a keyed `set()` for writing individual entries.\n *\n * Duck-typed: if a provider has a `load` method, it's a SkillProvider.\n */\n\nimport type { ContextProvider } from \"./context\";\n\n/**\n * Storage interface for skill collections.\n *\n * - `get()` returns metadata listing (rendered into system prompt)\n * - `load(key)` fetches full content (via load_context tool)\n * - `set(key, content, description?)` writes an entry (via set_context tool)\n */\nexport interface SkillProvider extends ContextProvider {\n load(key: string): Promise<string | null>;\n set?(key: string, content: string, description?: string): Promise<void>;\n}\n\n/**\n * Check if a provider is a SkillProvider (has a `load` method).\n */\nexport function isSkillProvider(provider: unknown): provider is SkillProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"load\" in provider &&\n typeof (provider as SkillProvider).load === \"function\"\n );\n}\n\n// ── R2 Skill Provider ──────────────────────────────────────────────\n\n/**\n * SkillProvider backed by an R2 bucket.\n *\n * - `get()` returns a metadata listing of all skills (key + description)\n * - `load(key)` fetches a skill's full content\n * - `set(key, content, description?)` writes a skill\n *\n * Descriptions are pulled from R2 custom metadata (`description` key).\n * If a prefix is provided, it is prepended on storage operations and\n * stripped from keys in metadata. `keys`, when provided, is matched against\n * these prefix-relative keys.\n *\n * @example\n * ```ts\n * const skills = new R2SkillProvider(env.SKILLS_BUCKET, {\n * prefix: \"skills/\",\n * keys: [\"code-review\", \"debugging\"]\n * });\n * ```\n */\nexport class R2SkillProvider implements SkillProvider {\n private bucket: R2Bucket;\n private prefix: string;\n private keys: Set<string> | null;\n\n constructor(\n bucket: R2Bucket,\n options?: { prefix?: string; keys?: string[] }\n ) {\n this.bucket = bucket;\n this.prefix = options?.prefix ?? \"\";\n this.keys = options?.keys?.length ? new Set(options.keys) : null;\n }\n\n async get(): Promise<string | null> {\n const entries: string[] = [];\n let cursor: string | undefined;\n let truncated = true;\n while (truncated) {\n const listed = await this.bucket.list({\n prefix: this.prefix,\n cursor,\n include: [\"customMetadata\"]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n for (const obj of listed.objects) {\n const key = obj.key.slice(this.prefix.length);\n if (!this.allowsKey(key)) continue;\n const desc = obj.customMetadata?.description;\n entries.push(`- ${key}${desc ? `: ${desc}` : \"\"}`);\n }\n truncated = listed.truncated;\n cursor = listed.truncated ? listed.cursor : undefined;\n }\n return entries.length > 0 ? entries.join(\"\\n\") : null;\n }\n\n async load(key: string): Promise<string | null> {\n if (!this.allowsKey(key)) return null;\n const obj = await this.bucket.get(this.prefix + key);\n if (!obj) return null;\n return obj.text();\n }\n\n async set(key: string, content: string, description?: string): Promise<void> {\n await this.bucket.put(this.prefix + key, content, {\n customMetadata: description ? { description } : undefined\n });\n }\n\n private allowsKey(key: string): boolean {\n return this.keys === null || this.keys.has(key);\n }\n}\n","/**\n * Context Block Management\n *\n * Persistent key-value blocks (MEMORY, USER, SOUL, etc.) that are:\n * - Loaded from their providers at init\n * - Frozen into a snapshot when toSystemPrompt() is called\n * - Updated via setBlock() which writes to the provider immediately\n * but does NOT update the frozen snapshot (preserves LLM prefix cache)\n * - Re-snapshotted on next toSystemPrompt() call\n *\n * Provider type determines behavior:\n * - ContextProvider (get only) → readonly block in system prompt\n * - WritableContextProvider (get+set) → writable via set_context tool\n * - SkillProvider (get+load+set?) → metadata in prompt, load_context tool\n * - SearchProvider (get+search+set?) → searchable via search_context tool\n */\n\nimport type { ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport { estimateStringTokens } from \"../utils/tokens\";\nimport { isSearchProvider, type SearchProvider } from \"./search\";\nimport { isSkillProvider, type SkillProvider } from \"./skills\";\n\n/**\n * Base storage interface for a context block.\n * A provider with only `get()` is readonly.\n */\nexport interface ContextProvider {\n get(): Promise<string | null>;\n /** Called by the context system to provide the block label before first use. */\n init?(label: string): void;\n}\n\n/**\n * Writable context provider — extends ContextProvider with `set()`.\n * Blocks backed by this provider are writable via the `set_context` tool.\n */\nexport interface WritableContextProvider extends ContextProvider {\n set(content: string): Promise<void>;\n}\n\n/**\n * Check if a provider is writable (has a `set` method).\n */\nexport function isWritableProvider(\n provider: unknown\n): provider is WritableContextProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"set\" in provider &&\n typeof (provider as WritableContextProvider).set === \"function\"\n );\n}\n\n/**\n * Configuration for a context block.\n */\nexport interface ContextConfig {\n /** Block label — used as key and in tool descriptions */\n label: string;\n /** Human-readable description (shown to AI in tool) */\n description?: string;\n /** Maximum tokens allowed. Enforced on set. */\n maxTokens?: number;\n /** Storage provider. Determines block behavior:\n * - ContextProvider (get only) → readonly\n * - WritableContextProvider (get+set) → writable via set_context\n * - SkillProvider (get+load+set?) → on-demand via load_context\n * - SearchProvider (get+search+set?) → searchable via search_context\n * If omitted, auto-wired to writable SQLite when using builder. */\n provider?:\n | ContextProvider\n | WritableContextProvider\n | SkillProvider\n | SearchProvider;\n}\n\n/**\n * A loaded context block with computed token count.\n */\nexport interface ContextBlock {\n label: string;\n description?: string;\n content: string;\n tokens: number;\n maxTokens?: number;\n /** True if provider is writable (has set) */\n writable: boolean;\n /** True if backed by a SkillProvider */\n isSkill: boolean;\n /** True if backed by a SearchProvider */\n isSearchable: boolean;\n}\n\n/**\n * Callback for when a skill is unloaded — allows Session to update\n * the stored message without ContextBlocks knowing about storage.\n */\nexport type SkillUnloadCallback = (label: string, key: string) => void;\n\n/**\n * Manages context blocks with frozen snapshot support.\n */\nexport class ContextBlocks {\n private configs: ContextConfig[];\n private blocks = new Map<string, ContextBlock>();\n private snapshot: string | null = null;\n private loaded = false;\n private promptStore: WritableContextProvider | null;\n private _loadedSkills = new Set<string>();\n private _onUnloadSkill: SkillUnloadCallback | null = null;\n\n constructor(configs: ContextConfig[], promptStore?: WritableContextProvider) {\n this.configs = configs;\n this.promptStore = promptStore ?? null;\n }\n\n /**\n * Register a callback invoked when a skill is unloaded.\n * Session uses this to update the stored tool result message.\n */\n setUnloadCallback(cb: SkillUnloadCallback): void {\n this._onUnloadSkill = cb;\n }\n\n isLoaded(): boolean {\n return this.loaded;\n }\n\n /**\n * Load all blocks from their providers.\n * Called once at session init.\n */\n async load(): Promise<void> {\n for (const config of this.configs) {\n // Pass the label to the provider before first use\n if (config.provider?.init) {\n config.provider.init(config.label);\n }\n\n const content = config.provider\n ? ((await config.provider.get()) ?? \"\")\n : \"\";\n\n const skill = config.provider ? isSkillProvider(config.provider) : false;\n const searchable = config.provider\n ? isSearchProvider(config.provider)\n : false;\n const writable = config.provider\n ? isWritableProvider(config.provider) ||\n (skill && !!(config.provider as SkillProvider).set) ||\n (searchable && !!(config.provider as SearchProvider).set)\n : false;\n\n this.blocks.set(config.label, {\n label: config.label,\n description: config.description,\n content,\n tokens: estimateStringTokens(content),\n maxTokens: config.maxTokens,\n writable,\n isSkill: skill,\n isSearchable: searchable\n });\n }\n this.loaded = true;\n }\n\n /**\n * Dynamically register a new context block after initialization.\n * Used by extensions to contribute context at runtime.\n *\n * If blocks have already been loaded, the new block's provider is\n * initialized and loaded immediately. The snapshot is NOT updated\n * automatically — call `refreshSystemPrompt()` to rebuild.\n */\n async addBlock(config: ContextConfig): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n\n if (this.configs.some((c) => c.label === config.label)) {\n throw new Error(`Block \"${config.label}\" already exists`);\n }\n\n this.configs.push(config);\n\n if (config.provider?.init) {\n config.provider.init(config.label);\n }\n\n const content = config.provider\n ? ((await config.provider.get()) ?? \"\")\n : \"\";\n\n const skill = config.provider ? isSkillProvider(config.provider) : false;\n const searchable = config.provider\n ? isSearchProvider(config.provider)\n : false;\n const writable = config.provider\n ? isWritableProvider(config.provider) ||\n (skill && !!(config.provider as SkillProvider).set) ||\n (searchable && !!(config.provider as SearchProvider).set)\n : false;\n\n const block: ContextBlock = {\n label: config.label,\n description: config.description,\n content,\n tokens: estimateStringTokens(content),\n maxTokens: config.maxTokens,\n writable,\n isSkill: skill,\n isSearchable: searchable\n };\n\n this.blocks.set(config.label, block);\n return block;\n }\n\n /**\n * Remove a dynamically registered context block.\n * Used during extension unload cleanup.\n *\n * Returns true if the block existed and was removed.\n * The snapshot is NOT updated automatically — call\n * `refreshSystemPrompt()` to rebuild.\n *\n * Note: loaded skills for this block are cleaned up from the\n * tracking set but the skill unload callback is NOT fired\n * (history reclamation is skipped — appropriate for full\n * extension removal).\n */\n removeBlock(label: string): boolean {\n const idx = this.configs.findIndex((c) => c.label === label);\n if (idx === -1) return false;\n\n this.configs.splice(idx, 1);\n this.blocks.delete(label);\n\n for (const id of this._loadedSkills) {\n if (id.startsWith(`${label}:`)) {\n this._loadedSkills.delete(id);\n }\n }\n\n return true;\n }\n\n /**\n * Get a block by label.\n */\n getBlock(label: string): ContextBlock | null {\n return this.blocks.get(label) ?? null;\n }\n\n /**\n * Get all blocks.\n */\n getBlocks(): ContextBlock[] {\n return Array.from(this.blocks.values());\n }\n\n /**\n * Set block content. Writes to provider immediately.\n * Does NOT update the frozen snapshot.\n */\n async setBlock(label: string, content: string): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.writable) {\n throw new Error(`Block \"${label}\" is readonly`);\n }\n\n if (existing.isSkill || existing.isSearchable) {\n throw new Error(\n `Block \"${label}\" is a keyed provider. Use setSkill() or setSearchEntry() instead.`\n );\n }\n\n const tokens = estimateStringTokens(content);\n const maxTokens = config?.maxTokens ?? existing?.maxTokens;\n\n if (maxTokens !== undefined && tokens > maxTokens) {\n throw new Error(\n `Block \"${label}\" exceeds maxTokens: ${tokens} > ${maxTokens}`\n );\n }\n\n const block: ContextBlock = {\n label,\n description: config?.description ?? existing?.description,\n content,\n tokens,\n maxTokens,\n writable: true,\n isSkill: false,\n isSearchable: false\n };\n\n this.blocks.set(label, block);\n\n // Write to provider immediately (durable)\n if (config?.provider && isWritableProvider(config.provider)) {\n await config.provider.set(content);\n }\n\n return block;\n }\n\n /**\n * Set a skill entry within a skill block.\n */\n async setSkill(\n label: string,\n key: string,\n content: string,\n description?: string\n ): Promise<void> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.isSkill) {\n throw new Error(`Block \"${label}\" is not a skill provider`);\n }\n\n const provider = config?.provider;\n if (!provider || !isSkillProvider(provider) || !provider.set) {\n throw new Error(`Block \"${label}\" does not support writes`);\n }\n\n await provider.set(key, content, description);\n\n // Refresh metadata\n const metadata = await provider.get();\n if (metadata) {\n existing.content = metadata;\n existing.tokens = estimateStringTokens(metadata);\n }\n }\n\n /**\n * Load a skill's full content from a skill block.\n */\n async loadSkill(label: string, key: string): Promise<string | null> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n\n if (!config?.provider || !isSkillProvider(config.provider)) {\n throw new Error(`Block \"${label}\" is not a skill provider`);\n }\n\n const content = await config.provider.load(key);\n if (content !== null) {\n this._loadedSkills.add(`${label}:${key}`);\n }\n return content;\n }\n\n /**\n * Unload a previously loaded skill. Updates the stored tool result\n * message via the unload callback (set by Session).\n */\n unloadSkill(label: string, key: string): boolean {\n const id = `${label}:${key}`;\n if (!this._loadedSkills.has(id)) return false;\n this._loadedSkills.delete(id);\n this._onUnloadSkill?.(label, key);\n return true;\n }\n\n /**\n * Get the set of currently loaded skill keys (as \"label:key\" strings).\n */\n getLoadedSkillKeys(): Set<string> {\n return this._loadedSkills;\n }\n\n /**\n * Restore loaded skill tracking from a set of \"label:key\" strings.\n * Used by Session to reconstruct state after hibernation.\n */\n restoreLoadedSkills(skillIds: Iterable<string>): void {\n this._loadedSkills = new Set(skillIds);\n }\n\n /**\n * Clear all loaded skill tracking. Called when messages are cleared.\n */\n clearSkillState(): void {\n this._loadedSkills.clear();\n }\n\n /**\n * Index a search entry within a searchable block.\n */\n async setSearchEntry(\n label: string,\n key: string,\n content: string\n ): Promise<void> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.isSearchable) {\n throw new Error(`Block \"${label}\" is not a search provider`);\n }\n\n const provider = config?.provider;\n if (!provider || !isSearchProvider(provider) || !provider.set) {\n throw new Error(`Block \"${label}\" does not support writes`);\n }\n\n await provider.set(key, content);\n\n // Refresh summary\n const summary = await provider.get();\n existing.content = summary ?? \"\";\n existing.tokens = estimateStringTokens(existing.content);\n }\n\n /**\n * Search a searchable block.\n */\n async searchContext(label: string, query: string): Promise<string | null> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n\n if (!config?.provider || !isSearchProvider(config.provider)) {\n throw new Error(`Block \"${label}\" is not a search provider`);\n }\n\n return config.provider.search(query);\n }\n\n /**\n * Append content to a block.\n */\n async appendToBlock(label: string, content: string): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n const existing = this.blocks.get(label);\n if (!existing) {\n throw new Error(`Block \"${label}\" not found`);\n }\n return this.setBlock(label, existing.content + content);\n }\n\n /**\n * Get the system prompt string with context blocks.\n *\n * Returns a frozen snapshot: first call renders and caches,\n * subsequent calls return the same string (preserves LLM prefix cache).\n * Call refreshSnapshot() to re-render after block changes take effect.\n */\n toSystemPrompt(): string {\n if (!this.loaded) {\n throw new Error(\"Context blocks not loaded. Call load() first.\");\n }\n\n if (this.snapshot !== null) {\n return this.snapshot;\n }\n\n return this.captureSnapshot();\n }\n\n /**\n * Force re-render the snapshot from current block state.\n */\n refreshSnapshot(): string {\n return this.captureSnapshot();\n }\n\n private captureSnapshot(): string {\n const parts: string[] = [];\n const sep = \"═\".repeat(46);\n\n for (const block of this.blocks.values()) {\n // Searchable blocks render even when empty so the model knows they exist\n if (!block.content && !block.isSearchable) continue;\n\n let header = block.label.toUpperCase();\n const hints: string[] = [];\n if (block.description) hints.push(block.description);\n if (block.isSkill) hints.push(\"use load_context to load\");\n if (block.isSearchable) hints.push(\"use search_context to search\");\n if (hints.length > 0) header += ` (${hints.join(\" — \")})`;\n if (block.maxTokens) {\n const pct = Math.round((block.tokens / block.maxTokens) * 100);\n header += ` [${pct}% — ${block.tokens}/${block.maxTokens} tokens]`;\n }\n if (!block.writable) header += \" [readonly]\";\n\n parts.push(`${sep}\\n${header}\\n${sep}\\n${block.content}`);\n }\n\n this.snapshot = parts.join(\"\\n\\n\");\n return this.snapshot;\n }\n\n /**\n * Get writable blocks (for tool description).\n */\n getWritableBlocks(): ContextBlock[] {\n return Array.from(this.blocks.values()).filter((b) => b.writable);\n }\n\n /**\n * Check if any skill providers are registered.\n */\n hasSkillBlocks(): boolean {\n return Array.from(this.blocks.values()).some((b) => b.isSkill);\n }\n\n /**\n * Get skill block labels.\n */\n getSkillLabels(): string[] {\n return Array.from(this.blocks.values())\n .filter((b) => b.isSkill)\n .map((b) => b.label);\n }\n\n /**\n * Check if any search providers are registered.\n */\n hasSearchBlocks(): boolean {\n return Array.from(this.blocks.values()).some((b) => b.isSearchable);\n }\n\n /**\n * Get searchable block labels.\n */\n getSearchLabels(): string[] {\n return Array.from(this.blocks.values())\n .filter((b) => b.isSearchable)\n .map((b) => b.label);\n }\n\n // ── Public API ──────────────────────────────────────────────────\n\n /**\n * Frozen system prompt. On first call:\n * 1. Checks store for a persisted prompt (survives DO eviction)\n * 2. If none, loads blocks from providers, renders, and persists\n */\n async freezeSystemPrompt(): Promise<string> {\n if (this.promptStore) {\n const stored = await this.promptStore.get();\n if (stored !== null) return stored;\n }\n\n if (!this.loaded) await this.load();\n const prompt = this.toSystemPrompt();\n\n if (this.promptStore) {\n await this.promptStore.set(prompt);\n }\n\n return prompt;\n }\n\n /**\n * Re-render the system prompt from current block state and persist.\n */\n async refreshSystemPrompt(): Promise<string> {\n if (!this.loaded) await this.load();\n const prompt = this.refreshSnapshot();\n\n if (this.promptStore) {\n await this.promptStore.set(prompt);\n }\n\n return prompt;\n }\n\n /**\n * AI tools for context blocks.\n *\n * Auto-wired based on provider capabilities:\n * - `set_context` — when any block is writable\n * - `load_context` — when any block is a skill provider\n * - `search_context` — when any block is a search provider\n */\n async tools(): Promise<ToolSet> {\n if (!this.loaded) await this.load();\n\n const writable = this.getWritableBlocks();\n const hasSkills = this.hasSkillBlocks();\n const hasSearch = this.hasSearchBlocks();\n const toolSet: ToolSet = {};\n\n // ── set_context ──────────────────────────────────────────────\n\n if (writable.length > 0) {\n const regularBlocks = writable.filter(\n (b) => !b.isSkill && !b.isSearchable\n );\n const keyedBlocks = writable.filter((b) => b.isSkill || b.isSearchable);\n\n const blockDescriptions: string[] = [];\n for (const b of regularBlocks) {\n blockDescriptions.push(\n `- \"${b.label}\": ${b.description ?? \"no description\"}`\n );\n }\n for (const b of keyedBlocks) {\n const kind = b.isSkill\n ? \"skill collection (requires key and optional description)\"\n : \"searchable (requires key)\";\n blockDescriptions.push(`- \"${b.label}\": ${kind}`);\n }\n\n const properties: Record<string, unknown> = {\n label: {\n type: \"string\" as const,\n enum: writable.map((b) => b.label),\n description: \"Block label to write to\"\n },\n content: {\n type: \"string\" as const,\n description: \"Content to write\"\n },\n action: {\n type: \"string\" as const,\n enum: [\"replace\", \"append\"],\n description: \"replace (default) or append\"\n }\n };\n\n const required = [\"label\", \"content\"];\n\n if (keyedBlocks.length > 0) {\n properties.key = {\n type: \"string\" as const,\n description:\n \"Entry key (required for keyed blocks: \" +\n keyedBlocks.map((b) => `\"${b.label}\"`).join(\", \") +\n \")\"\n };\n }\n\n if (keyedBlocks.some((b) => b.isSkill)) {\n properties.description = {\n type: \"string\" as const,\n description: \"Short description for the skill entry\"\n };\n }\n\n toolSet.set_context = {\n description: `Write to a context block. Available blocks:\\n${blockDescriptions.join(\"\\n\")}\\n\\nWrites are durable and persist across sessions.`,\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: properties as Record<string, Record<string, unknown>>,\n required\n }),\n execute: async ({\n label,\n content,\n key,\n description,\n action\n }: {\n label: string;\n content: string;\n key?: string;\n description?: string;\n action?: string;\n }) => {\n try {\n const block = this.blocks.get(label);\n if (!block) return `Error: block \"${label}\" not found`;\n\n if (block.isSkill) {\n if (!key)\n return `Error: key is required for skill block \"${label}\"`;\n await this.setSkill(label, key, content, description);\n return `Written skill \"${key}\" to ${label}.`;\n }\n\n if (block.isSearchable) {\n if (!key)\n return `Error: key is required for searchable block \"${label}\"`;\n await this.setSearchEntry(label, key, content);\n return `Indexed \"${key}\" in ${label}.`;\n }\n\n const updated =\n action === \"append\"\n ? await this.appendToBlock(label, content)\n : await this.setBlock(label, content);\n const usage = updated.maxTokens\n ? `${Math.round((updated.tokens / updated.maxTokens) * 100)}% (${updated.tokens}/${updated.maxTokens} tokens)`\n : `${updated.tokens} tokens`;\n return `Written to ${label}. Usage: ${usage}`;\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n }\n\n // ── load_context ─────────────────────────────────────────────\n\n if (hasSkills) {\n const skillLabels = this.getSkillLabels();\n\n toolSet.load_context = {\n description:\n \"Load a document from a skill block by key. \" +\n \"Available skill blocks: \" +\n skillLabels.map((l) => `\"${l}\"`).join(\", \") +\n \". Check the system prompt for available keys.\",\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n label: {\n type: \"string\" as const,\n enum: skillLabels,\n description: \"Skill block label\"\n },\n key: {\n type: \"string\" as const,\n description: \"Skill key to load\"\n }\n },\n required: [\"label\", \"key\"]\n }),\n execute: async ({ label, key }: { label: string; key: string }) => {\n try {\n const content = await this.loadSkill(label, key);\n return content ?? `Not found: ${key}`;\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n\n const loadedList = [...this._loadedSkills];\n toolSet.unload_context = {\n description:\n \"Unload a previously loaded skill to free context space. \" +\n \"The skill remains available for re-loading.\" +\n (loadedList.length > 0\n ? \" Currently loaded: \" + loadedList.join(\", \") + \".\"\n : \" No skills currently loaded.\"),\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n label: {\n type: \"string\" as const,\n enum: skillLabels,\n description: \"Skill block label\"\n },\n key: {\n type: \"string\" as const,\n description: \"Skill key to unload\"\n }\n },\n required: [\"label\", \"key\"]\n }),\n execute: async ({ label, key }: { label: string; key: string }) => {\n const unloaded = this.unloadSkill(label, key);\n if (!unloaded) {\n return `Skill \"${key}\" is not currently loaded in \"${label}\".`;\n }\n return `Unloaded \"${key}\" from ${label}. Context reclaimed.`;\n }\n };\n }\n\n // ── search_context ────────────────────────────────────────────\n\n if (hasSearch) {\n const searchLabels = this.getSearchLabels();\n\n toolSet.search_context = {\n description:\n \"Search for information in a searchable context block. \" +\n \"Available searchable blocks: \" +\n searchLabels.map((l) => `\"${l}\"`).join(\", \") +\n \".\",\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n label: {\n type: \"string\" as const,\n enum: searchLabels,\n description: \"Searchable block label\"\n },\n query: {\n type: \"string\" as const,\n description: \"Search query\"\n }\n },\n required: [\"label\", \"query\"]\n }),\n execute: async ({ label, query }: { label: string; query: string }) => {\n try {\n const results = await this.searchContext(label, query);\n return results ?? \"No results found.\";\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n }\n\n return toolSet;\n }\n}\n","/**\n * Agent Session Provider\n *\n * SQLite-backed provider with tree-structured messages (branching),\n * compaction overlays, and FTS5 search.\n */\n\nimport type { SessionMessage } from \"../types\";\nimport type {\n SessionProvider,\n SearchResult,\n StoredCompaction\n} from \"../provider\";\nimport { COMPACTION_PREFIX } from \"../../utils/compaction-helpers\";\n\nexport interface SqlProvider {\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ): T[];\n}\n\nexport class AgentSessionProvider implements SessionProvider {\n private agent: SqlProvider;\n private initialized = false;\n private sessionId: string;\n\n /**\n * @param agent - Agent or any object with a `sql` tagged template method\n * @param sessionId - Optional session ID to isolate multiple sessions in the same DO.\n * Messages are filtered by session_id within shared tables.\n */\n constructor(agent: SqlProvider, sessionId?: string) {\n this.agent = agent;\n this.sessionId = sessionId ?? \"\";\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL DEFAULT '',\n parent_id TEXT,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n this.agent.sql`\n CREATE INDEX IF NOT EXISTS idx_assistant_msg_parent\n ON assistant_messages(parent_id)\n `;\n\n this.agent.sql`\n CREATE INDEX IF NOT EXISTS idx_assistant_msg_session\n ON assistant_messages(session_id)\n `;\n\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_compactions (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL DEFAULT '',\n summary TEXT NOT NULL,\n from_message_id TEXT NOT NULL,\n to_message_id TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n this.agent.sql`\n CREATE VIRTUAL TABLE IF NOT EXISTS assistant_fts\n USING fts5(id UNINDEXED, session_id UNINDEXED, role UNINDEXED, content, tokenize='porter unicode61')\n `;\n\n // Reserved for SessionManager metadata (PR #1167) and Think integration (PR #1169)\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_config (\n session_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n PRIMARY KEY (session_id, key)\n )\n `;\n\n this.initialized = true;\n }\n\n // ── Read ───────────────────────────────────────────────────────\n\n getMessage(id: string): SessionMessage | null {\n this.ensureTable();\n const rows = this.agent.sql<{ content: string }>`\n SELECT content FROM assistant_messages WHERE id = ${id} AND session_id = ${this.sessionId}\n `;\n return rows.length > 0 ? this.parse(rows[0].content) : null;\n }\n\n getHistory(leafId?: string | null): SessionMessage[] {\n this.ensureTable();\n\n const leaf = leafId\n ? this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${leafId} AND session_id = ${this.sessionId}\n `[0]\n : this.latestLeafRow();\n\n if (!leaf) return [];\n\n const path = this.agent.sql<{ content: string }>`\n WITH RECURSIVE path AS (\n SELECT *, 0 as depth FROM assistant_messages WHERE id = ${leaf.id}\n UNION ALL\n SELECT m.*, p.depth + 1 FROM assistant_messages m\n JOIN path p ON m.id = p.parent_id\n WHERE m.session_id = ${this.sessionId} AND p.depth < 10000\n )\n SELECT content FROM path ORDER BY depth DESC\n `;\n\n const messages = this.parseRows(path);\n const compactions = this.getCompactions();\n if (compactions.length === 0) return messages;\n return this.applyCompactions(messages, compactions);\n }\n\n getLatestLeaf(): SessionMessage | null {\n this.ensureTable();\n const row = this.latestLeafRow();\n return row ? this.parse(row.content) : null;\n }\n\n getBranches(messageId: string): SessionMessage[] {\n this.ensureTable();\n const rows = this.agent.sql<{ content: string }>`\n SELECT content FROM assistant_messages\n WHERE parent_id = ${messageId} AND session_id = ${this.sessionId} ORDER BY created_at ASC\n `;\n return this.parseRows(rows);\n }\n\n getPathLength(leafId?: string | null): number {\n this.ensureTable();\n const leaf = leafId\n ? this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${leafId} AND session_id = ${this.sessionId}\n `[0]\n : this.latestLeafRow();\n if (!leaf) return 0;\n\n const rows = this.agent.sql<{ count: number }>`\n WITH RECURSIVE path AS (\n SELECT id, parent_id, 0 as depth FROM assistant_messages WHERE id = ${leaf.id}\n UNION ALL\n SELECT m.id, m.parent_id, p.depth + 1 FROM assistant_messages m\n JOIN path p ON m.id = p.parent_id\n WHERE m.session_id = ${this.sessionId} AND p.depth < 10000\n )\n SELECT COUNT(*) as count FROM path\n `;\n return rows[0]?.count ?? 0;\n }\n\n // ── Write ──────────────────────────────────────────────────────\n\n appendMessage(message: SessionMessage, parentId?: string | null): void {\n this.ensureTable();\n // Skip if message already exists (INSERT OR IGNORE idempotency)\n const existing = this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${message.id} AND session_id = ${this.sessionId}\n `;\n if (existing.length > 0) return;\n\n let parent = parentId ?? this.latestLeafRow()?.id ?? null;\n\n // Validate parentId belongs to this session\n if (parent) {\n const valid = this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${parent} AND session_id = ${this.sessionId}\n `;\n if (valid.length === 0) parent = null;\n }\n\n const json = JSON.stringify(message);\n\n this.agent.sql`\n INSERT INTO assistant_messages (id, session_id, parent_id, role, content)\n VALUES (${message.id}, ${this.sessionId}, ${parent}, ${message.role}, ${json})\n `;\n this.indexFTS(message);\n }\n\n updateMessage(message: SessionMessage): void {\n this.ensureTable();\n this.agent.sql`\n UPDATE assistant_messages SET content = ${JSON.stringify(message)}\n WHERE id = ${message.id} AND session_id = ${this.sessionId}\n `;\n this.indexFTS(message);\n }\n\n deleteMessages(messageIds: string[]): void {\n this.ensureTable();\n for (const id of messageIds) {\n this.agent\n .sql`DELETE FROM assistant_messages WHERE id = ${id} AND session_id = ${this.sessionId}`;\n this.deleteFTS(id);\n }\n }\n\n clearMessages(): void {\n this.ensureTable();\n this.agent\n .sql`DELETE FROM assistant_messages WHERE session_id = ${this.sessionId}`;\n this.agent\n .sql`DELETE FROM assistant_compactions WHERE session_id = ${this.sessionId}`;\n // FTS5 requires delete by rowid\n const ftsRows = this.agent.sql<{ rowid: number }>`\n SELECT rowid FROM assistant_fts WHERE session_id = ${this.sessionId}\n `;\n for (const row of ftsRows) {\n this.agent.sql`DELETE FROM assistant_fts WHERE rowid = ${row.rowid}`;\n }\n }\n\n // ── Compaction ─────────────────────────────────────────────────\n\n addCompaction(\n summary: string,\n fromMessageId: string,\n toMessageId: string\n ): StoredCompaction {\n this.ensureTable();\n const id = crypto.randomUUID();\n this.agent.sql`\n INSERT INTO assistant_compactions (id, session_id, summary, from_message_id, to_message_id)\n VALUES (${id}, ${this.sessionId}, ${summary}, ${fromMessageId}, ${toMessageId})\n `;\n return {\n id,\n summary,\n fromMessageId,\n toMessageId,\n createdAt: new Date().toISOString()\n };\n }\n\n getCompactions(): StoredCompaction[] {\n this.ensureTable();\n type Row = {\n id: string;\n summary: string;\n from_message_id: string;\n to_message_id: string;\n created_at: string;\n };\n return this.agent.sql<Row>`\n SELECT * FROM assistant_compactions WHERE session_id = ${this.sessionId} ORDER BY created_at ASC\n `.map((r) => ({\n id: r.id,\n summary: r.summary,\n fromMessageId: r.from_message_id,\n toMessageId: r.to_message_id,\n createdAt: r.created_at\n }));\n }\n\n // ── Search ─────────────────────────────────────────────────────\n\n searchMessages(query: string, limit = 20): SearchResult[] {\n this.ensureTable();\n // Sanitize query: wrap in double quotes to treat as literal phrase,\n // escaping any existing double quotes to prevent FTS5 syntax injection\n const sanitized = `\"${query.replace(/\"/g, '\"\"')}\"`;\n try {\n return this.agent.sql<{ id: string; role: string; content: string }>`\n SELECT f.id, f.role, f.content FROM assistant_fts f\n INNER JOIN assistant_messages m ON m.id = f.id AND m.session_id = f.session_id\n WHERE assistant_fts MATCH ${sanitized} AND f.session_id = ${this.sessionId}\n ORDER BY rank LIMIT ${limit}\n `.map((r) => ({\n id: r.id,\n role: r.role,\n content: r.content\n }));\n } catch {\n // Malformed FTS query — return empty results\n return [];\n }\n }\n\n // ── Internal ───────────────────────────────────────────────────\n\n private latestLeafRow(): { id: string; content: string } | null {\n const rows = this.agent.sql<{ id: string; content: string }>`\n SELECT m.id, m.content FROM assistant_messages m\n LEFT JOIN assistant_messages c ON c.parent_id = m.id AND c.session_id = ${this.sessionId}\n WHERE c.id IS NULL AND m.session_id = ${this.sessionId}\n ORDER BY m.created_at DESC, m.rowid DESC LIMIT 1\n `;\n return rows[0] ?? null;\n }\n\n private indexFTS(message: SessionMessage): void {\n const text = message.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\" \");\n // Always delete old entry first — handles text→no-text transitions\n this.deleteFTS(message.id);\n if (text) {\n this.agent.sql`\n INSERT INTO assistant_fts (id, session_id, role, content)\n VALUES (${message.id}, ${this.sessionId}, ${message.role}, ${text})\n `;\n }\n }\n\n private deleteFTS(id: string): void {\n const rows = this.agent.sql<{ rowid: number }>`\n SELECT rowid FROM assistant_fts WHERE id = ${id} AND session_id = ${this.sessionId}\n `;\n for (const row of rows) {\n this.agent.sql`DELETE FROM assistant_fts WHERE rowid = ${row.rowid}`;\n }\n }\n\n private applyCompactions(\n messages: SessionMessage[],\n compactions: StoredCompaction[]\n ): SessionMessage[] {\n const ids = messages.map((m) => m.id);\n const result: SessionMessage[] = [];\n let i = 0;\n while (i < messages.length) {\n // Find all compactions starting at this message, pick the latest\n // (widest range) so newer compactions supersede older ones\n const matching = compactions.filter((c) => c.fromMessageId === ids[i]);\n const comp =\n matching.length > 1 ? matching[matching.length - 1] : matching[0];\n if (comp) {\n const endIdx = ids.indexOf(comp.toMessageId);\n if (endIdx >= i) {\n result.push({\n id: `${COMPACTION_PREFIX}${comp.id}`,\n role: \"assistant\",\n parts: [\n {\n type: \"text\",\n text: comp.summary\n }\n ],\n createdAt: new Date()\n } as SessionMessage);\n i = endIdx + 1;\n continue;\n }\n }\n result.push(messages[i]);\n i++;\n }\n return result;\n }\n\n private parse(json: string): SessionMessage | null {\n try {\n const msg = JSON.parse(json);\n if (\n typeof msg?.id === \"string\" &&\n typeof msg?.role === \"string\" &&\n Array.isArray(msg?.parts)\n ) {\n return msg;\n }\n } catch {\n /* skip */\n }\n return null;\n }\n\n private parseRows(rows: { content: string }[]): SessionMessage[] {\n const result: SessionMessage[] = [];\n for (const row of rows) {\n const msg = this.parse(row.content);\n if (msg) result.push(msg);\n }\n return result;\n }\n}\n","/**\n * SQLite Context Block Provider\n *\n * Default durable storage for context blocks using DO SQLite.\n * Each block is a row in cf_agents_context_blocks.\n */\n\nimport type { WritableContextProvider } from \"../context\";\nimport type { SqlProvider } from \"./agent\";\n\nexport class AgentContextProvider implements WritableContextProvider {\n private agent: SqlProvider;\n private label: string;\n private initialized = false;\n\n constructor(agent: SqlProvider, label?: string) {\n this.agent = agent;\n this.label = label ?? \"\";\n }\n\n init(label: string): void {\n if (!this.label) {\n this.label = label;\n }\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_context_blocks (\n label TEXT PRIMARY KEY,\n content TEXT NOT NULL,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n this.initialized = true;\n }\n\n async get(): Promise<string | null> {\n this.ensureTable();\n const rows = this.agent.sql<{ content: string }>`\n SELECT content FROM cf_agents_context_blocks WHERE label = ${this.label}\n `;\n return rows[0]?.content ?? null;\n }\n\n async set(content: string): Promise<void> {\n this.ensureTable();\n this.agent.sql`\n INSERT INTO cf_agents_context_blocks (label, content)\n VALUES (${this.label}, ${content})\n ON CONFLICT(label) DO UPDATE SET content = ${content}, updated_at = CURRENT_TIMESTAMP\n `;\n }\n}\n","/**\n * Session — conversation history, context blocks, compaction, search, and tools.\n */\n\nimport type { ToolSet } from \"ai\";\nimport type { SessionProvider, StoredCompaction } from \"./provider\";\nimport type { SessionMessage, SessionOptions } from \"./types\";\nimport {\n ContextBlocks,\n type ContextBlock,\n type ContextConfig,\n type WritableContextProvider\n} from \"./context\";\nimport { AgentSessionProvider, type SqlProvider } from \"./providers/agent\";\nimport { AgentContextProvider } from \"./providers/agent-context\";\nimport type { CompactResult } from \"../utils/compaction-helpers\";\nimport { estimateMessageTokens } from \"../utils/tokens\";\nimport { MessageType } from \"../../../types\";\n\nexport type SessionContextOptions = Omit<ContextConfig, \"label\">;\n\n// Raw builder entry — provider resolved at init time so chain order doesn't matter\ninterface PendingContext {\n label: string;\n options: SessionContextOptions;\n}\n\n/** Agent-like object that can broadcast to connected clients */\ninterface Broadcaster {\n broadcast(message: string | ArrayBufferLike): void;\n}\n\nfunction isBroadcaster(obj: unknown): obj is Broadcaster {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"broadcast\" in obj &&\n typeof (obj as Broadcaster).broadcast === \"function\"\n );\n}\n\nexport class Session {\n private storage!: SessionProvider;\n private context!: ContextBlocks;\n\n // Builder state — only used with Session.create()\n private _agent?: SqlProvider;\n private _broadcaster?: Broadcaster;\n private _sessionId?: string;\n private _pending?: PendingContext[];\n private _cachedPrompt?: WritableContextProvider | true;\n private _compactionFn?:\n | ((messages: SessionMessage[]) => Promise<CompactResult | null>)\n | null;\n private _tokenThreshold?: number;\n private _ready = false;\n\n constructor(storage: SessionProvider, options?: SessionOptions) {\n this.storage = storage;\n this.context = new ContextBlocks(\n options?.context ?? [],\n options?.promptStore\n );\n this._ready = true;\n }\n\n /**\n * Chainable session creation with auto-wired SQLite providers.\n * Chain methods in any order — providers are resolved lazily on first use.\n *\n * @example\n * ```ts\n * const session = Session.create(this)\n * .withContext(\"soul\", { provider: { get: async () => \"You are helpful.\" } })\n * .withContext(\"memory\", { description: \"Learned facts\", maxTokens: 1100 })\n * .withCachedPrompt();\n *\n * // Skills from R2 (on-demand loading via load_context tool)\n * const session = Session.create(this)\n * .withContext(\"skills\", {\n * provider: new R2SkillProvider(env.SKILLS_BUCKET, { prefix: \"skills/\" })\n * })\n * .withCachedPrompt();\n * ```\n */\n static create(agent: SqlProvider): Session {\n const session: Session = Object.create(Session.prototype);\n session._agent = agent;\n if (isBroadcaster(agent)) {\n session._broadcaster = agent;\n }\n session._pending = [];\n session._ready = false;\n return session;\n }\n\n // ── Builder methods ─────────────────────────────────────────────\n\n forSession(sessionId: string): this {\n this._sessionId = sessionId;\n return this;\n }\n\n withContext(label: string, options?: SessionContextOptions): this {\n this._pending!.push({ label, options: options ?? {} });\n return this;\n }\n\n withCachedPrompt(provider?: WritableContextProvider): this {\n this._cachedPrompt = provider ?? true;\n return this;\n }\n\n /**\n * Register a compaction function. Called by `compact()` to compress\n * message history into a summary overlay.\n */\n onCompaction(\n fn: (messages: SessionMessage[]) => Promise<CompactResult | null>\n ): this {\n this._compactionFn = fn;\n return this;\n }\n\n /**\n * Auto-compact when estimated token count exceeds the threshold.\n * Checked after each `appendMessage`. Requires `onCompaction()`.\n */\n compactAfter(tokenThreshold: number): this {\n this._tokenThreshold = tokenThreshold;\n return this;\n }\n\n // ── Lazy init ───────────────────────────────────────────────────\n\n private _ensureReady(): void {\n if (this._ready) return;\n\n // Resolve context configs — sessionId is final by now\n const configs: ContextConfig[] = (this._pending ?? []).map(\n ({ label, options: opts }) => {\n let provider = opts.provider;\n if (!provider) {\n // No provider → auto-wire to writable SQLite\n const key = this._sessionId ? `${label}_${this._sessionId}` : label;\n provider = new AgentContextProvider(this._agent!, key);\n }\n return {\n label,\n description: opts.description,\n maxTokens: opts.maxTokens,\n provider\n };\n }\n );\n\n // Resolve prompt store\n let promptStore: WritableContextProvider | undefined;\n if (this._cachedPrompt === true) {\n const key = this._sessionId\n ? `_system_prompt_${this._sessionId}`\n : \"_system_prompt\";\n promptStore = new AgentContextProvider(this._agent!, key);\n } else if (this._cachedPrompt) {\n promptStore = this._cachedPrompt;\n }\n\n this.storage = new AgentSessionProvider(this._agent!, this._sessionId);\n this.context = new ContextBlocks(configs, promptStore);\n this.context.setUnloadCallback((label, key) => {\n this._reclaimLoadedSkill(label, key);\n });\n this._restoreLoadedSkills();\n this._ready = true;\n }\n\n /**\n * Reconstruct which skills are loaded by scanning conversation history\n * for load_context tool results that haven't been unloaded.\n * Called during init to survive hibernation/eviction.\n */\n private _restoreLoadedSkills(): void {\n const history = this.storage.getHistory();\n const loaded = new Set<string>();\n\n for (const msg of history) {\n if (msg.role !== \"assistant\") continue;\n for (const part of msg.parts) {\n if (\n part.toolName === \"load_context\" &&\n part.state === \"output-available\"\n ) {\n const input = part.input as\n | { label?: string; key?: string }\n | undefined;\n if (input?.label && input?.key) {\n const id = `${input.label}:${input.key}`;\n if (\n typeof part.output === \"string\" &&\n part.output.startsWith(\"[skill unloaded:\")\n ) {\n loaded.delete(id);\n } else {\n loaded.add(id);\n }\n }\n } else if (\n part.toolName === \"unload_context\" &&\n part.state === \"output-available\"\n ) {\n const input = part.input as\n | { label?: string; key?: string }\n | undefined;\n if (input?.label && input?.key) {\n loaded.delete(`${input.label}:${input.key}`);\n }\n }\n }\n }\n\n if (loaded.size > 0) {\n this.context.restoreLoadedSkills(loaded);\n }\n }\n\n /**\n * Replace a load_context tool result in conversation history\n * with a short marker to reclaim context space.\n */\n private _reclaimLoadedSkill(label: string, key: string): void {\n const history = this.storage.getHistory();\n for (let i = history.length - 1; i >= 0; i--) {\n const msg = history[i];\n if (msg.role !== \"assistant\") continue;\n\n let changed = false;\n const newParts = msg.parts.map((part) => {\n if (\n part.toolName === \"load_context\" &&\n part.state === \"output-available\"\n ) {\n const input = part.input as\n | { label?: string; key?: string }\n | undefined;\n if (input?.label === label && input?.key === key) {\n changed = true;\n return { ...part, output: `[skill unloaded: ${key}]` };\n }\n }\n return part;\n });\n\n if (changed) {\n this.storage.updateMessage({\n ...msg,\n parts: newParts as SessionMessage[\"parts\"]\n });\n return;\n }\n }\n }\n\n // ── History (tree-structured) ─────────────────────────────────\n\n getHistory(leafId?: string | null): SessionMessage[] {\n this._ensureReady();\n return this.storage.getHistory(leafId);\n }\n\n getMessage(id: string): SessionMessage | null {\n this._ensureReady();\n return this.storage.getMessage(id);\n }\n\n getLatestLeaf(): SessionMessage | null {\n this._ensureReady();\n return this.storage.getLatestLeaf();\n }\n\n getBranches(messageId: string): SessionMessage[] {\n this._ensureReady();\n return this.storage.getBranches(messageId);\n }\n\n getPathLength(leafId?: string | null): number {\n this._ensureReady();\n return this.storage.getPathLength(leafId);\n }\n\n // ── Broadcast ──────────────────────────────────────────────────\n\n private _broadcast(type: MessageType, data: Record<string, unknown>): void {\n if (!this._broadcaster) return;\n this._broadcaster.broadcast(JSON.stringify({ type, ...data }));\n }\n\n private _emitStatus(\n phase: \"idle\" | \"compacting\",\n extra?: Record<string, unknown>\n ): number {\n const tokenEstimate = estimateMessageTokens(this.getHistory());\n this._broadcast(MessageType.CF_AGENT_SESSION, {\n phase,\n tokenEstimate,\n tokenThreshold: this._tokenThreshold ?? null,\n ...extra\n });\n return tokenEstimate;\n }\n\n private _emitError(error: string): void {\n this._broadcast(MessageType.CF_AGENT_SESSION_ERROR, { error });\n }\n\n // ── Write ─────────────────────────────────────────────────────\n\n async appendMessage(\n message: SessionMessage,\n parentId?: string | null\n ): Promise<void> {\n this._ensureReady();\n this.storage.appendMessage(message, parentId);\n\n const tokenEstimate = this._emitStatus(\"idle\");\n\n if (\n this._tokenThreshold != null &&\n this._compactionFn &&\n tokenEstimate > this._tokenThreshold\n ) {\n try {\n await this.compact();\n } catch {\n // Auto-compact failure is non-fatal — message is already appended\n }\n }\n }\n\n updateMessage(message: SessionMessage): void {\n this._ensureReady();\n this.storage.updateMessage(message);\n this._emitStatus(\"idle\");\n }\n\n deleteMessages(messageIds: string[]): void {\n this._ensureReady();\n this.storage.deleteMessages(messageIds);\n this._emitStatus(\"idle\");\n }\n\n clearMessages(): void {\n this._ensureReady();\n this.storage.clearMessages();\n this.context.clearSkillState();\n this._emitStatus(\"idle\");\n }\n\n // ── Compaction ────────────────────────────────────────────────\n\n addCompaction(\n summary: string,\n fromMessageId: string,\n toMessageId: string\n ): StoredCompaction {\n this._ensureReady();\n return this.storage.addCompaction(summary, fromMessageId, toMessageId);\n }\n\n getCompactions(): StoredCompaction[] {\n this._ensureReady();\n return this.storage.getCompactions();\n }\n\n /**\n * Run the registered compaction function and store the result as an overlay.\n * Requires `onCompaction()` to be called first.\n */\n async compact(): Promise<CompactResult | null> {\n this._ensureReady();\n if (!this._compactionFn) {\n throw new Error(\n \"No compaction function registered. Call onCompaction() first.\"\n );\n }\n\n const tokensBefore = this._emitStatus(\"compacting\");\n\n let result: CompactResult | null;\n try {\n result = await this._compactionFn(this.getHistory());\n } catch (err) {\n this._emitError(err instanceof Error ? err.message : String(err));\n return null;\n }\n\n if (!result) {\n this._emitStatus(\"idle\");\n return null;\n }\n\n // Validate toMessageId exists in the history\n const historyIds = new Set(this.getHistory().map((m) => m.id));\n if (!historyIds.has(result.toMessageId)) {\n this._emitStatus(\"idle\");\n return null;\n }\n\n // Iterative compaction — extend from earliest existing compaction's start\n const existing = this.getCompactions();\n const fromId =\n existing.length > 0 ? existing[0].fromMessageId : result.fromMessageId;\n\n this.addCompaction(result.summary, fromId, result.toMessageId);\n await this.refreshSystemPrompt();\n\n this._emitStatus(\"idle\", {\n compacted: { tokensBefore }\n });\n\n return { ...result, fromMessageId: fromId };\n }\n\n // ── Context Blocks ────────────────────────────────────────────\n\n getContextBlock(label: string): ContextBlock | null {\n this._ensureReady();\n return this.context.getBlock(label);\n }\n\n getContextBlocks(): ContextBlock[] {\n this._ensureReady();\n return this.context.getBlocks();\n }\n\n async replaceContextBlock(\n label: string,\n content: string\n ): Promise<ContextBlock> {\n this._ensureReady();\n return this.context.setBlock(label, content);\n }\n\n async appendContextBlock(\n label: string,\n content: string\n ): Promise<ContextBlock> {\n this._ensureReady();\n return this.context.appendToBlock(label, content);\n }\n\n /**\n * Dynamically register a new context block after session initialization.\n * Used by extensions to contribute context blocks at runtime.\n *\n * The block's provider is initialized and loaded immediately.\n * Call `refreshSystemPrompt()` afterward to include the new block\n * in the system prompt.\n *\n * Note: When called without a provider, auto-wires to SQLite via\n * AgentContextProvider. Requires the session to have been created\n * via `Session.create(agent)` (not the direct constructor).\n */\n async addContext(\n label: string,\n options?: SessionContextOptions\n ): Promise<ContextBlock> {\n this._ensureReady();\n const opts = options ?? {};\n let provider = opts.provider;\n if (!provider) {\n const key = this._sessionId ? `${label}_${this._sessionId}` : label;\n provider = new AgentContextProvider(this._agent!, key);\n }\n return this.context.addBlock({\n label,\n description: opts.description,\n maxTokens: opts.maxTokens,\n provider\n });\n }\n\n /**\n * Remove a dynamically registered context block.\n * Used during extension unload cleanup.\n *\n * Returns true if the block existed and was removed.\n * Call `refreshSystemPrompt()` afterward to rebuild the prompt\n * without the removed block.\n */\n removeContext(label: string): boolean {\n this._ensureReady();\n return this.context.removeBlock(label);\n }\n\n // ── Skills ───────────────────────────────────────────────────\n\n /**\n * Unload a previously loaded skill, reclaiming context space.\n * The tool result in conversation history is replaced with a short marker.\n */\n unloadSkill(label: string, key: string): boolean {\n this._ensureReady();\n return this.context.unloadSkill(label, key);\n }\n\n /**\n * Get currently loaded skill keys (as \"label:key\" strings).\n */\n getLoadedSkillKeys(): Set<string> {\n this._ensureReady();\n return this.context.getLoadedSkillKeys();\n }\n\n // ── System Prompt ─────────────────────────────────────────────\n\n async freezeSystemPrompt(): Promise<string> {\n this._ensureReady();\n return this.context.freezeSystemPrompt();\n }\n\n async refreshSystemPrompt(): Promise<string> {\n this._ensureReady();\n return this.context.refreshSystemPrompt();\n }\n\n // ── Search ────────────────────────────────────────────────────\n\n search(\n query: string,\n options?: { limit?: number }\n ): Array<{\n id: string;\n role: string;\n content: string;\n createdAt?: string;\n }> {\n this._ensureReady();\n if (!this.storage.searchMessages) {\n throw new Error(\"Session provider does not support search\");\n }\n return this.storage.searchMessages(query, options?.limit ?? 20);\n }\n\n // ── Tools ─────────────────────────────────────────────────────\n\n /** Returns set_context and load_context tools. */\n async tools(): Promise<ToolSet> {\n this._ensureReady();\n return this.context.tools();\n }\n}\n","/**\n * SessionManager — registry of named sessions.\n *\n * Lifecycle: create, get, list, delete, rename.\n * Convenience methods for message ops by session ID.\n * Cross-session search and tools.\n */\n\nimport type { ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport type { CompactResult } from \"../utils/compaction-helpers\";\nimport type { WritableContextProvider } from \"./context\";\nimport type { StoredCompaction } from \"./provider\";\nimport type { SqlProvider } from \"./providers/agent\";\nimport type { SearchProvider } from \"./search\";\nimport { Session, type SessionContextOptions } from \"./session\";\nimport type { SessionMessage } from \"./types\";\n\nexport interface SessionInfo {\n id: string;\n name: string;\n parent_session_id: string | null;\n model: string | null;\n source: string | null;\n input_tokens: number;\n output_tokens: number;\n estimated_cost: number;\n end_reason: string | null;\n created_at: string;\n updated_at: string;\n}\n\n// Pending context entry — resolved per-session with namespaced providers\ninterface PendingManagerContext {\n label: string;\n options: SessionContextOptions;\n}\n\nexport interface SessionManagerOptions {}\n\nexport class SessionManager {\n private agent!: SqlProvider;\n private _pending: PendingManagerContext[] = [];\n private _cachedPrompt?: WritableContextProvider | true;\n private _compactionFn?:\n | ((messages: SessionMessage[]) => Promise<CompactResult | null>)\n | null;\n private _tokenThreshold?: number;\n private _sessions = new Map<string, Session>();\n private _historyLabel?: string;\n private _tableReady = false;\n private _ready = false;\n\n constructor(agent: SqlProvider, _options: SessionManagerOptions = {}) {\n this.agent = agent;\n this._ready = true;\n this._ensureTable();\n }\n\n /**\n * Chainable SessionManager creation with auto-wired context for all sessions.\n *\n * @example\n * ```ts\n * const manager = SessionManager.create(this)\n * .withContext(\"soul\", { provider: { get: async () => \"You are helpful.\" } })\n * .withContext(\"memory\", { description: \"Learned facts\", maxTokens: 1100 })\n * .withCachedPrompt()\n * .compactAfter(100_000);\n *\n * // Each getSession(id) auto-creates namespaced providers:\n * // memory key: \"memory_<sessionId>\"\n * // prompt key: \"_system_prompt_<sessionId>\"\n * const session = manager.getSession(\"chat-123\");\n * ```\n */\n static create(agent: SqlProvider): SessionManager {\n const mgr: SessionManager = Object.create(SessionManager.prototype);\n mgr.agent = agent;\n mgr._pending = [];\n mgr._compactionFn = null;\n mgr._tokenThreshold = undefined;\n mgr._sessions = new Map();\n mgr._tableReady = false;\n mgr._ready = false;\n return mgr;\n }\n\n // ── Builder methods ─────────────────────────────────────────────\n\n withContext(label: string, options?: SessionContextOptions): this {\n this._pending.push({ label, options: options ?? {} });\n return this;\n }\n\n withCachedPrompt(provider?: WritableContextProvider): this {\n this._cachedPrompt = provider ?? true;\n return this;\n }\n\n /**\n * Register a compaction function propagated to all sessions.\n * Called by `Session.compact()` to compress message history.\n */\n onCompaction(\n fn: (messages: SessionMessage[]) => Promise<CompactResult | null>\n ): this {\n this._compactionFn = fn;\n return this;\n }\n\n /**\n * Auto-compact when estimated token count exceeds the threshold.\n * Propagated to all sessions. Requires `onCompaction()`.\n */\n compactAfter(tokenThreshold: number): this {\n this._tokenThreshold = tokenThreshold;\n return this;\n }\n\n /**\n * Add a searchable context block that searches conversation history\n * across all sessions managed by this manager.\n *\n * The model can use `search_context` to find relevant messages from\n * any session. The block is readonly (no `set`).\n *\n * @example\n * ```ts\n * SessionManager.create(this)\n * .withContext(\"memory\", { maxTokens: 1100 })\n * .withSearchableHistory(\"history\")\n * .withCachedPrompt();\n * ```\n */\n withSearchableHistory(label: string): this {\n this._historyLabel = label;\n return this;\n }\n\n // ── Lazy init ───────────────────────────────────────────────────\n\n private _ensureReady(): void {\n if (this._ready) return;\n this._ready = true;\n this._ensureTable();\n }\n\n private _ensureTable(): void {\n if (this._tableReady) return;\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_sessions (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n parent_session_id TEXT,\n model TEXT,\n source TEXT,\n input_tokens INTEGER DEFAULT 0,\n output_tokens INTEGER DEFAULT 0,\n estimated_cost REAL DEFAULT 0,\n end_reason TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n this.agent.sql`\n CREATE VIRTUAL TABLE IF NOT EXISTS assistant_fts\n USING fts5(id UNINDEXED, session_id UNINDEXED, role UNINDEXED, content, tokenize='porter unicode61')\n `;\n this._tableReady = true;\n }\n\n private _createHistoryProvider(): SearchProvider {\n const mgr = this;\n return {\n async get() {\n const sessions = mgr.list();\n if (sessions.length === 0) return null;\n return `${sessions.length} session${sessions.length === 1 ? \"\" : \"s\"} available for search.`;\n },\n async search(query: string) {\n const results = mgr.search(query, { limit: 10 });\n if (results.length === 0) return null;\n return results.map((r) => `[${r.role}] ${r.content}`).join(\"\\n---\\n\");\n }\n // No set — conversation history is readonly\n };\n }\n\n // ── Session access ────────────────────────────────────────────\n\n /** Get or create the Session instance for a session ID. */\n getSession(sessionId: string): Session {\n this._ensureReady();\n let session = this._sessions.get(sessionId);\n if (!session) {\n const s = Session.create(this.agent).forSession(sessionId);\n for (const { label, options } of this._pending) {\n s.withContext(label, options);\n }\n if (this._cachedPrompt === true) {\n s.withCachedPrompt();\n } else if (this._cachedPrompt) {\n s.withCachedPrompt(this._cachedPrompt);\n }\n if (this._historyLabel) {\n s.withContext(this._historyLabel, {\n description: \"Cross-session conversation history\",\n provider: this._createHistoryProvider()\n });\n }\n if (this._compactionFn) {\n s.onCompaction(this._compactionFn);\n }\n if (this._tokenThreshold != null) {\n s.compactAfter(this._tokenThreshold);\n }\n session = s;\n this._sessions.set(sessionId, session);\n }\n return session;\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────\n\n create(\n name: string,\n opts?: { parentSessionId?: string; model?: string; source?: string }\n ): SessionInfo {\n this._ensureReady();\n const id = crypto.randomUUID();\n this.agent.sql`\n INSERT INTO assistant_sessions (id, name, parent_session_id, model, source)\n VALUES (${id}, ${name}, ${opts?.parentSessionId ?? null}, ${opts?.model ?? null}, ${opts?.source ?? null})\n `;\n return this.get(id)!;\n }\n\n get(sessionId: string): SessionInfo | null {\n this._ensureReady();\n const rows = this.agent.sql`\n SELECT * FROM assistant_sessions WHERE id = ${sessionId}\n ` as unknown as SessionInfo[];\n return rows[0] ?? null;\n }\n\n list(): SessionInfo[] {\n this._ensureReady();\n return this.agent.sql`\n SELECT * FROM assistant_sessions ORDER BY updated_at DESC\n ` as unknown as SessionInfo[];\n }\n\n delete(sessionId: string): void {\n this.getSession(sessionId).clearMessages();\n this.agent.sql`DELETE FROM assistant_sessions WHERE id = ${sessionId}`;\n this._sessions.delete(sessionId);\n }\n\n rename(sessionId: string, name: string): void {\n this._ensureReady();\n this.agent.sql`\n UPDATE assistant_sessions SET name = ${name}, updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n }\n\n // ── Message convenience methods ───────────────────────────────\n\n async append(\n sessionId: string,\n message: SessionMessage,\n parentId?: string\n ): Promise<string> {\n await this.getSession(sessionId).appendMessage(message, parentId);\n this._touch(sessionId);\n return message.id;\n }\n\n async upsert(\n sessionId: string,\n message: SessionMessage,\n parentId?: string\n ): Promise<string> {\n const session = this.getSession(sessionId);\n const existing = session.getMessage(message.id);\n if (existing) {\n session.updateMessage(message);\n } else {\n await session.appendMessage(message, parentId);\n }\n this._touch(sessionId);\n return message.id;\n }\n\n async appendAll(\n sessionId: string,\n messages: SessionMessage[],\n parentId?: string\n ): Promise<string | null> {\n const session = this.getSession(sessionId);\n let lastParent = parentId ?? null;\n for (const msg of messages) {\n await session.appendMessage(msg, lastParent);\n lastParent = msg.id;\n }\n this._touch(sessionId);\n return lastParent;\n }\n\n getHistory(sessionId: string, leafId?: string): SessionMessage[] {\n return this.getSession(sessionId).getHistory(leafId);\n }\n\n getMessageCount(sessionId: string): number {\n return this.getSession(sessionId).getPathLength();\n }\n\n clearMessages(sessionId: string): void {\n this.getSession(sessionId).clearMessages();\n this._touch(sessionId);\n }\n\n deleteMessages(sessionId: string, messageIds: string[]): void {\n this.getSession(sessionId).deleteMessages(messageIds);\n this._touch(sessionId);\n }\n\n // ── Branching ──────────────────────────────────────────────────\n\n getBranches(sessionId: string, messageId: string): SessionMessage[] {\n return this.getSession(sessionId).getBranches(messageId);\n }\n\n /**\n * Fork a session at a specific message, creating a new session\n * with the history up to that point copied over.\n */\n async fork(\n sessionId: string,\n atMessageId: string,\n newName: string\n ): Promise<SessionInfo> {\n const info = this.create(newName, { parentSessionId: sessionId });\n const history = this.getSession(sessionId).getHistory(atMessageId);\n const newSession = this.getSession(info.id);\n\n let parentId: string | null = null;\n for (const msg of history) {\n const newId = crypto.randomUUID();\n const copy: SessionMessage = { ...msg, id: newId };\n await newSession.appendMessage(copy, parentId);\n parentId = newId;\n }\n\n this._touch(info.id);\n return info;\n }\n\n // ── Compaction ────────────────────────────────────────────────\n\n addCompaction(\n sessionId: string,\n summary: string,\n fromId: string,\n toId: string\n ): StoredCompaction {\n return this.getSession(sessionId).addCompaction(summary, fromId, toId);\n }\n\n getCompactions(sessionId: string): StoredCompaction[] {\n return this.getSession(sessionId).getCompactions();\n }\n\n async compactAndSplit(\n sessionId: string,\n summary: string,\n newName?: string\n ): Promise<SessionInfo> {\n const old = this.get(sessionId);\n this.agent.sql`\n UPDATE assistant_sessions SET end_reason = 'compaction', updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n\n const info = this.create(newName ?? old?.name ?? \"Compacted\", {\n parentSessionId: sessionId,\n model: old?.model ?? undefined,\n source: old?.source ?? undefined\n });\n\n await this.append(info.id, {\n id: crypto.randomUUID(),\n role: \"assistant\",\n parts: [\n { type: \"text\", text: `[Context from previous session]\\n\\n${summary}` }\n ]\n });\n\n return info;\n }\n\n // ── Usage tracking ────────────────────────────────────────────\n\n addUsage(\n sessionId: string,\n inputTokens: number,\n outputTokens: number,\n cost: number\n ): void {\n this._ensureReady();\n this.agent.sql`\n UPDATE assistant_sessions SET\n input_tokens = input_tokens + ${inputTokens},\n output_tokens = output_tokens + ${outputTokens},\n estimated_cost = estimated_cost + ${cost},\n updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n }\n\n // ── Search ────────────────────────────────────────────────────\n\n search(query: string, options?: { limit?: number }) {\n this._ensureReady();\n const limit = options?.limit ?? 20;\n // Quote each word individually to prevent FTS5 syntax injection\n // while preserving implicit AND between terms\n const sanitized = query\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => `\"${w.replace(/\"/g, '\"\"')}\"`)\n .join(\" \");\n if (!sanitized) return [];\n try {\n return this.agent.sql<{ id: string; role: string; content: string }>`\n SELECT id, role, content FROM assistant_fts\n WHERE assistant_fts MATCH ${sanitized}\n ORDER BY rank LIMIT ${limit}\n `.map((r) => ({\n id: r.id,\n role: r.role,\n content: r.content,\n createdAt: \"\"\n }));\n } catch {\n return [];\n }\n }\n\n // ── Tools ─────────────────────────────────────────────────────\n\n tools(): ToolSet {\n return {\n session_search: {\n description:\n \"Search past conversations for relevant context. Searches across all sessions.\",\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n query: { type: \"string\" as const, description: \"Search query\" }\n },\n required: [\"query\"]\n }),\n execute: async ({ query }: { query: string }) => {\n try {\n const results = this.search(query, { limit: 10 });\n if (results.length === 0) return \"No results found.\";\n return results\n .map((r) => `[${r.role}] ${r.content}`)\n .join(\"\\n---\\n\");\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n }\n };\n }\n\n // ── Internal ──────────────────────────────────────────────────\n\n private _touch(sessionId: string): void {\n this.agent.sql`\n UPDATE assistant_sessions SET updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/experimental/memory/session/search.ts","../../../../src/experimental/memory/session/skills.ts","../../../../src/experimental/memory/session/context.ts","../../../../src/experimental/memory/session/providers/agent.ts","../../../../src/experimental/memory/session/providers/agent-context.ts","../../../../src/experimental/memory/session/session.ts","../../../../src/experimental/memory/session/manager.ts","../../../../src/experimental/memory/session/providers/postgres-adapter.ts","../../../../src/experimental/memory/session/providers/postgres.ts","../../../../src/experimental/memory/session/providers/postgres-context.ts","../../../../src/experimental/memory/session/providers/postgres-search.ts"],"sourcesContent":["/**\n * Search Provider — full-text searchable context blocks.\n *\n * Extends ContextProvider with `search()` for querying indexed content\n * and a keyed `set()` for indexing individual entries.\n *\n * Duck-typed: if a provider has a `search` method, it's a SearchProvider.\n */\n\nimport type { ContextProvider } from \"./context\";\nimport type { SqlProvider } from \"./providers/agent\";\n\n/**\n * Storage interface for searchable context.\n *\n * - `get()` returns a summary of indexed content (rendered into system prompt)\n * - `search(query)` full-text search (via search_context tool)\n * - `set(key, content)` indexes content under a key (via set_context tool)\n */\nexport interface SearchProvider extends ContextProvider {\n search(query: string): Promise<string | null>;\n set?(key: string, content: string): Promise<void>;\n}\n\n/**\n * Check if a provider is a SearchProvider (has a `search` method).\n */\nexport function isSearchProvider(\n provider: unknown\n): provider is SearchProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"search\" in provider &&\n typeof (provider as SearchProvider).search === \"function\"\n );\n}\n\n// ── Agent Search Provider (DO SQLite FTS5) ─────────────────────────\n\n/**\n * SearchProvider backed by Durable Object SQLite with FTS5.\n *\n * - `get()` returns a count of indexed entries\n * - `search(query)` full-text search using FTS5\n * - `set(key, content)` indexes or replaces content under a key\n *\n * Each instance uses a namespaced FTS5 table to avoid collisions\n * with the session message search.\n *\n * @example\n * ```ts\n * Session.create(this)\n * .withContext(\"knowledge\", {\n * provider: new AgentSearchProvider(this)\n * })\n * ```\n */\nexport class AgentSearchProvider implements SearchProvider {\n private agent: SqlProvider;\n private label = \"\";\n private initialized = false;\n\n constructor(agent: SqlProvider) {\n this.agent = agent;\n }\n\n init(label: string): void {\n this.label = label;\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_search_entries (\n label TEXT NOT NULL,\n key TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n PRIMARY KEY (label, key)\n )\n `;\n this.agent.sql`\n CREATE VIRTUAL TABLE IF NOT EXISTS cf_agents_search_fts\n USING fts5(\n label UNINDEXED,\n key UNINDEXED,\n content,\n tokenize='porter unicode61'\n )\n `;\n this.initialized = true;\n }\n\n async get(): Promise<string | null> {\n this.ensureTable();\n const rows = this.agent.sql<{ count: number }>`\n SELECT COUNT(*) as count FROM cf_agents_search_entries\n WHERE label = ${this.label}\n `;\n const count = rows[0]?.count ?? 0;\n if (count === 0) return null;\n return `${count} entries indexed.`;\n }\n\n async search(query: string): Promise<string | null> {\n this.ensureTable();\n // Quote each word individually to prevent FTS5 syntax injection\n // while preserving implicit AND between terms\n const sanitized = query\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => `\"${w.replace(/\"/g, '\"\"')}\"`)\n .join(\" \");\n if (!sanitized) return null;\n try {\n const rows = this.agent.sql<{\n key: string;\n content: string;\n }>`\n SELECT f.key, f.content\n FROM cf_agents_search_fts f\n WHERE cf_agents_search_fts MATCH ${sanitized}\n AND f.label = ${this.label}\n ORDER BY rank\n LIMIT 10\n `;\n if (rows.length === 0) return null;\n return rows.map((r) => `[${r.key}]\\n${r.content}`).join(\"\\n\\n\");\n } catch {\n // Malformed FTS query\n return null;\n }\n }\n\n async set(key: string, content: string): Promise<void> {\n this.ensureTable();\n\n // Delete old FTS entry if exists\n this.deleteFTS(key);\n\n // Upsert the entry\n this.agent.sql`\n INSERT INTO cf_agents_search_entries (label, key, content)\n VALUES (${this.label}, ${key}, ${content})\n ON CONFLICT(label, key) DO UPDATE SET\n content = ${content},\n updated_at = CURRENT_TIMESTAMP\n `;\n\n // Index in FTS\n this.agent.sql`\n INSERT INTO cf_agents_search_fts (label, key, content)\n VALUES (${this.label}, ${key}, ${content})\n `;\n }\n\n private deleteFTS(key: string): void {\n const rows = this.agent.sql<{ rowid: number }>`\n SELECT rowid FROM cf_agents_search_fts\n WHERE key = ${key} AND label = ${this.label}\n `;\n for (const row of rows) {\n this.agent\n .sql`DELETE FROM cf_agents_search_fts WHERE rowid = ${row.rowid}`;\n }\n }\n}\n","/**\n * Skill Provider — on-demand keyed document collections.\n *\n * Extends ContextProvider with `load()` for on-demand content fetching\n * and a keyed `set()` for writing individual entries.\n *\n * Duck-typed: if a provider has a `load` method, it's a SkillProvider.\n */\n\nimport type { ContextProvider } from \"./context\";\n\n/**\n * Storage interface for skill collections.\n *\n * - `get()` returns metadata listing (rendered into system prompt)\n * - `load(key)` fetches full content (via load_context tool)\n * - `set(key, content, description?)` writes an entry (via set_context tool)\n */\nexport interface SkillProvider extends ContextProvider {\n load(key: string): Promise<string | null>;\n set?(key: string, content: string, description?: string): Promise<void>;\n}\n\n/**\n * Check if a provider is a SkillProvider (has a `load` method).\n */\nexport function isSkillProvider(provider: unknown): provider is SkillProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"load\" in provider &&\n typeof (provider as SkillProvider).load === \"function\"\n );\n}\n\n// ── R2 Skill Provider ──────────────────────────────────────────────\n\n/**\n * SkillProvider backed by an R2 bucket.\n *\n * - `get()` returns a metadata listing of all skills (key + description)\n * - `load(key)` fetches a skill's full content\n * - `set(key, content, description?)` writes a skill\n *\n * Descriptions are pulled from R2 custom metadata (`description` key).\n * If a prefix is provided, it is prepended on storage operations and\n * stripped from keys in metadata. `keys`, when provided, is matched against\n * these prefix-relative keys.\n *\n * @example\n * ```ts\n * const skills = new R2SkillProvider(env.SKILLS_BUCKET, {\n * prefix: \"skills/\",\n * keys: [\"code-review\", \"debugging\"]\n * });\n * ```\n */\nexport class R2SkillProvider implements SkillProvider {\n private bucket: R2Bucket;\n private prefix: string;\n private keys: Set<string> | null;\n\n constructor(\n bucket: R2Bucket,\n options?: { prefix?: string; keys?: string[] }\n ) {\n this.bucket = bucket;\n this.prefix = options?.prefix ?? \"\";\n this.keys = options?.keys?.length ? new Set(options.keys) : null;\n }\n\n async get(): Promise<string | null> {\n const entries: string[] = [];\n let cursor: string | undefined;\n let truncated = true;\n while (truncated) {\n const listed = await this.bucket.list({\n prefix: this.prefix,\n cursor,\n include: [\"customMetadata\"]\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any);\n for (const obj of listed.objects) {\n const key = obj.key.slice(this.prefix.length);\n if (!this.allowsKey(key)) continue;\n const desc = obj.customMetadata?.description;\n entries.push(`- ${key}${desc ? `: ${desc}` : \"\"}`);\n }\n truncated = listed.truncated;\n cursor = listed.truncated ? listed.cursor : undefined;\n }\n return entries.length > 0 ? entries.join(\"\\n\") : null;\n }\n\n async load(key: string): Promise<string | null> {\n if (!this.allowsKey(key)) return null;\n const obj = await this.bucket.get(this.prefix + key);\n if (!obj) return null;\n return obj.text();\n }\n\n async set(key: string, content: string, description?: string): Promise<void> {\n await this.bucket.put(this.prefix + key, content, {\n customMetadata: description ? { description } : undefined\n });\n }\n\n private allowsKey(key: string): boolean {\n return this.keys === null || this.keys.has(key);\n }\n}\n","/**\n * Context Block Management\n *\n * Persistent key-value blocks (MEMORY, USER, SOUL, etc.) that are:\n * - Loaded from their providers at init\n * - Frozen into a snapshot when toSystemPrompt() is called\n * - Updated via setBlock() which writes to the provider immediately\n * but does NOT update the frozen snapshot (preserves LLM prefix cache)\n * - Re-snapshotted on next toSystemPrompt() call\n *\n * Provider type determines behavior:\n * - ContextProvider (get only) → readonly block in system prompt\n * - WritableContextProvider (get+set) → writable via set_context tool\n * - SkillProvider (get+load+set?) → metadata in prompt, load_context tool\n * - SearchProvider (get+search+set?) → searchable via search_context tool\n */\n\nimport type { ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport { estimateStringTokens } from \"../utils/tokens\";\nimport { isSearchProvider, type SearchProvider } from \"./search\";\nimport { isSkillProvider, type SkillProvider } from \"./skills\";\n\nfunction slugify(text: string): string {\n return text\n .slice(0, 60)\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\nfunction stableHash(text: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return (hash >>> 0).toString(36);\n}\n\nfunction contextEntryKey(metadataTitle: string | undefined, content: string) {\n if (metadataTitle?.trim()) {\n const slug = slugify(metadataTitle);\n return slug || `entry-${stableHash(metadataTitle)}`;\n }\n\n const slug = slugify(content) || \"entry\";\n return `${slug}-${stableHash(content)}`;\n}\n\n/**\n * Base storage interface for a context block.\n * A provider with only `get()` is readonly.\n */\nexport interface ContextProvider {\n get(): Promise<string | null>;\n /** Called by the context system to provide the block label before first use. */\n init?(label: string): void;\n}\n\n/**\n * Writable context provider — extends ContextProvider with `set()`.\n * Blocks backed by this provider are writable via the `set_context` tool.\n */\nexport interface WritableContextProvider extends ContextProvider {\n set(content: string): Promise<void>;\n}\n\n/**\n * Check if a provider is writable (has a `set` method).\n */\nexport function isWritableProvider(\n provider: unknown\n): provider is WritableContextProvider {\n return (\n typeof provider === \"object\" &&\n provider !== null &&\n \"set\" in provider &&\n typeof (provider as WritableContextProvider).set === \"function\"\n );\n}\n\n/**\n * Configuration for a context block.\n */\nexport interface ContextConfig {\n /** Block label — used as key and in tool descriptions */\n label: string;\n /** Human-readable description (shown to AI in tool) */\n description?: string;\n /** Maximum tokens allowed. Enforced on set. */\n maxTokens?: number;\n /** Storage provider. Determines block behavior:\n * - ContextProvider (get only) → readonly\n * - WritableContextProvider (get+set) → writable via set_context\n * - SkillProvider (get+load+set?) → on-demand via load_context\n * - SearchProvider (get+search+set?) → searchable via search_context\n * If omitted, auto-wired to writable SQLite when using builder. */\n provider?:\n | ContextProvider\n | WritableContextProvider\n | SkillProvider\n | SearchProvider;\n}\n\n/**\n * A loaded context block with computed token count.\n */\nexport interface ContextBlock {\n label: string;\n description?: string;\n content: string;\n tokens: number;\n maxTokens?: number;\n /** True if provider is writable (has set) */\n writable: boolean;\n /** True if backed by a SkillProvider */\n isSkill: boolean;\n /** True if backed by a SearchProvider */\n isSearchable: boolean;\n}\n\n/**\n * Callback for when a skill is unloaded — allows Session to update\n * the stored message without ContextBlocks knowing about storage.\n */\nexport type SkillUnloadCallback = (label: string, key: string) => void;\n\n/**\n * Manages context blocks with frozen snapshot support.\n */\nexport class ContextBlocks {\n private configs: ContextConfig[];\n private blocks = new Map<string, ContextBlock>();\n private snapshot: string | null = null;\n private loaded = false;\n private promptStore: WritableContextProvider | null;\n private _loadedSkills = new Set<string>();\n private _onUnloadSkill: SkillUnloadCallback | null = null;\n\n constructor(configs: ContextConfig[], promptStore?: WritableContextProvider) {\n this.configs = configs;\n this.promptStore = promptStore ?? null;\n }\n\n /**\n * Register a callback invoked when a skill is unloaded.\n * Session uses this to update the stored tool result message.\n */\n setUnloadCallback(cb: SkillUnloadCallback): void {\n this._onUnloadSkill = cb;\n }\n\n isLoaded(): boolean {\n return this.loaded;\n }\n\n /**\n * Load all blocks from their providers.\n * Called once at session init.\n */\n async load(): Promise<void> {\n for (const config of this.configs) {\n // Pass the label to the provider before first use\n if (config.provider?.init) {\n config.provider.init(config.label);\n }\n\n const content = config.provider\n ? ((await config.provider.get()) ?? \"\")\n : \"\";\n\n const skill = config.provider ? isSkillProvider(config.provider) : false;\n const searchable = config.provider\n ? isSearchProvider(config.provider)\n : false;\n const writable = config.provider\n ? isWritableProvider(config.provider) ||\n (skill && !!(config.provider as SkillProvider).set) ||\n (searchable && !!(config.provider as SearchProvider).set)\n : false;\n\n this.blocks.set(config.label, {\n label: config.label,\n description: config.description,\n content,\n tokens: estimateStringTokens(content),\n maxTokens: config.maxTokens,\n writable,\n isSkill: skill,\n isSearchable: searchable\n });\n }\n this.loaded = true;\n }\n\n /**\n * Dynamically register a new context block after initialization.\n * Used by extensions to contribute context at runtime.\n *\n * If blocks have already been loaded, the new block's provider is\n * initialized and loaded immediately. The snapshot is NOT updated\n * automatically — call `refreshSystemPrompt()` to rebuild.\n */\n async addBlock(config: ContextConfig): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n\n if (this.configs.some((c) => c.label === config.label)) {\n throw new Error(`Block \"${config.label}\" already exists`);\n }\n\n this.configs.push(config);\n\n if (config.provider?.init) {\n config.provider.init(config.label);\n }\n\n const content = config.provider\n ? ((await config.provider.get()) ?? \"\")\n : \"\";\n\n const skill = config.provider ? isSkillProvider(config.provider) : false;\n const searchable = config.provider\n ? isSearchProvider(config.provider)\n : false;\n const writable = config.provider\n ? isWritableProvider(config.provider) ||\n (skill && !!(config.provider as SkillProvider).set) ||\n (searchable && !!(config.provider as SearchProvider).set)\n : false;\n\n const block: ContextBlock = {\n label: config.label,\n description: config.description,\n content,\n tokens: estimateStringTokens(content),\n maxTokens: config.maxTokens,\n writable,\n isSkill: skill,\n isSearchable: searchable\n };\n\n this.blocks.set(config.label, block);\n return block;\n }\n\n /**\n * Remove a dynamically registered context block.\n * Used during extension unload cleanup.\n *\n * Returns true if the block existed and was removed.\n * The snapshot is NOT updated automatically — call\n * `refreshSystemPrompt()` to rebuild.\n *\n * Note: loaded skills for this block are cleaned up from the\n * tracking set but the skill unload callback is NOT fired\n * (history reclamation is skipped — appropriate for full\n * extension removal).\n */\n removeBlock(label: string): boolean {\n const idx = this.configs.findIndex((c) => c.label === label);\n if (idx === -1) return false;\n\n this.configs.splice(idx, 1);\n this.blocks.delete(label);\n\n for (const id of this._loadedSkills) {\n if (id.startsWith(`${label}:`)) {\n this._loadedSkills.delete(id);\n }\n }\n\n return true;\n }\n\n /**\n * Get a block by label.\n */\n getBlock(label: string): ContextBlock | null {\n return this.blocks.get(label) ?? null;\n }\n\n /**\n * Get all blocks.\n */\n getBlocks(): ContextBlock[] {\n return Array.from(this.blocks.values());\n }\n\n /**\n * Set block content. Writes to provider immediately.\n * Does NOT update the frozen snapshot.\n */\n async setBlock(label: string, content: string): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.writable) {\n throw new Error(`Block \"${label}\" is readonly`);\n }\n\n if (existing.isSkill || existing.isSearchable) {\n throw new Error(\n `Block \"${label}\" is a keyed provider. Use setSkill() or setSearchEntry() instead.`\n );\n }\n\n const tokens = estimateStringTokens(content);\n const maxTokens = config?.maxTokens ?? existing?.maxTokens;\n\n if (maxTokens !== undefined && tokens > maxTokens) {\n throw new Error(\n `Block \"${label}\" exceeds maxTokens: ${tokens} > ${maxTokens}`\n );\n }\n\n const block: ContextBlock = {\n label,\n description: config?.description ?? existing?.description,\n content,\n tokens,\n maxTokens,\n writable: true,\n isSkill: false,\n isSearchable: false\n };\n\n this.blocks.set(label, block);\n\n // Write to provider immediately (durable)\n if (config?.provider && isWritableProvider(config.provider)) {\n await config.provider.set(content);\n }\n\n return block;\n }\n\n /**\n * Set a skill entry within a skill block.\n */\n async setSkill(\n label: string,\n key: string,\n content: string,\n description?: string\n ): Promise<void> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.isSkill) {\n throw new Error(`Block \"${label}\" is not a skill provider`);\n }\n\n const provider = config?.provider;\n if (!provider || !isSkillProvider(provider) || !provider.set) {\n throw new Error(`Block \"${label}\" does not support writes`);\n }\n\n await provider.set(key, content, description);\n\n // Refresh metadata\n const metadata = await provider.get();\n if (metadata) {\n existing.content = metadata;\n existing.tokens = estimateStringTokens(metadata);\n }\n }\n\n /**\n * Load a skill's full content from a skill block.\n */\n async loadSkill(label: string, key: string): Promise<string | null> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n\n if (!config?.provider || !isSkillProvider(config.provider)) {\n throw new Error(`Block \"${label}\" is not a skill provider`);\n }\n\n const content = await config.provider.load(key);\n if (content !== null) {\n this._loadedSkills.add(`${label}:${key}`);\n }\n return content;\n }\n\n /**\n * Unload a previously loaded skill. Updates the stored tool result\n * message via the unload callback (set by Session).\n */\n unloadSkill(label: string, key: string): boolean {\n const id = `${label}:${key}`;\n if (!this._loadedSkills.has(id)) return false;\n this._loadedSkills.delete(id);\n this._onUnloadSkill?.(label, key);\n return true;\n }\n\n /**\n * Get the set of currently loaded skill keys (as \"label:key\" strings).\n */\n getLoadedSkillKeys(): Set<string> {\n return this._loadedSkills;\n }\n\n /**\n * Restore loaded skill tracking from a set of \"label:key\" strings.\n * Used by Session to reconstruct state after hibernation.\n */\n restoreLoadedSkills(skillIds: Iterable<string>): void {\n this._loadedSkills = new Set(skillIds);\n }\n\n /**\n * Clear all loaded skill tracking. Called when messages are cleared.\n */\n clearSkillState(): void {\n this._loadedSkills.clear();\n }\n\n /**\n * Index a search entry within a searchable block.\n */\n async setSearchEntry(\n label: string,\n key: string,\n content: string\n ): Promise<void> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n const existing = this.blocks.get(label);\n\n if (!existing?.isSearchable) {\n throw new Error(`Block \"${label}\" is not a search provider`);\n }\n\n const provider = config?.provider;\n if (!provider || !isSearchProvider(provider) || !provider.set) {\n throw new Error(`Block \"${label}\" does not support writes`);\n }\n\n await provider.set(key, content);\n\n // Refresh summary\n const summary = await provider.get();\n existing.content = summary ?? \"\";\n existing.tokens = estimateStringTokens(existing.content);\n }\n\n /**\n * Search a searchable block.\n */\n async searchContext(label: string, query: string): Promise<string | null> {\n if (!this.loaded) await this.load();\n const config = this.configs.find((c) => c.label === label);\n\n if (!config?.provider || !isSearchProvider(config.provider)) {\n throw new Error(`Block \"${label}\" is not a search provider`);\n }\n\n return config.provider.search(query);\n }\n\n /**\n * Append content to a block.\n */\n async appendToBlock(label: string, content: string): Promise<ContextBlock> {\n if (!this.loaded) await this.load();\n const existing = this.blocks.get(label);\n if (!existing) {\n throw new Error(`Block \"${label}\" not found`);\n }\n const needsSep = existing.content.length > 0 && !content.startsWith(\"\\n\");\n return this.setBlock(\n label,\n existing.content + (needsSep ? \"\\n\" : \"\") + content\n );\n }\n\n /**\n * Get the system prompt string with context blocks.\n *\n * Returns a frozen snapshot: first call renders and caches,\n * subsequent calls return the same string (preserves LLM prefix cache).\n * Call refreshSnapshot() to re-render after block changes take effect.\n */\n toSystemPrompt(): string {\n if (!this.loaded) {\n throw new Error(\"Context blocks not loaded. Call load() first.\");\n }\n\n if (this.snapshot !== null) {\n return this.snapshot;\n }\n\n return this.captureSnapshot();\n }\n\n /**\n * Force re-render the snapshot from current block state.\n */\n refreshSnapshot(): string {\n return this.captureSnapshot();\n }\n\n private captureSnapshot(): string {\n const parts: string[] = [];\n const sep = \"═\".repeat(46);\n\n for (const block of this.blocks.values()) {\n // Skip empty readonly blocks — writable/searchable/skill blocks always\n // render so the LLM knows which tools can address them.\n if (\n !block.content &&\n !block.writable &&\n !block.isSearchable &&\n !block.isSkill\n )\n continue;\n\n let header = block.label.toUpperCase();\n if (block.description) header += ` (${block.description})`;\n if (block.maxTokens) {\n const pct = Math.round((block.tokens / block.maxTokens) * 100);\n header += ` [${pct}% — ${block.tokens}/${block.maxTokens} tokens]`;\n }\n if (block.isSearchable) header += \" [searchable]\";\n else if (block.isSkill) header += \" [loadable]\";\n else if (!block.writable) header += \" [readonly]\";\n else header += \" [writable]\";\n\n parts.push(`${sep}\\n${header}\\n${sep}\\n${block.content}`);\n }\n\n this.snapshot = parts.join(\"\\n\\n\");\n return this.snapshot;\n }\n\n /**\n * Get writable blocks (for tool description).\n */\n getWritableBlocks(): ContextBlock[] {\n return Array.from(this.blocks.values()).filter((b) => b.writable);\n }\n\n /**\n * Check if any skill providers are registered.\n */\n hasSkillBlocks(): boolean {\n return Array.from(this.blocks.values()).some((b) => b.isSkill);\n }\n\n /**\n * Get skill block labels.\n */\n getSkillLabels(): string[] {\n return Array.from(this.blocks.values())\n .filter((b) => b.isSkill)\n .map((b) => b.label);\n }\n\n /**\n * Check if any search providers are registered.\n */\n hasSearchBlocks(): boolean {\n return Array.from(this.blocks.values()).some((b) => b.isSearchable);\n }\n\n /**\n * Get searchable block labels.\n */\n getSearchLabels(): string[] {\n return Array.from(this.blocks.values())\n .filter((b) => b.isSearchable)\n .map((b) => b.label);\n }\n\n // ── Public API ──────────────────────────────────────────────────\n\n /**\n * Return the cached system prompt. If no cached prompt exists,\n * loads blocks from providers, renders, and persists to the store.\n * Subsequent calls return the stored value without re-rendering.\n */\n async freezeSystemPrompt(): Promise<string> {\n if (this.promptStore) {\n const stored = await this.promptStore.get();\n if (stored !== null) return stored;\n }\n\n if (!this.loaded) await this.load();\n const prompt = this.toSystemPrompt();\n\n if (this.promptStore) {\n await this.promptStore.set(prompt);\n }\n\n return prompt;\n }\n\n /**\n * Force reload blocks from providers, re-render the system prompt,\n * and persist to the store. Use this after block content has changed\n * or to invalidate the cached prompt.\n */\n async refreshSystemPrompt(): Promise<string> {\n this.loaded = false;\n await this.load();\n const prompt = this.refreshSnapshot();\n\n if (this.promptStore) {\n await this.promptStore.set(prompt);\n }\n\n return prompt;\n }\n\n /**\n * AI tools for context blocks.\n *\n * Auto-wired based on provider capabilities:\n * - `set_context` — when any block is writable\n * - `load_context` — when any block is a skill provider\n * - `search_context` — when any block is a search provider\n */\n async tools(): Promise<ToolSet> {\n if (!this.loaded) await this.load();\n\n const writable = this.getWritableBlocks();\n const hasSkills = this.hasSkillBlocks();\n const hasSearch = this.hasSearchBlocks();\n const toolSet: ToolSet = {};\n\n // ── set_context ──────────────────────────────────────────────\n\n if (writable.length > 0) {\n const blockDescriptions = writable.map((b) => {\n const kind = b.isSkill\n ? \"skill collection, keyed entries\"\n : b.isSearchable\n ? \"searchable, keyed entries\"\n : \"writable\";\n return `- \"${b.label}\" (${kind}): ${b.description ?? \"no description\"}`;\n });\n const keyedBlocks = writable.filter((b) => b.isSkill || b.isSearchable);\n\n const properties: Record<string, unknown> = {\n label: {\n type: \"string\" as const,\n enum: writable.map((b) => b.label),\n description: \"Block label to write to\"\n },\n content: {\n type: \"string\" as const,\n description: \"The main content to write to the block.\"\n },\n action: {\n type: \"string\" as const,\n enum: [\"replace\", \"append\"],\n description: \"replace (default) or append\"\n }\n };\n\n if (keyedBlocks.length > 0) {\n properties.metadata = {\n type: \"object\" as const,\n description:\n \"Optional metadata for keyed entries (skill collections, searchable blocks: \" +\n keyedBlocks.map((b) => `\"${b.label}\"`).join(\", \") +\n \"). Short content doesn't need metadata; longer loadable entries (skills) \" +\n \"benefit from a title and description so the model can pick the right one \" +\n \"without loading it.\",\n properties: {\n title: {\n type: \"string\" as const,\n description:\n \"Short title. Used as a stable identifier — entries with the \" +\n \"same title are updated in place, different titles create new entries.\"\n },\n description: {\n type: \"string\" as const,\n description:\n \"One-line summary shown alongside the title in the system prompt \" +\n \"so the model can decide when to load the entry.\"\n }\n }\n };\n }\n\n const metadataHint =\n keyedBlocks.length > 0\n ? \"\\n\\nFor keyed blocks (skill collections / searchable), pass \" +\n \"`metadata: { title, description }` — title stabilises updates, \" +\n \"description helps the model pick entries. Metadata is optional; \" +\n \"short content rarely needs it, long loadable entries benefit most.\"\n : \"\";\n\n toolSet.set_context = {\n description: `Write to a context block. Available blocks:\\n${blockDescriptions.join(\"\\n\")}\\n\\nWrites are durable and persist across sessions.${metadataHint}`,\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: properties as Record<string, Record<string, unknown>>,\n required: [\"label\", \"content\"]\n }),\n execute: async ({\n label,\n content,\n metadata,\n action\n }: {\n label: string;\n content: string;\n metadata?: { title?: string; description?: string };\n action?: string;\n }) => {\n try {\n const block = this.blocks.get(label);\n if (!block) return `Error: block \"${label}\" not found`;\n\n if (block.isSkill || block.isSearchable) {\n const title = metadata?.title;\n const description = metadata?.description;\n const key = contextEntryKey(title, content);\n if (block.isSkill) {\n await this.setSkill(label, key, content, description ?? title);\n } else {\n await this.setSearchEntry(label, key, content);\n }\n return `Indexed \"${key}\" in ${label}.`;\n }\n\n const updated =\n action === \"append\"\n ? await this.appendToBlock(label, content)\n : await this.setBlock(label, content);\n const usage = updated.maxTokens\n ? `${Math.round((updated.tokens / updated.maxTokens) * 100)}% (${updated.tokens}/${updated.maxTokens} tokens)`\n : `${updated.tokens} tokens`;\n return `Written to ${label}. Usage: ${usage}`;\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n }\n\n // ── load_context ─────────────────────────────────────────────\n\n if (hasSkills) {\n const skillLabels = this.getSkillLabels();\n\n toolSet.load_context = {\n description:\n \"Load a document from a skill block by key. \" +\n \"Available skill blocks: \" +\n skillLabels.map((l) => `\"${l}\"`).join(\", \") +\n \". Check the system prompt for available keys.\",\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n label: {\n type: \"string\" as const,\n enum: skillLabels,\n description: \"Skill block label\"\n },\n key: {\n type: \"string\" as const,\n description: \"Skill key to load\"\n }\n },\n required: [\"label\", \"key\"]\n }),\n execute: async ({ label, key }: { label: string; key: string }) => {\n try {\n if (!skillLabels.includes(label)) {\n return `Error: \"${label}\" is not a skill block. Skill blocks: ${skillLabels.join(\", \")}`;\n }\n const content = await this.loadSkill(label, key);\n return content ?? `Not found: ${key}`;\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n\n const loadedList = [...this._loadedSkills];\n toolSet.unload_context = {\n description:\n \"Unload a previously loaded skill to free context space. \" +\n \"The skill remains available for re-loading.\" +\n (loadedList.length > 0\n ? \" Currently loaded: \" + loadedList.join(\", \") + \".\"\n : \" No skills currently loaded.\"),\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n label: {\n type: \"string\" as const,\n enum: skillLabels,\n description: \"Skill block label\"\n },\n key: {\n type: \"string\" as const,\n description: \"Skill key to unload\"\n }\n },\n required: [\"label\", \"key\"]\n }),\n execute: async ({ label, key }: { label: string; key: string }) => {\n if (!skillLabels.includes(label)) {\n return `Error: \"${label}\" is not a skill block. Skill blocks: ${skillLabels.join(\", \")}`;\n }\n const unloaded = this.unloadSkill(label, key);\n if (!unloaded) {\n return `Skill \"${key}\" is not currently loaded in \"${label}\".`;\n }\n return `Unloaded \"${key}\" from ${label}. Context reclaimed.`;\n }\n };\n }\n\n // ── search_context ────────────────────────────────────────────\n\n if (hasSearch) {\n const searchLabels = this.getSearchLabels();\n\n toolSet.search_context = {\n description:\n \"Search for information in a searchable context block. \" +\n \"ONLY these blocks are searchable: \" +\n searchLabels.map((l) => `\"${l}\"`).join(\", \") +\n \". Other blocks cannot be searched.\",\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n label: {\n type: \"string\" as const,\n enum: searchLabels,\n description: \"Searchable block label\"\n },\n query: {\n type: \"string\" as const,\n description: \"Search query\"\n }\n },\n required: [\"label\", \"query\"]\n }),\n execute: async ({ label, query }: { label: string; query: string }) => {\n try {\n if (!searchLabels.includes(label)) {\n return `Error: \"${label}\" is not searchable. Searchable blocks: ${searchLabels.join(\", \")}`;\n }\n const results = await this.searchContext(label, query);\n return results ?? \"No results found.\";\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n };\n }\n\n return toolSet;\n }\n}\n","/**\n * Agent Session Provider\n *\n * SQLite-backed provider with tree-structured messages (branching),\n * compaction overlays, and FTS5 search.\n */\n\nimport type { SessionMessage } from \"../types\";\nimport type {\n SessionProvider,\n SearchResult,\n StoredCompaction\n} from \"../provider\";\nimport { COMPACTION_PREFIX } from \"../../utils/compaction-helpers\";\n\nexport interface SqlProvider {\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ): T[];\n}\n\nexport class AgentSessionProvider implements SessionProvider {\n private agent: SqlProvider;\n private initialized = false;\n private sessionId: string;\n\n /**\n * @param agent - Agent or any object with a `sql` tagged template method\n * @param sessionId - Optional session ID to isolate multiple sessions in the same DO.\n * Messages are filtered by session_id within shared tables.\n */\n constructor(agent: SqlProvider, sessionId?: string) {\n this.agent = agent;\n this.sessionId = sessionId ?? \"\";\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL DEFAULT '',\n parent_id TEXT,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n this.agent.sql`\n CREATE INDEX IF NOT EXISTS idx_assistant_msg_parent\n ON assistant_messages(parent_id)\n `;\n\n this.agent.sql`\n CREATE INDEX IF NOT EXISTS idx_assistant_msg_session\n ON assistant_messages(session_id)\n `;\n\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_compactions (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL DEFAULT '',\n summary TEXT NOT NULL,\n from_message_id TEXT NOT NULL,\n to_message_id TEXT NOT NULL,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n this.agent.sql`\n CREATE VIRTUAL TABLE IF NOT EXISTS assistant_fts\n USING fts5(id UNINDEXED, session_id UNINDEXED, role UNINDEXED, content, tokenize='porter unicode61')\n `;\n\n // Reserved for SessionManager metadata (PR #1167) and Think integration (PR #1169)\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_config (\n session_id TEXT NOT NULL,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n PRIMARY KEY (session_id, key)\n )\n `;\n\n this.initialized = true;\n }\n\n // ── Read ───────────────────────────────────────────────────────\n\n getMessage(id: string): SessionMessage | null {\n this.ensureTable();\n const rows = this.agent.sql<{ content: string }>`\n SELECT content FROM assistant_messages WHERE id = ${id} AND session_id = ${this.sessionId}\n `;\n return rows.length > 0 ? this.parse(rows[0].content) : null;\n }\n\n getHistory(leafId?: string | null): SessionMessage[] {\n this.ensureTable();\n\n const leaf = leafId\n ? this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${leafId} AND session_id = ${this.sessionId}\n `[0]\n : this.latestLeafRow();\n\n if (!leaf) return [];\n\n const path = this.agent.sql<{ content: string }>`\n WITH RECURSIVE path AS (\n SELECT *, 0 as depth FROM assistant_messages WHERE id = ${leaf.id}\n UNION ALL\n SELECT m.*, p.depth + 1 FROM assistant_messages m\n JOIN path p ON m.id = p.parent_id\n WHERE m.session_id = ${this.sessionId} AND p.depth < 10000\n )\n SELECT content FROM path ORDER BY depth DESC\n `;\n\n const messages = this.parseRows(path);\n const compactions = this.getCompactions();\n if (compactions.length === 0) return messages;\n return this.applyCompactions(messages, compactions);\n }\n\n getLatestLeaf(): SessionMessage | null {\n this.ensureTable();\n const row = this.latestLeafRow();\n return row ? this.parse(row.content) : null;\n }\n\n getBranches(messageId: string): SessionMessage[] {\n this.ensureTable();\n const rows = this.agent.sql<{ content: string }>`\n SELECT content FROM assistant_messages\n WHERE parent_id = ${messageId} AND session_id = ${this.sessionId} ORDER BY created_at ASC\n `;\n return this.parseRows(rows);\n }\n\n getPathLength(leafId?: string | null): number {\n this.ensureTable();\n const leaf = leafId\n ? this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${leafId} AND session_id = ${this.sessionId}\n `[0]\n : this.latestLeafRow();\n if (!leaf) return 0;\n\n const rows = this.agent.sql<{ count: number }>`\n WITH RECURSIVE path AS (\n SELECT id, parent_id, 0 as depth FROM assistant_messages WHERE id = ${leaf.id}\n UNION ALL\n SELECT m.id, m.parent_id, p.depth + 1 FROM assistant_messages m\n JOIN path p ON m.id = p.parent_id\n WHERE m.session_id = ${this.sessionId} AND p.depth < 10000\n )\n SELECT COUNT(*) as count FROM path\n `;\n return rows[0]?.count ?? 0;\n }\n\n // ── Write ──────────────────────────────────────────────────────\n\n appendMessage(message: SessionMessage, parentId?: string | null): void {\n this.ensureTable();\n // Skip if message already exists (INSERT OR IGNORE idempotency)\n const existing = this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${message.id} AND session_id = ${this.sessionId}\n `;\n if (existing.length > 0) return;\n\n // Honour the `SessionProvider` contract:\n // - `undefined` / omitted → auto-detect (attach to latest leaf)\n // - explicit `null` → create a root message with no parent\n // Using `??` here would collapse those two cases; `parentId !== undefined`\n // preserves the distinction.\n let parent =\n parentId !== undefined ? parentId : (this.latestLeafRow()?.id ?? null);\n\n // Validate parentId belongs to this session\n if (parent) {\n const valid = this.agent.sql<{ id: string }>`\n SELECT id FROM assistant_messages WHERE id = ${parent} AND session_id = ${this.sessionId}\n `;\n if (valid.length === 0) parent = null;\n }\n\n const json = JSON.stringify(message);\n\n this.agent.sql`\n INSERT INTO assistant_messages (id, session_id, parent_id, role, content)\n VALUES (${message.id}, ${this.sessionId}, ${parent}, ${message.role}, ${json})\n `;\n this.indexFTS(message);\n }\n\n updateMessage(message: SessionMessage): void {\n this.ensureTable();\n this.agent.sql`\n UPDATE assistant_messages SET content = ${JSON.stringify(message)}\n WHERE id = ${message.id} AND session_id = ${this.sessionId}\n `;\n this.indexFTS(message);\n }\n\n deleteMessages(messageIds: string[]): void {\n this.ensureTable();\n for (const id of messageIds) {\n this.agent\n .sql`DELETE FROM assistant_messages WHERE id = ${id} AND session_id = ${this.sessionId}`;\n this.deleteFTS(id);\n }\n }\n\n clearMessages(): void {\n this.ensureTable();\n this.agent\n .sql`DELETE FROM assistant_messages WHERE session_id = ${this.sessionId}`;\n this.agent\n .sql`DELETE FROM assistant_compactions WHERE session_id = ${this.sessionId}`;\n // FTS5 requires delete by rowid\n const ftsRows = this.agent.sql<{ rowid: number }>`\n SELECT rowid FROM assistant_fts WHERE session_id = ${this.sessionId}\n `;\n for (const row of ftsRows) {\n this.agent.sql`DELETE FROM assistant_fts WHERE rowid = ${row.rowid}`;\n }\n }\n\n // ── Compaction ─────────────────────────────────────────────────\n\n addCompaction(\n summary: string,\n fromMessageId: string,\n toMessageId: string\n ): StoredCompaction {\n this.ensureTable();\n const id = crypto.randomUUID();\n this.agent.sql`\n INSERT INTO assistant_compactions (id, session_id, summary, from_message_id, to_message_id)\n VALUES (${id}, ${this.sessionId}, ${summary}, ${fromMessageId}, ${toMessageId})\n `;\n return {\n id,\n summary,\n fromMessageId,\n toMessageId,\n createdAt: new Date().toISOString()\n };\n }\n\n getCompactions(): StoredCompaction[] {\n this.ensureTable();\n type Row = {\n id: string;\n summary: string;\n from_message_id: string;\n to_message_id: string;\n created_at: string;\n };\n return this.agent.sql<Row>`\n SELECT * FROM assistant_compactions WHERE session_id = ${this.sessionId} ORDER BY created_at ASC\n `.map((r) => ({\n id: r.id,\n summary: r.summary,\n fromMessageId: r.from_message_id,\n toMessageId: r.to_message_id,\n createdAt: r.created_at\n }));\n }\n\n // ── Search ─────────────────────────────────────────────────────\n\n searchMessages(query: string, limit = 20): SearchResult[] {\n this.ensureTable();\n // Sanitize query: wrap in double quotes to treat as literal phrase,\n // escaping any existing double quotes to prevent FTS5 syntax injection\n const sanitized = `\"${query.replace(/\"/g, '\"\"')}\"`;\n try {\n return this.agent.sql<{ id: string; role: string; content: string }>`\n SELECT f.id, f.role, f.content FROM assistant_fts f\n INNER JOIN assistant_messages m ON m.id = f.id AND m.session_id = f.session_id\n WHERE assistant_fts MATCH ${sanitized} AND f.session_id = ${this.sessionId}\n ORDER BY rank LIMIT ${limit}\n `.map((r) => ({\n id: r.id,\n role: r.role,\n content: r.content\n }));\n } catch {\n // Malformed FTS query — return empty results\n return [];\n }\n }\n\n // ── Internal ───────────────────────────────────────────────────\n\n private latestLeafRow(): { id: string; content: string } | null {\n const rows = this.agent.sql<{ id: string; content: string }>`\n SELECT m.id, m.content FROM assistant_messages m\n LEFT JOIN assistant_messages c ON c.parent_id = m.id AND c.session_id = ${this.sessionId}\n WHERE c.id IS NULL AND m.session_id = ${this.sessionId}\n ORDER BY m.created_at DESC, m.rowid DESC LIMIT 1\n `;\n return rows[0] ?? null;\n }\n\n private indexFTS(message: SessionMessage): void {\n const text = message.parts\n .filter((p) => p.type === \"text\")\n .map((p) => (p as { text: string }).text)\n .join(\" \");\n // Always delete old entry first — handles text→no-text transitions\n this.deleteFTS(message.id);\n if (text) {\n this.agent.sql`\n INSERT INTO assistant_fts (id, session_id, role, content)\n VALUES (${message.id}, ${this.sessionId}, ${message.role}, ${text})\n `;\n }\n }\n\n private deleteFTS(id: string): void {\n const rows = this.agent.sql<{ rowid: number }>`\n SELECT rowid FROM assistant_fts WHERE id = ${id} AND session_id = ${this.sessionId}\n `;\n for (const row of rows) {\n this.agent.sql`DELETE FROM assistant_fts WHERE rowid = ${row.rowid}`;\n }\n }\n\n private applyCompactions(\n messages: SessionMessage[],\n compactions: StoredCompaction[]\n ): SessionMessage[] {\n const ids = messages.map((m) => m.id);\n const result: SessionMessage[] = [];\n let i = 0;\n while (i < messages.length) {\n // Find all compactions starting at this message, pick the latest\n // (widest range) so newer compactions supersede older ones\n const matching = compactions.filter((c) => c.fromMessageId === ids[i]);\n const comp =\n matching.length > 1 ? matching[matching.length - 1] : matching[0];\n if (comp) {\n const endIdx = ids.indexOf(comp.toMessageId);\n if (endIdx >= i) {\n result.push({\n id: `${COMPACTION_PREFIX}${comp.id}`,\n role: \"assistant\",\n parts: [\n {\n type: \"text\",\n text: comp.summary\n }\n ],\n createdAt: new Date()\n } as SessionMessage);\n i = endIdx + 1;\n continue;\n }\n }\n result.push(messages[i]);\n i++;\n }\n return result;\n }\n\n private parse(json: string): SessionMessage | null {\n try {\n const msg = JSON.parse(json);\n if (\n typeof msg?.id === \"string\" &&\n typeof msg?.role === \"string\" &&\n Array.isArray(msg?.parts)\n ) {\n return msg;\n }\n } catch {\n /* skip */\n }\n return null;\n }\n\n private parseRows(rows: { content: string }[]): SessionMessage[] {\n const result: SessionMessage[] = [];\n for (const row of rows) {\n const msg = this.parse(row.content);\n if (msg) result.push(msg);\n }\n return result;\n }\n}\n","/**\n * SQLite Context Block Provider\n *\n * Default durable storage for context blocks using DO SQLite.\n * Each block is a row in cf_agents_context_blocks.\n */\n\nimport type { WritableContextProvider } from \"../context\";\nimport type { SqlProvider } from \"./agent\";\n\nexport class AgentContextProvider implements WritableContextProvider {\n private agent: SqlProvider;\n private label: string;\n private initialized = false;\n\n constructor(agent: SqlProvider, label?: string) {\n this.agent = agent;\n this.label = label ?? \"\";\n }\n\n init(label: string): void {\n if (!this.label) {\n this.label = label;\n }\n }\n\n private ensureTable(): void {\n if (this.initialized) return;\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS cf_agents_context_blocks (\n label TEXT PRIMARY KEY,\n content TEXT NOT NULL,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n this.initialized = true;\n }\n\n async get(): Promise<string | null> {\n this.ensureTable();\n const rows = this.agent.sql<{ content: string }>`\n SELECT content FROM cf_agents_context_blocks WHERE label = ${this.label}\n `;\n return rows[0]?.content ?? null;\n }\n\n async set(content: string): Promise<void> {\n this.ensureTable();\n this.agent.sql`\n INSERT INTO cf_agents_context_blocks (label, content)\n VALUES (${this.label}, ${content})\n ON CONFLICT(label) DO UPDATE SET content = ${content}, updated_at = CURRENT_TIMESTAMP\n `;\n }\n}\n","/**\n * Session — conversation history, context blocks, compaction, search, and tools.\n */\n\nimport type { ToolSet } from \"ai\";\nimport type { SessionProvider, StoredCompaction } from \"./provider\";\nimport type { SessionMessage, SessionOptions } from \"./types\";\nimport {\n ContextBlocks,\n type ContextBlock,\n type ContextConfig,\n type WritableContextProvider\n} from \"./context\";\nimport { AgentSessionProvider, type SqlProvider } from \"./providers/agent\";\nimport { AgentContextProvider } from \"./providers/agent-context\";\nimport type { CompactResult } from \"../utils/compaction-helpers\";\nimport { estimateMessageTokens } from \"../utils/tokens\";\nimport { MessageType } from \"../../../types\";\n\nexport type SessionContextOptions = Omit<ContextConfig, \"label\">;\n\ntype InternalMessageChangeEvent =\n | {\n type: \"append\";\n message: SessionMessage;\n parentId?: string | null;\n inserted: boolean;\n }\n | { type: \"update\"; message: SessionMessage }\n | { type: \"delete\"; messageIds: string[] }\n | { type: \"clear\" }\n | { type: \"compact\" };\n\n// Raw builder entry — provider resolved at init time so chain order doesn't matter\ninterface PendingContext {\n label: string;\n options: SessionContextOptions;\n}\n\n/** Agent-like object that can broadcast to connected clients */\ninterface Broadcaster {\n broadcast(message: string | ArrayBufferLike): void;\n}\n\nfunction isBroadcaster(obj: unknown): obj is Broadcaster {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"broadcast\" in obj &&\n typeof (obj as Broadcaster).broadcast === \"function\"\n );\n}\n\n// Detect whether the argument is a SqlProvider (has sql tagged template method)\nfunction isSqlProvider(arg: SqlProvider | SessionProvider): arg is SqlProvider {\n return \"sql\" in arg && typeof (arg as SqlProvider).sql === \"function\";\n}\n\nexport class Session {\n private storage!: SessionProvider;\n private context!: ContextBlocks;\n\n // Builder state — only used with Session.create()\n private _agent?: SqlProvider;\n private _broadcaster?: Broadcaster;\n private _storageProvider?: SessionProvider;\n private _sessionId?: string;\n private _pending?: PendingContext[];\n private _cachedPrompt?: WritableContextProvider | true;\n private _compactionFn?:\n | ((messages: SessionMessage[]) => Promise<CompactResult | null>)\n | null;\n private _tokenThreshold?: number;\n private _ready = false;\n // Promise for the async skill restore kicked off during _ensureReady().\n // Every async public method awaits this before touching storage or\n // skill-state — guarantees loaded-skill tracking is rehydrated after\n // hibernation, even for async SessionProviders.\n private _restorePromise?: Promise<void>;\n private _messageChangeListener?: (\n event: InternalMessageChangeEvent\n ) => void | Promise<void>;\n\n constructor(storage: SessionProvider, options?: SessionOptions) {\n this.storage = storage;\n this.context = new ContextBlocks(\n options?.context ?? [],\n options?.promptStore\n );\n this._ready = true;\n }\n\n /**\n * Chainable session creation with auto-wired providers.\n *\n * Pass a `SqlProvider` (Agent with `sql` method) for auto-wired SQLite,\n * or a `SessionProvider` directly for custom storage (Postgres, etc.).\n *\n * @example\n * ```ts\n * // Auto-wired SQLite (DO Agent)\n * const session = Session.create(this)\n * .withContext(\"soul\", { provider: { get: async () => \"You are helpful.\" } })\n * .withContext(\"memory\", { description: \"Learned facts\", maxTokens: 1100 })\n * .withCachedPrompt();\n *\n * // Skills from R2 (on-demand loading via load_context tool)\n * const session = Session.create(this)\n * .withContext(\"skills\", {\n * provider: new R2SkillProvider(env.SKILLS_BUCKET, { prefix: \"skills/\" })\n * })\n * .withCachedPrompt();\n *\n * // Custom storage provider (Postgres, etc.)\n * const session = Session.create(postgresProvider)\n * .withContext(\"memory\", {\n * maxTokens: 1100,\n * provider: new PostgresContextProvider(conn, \"memory\")\n * })\n * .withCachedPrompt(new PostgresContextProvider(conn, \"_prompt\"));\n * ```\n */\n static create(provider: SqlProvider | SessionProvider): Session {\n const session: Session = Object.create(Session.prototype);\n if (isSqlProvider(provider)) {\n session._agent = provider;\n if (isBroadcaster(provider)) {\n session._broadcaster = provider;\n }\n } else {\n session._storageProvider = provider;\n }\n session._pending = [];\n session._ready = false;\n return session;\n }\n\n // ── Builder methods ─────────────────────────────────────────────\n\n forSession(sessionId: string): this {\n this._sessionId = sessionId;\n return this;\n }\n\n withContext(label: string, options?: SessionContextOptions): this {\n this._pending!.push({ label, options: options ?? {} });\n return this;\n }\n\n withCachedPrompt(provider?: WritableContextProvider): this {\n this._cachedPrompt = provider ?? true;\n return this;\n }\n\n /**\n * Register a compaction function. Called by `compact()` to compress\n * message history into a summary overlay.\n */\n onCompaction(\n fn: (messages: SessionMessage[]) => Promise<CompactResult | null>\n ): this {\n this._compactionFn = fn;\n return this;\n }\n\n /**\n * Auto-compact when estimated token count exceeds the threshold.\n * Checked after each `appendMessage`. Requires `onCompaction()`.\n */\n compactAfter(tokenThreshold: number): this {\n this._tokenThreshold = tokenThreshold;\n return this;\n }\n\n /**\n * @internal\n * Framework hook for cache-owning callers that need to mirror message\n * storage changes. Application code should use the normal Session methods.\n */\n internal_onMessagesChanged(\n listener:\n | ((event: InternalMessageChangeEvent) => void | Promise<void>)\n | null\n ): this {\n this._messageChangeListener = listener ?? undefined;\n return this;\n }\n\n // ── Lazy init ───────────────────────────────────────────────────\n\n private _ensureReady(): void {\n if (this._ready) return;\n\n // Resolve context configs — sessionId is final by now\n const configs: ContextConfig[] = (this._pending ?? []).map(\n ({ label, options: opts }) => {\n let provider = opts.provider;\n if (!provider && this._agent) {\n // No provider + has SqlProvider → auto-wire to writable SQLite\n const key = this._sessionId ? `${label}_${this._sessionId}` : label;\n provider = new AgentContextProvider(this._agent, key);\n }\n return {\n label,\n description: opts.description,\n maxTokens: opts.maxTokens,\n provider\n };\n }\n );\n\n // Resolve prompt store\n let promptStore: WritableContextProvider | undefined;\n if (this._cachedPrompt === true && this._agent) {\n const key = this._sessionId\n ? `_system_prompt_${this._sessionId}`\n : \"_system_prompt\";\n promptStore = new AgentContextProvider(this._agent, key);\n } else if (this._cachedPrompt && this._cachedPrompt !== true) {\n promptStore = this._cachedPrompt;\n }\n\n // Resolve storage\n if (this._storageProvider) {\n this.storage = this._storageProvider;\n } else if (this._agent) {\n this.storage = new AgentSessionProvider(this._agent, this._sessionId);\n } else {\n throw new Error(\n \"Session.create() requires a SqlProvider or SessionProvider\"\n );\n }\n\n this.context = new ContextBlocks(configs, promptStore);\n this.context.setUnloadCallback((label, key) => {\n this._reclaimLoadedSkill(label, key).catch(() => {});\n });\n this._ready = true;\n // Kick off skill restoration in the background. Async public methods\n // await `_ensureRestored()` before touching skill-tracking state.\n this._restorePromise = this._restoreLoadedSkills().catch(() => {\n // Restore failures are non-fatal: we lose tracking for this DO\n // lifetime but the session itself stays usable.\n });\n }\n\n /**\n * Await the background skill-restore kicked off by `_ensureReady()`.\n * Idempotent and cheap — every async public method calls this so that\n * `_loadedSkills` reflects conversation history before any read or write.\n */\n private async _ensureRestored(): Promise<void> {\n this._ensureReady();\n if (this._restorePromise) await this._restorePromise;\n }\n\n private async _notifyMessagesChanged(\n event: InternalMessageChangeEvent\n ): Promise<void> {\n await this._messageChangeListener?.(event);\n }\n\n /**\n * Reconstruct which skills are loaded by scanning conversation history\n * for load_context tool results that haven't been unloaded.\n * Runs once per init to survive hibernation / eviction, including for\n * async SessionProviders (e.g. Postgres) where we must `await` history.\n */\n private async _restoreLoadedSkills(): Promise<void> {\n const history = await this.storage.getHistory();\n\n const loaded = new Set<string>();\n\n for (const msg of history) {\n if (msg.role !== \"assistant\") continue;\n for (const part of msg.parts) {\n if (\n part.toolName === \"load_context\" &&\n part.state === \"output-available\"\n ) {\n const input = part.input as\n | { label?: string; key?: string }\n | undefined;\n if (input?.label && input?.key) {\n const id = `${input.label}:${input.key}`;\n if (\n typeof part.output === \"string\" &&\n part.output.startsWith(\"[skill unloaded:\")\n ) {\n loaded.delete(id);\n } else {\n loaded.add(id);\n }\n }\n } else if (\n part.toolName === \"unload_context\" &&\n part.state === \"output-available\"\n ) {\n const input = part.input as\n | { label?: string; key?: string }\n | undefined;\n if (input?.label && input?.key) {\n loaded.delete(`${input.label}:${input.key}`);\n }\n }\n }\n }\n\n if (loaded.size > 0) {\n this.context.restoreLoadedSkills(loaded);\n }\n }\n\n /**\n * Reclaim context-window tokens consumed by a previously loaded skill.\n *\n * When a skill is loaded via the `load_context` tool, its full body is\n * embedded as that tool call's `output-available` result inside the\n * assistant message — which means every subsequent turn replays the\n * entire skill as part of the conversation history and pays for it in\n * input tokens.\n *\n * This method walks back through history, finds the matching\n * `load_context` tool result for `(label, key)`, and replaces its bulky\n * `output` with a short marker `[skill unloaded: <key>]`. The skill\n * content is dropped from future turns and the tokens are reclaimed.\n * The skill itself stays available to reload via `load_context`.\n */\n private async _reclaimLoadedSkill(label: string, key: string): Promise<void> {\n const history = await this.storage.getHistory();\n for (let i = history.length - 1; i >= 0; i--) {\n const msg = history[i];\n if (msg.role !== \"assistant\") continue;\n\n let changed = false;\n const newParts = msg.parts.map((part) => {\n if (\n part.toolName === \"load_context\" &&\n part.state === \"output-available\"\n ) {\n const input = part.input as\n | { label?: string; key?: string }\n | undefined;\n if (input?.label === label && input?.key === key) {\n changed = true;\n return { ...part, output: `[skill unloaded: ${key}]` };\n }\n }\n return part;\n });\n\n if (changed) {\n await this.updateMessage({\n ...msg,\n parts: newParts as SessionMessage[\"parts\"]\n });\n return;\n }\n }\n }\n\n // ── History (tree-structured) ─────────────────────────────────\n\n async getHistory(leafId?: string | null): Promise<SessionMessage[]> {\n await this._ensureRestored();\n return this.storage.getHistory(leafId);\n }\n\n async getMessage(id: string): Promise<SessionMessage | null> {\n await this._ensureRestored();\n return this.storage.getMessage(id);\n }\n\n async getLatestLeaf(): Promise<SessionMessage | null> {\n await this._ensureRestored();\n return this.storage.getLatestLeaf();\n }\n\n async getBranches(messageId: string): Promise<SessionMessage[]> {\n await this._ensureRestored();\n return this.storage.getBranches(messageId);\n }\n\n async getPathLength(leafId?: string | null): Promise<number> {\n await this._ensureRestored();\n return this.storage.getPathLength(leafId);\n }\n\n // ── Broadcast ──────────────────────────────────────────────────\n\n private _broadcast(type: MessageType, data: Record<string, unknown>): void {\n if (!this._broadcaster) return;\n this._broadcaster.broadcast(JSON.stringify({ type, ...data }));\n }\n\n private async _emitStatus(\n phase: \"idle\" | \"compacting\",\n extra?: Record<string, unknown>\n ): Promise<number> {\n const tokenEstimate = estimateMessageTokens(await this.getHistory());\n this._broadcast(MessageType.CF_AGENT_SESSION, {\n phase,\n tokenEstimate,\n tokenThreshold: this._tokenThreshold ?? null,\n ...extra\n });\n return tokenEstimate;\n }\n\n private _emitError(error: string): void {\n this._broadcast(MessageType.CF_AGENT_SESSION_ERROR, { error });\n }\n\n // ── Write ─────────────────────────────────────────────────────\n\n async appendMessage(\n message: SessionMessage,\n parentId?: string | null\n ): Promise<void> {\n await this._appendMessage(message, parentId);\n }\n\n private async _appendMessage(\n message: SessionMessage,\n parentId?: string | null\n ): Promise<void> {\n await this._ensureRestored();\n\n const existing = await this.storage.getMessage(message.id);\n if (existing) {\n await this._emitStatus(\"idle\");\n await this._notifyMessagesChanged({\n type: \"append\",\n message,\n parentId,\n inserted: false\n });\n return;\n }\n\n await this.storage.appendMessage(message, parentId);\n\n const tokenEstimate = await this._emitStatus(\"idle\");\n let compacted = false;\n\n if (\n this._tokenThreshold != null &&\n this._compactionFn &&\n tokenEstimate > this._tokenThreshold\n ) {\n try {\n compacted = Boolean(await this.compact());\n } catch {\n // Auto-compact failure is non-fatal — message is already appended\n }\n }\n\n if (!compacted) {\n await this._notifyMessagesChanged({\n type: \"append\",\n message,\n parentId,\n inserted: true\n });\n }\n }\n\n async updateMessage(message: SessionMessage): Promise<void> {\n await this._ensureRestored();\n await this.storage.updateMessage(message);\n await this._emitStatus(\"idle\");\n await this._notifyMessagesChanged({ type: \"update\", message });\n }\n\n async deleteMessages(messageIds: string[]): Promise<void> {\n await this._ensureRestored();\n await this.storage.deleteMessages(messageIds);\n await this._emitStatus(\"idle\");\n await this._notifyMessagesChanged({ type: \"delete\", messageIds });\n }\n\n async clearMessages(): Promise<void> {\n await this._ensureRestored();\n await this.storage.clearMessages();\n this.context.clearSkillState();\n await this.context.refreshSystemPrompt();\n await this._emitStatus(\"idle\");\n await this._notifyMessagesChanged({ type: \"clear\" });\n }\n\n // ── Compaction ────────────────────────────────────────────────\n\n async addCompaction(\n summary: string,\n fromMessageId: string,\n toMessageId: string\n ): Promise<StoredCompaction> {\n await this._ensureRestored();\n return this.storage.addCompaction(summary, fromMessageId, toMessageId);\n }\n\n async getCompactions(): Promise<StoredCompaction[]> {\n await this._ensureRestored();\n return this.storage.getCompactions();\n }\n\n /**\n * Run the registered compaction function and store the result as an overlay.\n * Requires `onCompaction()` to be called first.\n */\n async compact(): Promise<CompactResult | null> {\n await this._ensureRestored();\n if (!this._compactionFn) {\n throw new Error(\n \"No compaction function registered. Call onCompaction() first.\"\n );\n }\n\n const tokensBefore = await this._emitStatus(\"compacting\");\n\n let result: CompactResult | null;\n try {\n result = await this._compactionFn(await this.getHistory());\n } catch (err) {\n this._emitError(err instanceof Error ? err.message : String(err));\n return null;\n }\n\n if (!result) {\n await this._emitStatus(\"idle\");\n return null;\n }\n\n // Validate toMessageId exists in the history\n const historyIds = new Set((await this.getHistory()).map((m) => m.id));\n if (!historyIds.has(result.toMessageId)) {\n await this._emitStatus(\"idle\");\n return null;\n }\n\n // Iterative compaction — extend from earliest existing compaction's start\n const existing = await this.getCompactions();\n const fromId =\n existing.length > 0 ? existing[0].fromMessageId : result.fromMessageId;\n\n await this.addCompaction(result.summary, fromId, result.toMessageId);\n await this.refreshSystemPrompt();\n\n await this._emitStatus(\"idle\", {\n compacted: { tokensBefore }\n });\n await this._notifyMessagesChanged({ type: \"compact\" });\n\n return { ...result, fromMessageId: fromId };\n }\n\n // ── Context Blocks ────────────────────────────────────────────\n\n getContextBlock(label: string): ContextBlock | null {\n this._ensureReady();\n return this.context.getBlock(label);\n }\n\n getContextBlocks(): ContextBlock[] {\n this._ensureReady();\n return this.context.getBlocks();\n }\n\n async replaceContextBlock(\n label: string,\n content: string\n ): Promise<ContextBlock> {\n await this._ensureRestored();\n return this.context.setBlock(label, content);\n }\n\n async appendContextBlock(\n label: string,\n content: string\n ): Promise<ContextBlock> {\n await this._ensureRestored();\n return this.context.appendToBlock(label, content);\n }\n\n /**\n * Dynamically register a new context block after session initialization.\n *\n * This is a **builder / runtime API**, not an LLM tool. The LLM writes\n * into existing context blocks via the `set_context` tool (see\n * `ContextBlocks.tools()`); it cannot declare new blocks itself. This\n * method is how extension / host code contributes blocks at runtime\n * (e.g. an extension's `onLoad` handler registering its own memory block).\n *\n * The block's provider is initialized and loaded immediately.\n * Call `refreshSystemPrompt()` afterward to include the new block\n * in the system prompt.\n *\n * Note: When called without a provider, auto-wires to SQLite via\n * AgentContextProvider. Requires the session to have been created\n * via `Session.create(agent)` (not the direct constructor).\n */\n async addContext(\n label: string,\n options?: SessionContextOptions\n ): Promise<ContextBlock> {\n await this._ensureRestored();\n const opts = options ?? {};\n let provider = opts.provider;\n if (!provider) {\n if (!this._agent) {\n throw new Error(\n `addContext(\"${label}\") requires an explicit provider when Session uses a SessionProvider`\n );\n }\n const key = this._sessionId ? `${label}_${this._sessionId}` : label;\n provider = new AgentContextProvider(this._agent, key);\n }\n return this.context.addBlock({\n label,\n description: opts.description,\n maxTokens: opts.maxTokens,\n provider\n });\n }\n\n /**\n * Remove a dynamically registered context block.\n * Used during extension unload cleanup.\n *\n * Returns true if the block existed and was removed.\n * Call `refreshSystemPrompt()` afterward to rebuild the prompt\n * without the removed block.\n */\n removeContext(label: string): boolean {\n this._ensureReady();\n return this.context.removeBlock(label);\n }\n\n // ── Skills ───────────────────────────────────────────────────\n\n /**\n * Unload a previously loaded skill, reclaiming context space.\n * The tool result in conversation history is replaced with a short marker.\n *\n * Async so that the session's background skill-state restore (which\n * reads conversation history) is awaited first — otherwise a freshly\n * rehydrated DO could report \"not loaded\" for a skill that's actually\n * present in history.\n */\n async unloadSkill(label: string, key: string): Promise<boolean> {\n await this._ensureRestored();\n return this.context.unloadSkill(label, key);\n }\n\n /**\n * Get currently loaded skill keys (as \"label:key\" strings).\n * Async for the same reason as `unloadSkill` — must wait for restore.\n */\n async getLoadedSkillKeys(): Promise<Set<string>> {\n await this._ensureRestored();\n return this.context.getLoadedSkillKeys();\n }\n\n // ── System Prompt ─────────────────────────────────────────────\n\n async freezeSystemPrompt(): Promise<string> {\n await this._ensureRestored();\n return this.context.freezeSystemPrompt();\n }\n\n async refreshSystemPrompt(): Promise<string> {\n await this._ensureRestored();\n return this.context.refreshSystemPrompt();\n }\n\n // ── Search ────────────────────────────────────────────────────\n\n async search(\n query: string,\n options?: { limit?: number }\n ): Promise<\n Array<{\n id: string;\n role: string;\n content: string;\n createdAt?: string;\n }>\n > {\n await this._ensureRestored();\n if (!this.storage.searchMessages) {\n throw new Error(\"Session provider does not support search\");\n }\n return this.storage.searchMessages(query, options?.limit ?? 20);\n }\n\n // ── Tools ─────────────────────────────────────────────────────\n\n /** Returns set_context and load_context tools. */\n async tools(): Promise<ToolSet> {\n await this._ensureRestored();\n return this.context.tools();\n }\n}\n","/**\n * SessionManager — registry of named sessions.\n *\n * Lifecycle: create, get, list, delete, rename.\n * Convenience methods for message ops by session ID.\n * Cross-session search and tools.\n */\n\nimport type { ToolSet } from \"ai\";\nimport { z } from \"zod\";\nimport type { CompactResult } from \"../utils/compaction-helpers\";\nimport type { WritableContextProvider } from \"./context\";\nimport type { StoredCompaction } from \"./provider\";\nimport type { SqlProvider } from \"./providers/agent\";\nimport type { SearchProvider } from \"./search\";\nimport { Session, type SessionContextOptions } from \"./session\";\nimport type { SessionMessage } from \"./types\";\n\nexport interface SessionInfo {\n id: string;\n name: string;\n parent_session_id: string | null;\n model: string | null;\n source: string | null;\n input_tokens: number;\n output_tokens: number;\n estimated_cost: number;\n end_reason: string | null;\n created_at: string;\n updated_at: string;\n}\n\n// Pending context entry — resolved per-session with namespaced providers\ninterface PendingManagerContext {\n label: string;\n options: SessionContextOptions;\n}\n\nexport interface SessionManagerOptions {}\n\nexport class SessionManager {\n private agent!: SqlProvider;\n private _pending: PendingManagerContext[] = [];\n private _cachedPrompt?: WritableContextProvider | true;\n private _compactionFn?:\n | ((messages: SessionMessage[]) => Promise<CompactResult | null>)\n | null;\n private _tokenThreshold?: number;\n private _sessions = new Map<string, Session>();\n private _historyLabel?: string;\n private _tableReady = false;\n private _ready = false;\n\n constructor(agent: SqlProvider, _options: SessionManagerOptions = {}) {\n this.agent = agent;\n this._ready = true;\n this._ensureTable();\n }\n\n /**\n * Chainable SessionManager creation with auto-wired context for all sessions.\n *\n * @example\n * ```ts\n * const manager = SessionManager.create(this)\n * .withContext(\"soul\", { provider: { get: async () => \"You are helpful.\" } })\n * .withContext(\"memory\", { description: \"Learned facts\", maxTokens: 1100 })\n * .withCachedPrompt()\n * .compactAfter(100_000);\n *\n * // Each getSession(id) auto-creates namespaced providers:\n * // memory key: \"memory_<sessionId>\"\n * // prompt key: \"_system_prompt_<sessionId>\"\n * const session = manager.getSession(\"chat-123\");\n * ```\n */\n static create(agent: SqlProvider): SessionManager {\n const mgr: SessionManager = Object.create(SessionManager.prototype);\n mgr.agent = agent;\n mgr._pending = [];\n mgr._compactionFn = null;\n mgr._tokenThreshold = undefined;\n mgr._sessions = new Map();\n mgr._tableReady = false;\n mgr._ready = false;\n return mgr;\n }\n\n // ── Builder methods ─────────────────────────────────────────────\n\n withContext(label: string, options?: SessionContextOptions): this {\n this._pending.push({ label, options: options ?? {} });\n return this;\n }\n\n withCachedPrompt(provider?: WritableContextProvider): this {\n this._cachedPrompt = provider ?? true;\n return this;\n }\n\n /**\n * Register a compaction function propagated to all sessions.\n * Called by `Session.compact()` to compress message history.\n */\n onCompaction(\n fn: (messages: SessionMessage[]) => Promise<CompactResult | null>\n ): this {\n this._compactionFn = fn;\n return this;\n }\n\n /**\n * Auto-compact when estimated token count exceeds the threshold.\n * Propagated to all sessions. Requires `onCompaction()`.\n */\n compactAfter(tokenThreshold: number): this {\n this._tokenThreshold = tokenThreshold;\n return this;\n }\n\n /**\n * Add a searchable context block that searches conversation history\n * across all sessions managed by this manager.\n *\n * The model can use `search_context` to find relevant messages from\n * any session. The block is readonly (no `set`).\n *\n * @example\n * ```ts\n * SessionManager.create(this)\n * .withContext(\"memory\", { maxTokens: 1100 })\n * .withSearchableHistory(\"history\")\n * .withCachedPrompt();\n * ```\n */\n withSearchableHistory(label: string): this {\n this._historyLabel = label;\n return this;\n }\n\n // ── Lazy init ───────────────────────────────────────────────────\n\n private _ensureReady(): void {\n if (this._ready) return;\n this._ready = true;\n this._ensureTable();\n }\n\n private _ensureTable(): void {\n if (this._tableReady) return;\n this.agent.sql`\n CREATE TABLE IF NOT EXISTS assistant_sessions (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n parent_session_id TEXT,\n model TEXT,\n source TEXT,\n input_tokens INTEGER DEFAULT 0,\n output_tokens INTEGER DEFAULT 0,\n estimated_cost REAL DEFAULT 0,\n end_reason TEXT,\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n )\n `;\n this.agent.sql`\n CREATE VIRTUAL TABLE IF NOT EXISTS assistant_fts\n USING fts5(id UNINDEXED, session_id UNINDEXED, role UNINDEXED, content, tokenize='porter unicode61')\n `;\n this._tableReady = true;\n }\n\n private _createHistoryProvider(): SearchProvider {\n const mgr = this;\n return {\n async get() {\n const sessions = mgr.list();\n if (sessions.length === 0) return null;\n return `${sessions.length} session${sessions.length === 1 ? \"\" : \"s\"} available for search.`;\n },\n async search(query: string) {\n const results = mgr.search(query, { limit: 10 });\n if (results.length === 0) return null;\n return results.map((r) => `[${r.role}] ${r.content}`).join(\"\\n---\\n\");\n }\n // No set — conversation history is readonly\n };\n }\n\n // ── Session access ────────────────────────────────────────────\n\n /** Get or create the Session instance for a session ID. */\n getSession(sessionId: string): Session {\n this._ensureReady();\n let session = this._sessions.get(sessionId);\n if (!session) {\n const s = Session.create(this.agent).forSession(sessionId);\n for (const { label, options } of this._pending) {\n s.withContext(label, options);\n }\n if (this._cachedPrompt === true) {\n s.withCachedPrompt();\n } else if (this._cachedPrompt) {\n s.withCachedPrompt(this._cachedPrompt);\n }\n if (this._historyLabel) {\n s.withContext(this._historyLabel, {\n description: \"Cross-session conversation history\",\n provider: this._createHistoryProvider()\n });\n }\n if (this._compactionFn) {\n s.onCompaction(this._compactionFn);\n }\n if (this._tokenThreshold != null) {\n s.compactAfter(this._tokenThreshold);\n }\n session = s;\n this._sessions.set(sessionId, session);\n }\n return session;\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────\n\n create(\n name: string,\n opts?: { parentSessionId?: string; model?: string; source?: string }\n ): SessionInfo {\n this._ensureReady();\n const id = crypto.randomUUID();\n this.agent.sql`\n INSERT INTO assistant_sessions (id, name, parent_session_id, model, source)\n VALUES (${id}, ${name}, ${opts?.parentSessionId ?? null}, ${opts?.model ?? null}, ${opts?.source ?? null})\n `;\n return this.get(id)!;\n }\n\n get(sessionId: string): SessionInfo | null {\n this._ensureReady();\n const rows = this.agent.sql`\n SELECT * FROM assistant_sessions WHERE id = ${sessionId}\n ` as unknown as SessionInfo[];\n return rows[0] ?? null;\n }\n\n list(): SessionInfo[] {\n this._ensureReady();\n return this.agent.sql`\n SELECT * FROM assistant_sessions ORDER BY updated_at DESC\n ` as unknown as SessionInfo[];\n }\n\n async delete(sessionId: string): Promise<void> {\n await this.getSession(sessionId).clearMessages();\n this.agent.sql`DELETE FROM assistant_sessions WHERE id = ${sessionId}`;\n this._sessions.delete(sessionId);\n }\n\n rename(sessionId: string, name: string): void {\n this._ensureReady();\n this.agent.sql`\n UPDATE assistant_sessions SET name = ${name}, updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n }\n\n // ── Message convenience methods ───────────────────────────────\n\n async append(\n sessionId: string,\n message: SessionMessage,\n parentId?: string\n ): Promise<string> {\n await this.getSession(sessionId).appendMessage(message, parentId);\n this._touch(sessionId);\n return message.id;\n }\n\n async upsert(\n sessionId: string,\n message: SessionMessage,\n parentId?: string\n ): Promise<string> {\n const session = this.getSession(sessionId);\n const existing = await session.getMessage(message.id);\n if (existing) {\n await session.updateMessage(message);\n } else {\n await session.appendMessage(message, parentId);\n }\n this._touch(sessionId);\n return message.id;\n }\n\n async appendAll(\n sessionId: string,\n messages: SessionMessage[],\n parentId?: string\n ): Promise<string | null> {\n const session = this.getSession(sessionId);\n let lastParent = parentId ?? null;\n for (const msg of messages) {\n await session.appendMessage(msg, lastParent);\n lastParent = msg.id;\n }\n this._touch(sessionId);\n return lastParent;\n }\n\n async getHistory(\n sessionId: string,\n leafId?: string\n ): Promise<SessionMessage[]> {\n return this.getSession(sessionId).getHistory(leafId);\n }\n\n async getMessageCount(sessionId: string): Promise<number> {\n return this.getSession(sessionId).getPathLength();\n }\n\n async clearMessages(sessionId: string): Promise<void> {\n await this.getSession(sessionId).clearMessages();\n this._touch(sessionId);\n }\n\n async deleteMessages(sessionId: string, messageIds: string[]): Promise<void> {\n await this.getSession(sessionId).deleteMessages(messageIds);\n this._touch(sessionId);\n }\n\n // ── Branching ──────────────────────────────────────────────────\n\n async getBranches(\n sessionId: string,\n messageId: string\n ): Promise<SessionMessage[]> {\n return this.getSession(sessionId).getBranches(messageId);\n }\n\n /**\n * Fork a session at a specific message, creating a new session\n * with the history up to that point copied over.\n */\n async fork(\n sessionId: string,\n atMessageId: string,\n newName: string\n ): Promise<SessionInfo> {\n const info = this.create(newName, { parentSessionId: sessionId });\n const history = await this.getSession(sessionId).getHistory(atMessageId);\n const newSession = this.getSession(info.id);\n\n let parentId: string | null = null;\n for (const msg of history) {\n const newId = crypto.randomUUID();\n const copy: SessionMessage = { ...msg, id: newId };\n await newSession.appendMessage(copy, parentId);\n parentId = newId;\n }\n\n this._touch(info.id);\n return info;\n }\n\n // ── Compaction ────────────────────────────────────────────────\n\n async addCompaction(\n sessionId: string,\n summary: string,\n fromId: string,\n toId: string\n ): Promise<StoredCompaction> {\n return this.getSession(sessionId).addCompaction(summary, fromId, toId);\n }\n\n async getCompactions(sessionId: string): Promise<StoredCompaction[]> {\n return this.getSession(sessionId).getCompactions();\n }\n\n async compactAndSplit(\n sessionId: string,\n summary: string,\n newName?: string\n ): Promise<SessionInfo> {\n const old = this.get(sessionId);\n this.agent.sql`\n UPDATE assistant_sessions SET end_reason = 'compaction', updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n\n const info = this.create(newName ?? old?.name ?? \"Compacted\", {\n parentSessionId: sessionId,\n model: old?.model ?? undefined,\n source: old?.source ?? undefined\n });\n\n await this.append(info.id, {\n id: crypto.randomUUID(),\n role: \"assistant\",\n parts: [\n { type: \"text\", text: `[Context from previous session]\\n\\n${summary}` }\n ]\n });\n\n return info;\n }\n\n // ── Usage tracking ────────────────────────────────────────────\n\n addUsage(\n sessionId: string,\n inputTokens: number,\n outputTokens: number,\n cost: number\n ): void {\n this._ensureReady();\n this.agent.sql`\n UPDATE assistant_sessions SET\n input_tokens = input_tokens + ${inputTokens},\n output_tokens = output_tokens + ${outputTokens},\n estimated_cost = estimated_cost + ${cost},\n updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n }\n\n // ── Search ────────────────────────────────────────────────────\n\n search(query: string, options?: { limit?: number }) {\n this._ensureReady();\n const limit = options?.limit ?? 20;\n // Quote each word individually to prevent FTS5 syntax injection\n // while preserving implicit AND between terms\n const sanitized = query\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => `\"${w.replace(/\"/g, '\"\"')}\"`)\n .join(\" \");\n if (!sanitized) return [];\n try {\n return this.agent.sql<{ id: string; role: string; content: string }>`\n SELECT id, role, content FROM assistant_fts\n WHERE assistant_fts MATCH ${sanitized}\n ORDER BY rank LIMIT ${limit}\n `.map((r) => ({\n id: r.id,\n role: r.role,\n content: r.content,\n createdAt: \"\"\n }));\n } catch {\n return [];\n }\n }\n\n // ── Tools ─────────────────────────────────────────────────────\n\n tools(): ToolSet {\n return {\n session_search: {\n description:\n \"Search past conversations for relevant context. Searches across all sessions.\",\n inputSchema: z.fromJSONSchema({\n type: \"object\" as const,\n properties: {\n query: { type: \"string\" as const, description: \"Search query\" }\n },\n required: [\"query\"]\n }),\n execute: async ({ query }: { query: string }) => {\n try {\n const results = this.search(query, { limit: 10 });\n if (results.length === 0) return \"No results found.\";\n return results\n .map((r) => `[${r.role}] ${r.content}`)\n .join(\"\\n---\\n\");\n } catch (err) {\n return `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n }\n }\n };\n }\n\n // ── Internal ──────────────────────────────────────────────────\n\n private _touch(sessionId: string): void {\n this.agent.sql`\n UPDATE assistant_sessions SET updated_at = CURRENT_TIMESTAMP\n WHERE id = ${sessionId}\n `;\n }\n}\n","/**\n * Postgres connection adapter.\n *\n * Lets the Postgres-backed providers accept either:\n * - a raw `pg.Client` (or any client with a compatible `query` method), or\n * - the internal `PostgresConnection` interface used by tests and custom drivers.\n *\n * When a `pg`-style client is passed, `?` placeholders are rewritten to\n * `$1, $2, ...` on the way through, so the providers can keep using the\n * portable `?` syntax internally without users having to write a wrapper.\n */\n\n/**\n * Minimal connection interface used internally by the Postgres providers.\n * Tests and custom drivers can implement this directly.\n */\nexport interface PostgresConnection {\n execute(\n query: string,\n args?: (string | number | boolean | null)[]\n ): Promise<{ rows: Record<string, unknown>[] }>;\n}\n\n/**\n * Structural type matching `pg.Client` (and most `pg`-compatible pools).\n * Accepts the subset of the real client that the providers need, so users\n * can pass `new pg.Client({ connectionString: env.HYPERDRIVE.connectionString })`\n * directly without a wrapper.\n */\nexport interface PgClientLike {\n query(\n queryText: string,\n values?: readonly unknown[]\n ): Promise<{ rows: Record<string, unknown>[] }>;\n}\n\n/**\n * Accepted client type across the Postgres providers.\n *\n * Use `pg.Client` (the recommended path for Hyperdrive):\n * ```ts\n * const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });\n * await client.connect();\n * new PostgresSessionProvider(client, sessionId);\n * ```\n *\n * Or implement `PostgresConnection` for tests / bespoke drivers.\n */\nexport type PostgresClient = PostgresConnection | PgClientLike;\n\nfunction isPostgresConnection(\n client: PostgresClient\n): client is PostgresConnection {\n return typeof (client as PostgresConnection).execute === \"function\";\n}\n\n/**\n * Normalise an incoming client into a `PostgresConnection`. When given a\n * `pg`-style client we translate `?` placeholders to `$1, $2, ...` so the\n * providers can keep using the portable `?` syntax internally.\n */\nexport function toPostgresConnection(\n client: PostgresClient\n): PostgresConnection {\n if (isPostgresConnection(client)) return client;\n\n const pg = client as PgClientLike;\n return {\n async execute(query, args) {\n let idx = 0;\n const pgQuery = query.replace(/\\?/g, () => `$${++idx}`);\n const result = await pg.query(pgQuery, args ?? []);\n return { rows: result.rows };\n }\n };\n}\n","/**\n * Postgres Session Provider\n *\n * Postgres-backed provider with tree-structured messages,\n * compaction overlays, and full-text search.\n *\n * Accepts either a raw `pg.Client` (recommended for Hyperdrive) or any\n * object implementing the internal `PostgresConnection` interface.\n *\n * ```ts\n * import { Client } from \"pg\";\n * const client = new Client({ connectionString: env.HYPERDRIVE.connectionString });\n * await client.connect();\n * new PostgresSessionProvider(client, sessionId);\n * ```\n *\n * Tables must be created by the customer via migration — see docs for the schema.\n */\n\nimport type {\n SessionProvider,\n SearchResult,\n StoredCompaction\n} from \"../provider\";\nimport type { SessionMessage } from \"../types\";\nimport {\n toPostgresConnection,\n type PostgresClient,\n type PostgresConnection\n} from \"./postgres-adapter\";\n\nexport type {\n PostgresClient,\n PostgresConnection,\n PgClientLike\n} from \"./postgres-adapter\";\n\nexport class PostgresSessionProvider implements SessionProvider {\n private conn: PostgresConnection;\n private sessionId: string;\n\n /**\n * @param client A raw `pg.Client` (recommended) or any `PostgresConnection`.\n * Must already be connected — this provider never opens or closes the\n * underlying client.\n * @param sessionId Session identifier. Different ids are fully isolated\n * rows within the shared tables. Defaults to `\"\"`.\n */\n constructor(client: PostgresClient, sessionId?: string) {\n this.conn = toPostgresConnection(client);\n this.sessionId = sessionId ?? \"\";\n }\n\n // ── Read ───────────────────────────────────────────────────────\n\n async getMessage(id: string): Promise<SessionMessage | null> {\n const { rows } = await this.conn.execute(\n \"SELECT content FROM assistant_messages WHERE id = ? AND session_id = ?\",\n [id, this.sessionId]\n );\n return rows.length > 0 ? this.parse(rows[0].content as string) : null;\n }\n\n async getHistory(leafId?: string | null): Promise<SessionMessage[]> {\n const leaf = leafId\n ? (\n await this.conn.execute(\n \"SELECT id FROM assistant_messages WHERE id = ? AND session_id = ?\",\n [leafId, this.sessionId]\n )\n ).rows[0]\n : await this.latestLeafRow();\n\n if (!leaf) return [];\n\n const { rows } = await this.conn.execute(\n `WITH RECURSIVE path AS (\n SELECT id, parent_id, content, 0 as depth FROM assistant_messages WHERE id = ? AND session_id = ?\n UNION ALL\n SELECT m.id, m.parent_id, m.content, p.depth + 1 FROM assistant_messages m\n JOIN path p ON m.id = p.parent_id\n WHERE m.session_id = ? AND p.depth < 10000\n )\n SELECT content FROM path ORDER BY depth DESC`,\n [leaf.id as string, this.sessionId, this.sessionId]\n );\n\n const messages = this.parseRows(rows);\n const compactions = await this.getCompactions();\n if (compactions.length === 0) return messages;\n return this.applyCompactions(messages, compactions);\n }\n\n async getLatestLeaf(): Promise<SessionMessage | null> {\n const row = await this.latestLeafRow();\n return row ? this.parse(row.content as string) : null;\n }\n\n async getBranches(messageId: string): Promise<SessionMessage[]> {\n const { rows } = await this.conn.execute(\n \"SELECT content FROM assistant_messages WHERE parent_id = ? AND session_id = ? ORDER BY created_at ASC\",\n [messageId, this.sessionId]\n );\n return this.parseRows(rows);\n }\n\n async getPathLength(leafId?: string | null): Promise<number> {\n const leaf = leafId\n ? (\n await this.conn.execute(\n \"SELECT id FROM assistant_messages WHERE id = ? AND session_id = ?\",\n [leafId, this.sessionId]\n )\n ).rows[0]\n : await this.latestLeafRow();\n if (!leaf) return 0;\n\n const { rows } = await this.conn.execute(\n `WITH RECURSIVE path AS (\n SELECT id, parent_id, 0 as depth FROM assistant_messages WHERE id = ? AND session_id = ?\n UNION ALL\n SELECT m.id, m.parent_id, p.depth + 1 FROM assistant_messages m\n JOIN path p ON m.id = p.parent_id\n WHERE m.session_id = ? AND p.depth < 10000\n )\n SELECT COUNT(*) as count FROM path`,\n [leaf.id as string, this.sessionId, this.sessionId]\n );\n return Number(rows[0]?.count ?? 0);\n }\n\n // ── Write ──────────────────────────────────────────────────────\n\n async appendMessage(\n message: SessionMessage,\n parentId?: string | null\n ): Promise<void> {\n // Honour the `SessionProvider` contract:\n // - `undefined` / omitted → auto-detect (attach to latest leaf)\n // - explicit `null` → create a root message with no parent\n // Using `??` here would collapse those two cases; `parentId !== undefined`\n // preserves the distinction.\n let parent =\n parentId !== undefined\n ? parentId\n : (((await this.latestLeafRow())?.id as string | undefined) ?? null);\n\n if (parent) {\n const { rows } = await this.conn.execute(\n \"SELECT id FROM assistant_messages WHERE id = ? AND session_id = ?\",\n [parent, this.sessionId]\n );\n if (rows.length === 0) parent = null;\n }\n\n const json = JSON.stringify(message);\n const text = this.extractSearchableText(json);\n\n await this.conn.execute(\n `INSERT INTO assistant_messages (id, session_id, parent_id, role, content, text_content)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT (session_id, id) DO NOTHING`,\n [message.id, this.sessionId, parent, message.role, json, text]\n );\n }\n\n async updateMessage(message: SessionMessage): Promise<void> {\n const json = JSON.stringify(message);\n await this.conn.execute(\n \"UPDATE assistant_messages SET content = ?, text_content = ? WHERE id = ? AND session_id = ?\",\n [json, this.extractSearchableText(json), message.id, this.sessionId]\n );\n }\n\n async deleteMessages(messageIds: string[]): Promise<void> {\n for (const id of messageIds) {\n await this.conn.execute(\n \"DELETE FROM assistant_messages WHERE id = ? AND session_id = ?\",\n [id, this.sessionId]\n );\n }\n }\n\n async clearMessages(): Promise<void> {\n await this.conn.execute(\n \"DELETE FROM assistant_messages WHERE session_id = ?\",\n [this.sessionId]\n );\n await this.conn.execute(\n \"DELETE FROM assistant_compactions WHERE session_id = ?\",\n [this.sessionId]\n );\n }\n\n // ── Compaction ─────────────────────────────────────────────────\n\n async addCompaction(\n summary: string,\n fromMessageId: string,\n toMessageId: string\n ): Promise<StoredCompaction> {\n const id = crypto.randomUUID();\n await this.conn.execute(\n \"INSERT INTO assistant_compactions (id, session_id, summary, from_message_id, to_message_id) VALUES (?, ?, ?, ?, ?)\",\n [id, this.sessionId, summary, fromMessageId, toMessageId]\n );\n return {\n id,\n summary,\n fromMessageId,\n toMessageId,\n createdAt: new Date().toISOString()\n };\n }\n\n async getCompactions(): Promise<StoredCompaction[]> {\n const { rows } = await this.conn.execute(\n \"SELECT * FROM assistant_compactions WHERE session_id = ? ORDER BY created_at ASC\",\n [this.sessionId]\n );\n return rows.map((r) => ({\n id: r.id as string,\n summary: r.summary as string,\n fromMessageId: r.from_message_id as string,\n toMessageId: r.to_message_id as string,\n createdAt:\n r.created_at instanceof Date\n ? r.created_at.toISOString()\n : String(r.created_at)\n }));\n }\n\n // ── Search ─────────────────────────────────────────────────────\n\n async searchMessages(query: string, limit = 20): Promise<SearchResult[]> {\n const { rows } = await this.conn.execute(\n `SELECT id, role, text_content FROM assistant_messages\n WHERE session_id = ? AND content_tsv @@ plainto_tsquery('english', ?)\n ORDER BY ts_rank(content_tsv, plainto_tsquery('english', ?)) DESC\n LIMIT ?`,\n [this.sessionId, query, query, limit]\n );\n return rows.map((r) => ({\n id: r.id as string,\n role: r.role as string,\n content: (r.text_content as string) ?? \"\",\n createdAt: \"\"\n }));\n }\n\n // ── Internal ───────────────────────────────────────────────────\n\n private async latestLeafRow(): Promise<Record<string, unknown> | null> {\n const { rows } = await this.conn.execute(\n `SELECT m.id, m.content FROM assistant_messages m\n LEFT JOIN assistant_messages c ON c.parent_id = m.id AND c.session_id = ?\n WHERE c.id IS NULL AND m.session_id = ?\n ORDER BY m.created_at DESC LIMIT 1`,\n [this.sessionId, this.sessionId]\n );\n return rows[0] ?? null;\n }\n\n private applyCompactions(\n messages: SessionMessage[],\n compactions: StoredCompaction[]\n ): SessionMessage[] {\n const ids = messages.map((m) => m.id);\n const result: SessionMessage[] = [];\n let i = 0;\n while (i < messages.length) {\n const matching = compactions.filter((c) => c.fromMessageId === ids[i]);\n const comp =\n matching.length > 1 ? matching[matching.length - 1] : matching[0];\n if (comp) {\n const endIdx = ids.indexOf(comp.toMessageId);\n if (endIdx >= i) {\n result.push({\n id: `compaction_${comp.id}`,\n role: \"assistant\",\n parts: [\n {\n type: \"text\",\n text: comp.summary\n }\n ],\n createdAt: new Date()\n });\n i = endIdx + 1;\n continue;\n }\n }\n result.push(messages[i]);\n i++;\n }\n return result;\n }\n\n private parse(json: string): SessionMessage | null {\n try {\n const msg = JSON.parse(json);\n if (\n typeof msg?.id === \"string\" &&\n typeof msg?.role === \"string\" &&\n Array.isArray(msg?.parts)\n ) {\n return msg;\n }\n } catch {\n /* skip */\n }\n return null;\n }\n\n private parseRows(rows: Record<string, unknown>[]): SessionMessage[] {\n const result: SessionMessage[] = [];\n for (const row of rows) {\n const msg = this.parse(row.content as string);\n if (msg) result.push(msg);\n }\n return result;\n }\n\n /**\n * Extract just the human-readable text from a message's JSON blob\n * and store it in `text_content`, which feeds the generated `content_tsv`\n * column used for FTS. The full structured message (parts, tool calls,\n * metadata) is still stored verbatim in `content` — this is the source\n * of truth. Indexing the raw JSON would return FTS hits on keys like\n * `\"role\"`, `\"parts\"`, `\"dynamic-tool\"`, etc.\n */\n private extractSearchableText(json: string): string {\n const msg = this.parse(json);\n if (!msg) return json;\n return msg.parts\n .filter((p) => p.type === \"text\" && p.text)\n .map((p) => p.text)\n .join(\"\\n\");\n }\n}\n","/**\n * Postgres Context Block Provider\n *\n * Durable storage for context blocks using Postgres.\n * Table must be created by the customer via migration — see docs for the schema.\n */\n\nimport type { WritableContextProvider } from \"../context\";\nimport {\n toPostgresConnection,\n type PostgresClient,\n type PostgresConnection\n} from \"./postgres-adapter\";\n\nexport class PostgresContextProvider implements WritableContextProvider {\n private conn: PostgresConnection;\n private label: string;\n\n /**\n * @param client A raw `pg.Client` (recommended) or any `PostgresConnection`.\n * Must already be connected.\n * @param label Block label used as the primary key row in\n * `cf_agents_context_blocks`. Pass a session-scoped label (e.g.\n * `` `memory_${sessionId}` ``) for per-session state.\n */\n constructor(client: PostgresClient, label: string) {\n this.conn = toPostgresConnection(client);\n this.label = label;\n }\n\n async get(): Promise<string | null> {\n const { rows } = await this.conn.execute(\n \"SELECT content FROM cf_agents_context_blocks WHERE label = ?\",\n [this.label]\n );\n return (rows[0]?.content as string) ?? null;\n }\n\n async set(content: string): Promise<void> {\n await this.conn.execute(\n `INSERT INTO cf_agents_context_blocks (label, content)\n VALUES (?, ?)\n ON CONFLICT (label) DO UPDATE SET content = EXCLUDED.content, updated_at = NOW()`,\n [this.label, content]\n );\n }\n}\n","/**\n * Postgres Search Provider\n *\n * Full-text searchable context blocks backed by Postgres.\n * Uses tsvector + GIN index for ranked search.\n *\n * Requires migration — see docs for the schema:\n *\n * CREATE TABLE cf_agents_search_entries (\n * label TEXT NOT NULL,\n * key TEXT NOT NULL,\n * content TEXT NOT NULL,\n * content_tsv TSVECTOR GENERATED ALWAYS AS (to_tsvector('english', content)) STORED,\n * created_at TIMESTAMPTZ DEFAULT NOW(),\n * updated_at TIMESTAMPTZ DEFAULT NOW(),\n * PRIMARY KEY (label, key)\n * );\n * CREATE INDEX idx_search_entries_fts ON cf_agents_search_entries USING GIN (content_tsv);\n */\n\nimport type { SearchProvider } from \"../search\";\nimport {\n toPostgresConnection,\n type PostgresClient,\n type PostgresConnection\n} from \"./postgres-adapter\";\n\nexport class PostgresSearchProvider implements SearchProvider {\n private conn: PostgresConnection;\n private label = \"\";\n\n /**\n * @param client A raw `pg.Client` (recommended) or any `PostgresConnection`.\n * Must already be connected.\n */\n constructor(client: PostgresClient) {\n this.conn = toPostgresConnection(client);\n }\n\n init(label: string): void {\n this.label = label;\n }\n\n async get(): Promise<string | null> {\n const { rows } = await this.conn.execute(\n \"SELECT COUNT(*) as count FROM cf_agents_search_entries WHERE label = ?\",\n [this.label]\n );\n const count = Number(rows[0]?.count ?? 0);\n if (count === 0) return null;\n return `${count} entries indexed.`;\n }\n\n async search(query: string): Promise<string | null> {\n if (!query.trim()) return null;\n\n const { rows } = await this.conn.execute(\n `SELECT key, content FROM cf_agents_search_entries\n WHERE label = ? AND content_tsv @@ plainto_tsquery('english', ?)\n ORDER BY ts_rank(content_tsv, plainto_tsquery('english', ?)) DESC\n LIMIT 10`,\n [this.label, query, query]\n );\n\n if (rows.length === 0) return \"No results found.\";\n return rows\n .map((r) => `[${r.key as string}]\\n${r.content as string}`)\n .join(\"\\n\\n\");\n }\n\n async set(key: string, content: string): Promise<void> {\n await this.conn.execute(\n `INSERT INTO cf_agents_search_entries (label, key, content)\n VALUES (?, ?, ?)\n ON CONFLICT (label, key) DO UPDATE SET\n content = EXCLUDED.content,\n updated_at = NOW()`,\n [this.label, key, content]\n );\n }\n}\n"],"mappings":"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"}
|