Skip to content

Commit 1b7199b

Browse files
anandgupta42claude
andcommitted
feat: wire up memory injection into system prompt with telemetry
- Inject memory blocks into system prompt at session start, gated by ALTIMATE_DISABLE_MEMORY flag - Add memory_operation and memory_injection telemetry events to App Insights - Add memory tool categorization for telemetry - Document disabling memory for benchmarks/CI - Add injection integration tests and telemetry event tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3374b61 commit 1b7199b

7 files changed

Lines changed: 465 additions & 1 deletion

File tree

docs/docs/data-engineering/tools/memory-tools.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,27 @@ Files are human-readable and editable. You can create, edit, or delete them manu
132132

133133
Blocks are written to a temporary file first, then atomically renamed. This prevents corruption if the process is interrupted mid-write.
134134

135+
## Disabling memory
136+
137+
Set the environment variable to disable all memory functionality — tools and automatic injection:
138+
139+
```bash
140+
ALTIMATE_DISABLE_MEMORY=true
141+
```
142+
143+
This is useful for **benchmarks**, CI pipelines, or any environment where persistent memory should not influence agent behavior. When disabled, memory tools are removed from the tool registry and no memory blocks are injected into the system prompt.
144+
135145
## Context window impact
136146

137-
Altimate Memory injects relevant blocks into the system prompt at session start, subject to a configurable token budget (default: 8,000 characters). Blocks are sorted by last-updated timestamp, so the most recently relevant information is loaded first.
147+
Altimate Memory automatically injects relevant blocks into the system prompt at session start, subject to a configurable token budget (default: 8,000 characters). Blocks are sorted by last-updated timestamp, so the most recently relevant information is loaded first. The agent also has access to memory tools (`altimate_memory_read`, `altimate_memory_write`, `altimate_memory_delete`) to manage blocks on demand during a session.
138148

139149
**What this means in practice:**
140150

141151
- With a typical block size of 200-500 characters, the default budget comfortably fits 15-40 blocks
142152
- Memory injection adds a one-time cost at session start — it does not grow during the session
143153
- If you notice context pressure, reduce the number of blocks or keep them concise
144154
- The agent's own tool calls and responses consume far more context than memory blocks
155+
- To disable injection entirely (e.g., for benchmarks), set `ALTIMATE_DISABLE_MEMORY=true`
145156

146157
!!! tip
147158
Keep blocks concise and focused. A block titled "warehouse-config" with 5 bullet points is better than a wall of text. The agent can always call `altimate_memory_read` to fetch specific blocks on demand.

packages/opencode/src/altimate/telemetry/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,26 @@ export namespace Telemetry {
254254
tool_count: number
255255
resource_count: number
256256
}
257+
| {
258+
type: "memory_operation"
259+
timestamp: number
260+
session_id: string
261+
operation: "write" | "delete"
262+
scope: "global" | "project"
263+
block_id: string
264+
is_update: boolean
265+
duplicate_count: number
266+
tags_count: number
267+
}
268+
| {
269+
type: "memory_injection"
270+
timestamp: number
271+
session_id: string
272+
block_count: number
273+
total_chars: number
274+
budget: number
275+
scopes_used: string[]
276+
}
257277

258278
const FILE_TOOLS = new Set(["read", "write", "edit", "glob", "grep", "bash"])
259279

@@ -266,6 +286,7 @@ export namespace Telemetry {
266286
{ category: "dbt", keywords: ["dbt"] },
267287
{ category: "warehouse", keywords: ["warehouse", "connection"] },
268288
{ category: "lineage", keywords: ["lineage", "dag"] },
289+
{ category: "memory", keywords: ["memory"] },
269290
]
270291

271292
export function categorizeToolName(name: string, type: "standard" | "mcp"): string {

packages/opencode/src/memory/prompt.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { MemoryStore, isExpired } from "./store"
22
import { MEMORY_DEFAULT_INJECTION_BUDGET, type MemoryBlock } from "./types"
3+
import { Telemetry } from "@/altimate/telemetry"
34

45
export namespace MemoryPrompt {
56
export function formatBlock(block: MemoryBlock): string {
@@ -26,6 +27,8 @@ export namespace MemoryPrompt {
2627
const header = "## Altimate Memory\n\nThe following memory blocks were saved from previous sessions:\n"
2728
let result = header
2829
let used = header.length
30+
let injectedCount = 0
31+
const scopesSeen = new Set<string>()
2932

3033
for (const block of blocks) {
3134
if (isExpired(block)) continue
@@ -34,6 +37,20 @@ export namespace MemoryPrompt {
3437
if (used + needed > budget) break
3538
result += "\n" + formatted + "\n"
3639
used += needed
40+
injectedCount++
41+
scopesSeen.add(block.scope)
42+
}
43+
44+
if (injectedCount > 0) {
45+
Telemetry.track({
46+
type: "memory_injection",
47+
timestamp: Date.now(),
48+
session_id: Telemetry.getContext().sessionId,
49+
block_count: injectedCount,
50+
total_chars: used,
51+
budget,
52+
scopes_used: [...scopesSeen],
53+
})
3754
}
3855

3956
return result

packages/opencode/src/memory/store.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from "path"
44
import { Global } from "@/global"
55
import { Instance } from "@/project/instance"
66
import { MEMORY_MAX_BLOCK_SIZE, MEMORY_MAX_BLOCKS_PER_SCOPE, MemoryBlockSchema, type MemoryBlock, type Citation } from "./types"
7+
import { Telemetry } from "@/altimate/telemetry"
78

89
const FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/
910

@@ -232,6 +233,18 @@ export namespace MemoryStore {
232233
const action = isUpdate ? "UPDATE" : "CREATE"
233234
await appendAuditLog(block.scope, auditEntry(action, block.id, block.scope))
234235

236+
Telemetry.track({
237+
type: "memory_operation",
238+
timestamp: Date.now(),
239+
session_id: Telemetry.getContext().sessionId,
240+
operation: "write",
241+
scope: block.scope,
242+
block_id: block.id,
243+
is_update: isUpdate,
244+
duplicate_count: duplicates.length,
245+
tags_count: block.tags.length,
246+
})
247+
235248
// Auto-clean expired blocks AFTER successful write to avoid data loss
236249
if (needsCleanup) {
237250
const expiredBlocks = allBlocks.filter((b) => isExpired(b))
@@ -248,6 +261,17 @@ export namespace MemoryStore {
248261
try {
249262
await fs.unlink(filepath)
250263
await appendAuditLog(scope, auditEntry("DELETE", id, scope))
264+
Telemetry.track({
265+
type: "memory_operation",
266+
timestamp: Date.now(),
267+
session_id: Telemetry.getContext().sessionId,
268+
operation: "delete",
269+
scope,
270+
block_id: id,
271+
is_update: false,
272+
duplicate_count: 0,
273+
tags_count: 0,
274+
})
251275
return true
252276
} catch (e: any) {
253277
if (e.code === "ENOENT") return false

packages/opencode/src/session/prompt.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { Bus } from "../bus"
1717
import { ProviderTransform } from "../provider/transform"
1818
import { SystemPrompt } from "./system"
1919
import { InstructionPrompt } from "./instruction"
20+
import { MemoryPrompt } from "../memory/prompt"
2021
import { Plugin } from "../plugin"
2122
import PROMPT_PLAN from "../session/prompt/plan.txt"
2223
import BUILD_SWITCH from "../session/prompt/build-switch.txt"
@@ -712,8 +713,11 @@ export namespace SessionPrompt {
712713
await Plugin.trigger("experimental.chat.messages.transform", {}, { messages: msgs })
713714

714715
// Build system prompt, adding structured output instruction if needed
716+
// Inject persistent memory blocks from previous sessions (gated by feature flag)
717+
const memoryInjection = Flag.ALTIMATE_DISABLE_MEMORY ? "" : await MemoryPrompt.inject()
715718
const system = [
716719
...(await SystemPrompt.environment(model)),
720+
...(memoryInjection ? [memoryInjection] : []),
717721
...(await InstructionPrompt.system()),
718722
...(lastUser.system ? [lastUser.system] : []),
719723
]

0 commit comments

Comments
 (0)