Skip to content

Commit 293af5b

Browse files
committed
logging and caching
1 parent f093cb4 commit 293af5b

4 files changed

Lines changed: 66 additions & 46 deletions

File tree

packages/core/src/agent.ts

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,33 @@ import { GenerationOptions } from "./generation"
99
import { HTMLEscape } from "./html"
1010
import { prettifyMarkdown } from "./markdown"
1111
import { TraceOptions } from "./trace"
12-
import { logVerbose } from "./util"
12+
import { ellipse } from "./util"
13+
import debug from "debug"
14+
const dbg = debug("agent:memory")
15+
16+
export type AgentMemoryCacheKey = { agent: string; query: string }
17+
export type AgentMemoryCacheValue = AgentMemoryCacheKey & {
18+
answer: string
19+
createdAt: number
20+
}
21+
export type AgentMemoryCache = WorkspaceFileCache<
22+
AgentMemoryCacheKey,
23+
AgentMemoryCacheValue
24+
>
25+
26+
export function agentCreateCache(
27+
options: Pick<GenerationOptions, "userState"> & { lookupOnly?: boolean }
28+
): AgentMemoryCache {
29+
const cache = createCache<AgentMemoryCacheKey, AgentMemoryCacheValue>(
30+
AGENT_MEMORY_CACHE_NAME,
31+
{
32+
type: "memory",
33+
userState: options.userState,
34+
lookupOnly: options.lookupOnly,
35+
}
36+
)
37+
return cache
38+
}
1339

1440
/**
1541
* Queries the agent's memory to retrieve contextual information relevant to a given query.
@@ -26,17 +52,19 @@ import { logVerbose } from "./util"
2652
* @returns Memory answer or undefined if no relevant memories are retrieved.
2753
*/
2854
export async function agentQueryMemory(
55+
cache: AgentMemoryCache,
2956
ctx: ChatGenerationContext,
3057
query: string,
31-
options: Pick<GenerationOptions, "userState"> & Required<TraceOptions>
58+
options: Required<TraceOptions>
3259
) {
3360
if (!query) return undefined
3461

35-
const memories = await loadMemories(options)
62+
const memories = await loadMemories(cache)
3663
if (!memories?.length) return undefined
3764

3865
let memoryAnswer: string | undefined
3966
// always pre-query memory with cheap model
67+
dbg(`query: ${query}`)
4068
const res = await ctx.runPrompt(
4169
async (_) => {
4270
_.$`Return the contextual information useful to answer <QUERY> from the content in <MEMORY>.
@@ -47,18 +75,21 @@ export async function agentQueryMemory(
4775
"system"
4876
)
4977
_.def("QUERY", query)
50-
await defMemory(_)
78+
await defMemory(cache, _)
5179
},
5280
{
5381
model: "memory",
5482
system: [],
5583
flexTokens: AGENT_MEMORY_FLEX_TOKENS,
5684
label: "agent memory query",
85+
cache: "agent_memory",
5786
}
5887
)
5988
if (!res.error)
6089
memoryAnswer = res.text.includes(TOKEN_NO_ANSWER) ? "" : res.text
61-
else logVerbose(`agent memory query error: ${errorMessage(res.error)}`)
90+
else dbg(`error: ${errorMessage(res.error)}`)
91+
92+
dbg(`answer: ${ellipse(memoryAnswer, 128)}`)
6293
return memoryAnswer
6394
}
6495

@@ -73,25 +104,20 @@ export async function agentQueryMemory(
73104
* @param options - Configuration options, including user state and tracing details.
74105
*/
75106
export async function agentAddMemory(
107+
cache: AgentMemoryCache,
76108
agent: string,
77109
query: string,
78110
text: string,
79-
options: Pick<GenerationOptions, "userState"> & Required<TraceOptions>
111+
options: Required<TraceOptions>
80112
) {
81113
const { trace } = options || {}
82-
const cache = createCache<
83-
{ agent: string; query: string },
84-
{
85-
agent: string
86-
query: string
87-
answer: string
88-
}
89-
>(AGENT_MEMORY_CACHE_NAME)
90-
const cacheKey = { agent, query }
91-
const cachedValue = {
114+
const cacheKey: AgentMemoryCacheKey = { agent, query }
115+
const cachedValue: AgentMemoryCacheValue = {
92116
...cacheKey,
93117
answer: text,
118+
createdAt: Date.now(),
94119
}
120+
dbg(`add ${agent}: ${ellipse(query, 80)} -> ${ellipse(text, 128)}`)
95121
await cache.set(cacheKey, cachedValue)
96122
trace.detailsFenced(
97123
`🧠 agent memory: ${HTMLEscape(query)}`,
@@ -100,19 +126,9 @@ export async function agentAddMemory(
100126
)
101127
}
102128

103-
async function loadMemories(options: Pick<GenerationOptions, "userState">) {
104-
const cache = createCache<
105-
{ agent: string; query: string },
106-
{
107-
agent: string
108-
query: string
109-
answer: string
110-
}
111-
>(AGENT_MEMORY_CACHE_NAME, {
112-
lookupOnly: true,
113-
userState: options.userState,
114-
})
129+
async function loadMemories(cache: AgentMemoryCache) {
115130
const memories = await cache?.values()
131+
memories?.sort((l, r) => l.createdAt - r.createdAt)
116132
return memories
117133
}
118134

@@ -131,7 +147,11 @@ export async function traceAgentMemory(
131147
options: Pick<GenerationOptions, "userState"> & Required<TraceOptions>
132148
) {
133149
const { trace } = options || {}
134-
const memories = await loadMemories(options)
150+
const cache = agentCreateCache({
151+
userState: options.userState,
152+
lookupOnly: true,
153+
})
154+
const memories = await loadMemories(cache)
135155
if (memories) {
136156
try {
137157
trace.startDetails("🧠 agent memory")
@@ -150,15 +170,10 @@ export async function traceAgentMemory(
150170
}
151171
}
152172

153-
async function defMemory(ctx: ChatTurnGenerationContext) {
154-
const cache = createCache<
155-
{ agent: string; query: string },
156-
{
157-
agent: string
158-
query: string
159-
answer: string
160-
}
161-
>(AGENT_MEMORY_CACHE_NAME)
173+
async function defMemory(
174+
cache: AgentMemoryCache,
175+
ctx: ChatTurnGenerationContext
176+
) {
162177
const memories = await cache.values()
163178
memories.reverse().forEach(({ agent, query, answer }, index) =>
164179
ctx.def(

packages/core/src/chatcache.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export function getChatCompletionCache(
2525
name?: string
2626
): ChatCompletationRequestCache {
2727
return createCache<ChatCompletionRequestCacheKey, ChatCompletionResponse>(
28-
name || CHAT_CACHE
28+
name || CHAT_CACHE,
29+
{ type: "fs" }
2930
)
3031
}

packages/core/src/runpromptcontext.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ import { resolveScript } from "./ast"
8787
import { dedent } from "./indent"
8888
import { runtimeHost } from "./host"
8989
import { writeFileEdits } from "./fileedits"
90-
import { agentAddMemory, agentQueryMemory } from "./agent"
90+
import { agentAddMemory, agentCreateCache, agentQueryMemory } from "./agent"
9191
import { YAMLStringify } from "./yaml"
9292
import { Project } from "./server/messages"
9393
import { mergeEnvVarsWithSystem, parametersToVars } from "./vars"
@@ -470,6 +470,7 @@ export function createChatGenerationContext(
470470
}
471471
}
472472

473+
const adbgm = debug(`agent:memory`)
473474
const defAgent = (
474475
name: string,
475476
description: string,
@@ -488,11 +489,12 @@ export function createChatGenerationContext(
488489
disableMemoryQuery,
489490
...rest
490491
} = options || {}
491-
const memory = !disableMemory
492+
const memory = disableMemory
493+
? undefined
494+
: agentCreateCache({ userState })
492495

493496
name = name.replace(/^agent_/i, "")
494497
const adbg = debug(`agent:${name}`)
495-
const adbgm = debug(`agent:${name}:memory`)
496498
adbg(`created ${variant || ""}`)
497499
const agentName = `agent_${name}${variant ? "_" + variant : ""}`
498500
const agentLabel = `agent ${name}${variant ? " " + variant : ""}`
@@ -547,12 +549,13 @@ export function createChatGenerationContext(
547549
let memoryAnswer: string
548550
if (memory && query && !disableMemoryQuery) {
549551
memoryAnswer = await agentQueryMemory(
552+
memory,
550553
ctx,
551554
query +
552555
(hasExtraArgs
553556
? `\n${YAMLStringify(argsNoQuery)}`
554557
: ""),
555-
{ userState, trace }
558+
{ trace }
556559
)
557560
if (memoryAnswer) adbgm(`found ${memoryAnswer}`)
558561
}
@@ -590,11 +593,11 @@ export function createChatGenerationContext(
590593
) {
591594
adbgm(`add ${text}`)
592595
await agentAddMemory(
596+
memory,
593597
agentName,
594598
query,
595599
text,
596600
{
597-
userState,
598601
trace,
599602
}
600603
)
@@ -836,7 +839,8 @@ export function createChatGenerationContext(
836839
? TRANSCRIPTION_CACHE_NAME
837840
: typeof cache === "string"
838841
? cache
839-
: undefined
842+
: undefined,
843+
{ type: "fs" }
840844
)
841845
if (cache) {
842846
const hit = await _cache.getOrUpdate(

packages/core/src/vectorsearch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export function createCachedEmbedder(
5656
const cache: EmbeddingsCache = createCache<
5757
EmbeddingsCacheKey,
5858
EmbeddingsResponse
59-
>(cacheName || "embeddings")
59+
>(cacheName || "embeddings", { type: "fs" })
6060

6161
return async (inputs: string, cfg, options) => {
6262
const key: EmbeddingsCacheKey = {

0 commit comments

Comments
 (0)