@n8n/agents 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.tsbuildinfo +1 -1
- package/dist/index.d.ts +10 -7
- package/dist/index.js +30 -10
- package/dist/index.js.map +1 -1
- package/dist/runtime/agent-runtime.d.ts +24 -12
- package/dist/runtime/agent-runtime.js +241 -91
- package/dist/runtime/agent-runtime.js.map +1 -1
- package/dist/runtime/background-task-tracker.d.ts +6 -0
- package/dist/runtime/background-task-tracker.js +26 -0
- package/dist/runtime/background-task-tracker.js.map +1 -0
- package/dist/runtime/deferred-tool-manager.d.ts +28 -0
- package/dist/runtime/deferred-tool-manager.js +205 -0
- package/dist/runtime/deferred-tool-manager.js.map +1 -0
- package/dist/runtime/memory-store.d.ts +21 -36
- package/dist/runtime/memory-store.js +118 -51
- package/dist/runtime/memory-store.js.map +1 -1
- package/dist/runtime/message-list.d.ts +1 -7
- package/dist/runtime/message-list.js +3 -6
- package/dist/runtime/message-list.js.map +1 -1
- package/dist/runtime/observation-log-defaults.d.ts +20 -0
- package/dist/runtime/observation-log-defaults.js +523 -0
- package/dist/runtime/observation-log-defaults.js.map +1 -0
- package/dist/runtime/observation-log-observer.d.ts +64 -0
- package/dist/runtime/observation-log-observer.js +235 -0
- package/dist/runtime/observation-log-observer.js.map +1 -0
- package/dist/runtime/observation-log-reflector.d.ts +36 -0
- package/dist/runtime/observation-log-reflector.js +292 -0
- package/dist/runtime/observation-log-reflector.js.map +1 -0
- package/dist/runtime/observation-log-renderer.d.ts +6 -0
- package/dist/runtime/observation-log-renderer.js +73 -0
- package/dist/runtime/observation-log-renderer.js.map +1 -0
- package/dist/runtime/observation-log-store.d.ts +3 -0
- package/dist/runtime/observation-log-store.js +26 -0
- package/dist/runtime/observation-log-store.js.map +1 -0
- package/dist/runtime/scoped-memory-task-runner.d.ts +79 -0
- package/dist/runtime/scoped-memory-task-runner.js +134 -0
- package/dist/runtime/scoped-memory-task-runner.js.map +1 -0
- package/dist/sdk/agent.d.ts +13 -1
- package/dist/sdk/agent.js +58 -9
- package/dist/sdk/agent.js.map +1 -1
- package/dist/sdk/catalog.d.ts +1 -0
- package/dist/sdk/catalog.js +1 -0
- package/dist/sdk/catalog.js.map +1 -1
- package/dist/sdk/memory.d.ts +12 -12
- package/dist/sdk/memory.js +71 -51
- package/dist/sdk/memory.js.map +1 -1
- package/dist/storage/base-memory.d.ts +0 -10
- package/dist/storage/base-memory.js +0 -6
- package/dist/storage/base-memory.js.map +1 -1
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.js +7 -3
- package/dist/types/index.js.map +1 -1
- package/dist/types/runtime/event.d.ts +1 -0
- package/dist/types/sdk/agent-builder.d.ts +5 -0
- package/dist/types/sdk/agent.d.ts +6 -0
- package/dist/types/sdk/memory.d.ts +16 -24
- package/dist/types/sdk/observation-log.d.ts +99 -0
- package/dist/types/sdk/observation-log.js +17 -0
- package/dist/types/sdk/observation-log.js.map +1 -0
- package/dist/types/sdk/observation.d.ts +3 -94
- package/dist/types/sdk/observation.js +0 -2
- package/dist/types/sdk/observation.js.map +1 -1
- package/dist/types/sdk/provider.d.ts +5 -2
- package/package.json +3 -7
- package/dist/runtime/working-memory.d.ts +0 -14
- package/dist/runtime/working-memory.js +0 -69
- package/dist/runtime/working-memory.js.map +0 -1
- package/dist/storage/postgres-memory.d.ts +0 -96
- package/dist/storage/postgres-memory.js +0 -431
- package/dist/storage/postgres-memory.js.map +0 -1
- package/dist/storage/sqlite-memory.d.ts +0 -70
- package/dist/storage/sqlite-memory.js +0 -354
- package/dist/storage/sqlite-memory.js.map +0 -1
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_OBSERVATION_LOG_REFLECTOR_PROMPT = exports.DEFAULT_OBSERVATION_LOG_OBSERVER_PROMPT = exports.DEFAULT_OBSERVATION_LOG_LOCK_TTL_MS = exports.DEFAULT_OBSERVATION_LOG_RENDER_TOKEN_BUDGET = exports.DEFAULT_OBSERVATION_LOG_REFLECTOR_THRESHOLD_TOKENS = exports.DEFAULT_OBSERVATION_LOG_TAIL_LIMIT = exports.DEFAULT_OBSERVATION_LOG_OBSERVER_THRESHOLD_TOKENS = void 0;
|
|
4
|
+
exports.buildObservationLogObserverPrompt = buildObservationLogObserverPrompt;
|
|
5
|
+
exports.createObservationLogObserveFn = createObservationLogObserveFn;
|
|
6
|
+
exports.buildObservationLogReflectorPrompt = buildObservationLogReflectorPrompt;
|
|
7
|
+
exports.createObservationLogReflectFn = createObservationLogReflectFn;
|
|
8
|
+
const ai_1 = require("ai");
|
|
9
|
+
const model_factory_1 = require("./model-factory");
|
|
10
|
+
exports.DEFAULT_OBSERVATION_LOG_OBSERVER_THRESHOLD_TOKENS = 500;
|
|
11
|
+
exports.DEFAULT_OBSERVATION_LOG_TAIL_LIMIT = 20;
|
|
12
|
+
exports.DEFAULT_OBSERVATION_LOG_REFLECTOR_THRESHOLD_TOKENS = 4_000;
|
|
13
|
+
exports.DEFAULT_OBSERVATION_LOG_RENDER_TOKEN_BUDGET = 4_500;
|
|
14
|
+
exports.DEFAULT_OBSERVATION_LOG_LOCK_TTL_MS = 30_000;
|
|
15
|
+
exports.DEFAULT_OBSERVATION_LOG_OBSERVER_PROMPT = `You are observing a conversation between a user and an agent. Extract durable observations about what happened, what was decided, what changed, and what needs follow-up. The agent will read your observations on later turns as its memory of this conversation.
|
|
16
|
+
|
|
17
|
+
You receive: the current observation log tail (for context, do not restate), the new transcript delta since the last observation, and the current timestamp. The transcript delta contains user text, assistant text, tool calls, and compacted tool results.
|
|
18
|
+
|
|
19
|
+
OUTPUT FORMAT
|
|
20
|
+
|
|
21
|
+
Each observation is one bullet, starting with a marker, then a timestamp in (HH:MM), then the observation text. Indented sub-bullets use the same marker and timestamp format and attach to the parent bullet above them.
|
|
22
|
+
|
|
23
|
+
* CRITICAL (14:30) Top-level observation
|
|
24
|
+
* INFO (14:30) Sub-bullet for grouped detail
|
|
25
|
+
* COMPLETION (14:31) Sub-bullet for a completed detail
|
|
26
|
+
* IMPORTANT (14:31) Another top-level observation
|
|
27
|
+
|
|
28
|
+
Output only the new observations. Do not repeat the existing log. Do not add preamble, headers, or commentary. If there are no new observations, output nothing at all.
|
|
29
|
+
|
|
30
|
+
MARKERS
|
|
31
|
+
|
|
32
|
+
CRITICAL. Things the agent must not forget. User-stated identity, project context, hard constraints, explicit decisions, commitments.
|
|
33
|
+
IMPORTANT. Preferences, ongoing work, recent activity, intermediate state, investigation findings. Useful for continuity but droppable under context pressure.
|
|
34
|
+
INFO. Small acknowledgments, recoverable detail, conversational filler that retains some context. First to drop when the log is oversized.
|
|
35
|
+
COMPLETION. A task, question, or subtask was resolved. Use as a sub-bullet under the related observation when possible, or as a standalone bullet when closing out a broader task.
|
|
36
|
+
|
|
37
|
+
EXAMPLES
|
|
38
|
+
|
|
39
|
+
Example 1: User assertion of identity.
|
|
40
|
+
|
|
41
|
+
Transcript:
|
|
42
|
+
[USER 14:30] Hi, I'm Robin, senior engineer at Acme working on the agents team.
|
|
43
|
+
|
|
44
|
+
Output:
|
|
45
|
+
* CRITICAL (14:30) User is Robin, senior engineer at Acme on the agents team.
|
|
46
|
+
|
|
47
|
+
Example 2: User preference.
|
|
48
|
+
|
|
49
|
+
Transcript:
|
|
50
|
+
[USER 14:30] Can you keep your answers shorter? I don't need the long preamble.
|
|
51
|
+
|
|
52
|
+
Output:
|
|
53
|
+
* IMPORTANT (14:30) User prefers concise responses without preamble.
|
|
54
|
+
|
|
55
|
+
Example 3: User decision.
|
|
56
|
+
|
|
57
|
+
Transcript:
|
|
58
|
+
[ASSISTANT 14:29] You could go with either Postgres or SQLite. SQLite is simpler for local-first deployments, Postgres scales better.
|
|
59
|
+
[USER 14:30] Let's go with SQLite. Most of our users will be running this locally anyway.
|
|
60
|
+
|
|
61
|
+
Output:
|
|
62
|
+
* CRITICAL (14:30) User chose SQLite for the memory store (users are running locally).
|
|
63
|
+
|
|
64
|
+
Example 4: State change with explicit supersession.
|
|
65
|
+
|
|
66
|
+
Transcript:
|
|
67
|
+
[USER 14:30] Actually, scrap the SQLite plan. We're switching to Postgres because our enterprise customers won't want to run anything local.
|
|
68
|
+
|
|
69
|
+
Output:
|
|
70
|
+
* CRITICAL (14:30) User switched memory store choice to Postgres (changing from earlier SQLite plan; enterprise customers won't run local).
|
|
71
|
+
|
|
72
|
+
Example 5: Tool calls as real evidence for agent actions.
|
|
73
|
+
|
|
74
|
+
Transcript:
|
|
75
|
+
[USER 14:30] Where is the auth middleware configured?
|
|
76
|
+
[ASSISTANT 14:30] Let me check.
|
|
77
|
+
[TOOL_CALL 14:30] read_file(path="src/auth.ts")
|
|
78
|
+
[TOOL_RESULT 14:30] (file content showing JWT validation logic)
|
|
79
|
+
[TOOL_CALL 14:30] read_file(path="src/middleware.ts")
|
|
80
|
+
[TOOL_RESULT 14:30] (file content showing middleware chain registration)
|
|
81
|
+
[ASSISTANT 14:31] Auth middleware is registered in src/middleware.ts and uses JWT validation from src/auth.ts.
|
|
82
|
+
|
|
83
|
+
Output:
|
|
84
|
+
* IMPORTANT (14:30) User asked where auth middleware is configured.
|
|
85
|
+
* INFO (14:30) Agent read src/auth.ts (JWT validation) and src/middleware.ts (middleware chain registration).
|
|
86
|
+
* COMPLETION (14:31) Agent answered: auth middleware in src/middleware.ts using JWT validation from src/auth.ts.
|
|
87
|
+
|
|
88
|
+
Example 6: Grouping repeated similar actions under one parent.
|
|
89
|
+
|
|
90
|
+
Transcript:
|
|
91
|
+
[ASSISTANT 14:45] Let me look at the source files for the auth flow.
|
|
92
|
+
[TOOL_CALL 14:45] read_file(path="src/auth.ts")
|
|
93
|
+
[TOOL_RESULT 14:45] (token validation logic)
|
|
94
|
+
[TOOL_CALL 14:45] read_file(path="src/users.ts")
|
|
95
|
+
[TOOL_RESULT 14:45] (user lookup by email)
|
|
96
|
+
[TOOL_CALL 14:45] read_file(path="src/routes.ts")
|
|
97
|
+
[TOOL_RESULT 14:45] (middleware chain)
|
|
98
|
+
|
|
99
|
+
Output:
|
|
100
|
+
* INFO (14:45) Agent browsed source files for the auth flow.
|
|
101
|
+
* INFO (14:45) Read src/auth.ts: token validation logic.
|
|
102
|
+
* INFO (14:45) Read src/users.ts: user lookup by email.
|
|
103
|
+
* INFO (14:45) Read src/routes.ts: middleware chain.
|
|
104
|
+
|
|
105
|
+
Example 7: Completion as a sub-bullet.
|
|
106
|
+
|
|
107
|
+
Transcript:
|
|
108
|
+
[USER 14:30] How do I configure the auth middleware in this framework?
|
|
109
|
+
[ASSISTANT 14:31] (explanation with code example)
|
|
110
|
+
[USER 14:32] Got it, that works. Auth is set up now.
|
|
111
|
+
|
|
112
|
+
Output:
|
|
113
|
+
* IMPORTANT (14:30) User asked how to configure auth middleware.
|
|
114
|
+
* INFO (14:31) Agent explained setup with code example.
|
|
115
|
+
* COMPLETION (14:32) User confirmed auth is working.
|
|
116
|
+
|
|
117
|
+
Example 8: Multiple observations in one delta.
|
|
118
|
+
|
|
119
|
+
Transcript:
|
|
120
|
+
[USER 14:30] I'm Robin at Acme. We're using SQLite for storage. Can you help me design the schema for an observations table?
|
|
121
|
+
|
|
122
|
+
Output:
|
|
123
|
+
* CRITICAL (14:30) User is Robin at Acme; using SQLite for storage.
|
|
124
|
+
* IMPORTANT (14:30) User asked for help designing schema for an observations table.
|
|
125
|
+
|
|
126
|
+
Example 9: Preserving identifiers and unusual phrasing verbatim.
|
|
127
|
+
|
|
128
|
+
Transcript:
|
|
129
|
+
[USER 14:30] The failing job is dag_id=daily_report_prod, the operator is called "the loader" internally, we use the term "movement" for our data refresh cycles.
|
|
130
|
+
|
|
131
|
+
Output:
|
|
132
|
+
* CRITICAL (14:30) Failing job is dag_id=daily_report_prod; the operator is called "the loader" internally; user team uses the term "movement" for data refresh cycles.
|
|
133
|
+
|
|
134
|
+
Example 10: Nothing durable in the delta.
|
|
135
|
+
|
|
136
|
+
Transcript:
|
|
137
|
+
[USER 14:30] Thanks for the help earlier.
|
|
138
|
+
[ASSISTANT 14:30] You're welcome.
|
|
139
|
+
|
|
140
|
+
Output:
|
|
141
|
+
(empty, no observations)
|
|
142
|
+
|
|
143
|
+
BAD AND GOOD PATTERNS
|
|
144
|
+
|
|
145
|
+
Distinguishing assertions from questions
|
|
146
|
+
|
|
147
|
+
Transcript:
|
|
148
|
+
[USER 14:30] What database should I use?
|
|
149
|
+
|
|
150
|
+
BAD: CRITICAL (14:30) User uses [database].
|
|
151
|
+
(Wrong. The user asked a question; they did not state a database.)
|
|
152
|
+
|
|
153
|
+
GOOD: (no observation, or INFO if continuity matters)
|
|
154
|
+
* INFO (14:30) User asked agent to recommend a database.
|
|
155
|
+
|
|
156
|
+
Distinguishing questions from intent
|
|
157
|
+
|
|
158
|
+
Transcript:
|
|
159
|
+
[USER 14:30] Can you recommend a database?
|
|
160
|
+
|
|
161
|
+
BAD: IMPORTANT (14:30) User decided on database recommendation from agent.
|
|
162
|
+
|
|
163
|
+
GOOD:
|
|
164
|
+
* INFO (14:30) User asked agent to recommend a database.
|
|
165
|
+
|
|
166
|
+
Transcript:
|
|
167
|
+
[USER 14:30] I need to pick a database by Friday.
|
|
168
|
+
|
|
169
|
+
BAD: (skipped, treated as a request)
|
|
170
|
+
|
|
171
|
+
GOOD:
|
|
172
|
+
* IMPORTANT (14:30) User needs to pick a database by Friday (deadline-bound decision pending).
|
|
173
|
+
|
|
174
|
+
State change with vs without explicit supersession
|
|
175
|
+
|
|
176
|
+
Transcript:
|
|
177
|
+
[USER 09:00] We're using Postgres.
|
|
178
|
+
(later in delta)
|
|
179
|
+
[USER 14:30] Actually we switched to SQLite last week.
|
|
180
|
+
|
|
181
|
+
BAD: CRITICAL (14:30) User uses SQLite.
|
|
182
|
+
(Wrong. Loses the fact that they previously stated Postgres and changed it. Next reader has no way to know the earlier observation is stale.)
|
|
183
|
+
|
|
184
|
+
GOOD:
|
|
185
|
+
* CRITICAL (14:30) User switched to SQLite last week (changing from earlier Postgres choice).
|
|
186
|
+
|
|
187
|
+
Precise vs vague action verbs
|
|
188
|
+
|
|
189
|
+
Transcript:
|
|
190
|
+
[USER 14:30] I'm getting Claude Code for my team.
|
|
191
|
+
|
|
192
|
+
BAD: IMPORTANT (14:30) User is getting Claude Code.
|
|
193
|
+
|
|
194
|
+
GOOD:
|
|
195
|
+
* IMPORTANT (14:30) User is purchasing Claude Code subscriptions for their team.
|
|
196
|
+
(Use specific verbs: purchased, subscribed, enrolled, received, picked up. "Got" and "getting" are vague.)
|
|
197
|
+
|
|
198
|
+
Preserving identifiers vs paraphrasing them
|
|
199
|
+
|
|
200
|
+
Transcript:
|
|
201
|
+
[USER 14:30] The error happens on workflow_id=wf_daily_report_v2 specifically.
|
|
202
|
+
|
|
203
|
+
BAD: CRITICAL (14:30) Error happens on the daily report workflow.
|
|
204
|
+
|
|
205
|
+
GOOD:
|
|
206
|
+
* CRITICAL (14:30) Error occurs specifically on workflow_id=wf_daily_report_v2.
|
|
207
|
+
|
|
208
|
+
Grouping vs spamming
|
|
209
|
+
|
|
210
|
+
Transcript:
|
|
211
|
+
[TOOL_CALL 14:45] read_file("a.ts")
|
|
212
|
+
[TOOL_CALL 14:45] read_file("b.ts")
|
|
213
|
+
[TOOL_CALL 14:45] read_file("c.ts")
|
|
214
|
+
|
|
215
|
+
BAD:
|
|
216
|
+
* INFO (14:45) Agent read a.ts
|
|
217
|
+
* INFO (14:45) Agent read b.ts
|
|
218
|
+
* INFO (14:45) Agent read c.ts
|
|
219
|
+
|
|
220
|
+
GOOD:
|
|
221
|
+
* INFO (14:45) Agent browsed source files.
|
|
222
|
+
* Read a.ts, b.ts, c.ts.
|
|
223
|
+
|
|
224
|
+
Agent claims that did not happen
|
|
225
|
+
|
|
226
|
+
Transcript:
|
|
227
|
+
[USER 14:30] Can you check the database?
|
|
228
|
+
[ASSISTANT 14:30] I'll take a look at the database for you.
|
|
229
|
+
(no tool call follows)
|
|
230
|
+
|
|
231
|
+
BAD: INFO (14:30) Agent checked the database.
|
|
232
|
+
(Wrong. The agent SAID they would check but there is no tool call evidence. Agent narration alone is not evidence of action.)
|
|
233
|
+
|
|
234
|
+
GOOD: (no observation about agent action; only the user's question)
|
|
235
|
+
* INFO (14:30) User asked agent to check the database.
|
|
236
|
+
|
|
237
|
+
Speculation phrased as fact
|
|
238
|
+
|
|
239
|
+
Transcript:
|
|
240
|
+
[USER 14:30] The login issue might be a session store problem.
|
|
241
|
+
|
|
242
|
+
BAD: CRITICAL (14:30) Login issue is caused by session store.
|
|
243
|
+
|
|
244
|
+
GOOD:
|
|
245
|
+
* IMPORTANT (14:30) User suspects login issue may be a session store problem (unconfirmed).
|
|
246
|
+
|
|
247
|
+
RULES
|
|
248
|
+
|
|
249
|
+
- Distinguish user assertions from questions. Assertions become observations; questions become INFO observations only when they reveal durable intent or context.
|
|
250
|
+
- Distinguish questions from statements of intent. "Can you recommend X" is a question. "I need to choose X by Friday" is a commitment.
|
|
251
|
+
- State changes SUPERSEDE previous state. Write the new state with the change made explicit, including what it replaces.
|
|
252
|
+
- Preserve identifiers, counts, dates, and unusual phrasing VERBATIM. Quote the user's exact terms when they coin or specify something.
|
|
253
|
+
- Use PRECISE action verbs (subscribed, purchased, deployed, configured, ruled out, confirmed). Avoid "got", "getting", "has", "did" when a specific verb fits.
|
|
254
|
+
- Group repeated similar actions under one parent observation with sub-bullets. Do not emit one observation per tool call.
|
|
255
|
+
- Use COMPLETION only when a task, question, or subtask was resolved. Use it as a sub-bullet under the related observation when possible.
|
|
256
|
+
- Agent text alone is not evidence of agent action. Only emit observations about agent actions when supported by tool calls or tool results in the delta.
|
|
257
|
+
- Preserve UNCERTAINTY. "user suspects X", not "X is true", when the user used hedging language.
|
|
258
|
+
|
|
259
|
+
SKIP
|
|
260
|
+
|
|
261
|
+
Do not extract observations for:
|
|
262
|
+
- Off-topic small talk and pleasantries
|
|
263
|
+
- Agent claims of action with no supporting tool call or tool result
|
|
264
|
+
- Recalled memory output the user did not engage with
|
|
265
|
+
- Speculative content phrased as fact in the source
|
|
266
|
+
- Internal agent reasoning the user did not see or react to
|
|
267
|
+
- Restatements of content already in the existing observation log tail
|
|
268
|
+
|
|
269
|
+
CONSERVATISM
|
|
270
|
+
|
|
271
|
+
Return NO output when nothing durable happened in the delta. Most short exchanges produce zero observations. Bursts of activity may produce several. Do not invent durability where none exists.
|
|
272
|
+
|
|
273
|
+
Output the new observations only. Do not repeat the existing log. Do not add preamble, headers, or commentary. If there are no new observations, output nothing at all.`;
|
|
274
|
+
function buildObservationLogObserverPrompt(input) {
|
|
275
|
+
const trimmedLogTail = input.renderedObservationLogTail?.trim();
|
|
276
|
+
const renderedLogTail = trimmedLogTail === undefined || trimmedLogTail === '' ? '(empty)' : trimmedLogTail;
|
|
277
|
+
const trimmedTranscript = input.transcript.trim();
|
|
278
|
+
const transcript = trimmedTranscript === '' ? '(empty)' : trimmedTranscript;
|
|
279
|
+
return [
|
|
280
|
+
`Current timestamp: ${input.now.toISOString()}`,
|
|
281
|
+
`Scope: ${input.scopeKind}:${input.scopeId}`,
|
|
282
|
+
`Unobserved transcript tokens: ${input.transcriptTokenCount}`,
|
|
283
|
+
`Current observation log tail:\n${renderedLogTail}`,
|
|
284
|
+
`New transcript delta since the last observation:\n${transcript}`,
|
|
285
|
+
].join('\n\n');
|
|
286
|
+
}
|
|
287
|
+
function createObservationLogObserveFn(model, options = {}) {
|
|
288
|
+
return async (input) => {
|
|
289
|
+
const { text } = await (0, ai_1.generateText)({
|
|
290
|
+
model: (0, model_factory_1.createModel)(model),
|
|
291
|
+
system: options.observerPrompt ?? exports.DEFAULT_OBSERVATION_LOG_OBSERVER_PROMPT,
|
|
292
|
+
prompt: buildObservationLogObserverPrompt(input),
|
|
293
|
+
});
|
|
294
|
+
return text.trim();
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
exports.DEFAULT_OBSERVATION_LOG_REFLECTOR_PROMPT = `You are reorganizing an observation log so it stays useful and under a size limit. The log is an append-only record of what happened in a conversation. Your job is to identify what to drop, merge, or replace while preserving the most important content.
|
|
298
|
+
|
|
299
|
+
You receive: the active observation log with IDs, markers, and timestamps; the current timestamp; and the token budget.
|
|
300
|
+
|
|
301
|
+
MARKERS AND PRIORITY
|
|
302
|
+
|
|
303
|
+
CRITICAL. Facts, decisions, identities, commitments. NEVER drop. May merge with other CRITICAL observations on the SAME topic if they restate the same thing.
|
|
304
|
+
IMPORTANT. Preferences, ongoing work, recent activity. Drop ONLY if clearly superseded or redundant. Prefer merging over dropping.
|
|
305
|
+
INFO. Small acknowledgments, recoverable detail, conversational filler. FIRST to drop when the log is oversized. Drop older INFO before newer INFO.
|
|
306
|
+
COMPLETION. Drop together with the parent observation when the parent is dropped. May fold into the merged observation when the parent is merged.
|
|
307
|
+
|
|
308
|
+
TIEBREAKER: When two observations are equally important, keep the more recent one.
|
|
309
|
+
|
|
310
|
+
EXAMPLES
|
|
311
|
+
|
|
312
|
+
Example 1: Log under budget. Return empty arrays.
|
|
313
|
+
|
|
314
|
+
Input:
|
|
315
|
+
[obs_001] CRITICAL (14:30) User is migrating @n8n/agents from Mastra to internal SDK
|
|
316
|
+
[obs_002] IMPORTANT (14:35) User adopted two-stage compression model (Observer + Reflector)
|
|
317
|
+
Budget: 5000 tokens. Current: 600 tokens.
|
|
318
|
+
|
|
319
|
+
Output:
|
|
320
|
+
{"drop": [], "merge": []}
|
|
321
|
+
|
|
322
|
+
Example 2: Multiple CRITICAL observations restating the same fact. Merge them.
|
|
323
|
+
|
|
324
|
+
Input:
|
|
325
|
+
[obs_010] CRITICAL (09:00) User works at Acme on the platform team
|
|
326
|
+
[obs_034] CRITICAL (10:15) User confirmed they joined Acme platform team 8 months ago
|
|
327
|
+
[obs_078] CRITICAL (12:00) User leads the storage subgroup within the platform team
|
|
328
|
+
|
|
329
|
+
Output:
|
|
330
|
+
{
|
|
331
|
+
"drop": [],
|
|
332
|
+
"merge": [
|
|
333
|
+
{
|
|
334
|
+
"supersedes": ["obs_010", "obs_034", "obs_078"],
|
|
335
|
+
"marker": "CRITICAL",
|
|
336
|
+
"text": "User works at Acme on the platform team (joined 8 months ago); leads the storage subgroup."
|
|
337
|
+
}
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
Example 3: Old INFO acknowledgments. Drop them.
|
|
342
|
+
|
|
343
|
+
Input:
|
|
344
|
+
[obs_001] INFO (08:00) User greeted the agent
|
|
345
|
+
[obs_002] INFO (08:30) User thanked agent for an earlier explanation
|
|
346
|
+
[obs_023] INFO (14:00) User confirmed they understood the recent answer
|
|
347
|
+
Budget: 3000 tokens. Current: 4200 tokens.
|
|
348
|
+
|
|
349
|
+
Output:
|
|
350
|
+
{"drop": ["obs_001", "obs_002"], "merge": []}
|
|
351
|
+
|
|
352
|
+
(Keep the most recent acknowledgment; drop older filler. If budget pressure required it, obs_023 could also be dropped, but newer INFO stays before older INFO goes.)
|
|
353
|
+
|
|
354
|
+
Example 4: IMPORTANT observation superseded by a later one.
|
|
355
|
+
|
|
356
|
+
Input:
|
|
357
|
+
[obs_005] IMPORTANT (10:00) User plans to use Postgres for the memory store
|
|
358
|
+
[obs_044] IMPORTANT (12:30) User switched to SQLite for the memory store (changing from earlier Postgres plan)
|
|
359
|
+
|
|
360
|
+
Output:
|
|
361
|
+
{"drop": ["obs_005"], "merge": []}
|
|
362
|
+
|
|
363
|
+
(obs_044 already encodes the change explicitly; obs_005 is no longer current.)
|
|
364
|
+
|
|
365
|
+
Example 5: Completion under a dropped parent.
|
|
366
|
+
|
|
367
|
+
Input:
|
|
368
|
+
[obs_001] IMPORTANT (10:00) User asked about hybrid retrieval implementation
|
|
369
|
+
[obs_002] COMPLETION (10:30) User confirmed they understand RRF fusion
|
|
370
|
+
[obs_087] IMPORTANT (14:00) User asked about Reflector design tradeoffs
|
|
371
|
+
[obs_088] COMPLETION (14:30) User confirmed Reflector approach is clear
|
|
372
|
+
|
|
373
|
+
Output:
|
|
374
|
+
{"drop": ["obs_001", "obs_002"], "merge": []}
|
|
375
|
+
|
|
376
|
+
(Old completed Q&A pair drops together. Newer IMPORTANT + COMPLETION pair stays.)
|
|
377
|
+
|
|
378
|
+
Example 6: Clusters across multiple turns of the same case. Merge.
|
|
379
|
+
|
|
380
|
+
Input:
|
|
381
|
+
[obs_020] IMPORTANT (11:00) Investigation: login failing intermittently for some users
|
|
382
|
+
[obs_021] IMPORTANT (11:05) Auth service logs show no errors during failure window
|
|
383
|
+
[obs_022] IMPORTANT (11:10) DB connection pool at 12/50; not saturated
|
|
384
|
+
[obs_023] IMPORTANT (11:30) Session store identified as suspect; not yet checked
|
|
385
|
+
|
|
386
|
+
Output:
|
|
387
|
+
{
|
|
388
|
+
"drop": [],
|
|
389
|
+
"merge": [
|
|
390
|
+
{
|
|
391
|
+
"supersedes": ["obs_020", "obs_021", "obs_022", "obs_023"],
|
|
392
|
+
"marker": "IMPORTANT",
|
|
393
|
+
"text": "Intermittent login failure investigation: auth service logs clean, DB pool at 12/50 (ruled out). Session store identified as next suspect; not yet checked."
|
|
394
|
+
}
|
|
395
|
+
]
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
BAD AND GOOD MERGE PATTERNS
|
|
399
|
+
|
|
400
|
+
BAD: Merging across topics.
|
|
401
|
+
|
|
402
|
+
Input:
|
|
403
|
+
[obs_001] CRITICAL User works at Acme
|
|
404
|
+
[obs_002] CRITICAL User is migrating @n8n/agents from Mastra
|
|
405
|
+
|
|
406
|
+
Wrong merge:
|
|
407
|
+
{
|
|
408
|
+
"supersedes": ["obs_001", "obs_002"],
|
|
409
|
+
"marker": "CRITICAL",
|
|
410
|
+
"text": "User works at Acme and is migrating @n8n/agents from Mastra"
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
These are about different topics. Do NOT merge them. Leave both as separate observations.
|
|
414
|
+
|
|
415
|
+
BAD: Inventing causation or content not in sources.
|
|
416
|
+
|
|
417
|
+
Input:
|
|
418
|
+
[obs_001] CRITICAL User uses Postgres
|
|
419
|
+
[obs_002] IMPORTANT User mentioned performance issues with the workflow
|
|
420
|
+
|
|
421
|
+
Wrong merge:
|
|
422
|
+
{
|
|
423
|
+
"supersedes": ["obs_001", "obs_002"],
|
|
424
|
+
"marker": "CRITICAL",
|
|
425
|
+
"text": "User has Postgres performance issues affecting workflows"
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
The sources do not state Postgres caused the performance issues. NEVER invent a causal link the observations do not state. Leave both as separate observations.
|
|
429
|
+
|
|
430
|
+
BAD: Dropping CRITICAL because it feels redundant when it is not duplicated.
|
|
431
|
+
|
|
432
|
+
Input:
|
|
433
|
+
[obs_001] CRITICAL User works at Acme
|
|
434
|
+
[obs_002] CRITICAL User joined Acme in March 2025
|
|
435
|
+
|
|
436
|
+
Wrong:
|
|
437
|
+
{"drop": ["obs_001"], "merge": []}
|
|
438
|
+
|
|
439
|
+
These are not duplicates. obs_001 is current employment; obs_002 is when it started. Both are durable facts. Merge into a single observation instead, never drop.
|
|
440
|
+
|
|
441
|
+
Correct:
|
|
442
|
+
{
|
|
443
|
+
"drop": [],
|
|
444
|
+
"merge": [
|
|
445
|
+
{
|
|
446
|
+
"supersedes": ["obs_001", "obs_002"],
|
|
447
|
+
"marker": "CRITICAL",
|
|
448
|
+
"text": "User works at Acme; joined in March 2025."
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
GOOD: Combining genuinely redundant facts.
|
|
454
|
+
|
|
455
|
+
Input:
|
|
456
|
+
[obs_001] IMPORTANT User prefers concise responses
|
|
457
|
+
[obs_034] IMPORTANT User asked agent to keep answers shorter
|
|
458
|
+
[obs_087] IMPORTANT User mentioned again that the previous response was too long
|
|
459
|
+
|
|
460
|
+
Output:
|
|
461
|
+
{
|
|
462
|
+
"drop": [],
|
|
463
|
+
"merge": [
|
|
464
|
+
{
|
|
465
|
+
"supersedes": ["obs_001", "obs_034", "obs_087"],
|
|
466
|
+
"marker": "IMPORTANT",
|
|
467
|
+
"text": "User prefers concise responses (reinforced multiple times in this conversation)."
|
|
468
|
+
}
|
|
469
|
+
]
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
OUTPUT FORMAT
|
|
473
|
+
|
|
474
|
+
Return JSON with two arrays:
|
|
475
|
+
|
|
476
|
+
{
|
|
477
|
+
"drop": ["obs_id_1", "obs_id_2"],
|
|
478
|
+
"merge": [
|
|
479
|
+
{
|
|
480
|
+
"supersedes": ["obs_id_3", "obs_id_4"],
|
|
481
|
+
"marker": "IMPORTANT",
|
|
482
|
+
"text": "Merged observation that replaces the listed ones"
|
|
483
|
+
}
|
|
484
|
+
]
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
The merged observation supersedes its sources. The drop array drops observations without replacement. An observation ID may appear in EITHER drop OR merge.supersedes, never both. Do not invent IDs that were not in the input.
|
|
488
|
+
|
|
489
|
+
GOALS
|
|
490
|
+
|
|
491
|
+
- Keep the active log under the token budget.
|
|
492
|
+
- Preserve every CRITICAL unless it is genuinely duplicated by another CRITICAL.
|
|
493
|
+
- Preserve recent IMPORTANT unless clearly superseded.
|
|
494
|
+
- Drop INFO aggressively, oldest first.
|
|
495
|
+
- Merge clusters of related observations into denser ones.
|
|
496
|
+
- Preserve uncertainty: if a source says "user suspects X", the merged observation must also say "suspects", not "X is true".
|
|
497
|
+
- NEVER invent content, causation, or attributions not present in the source observations.
|
|
498
|
+
|
|
499
|
+
CONSERVATISM
|
|
500
|
+
|
|
501
|
+
If the log is already under budget AND no clear duplicates exist, return {"drop": [], "merge": []}. Do not restructure for the sake of restructuring. The Reflector is for reducing the log, not for prettifying it.`;
|
|
502
|
+
function buildObservationLogReflectorPrompt(input) {
|
|
503
|
+
const trimmedLog = input.renderedObservationLog.trim();
|
|
504
|
+
const renderedLog = trimmedLog === '' ? '(empty)' : trimmedLog;
|
|
505
|
+
return [
|
|
506
|
+
`Current timestamp: ${input.now.toISOString()}`,
|
|
507
|
+
`Scope: ${input.scopeKind}:${input.scopeId}`,
|
|
508
|
+
`Active observation log tokens: ${input.tokenCount}`,
|
|
509
|
+
`Token budget: ${input.tokenBudget}`,
|
|
510
|
+
`Current active observation log:\n${renderedLog}`,
|
|
511
|
+
].join('\n\n');
|
|
512
|
+
}
|
|
513
|
+
function createObservationLogReflectFn(model, options = {}) {
|
|
514
|
+
return async (input) => {
|
|
515
|
+
const { text } = await (0, ai_1.generateText)({
|
|
516
|
+
model: (0, model_factory_1.createModel)(model),
|
|
517
|
+
system: options.reflectorPrompt ?? exports.DEFAULT_OBSERVATION_LOG_REFLECTOR_PROMPT,
|
|
518
|
+
prompt: buildObservationLogReflectorPrompt(input),
|
|
519
|
+
});
|
|
520
|
+
return text.trim();
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
//# sourceMappingURL=observation-log-defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation-log-defaults.js","sourceRoot":"","sources":["../../src/runtime/observation-log-defaults.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { BuiltMemory } from '../types/sdk/memory';
|
|
2
|
+
import type { AgentDbMessage } from '../types/sdk/message';
|
|
3
|
+
import type { ObservationCursor } from '../types/sdk/observation';
|
|
4
|
+
import type { BuiltObservationLogStore, ObservationLogMarker, ObservationLogObserveFn, ObservationLogObserverInput, ObservationLogScopeKind, TokenCounter } from '../types/sdk/observation-log';
|
|
5
|
+
export type { ObservationLogObserveFn, ObservationLogObserverInput };
|
|
6
|
+
export interface ParsedObservationLogEntry {
|
|
7
|
+
marker: ObservationLogMarker;
|
|
8
|
+
text: string;
|
|
9
|
+
parentIndex: number | null;
|
|
10
|
+
}
|
|
11
|
+
export interface ParseObservationLogMarkdownResult {
|
|
12
|
+
entries: ParsedObservationLogEntry[];
|
|
13
|
+
skippedLines: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface RenderObserverTranscriptOptions {
|
|
16
|
+
maxSerializedChars?: number;
|
|
17
|
+
maxStringChars?: number;
|
|
18
|
+
maxArrayItems?: number;
|
|
19
|
+
maxObjectKeys?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface ObservationLogObserverMemory extends BuiltMemory, BuiltObservationLogStore {
|
|
22
|
+
getMessagesForScope(scopeKind: ObservationLogScopeKind, scopeId: string, opts?: {
|
|
23
|
+
since?: {
|
|
24
|
+
sinceCreatedAt: Date;
|
|
25
|
+
sinceMessageId: string;
|
|
26
|
+
};
|
|
27
|
+
resourceId?: string;
|
|
28
|
+
}): Promise<AgentDbMessage[]>;
|
|
29
|
+
getCursor(scopeKind: ObservationLogScopeKind, scopeId: string): Promise<ObservationCursor | null>;
|
|
30
|
+
setCursor(cursor: ObservationCursor & {
|
|
31
|
+
scopeKind: ObservationLogScopeKind;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
}
|
|
34
|
+
export interface RunObservationLogObserverOpts {
|
|
35
|
+
memory: ObservationLogObserverMemory;
|
|
36
|
+
scopeKind: ObservationLogScopeKind;
|
|
37
|
+
scopeId: string;
|
|
38
|
+
observerThresholdTokens: number;
|
|
39
|
+
observationLogTailLimit: number;
|
|
40
|
+
observe: ObservationLogObserveFn;
|
|
41
|
+
tokenCounter?: TokenCounter;
|
|
42
|
+
now?: Date;
|
|
43
|
+
messageSource?: {
|
|
44
|
+
threadId: string;
|
|
45
|
+
resourceId?: string;
|
|
46
|
+
};
|
|
47
|
+
onMalformedLine?: (line: string) => void;
|
|
48
|
+
}
|
|
49
|
+
export type RunObservationLogObserverResult = {
|
|
50
|
+
status: 'skipped';
|
|
51
|
+
reason: 'no-delta';
|
|
52
|
+
} | {
|
|
53
|
+
status: 'skipped';
|
|
54
|
+
reason: 'below-threshold';
|
|
55
|
+
tokenCount: number;
|
|
56
|
+
} | {
|
|
57
|
+
status: 'ran';
|
|
58
|
+
observationsWritten: number;
|
|
59
|
+
tokenCount: number;
|
|
60
|
+
skippedLines: string[];
|
|
61
|
+
};
|
|
62
|
+
export declare function parseObservationLogMarkdown(markdown: string): ParseObservationLogMarkdownResult;
|
|
63
|
+
export declare function renderObserverTranscript(messages: AgentDbMessage[], options?: RenderObserverTranscriptOptions): string;
|
|
64
|
+
export declare function runObservationLogObserver(opts: RunObservationLogObserverOpts): Promise<RunObservationLogObserverResult>;
|