@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.
Files changed (73) hide show
  1. package/dist/build.tsbuildinfo +1 -1
  2. package/dist/index.d.ts +10 -7
  3. package/dist/index.js +30 -10
  4. package/dist/index.js.map +1 -1
  5. package/dist/runtime/agent-runtime.d.ts +24 -12
  6. package/dist/runtime/agent-runtime.js +241 -91
  7. package/dist/runtime/agent-runtime.js.map +1 -1
  8. package/dist/runtime/background-task-tracker.d.ts +6 -0
  9. package/dist/runtime/background-task-tracker.js +26 -0
  10. package/dist/runtime/background-task-tracker.js.map +1 -0
  11. package/dist/runtime/deferred-tool-manager.d.ts +28 -0
  12. package/dist/runtime/deferred-tool-manager.js +205 -0
  13. package/dist/runtime/deferred-tool-manager.js.map +1 -0
  14. package/dist/runtime/memory-store.d.ts +21 -36
  15. package/dist/runtime/memory-store.js +118 -51
  16. package/dist/runtime/memory-store.js.map +1 -1
  17. package/dist/runtime/message-list.d.ts +1 -7
  18. package/dist/runtime/message-list.js +3 -6
  19. package/dist/runtime/message-list.js.map +1 -1
  20. package/dist/runtime/observation-log-defaults.d.ts +20 -0
  21. package/dist/runtime/observation-log-defaults.js +523 -0
  22. package/dist/runtime/observation-log-defaults.js.map +1 -0
  23. package/dist/runtime/observation-log-observer.d.ts +64 -0
  24. package/dist/runtime/observation-log-observer.js +235 -0
  25. package/dist/runtime/observation-log-observer.js.map +1 -0
  26. package/dist/runtime/observation-log-reflector.d.ts +36 -0
  27. package/dist/runtime/observation-log-reflector.js +292 -0
  28. package/dist/runtime/observation-log-reflector.js.map +1 -0
  29. package/dist/runtime/observation-log-renderer.d.ts +6 -0
  30. package/dist/runtime/observation-log-renderer.js +73 -0
  31. package/dist/runtime/observation-log-renderer.js.map +1 -0
  32. package/dist/runtime/observation-log-store.d.ts +3 -0
  33. package/dist/runtime/observation-log-store.js +26 -0
  34. package/dist/runtime/observation-log-store.js.map +1 -0
  35. package/dist/runtime/scoped-memory-task-runner.d.ts +79 -0
  36. package/dist/runtime/scoped-memory-task-runner.js +134 -0
  37. package/dist/runtime/scoped-memory-task-runner.js.map +1 -0
  38. package/dist/sdk/agent.d.ts +13 -1
  39. package/dist/sdk/agent.js +58 -9
  40. package/dist/sdk/agent.js.map +1 -1
  41. package/dist/sdk/catalog.d.ts +1 -0
  42. package/dist/sdk/catalog.js +1 -0
  43. package/dist/sdk/catalog.js.map +1 -1
  44. package/dist/sdk/memory.d.ts +12 -12
  45. package/dist/sdk/memory.js +71 -51
  46. package/dist/sdk/memory.js.map +1 -1
  47. package/dist/storage/base-memory.d.ts +0 -10
  48. package/dist/storage/base-memory.js +0 -6
  49. package/dist/storage/base-memory.js.map +1 -1
  50. package/dist/types/index.d.ts +5 -4
  51. package/dist/types/index.js +7 -3
  52. package/dist/types/index.js.map +1 -1
  53. package/dist/types/runtime/event.d.ts +1 -0
  54. package/dist/types/sdk/agent-builder.d.ts +5 -0
  55. package/dist/types/sdk/agent.d.ts +6 -0
  56. package/dist/types/sdk/memory.d.ts +16 -24
  57. package/dist/types/sdk/observation-log.d.ts +99 -0
  58. package/dist/types/sdk/observation-log.js +17 -0
  59. package/dist/types/sdk/observation-log.js.map +1 -0
  60. package/dist/types/sdk/observation.d.ts +3 -94
  61. package/dist/types/sdk/observation.js +0 -2
  62. package/dist/types/sdk/observation.js.map +1 -1
  63. package/dist/types/sdk/provider.d.ts +5 -2
  64. package/package.json +3 -7
  65. package/dist/runtime/working-memory.d.ts +0 -14
  66. package/dist/runtime/working-memory.js +0 -69
  67. package/dist/runtime/working-memory.js.map +0 -1
  68. package/dist/storage/postgres-memory.d.ts +0 -96
  69. package/dist/storage/postgres-memory.js +0 -431
  70. package/dist/storage/postgres-memory.js.map +0 -1
  71. package/dist/storage/sqlite-memory.d.ts +0 -70
  72. package/dist/storage/sqlite-memory.js +0 -354
  73. 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":";;;AA6RA,8EAcC;AAED,sEAaC;AAoND,gFAWC;AAED,sEAaC;AAxiBD,2BAAkC;AAElC,mDAA8C;AAajC,QAAA,iDAAiD,GAAG,GAAG,CAAC;AACxD,QAAA,kCAAkC,GAAG,EAAE,CAAC;AACxC,QAAA,kDAAkD,GAAG,KAAK,CAAC;AAC3D,QAAA,2CAA2C,GAAG,KAAK,CAAC;AACpD,QAAA,mCAAmC,GAAG,MAAM,CAAC;AAE7C,QAAA,uCAAuC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wKAkQiH,CAAC;AAMzK,SAAgB,iCAAiC,CAAC,KAAkC;IACnF,MAAM,cAAc,GAAG,KAAK,CAAC,0BAA0B,EAAE,IAAI,EAAE,CAAC;IAChE,MAAM,eAAe,GACpB,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC;IACpF,MAAM,iBAAiB,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,UAAU,GAAG,iBAAiB,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAE5E,OAAO;QACN,sBAAsB,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE;QAC/C,UAAU,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,EAAE;QAC5C,iCAAiC,KAAK,CAAC,oBAAoB,EAAE;QAC7D,kCAAkC,eAAe,EAAE;QACnD,qDAAqD,UAAU,EAAE;KACjE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAChB,CAAC;AAED,SAAgB,6BAA6B,CAC5C,KAAkB,EAClB,UAAgD,EAAE;IAElD,OAAO,KAAK,EAAE,KAAK,EAAE,EAAE;QACtB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,iBAAY,EAAC;YACnC,KAAK,EAAE,IAAA,2BAAW,EAAC,KAAK,CAAC;YACzB,MAAM,EAAE,OAAO,CAAC,cAAc,IAAI,+CAAuC;YACzE,MAAM,EAAE,iCAAiC,CAAC,KAAK,CAAC;SAChD,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC,CAAC;AACH,CAAC;AAEY,QAAA,wCAAwC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qNA4M6J,CAAC;AAMtN,SAAgB,kCAAkC,CAAC,KAAmC;IACrF,MAAM,UAAU,GAAG,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC;IACvD,MAAM,WAAW,GAAG,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;IAE/D,OAAO;QACN,sBAAsB,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE;QAC/C,UAAU,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,EAAE;QAC5C,kCAAkC,KAAK,CAAC,UAAU,EAAE;QACpD,iBAAiB,KAAK,CAAC,WAAW,EAAE;QACpC,oCAAoC,WAAW,EAAE;KACjD,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAChB,CAAC;AAED,SAAgB,6BAA6B,CAC5C,KAAkB,EAClB,UAAgD,EAAE;IAElD,OAAO,KAAK,EAAE,KAAK,EAAE,EAAE;QACtB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAA,iBAAY,EAAC;YACnC,KAAK,EAAE,IAAA,2BAAW,EAAC,KAAK,CAAC;YACzB,MAAM,EAAE,OAAO,CAAC,eAAe,IAAI,gDAAwC;YAC3E,MAAM,EAAE,kCAAkC,CAAC,KAAK,CAAC;SACjD,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC,CAAC;AACH,CAAC"}
@@ -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>;