agentel 0.2.8 → 0.3.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/README.md +222 -68
- package/docs/code-reference.md +121 -37
- package/docs/history-source-handling.md +555 -124
- package/docs/release.md +35 -8
- package/npm-shrinkwrap.json +478 -0
- package/package.json +18 -5
- package/scripts/postinstall.js +156 -0
- package/src/archive.js +1174 -65
- package/src/canonical-events.js +346 -35
- package/src/cli.js +7121 -819
- package/src/collector.js +42 -4
- package/src/config.js +15 -4
- package/src/diffs.js +156 -0
- package/src/doctor.js +48 -5
- package/src/importers/claude.js +51 -4
- package/src/importers/copilot.js +385 -0
- package/src/importers/cursor-recovery.js +22 -0
- package/src/importers/factory.js +396 -0
- package/src/importers/gemini.js +39 -0
- package/src/importers/grok.js +367 -0
- package/src/importers/pi.js +422 -0
- package/src/importers/providers.js +64 -5
- package/src/importers.js +4524 -383
- package/src/mcp.js +1 -0
- package/src/memory-sources.js +671 -0
- package/src/memory-store.js +0 -0
- package/src/parser-versions.js +13 -0
- package/src/pricing.js +84 -0
- package/src/search.js +256 -70
- package/src/session-store.js +405 -0
- package/src/source-watch.js +293 -0
- package/src/sources.js +60 -11
- package/src/supervisor.js +197 -9
- package/src/sync.js +6 -0
- package/src/unavailable-sources.js +358 -0
package/src/canonical-events.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const crypto = require("crypto");
|
|
4
|
+
const { normalizeStructuredPatch, structuredPatchFromDiffText, structuredPatchFromToolArguments } = require("./diffs");
|
|
4
5
|
const { parserVersionForSource } = require("./parser-versions");
|
|
5
6
|
|
|
6
|
-
const CANONICAL_EVENT_SCHEMA_VERSION = "agentlog.events.
|
|
7
|
+
const CANONICAL_EVENT_SCHEMA_VERSION = "agentlog.events.v5";
|
|
7
8
|
|
|
8
9
|
const EVENT_KINDS = {
|
|
9
10
|
SESSION_STARTED: "session.started",
|
|
10
11
|
PROMPT_SUBMITTED: "prompt.submitted",
|
|
11
12
|
TOOL_CALLED: "tool.called",
|
|
12
13
|
TOOL_COMPLETED: "tool.completed",
|
|
14
|
+
MEMORY_READ: "memory.read",
|
|
15
|
+
MEMORY_WRITE: "memory.write",
|
|
16
|
+
MEMORY_LOADED: "memory.loaded",
|
|
13
17
|
RESPONSE_GENERATED: "response.generated"
|
|
14
18
|
};
|
|
15
19
|
|
|
@@ -95,7 +99,15 @@ function normalizeSessionEvents(session, messages, options = {}) {
|
|
|
95
99
|
const parserVersion = options.parserVersion ?? session.parserVersion ?? parserVersionForSource(session.sourceType);
|
|
96
100
|
const state = {
|
|
97
101
|
toolCallEventIdsByKey: new Map(),
|
|
98
|
-
|
|
102
|
+
// Ordered list of tool-call event ids still awaiting a result, plus a Set
|
|
103
|
+
// for O(1) membership and a head pointer for the FIFO fallback. Consumed
|
|
104
|
+
// ids are tombstoned (left in the array, removed from the set) so we never
|
|
105
|
+
// pay O(n) splice/indexOf per result — important for sessions with tens of
|
|
106
|
+
// thousands of tool calls.
|
|
107
|
+
unmatchedToolCallEventIds: [],
|
|
108
|
+
unmatchedToolCallEventIdSet: new Set(),
|
|
109
|
+
unmatchedHead: 0,
|
|
110
|
+
memoryByToolCallEventId: new Map()
|
|
99
111
|
};
|
|
100
112
|
const events = [
|
|
101
113
|
baseEvent(session, {
|
|
@@ -125,7 +137,7 @@ function normalizeSessionEvents(session, messages, options = {}) {
|
|
|
125
137
|
|
|
126
138
|
function messageToCanonicalEvents(message, session, options = {}) {
|
|
127
139
|
const role = String(message?.role || "").toLowerCase();
|
|
128
|
-
if (!message
|
|
140
|
+
if (!message) return [];
|
|
129
141
|
const messageIndex = Number.isFinite(Number(message.index)) ? Number(message.index) : options.messageIndex || 0;
|
|
130
142
|
const parserVersion = options.parserVersion ?? session.parserVersion ?? parserVersionForSource(session.sourceType);
|
|
131
143
|
const occurredAt = message.timestamp || session.startedAt || new Date().toISOString();
|
|
@@ -133,7 +145,26 @@ function messageToCanonicalEvents(message, session, options = {}) {
|
|
|
133
145
|
const metadata = message.metadata || {};
|
|
134
146
|
const events = [];
|
|
135
147
|
|
|
148
|
+
if (role === "system" || role === "developer") {
|
|
149
|
+
const memory = memoryActivityFromSystemMessage(message);
|
|
150
|
+
return memory
|
|
151
|
+
? [
|
|
152
|
+
memoryCanonicalEvent(session, {
|
|
153
|
+
messageIndex,
|
|
154
|
+
ordinal: 0,
|
|
155
|
+
occurredAt,
|
|
156
|
+
parserVersion,
|
|
157
|
+
role,
|
|
158
|
+
memory,
|
|
159
|
+
text: memory.contentPreview || memoryEventSummary(memory),
|
|
160
|
+
status: "loaded"
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
: [];
|
|
164
|
+
}
|
|
165
|
+
|
|
136
166
|
if (role === "user") {
|
|
167
|
+
const skills = skillInvocationsFromPromptText(content);
|
|
137
168
|
events.push(
|
|
138
169
|
baseEvent(session, {
|
|
139
170
|
messageIndex,
|
|
@@ -145,7 +176,8 @@ function messageToCanonicalEvents(message, session, options = {}) {
|
|
|
145
176
|
indexed: {
|
|
146
177
|
title: "User prompt",
|
|
147
178
|
summary: summarize(content),
|
|
148
|
-
status: "submitted"
|
|
179
|
+
status: "submitted",
|
|
180
|
+
...(skills.length ? { skills } : {})
|
|
149
181
|
},
|
|
150
182
|
body: { text: content, toolCall: null, toolResult: null }
|
|
151
183
|
})
|
|
@@ -178,6 +210,8 @@ function messageToCanonicalEvents(message, session, options = {}) {
|
|
|
178
210
|
const toolCall = normalizeToolCall(toolCalls[index], metadata.provider || session.provider);
|
|
179
211
|
if (!toolCall) continue;
|
|
180
212
|
const rendered = renderToolCallText(toolCall);
|
|
213
|
+
const toolSkills = skillNamesFromToolCall(toolCall);
|
|
214
|
+
const memory = memoryActivityFromToolCall(toolCall);
|
|
181
215
|
const event = baseEvent(session, {
|
|
182
216
|
messageIndex,
|
|
183
217
|
ordinal: index + 1,
|
|
@@ -193,42 +227,296 @@ function messageToCanonicalEvents(message, session, options = {}) {
|
|
|
193
227
|
toolCategory: toolCall.category || "",
|
|
194
228
|
toolIcon: toolCall.icon || "",
|
|
195
229
|
target: toolCall.target || "",
|
|
196
|
-
status: toolCall.status || "tool_call"
|
|
230
|
+
status: toolCall.status || "tool_call",
|
|
231
|
+
...(toolSkills.length ? { skills: toolSkills } : {})
|
|
197
232
|
},
|
|
198
233
|
body: { text: rendered, toolCall, toolResult: null }
|
|
199
234
|
});
|
|
200
235
|
rememberToolCallEvent(options.state, toolCall, event.eventId);
|
|
236
|
+
if (memory && options.state?.memoryByToolCallEventId) options.state.memoryByToolCallEventId.set(event.eventId, memory);
|
|
201
237
|
events.push(event);
|
|
202
238
|
}
|
|
203
239
|
|
|
204
240
|
const toolResult = metadata.toolResult ? normalizeToolResult(metadata.toolResult, metadata.provider || session.provider) : role === "tool" ? normalizeToolResult(content, metadata.provider || session.provider) : null;
|
|
205
241
|
if (toolResult) {
|
|
206
242
|
const parentEventId = consumeToolCallEventId(options.state, toolResult);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
);
|
|
243
|
+
const completedEvent = baseEvent(session, {
|
|
244
|
+
messageIndex,
|
|
245
|
+
ordinal: events.length + 1,
|
|
246
|
+
kind: EVENT_KINDS.TOOL_COMPLETED,
|
|
247
|
+
occurredAt,
|
|
248
|
+
parserVersion,
|
|
249
|
+
role: "tool",
|
|
250
|
+
indexed: {
|
|
251
|
+
title: toolResult.title || toolResult.kind || "Tool result",
|
|
252
|
+
summary: summarize(toolResult.summary || toolResult.output || content),
|
|
253
|
+
toolName: toolResult.name || toolResult.kind || "",
|
|
254
|
+
toolCategory: toolResult.category || "",
|
|
255
|
+
toolIcon: toolResult.icon || "",
|
|
256
|
+
status: toolResult.status || "completed"
|
|
257
|
+
},
|
|
258
|
+
parentEventId,
|
|
259
|
+
body: { text: toolResult.output || content, toolCall: null, toolResult }
|
|
260
|
+
});
|
|
261
|
+
events.push(completedEvent);
|
|
262
|
+
const memory = parentEventId ? options.state?.memoryByToolCallEventId?.get(parentEventId) : null;
|
|
263
|
+
if (memory && isSuccessfulToolResult(toolResult)) {
|
|
264
|
+
events.push(
|
|
265
|
+
memoryCanonicalEvent(session, {
|
|
266
|
+
messageIndex,
|
|
267
|
+
ordinal: events.length + 1,
|
|
268
|
+
occurredAt,
|
|
269
|
+
parserVersion,
|
|
270
|
+
role: "tool",
|
|
271
|
+
parentEventId: completedEvent.eventId,
|
|
272
|
+
memory,
|
|
273
|
+
text: memoryEventSummary(memory),
|
|
274
|
+
status: "completed"
|
|
275
|
+
})
|
|
276
|
+
);
|
|
277
|
+
}
|
|
227
278
|
}
|
|
228
279
|
|
|
229
280
|
return events;
|
|
230
281
|
}
|
|
231
282
|
|
|
283
|
+
function memoryCanonicalEvent(session, options = {}) {
|
|
284
|
+
const memory = options.memory || {};
|
|
285
|
+
const action = String(memory.action || "loaded").toLowerCase();
|
|
286
|
+
const kind = action === "read" ? EVENT_KINDS.MEMORY_READ : action === "write" ? EVENT_KINDS.MEMORY_WRITE : EVENT_KINDS.MEMORY_LOADED;
|
|
287
|
+
return baseEvent(session, {
|
|
288
|
+
messageIndex: options.messageIndex,
|
|
289
|
+
ordinal: options.ordinal,
|
|
290
|
+
kind,
|
|
291
|
+
occurredAt: options.occurredAt,
|
|
292
|
+
parserVersion: options.parserVersion,
|
|
293
|
+
role: options.role || "system",
|
|
294
|
+
parentEventId: options.parentEventId || "",
|
|
295
|
+
indexed: {
|
|
296
|
+
title: memoryEventTitle(memory),
|
|
297
|
+
summary: summarize(options.text || memoryEventSummary(memory)),
|
|
298
|
+
status: options.status || "completed",
|
|
299
|
+
memoryAction: action,
|
|
300
|
+
memoryPath: memory.path || "",
|
|
301
|
+
memorySource: memory.source || "",
|
|
302
|
+
memoryScope: memory.scope || ""
|
|
303
|
+
},
|
|
304
|
+
body: {
|
|
305
|
+
text: options.text || memoryEventSummary(memory),
|
|
306
|
+
toolCall: null,
|
|
307
|
+
toolResult: null,
|
|
308
|
+
memory
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Skill invocations appear in prompt text as Codex-style markdown markers
|
|
314
|
+
// ("[$name](/path/to/SKILL.md)") or Claude-style command tags
|
|
315
|
+
// ("<command-name>/recall</command-name>"). Names are normalized without the
|
|
316
|
+
// "$"/"/" decorations so telemetry can aggregate across providers.
|
|
317
|
+
function skillInvocationsFromPromptText(text) {
|
|
318
|
+
const value = String(text || "");
|
|
319
|
+
const names = new Set();
|
|
320
|
+
const markerPattern = /\[\$([^\]\n]+)\]\(([^)\n]*)\)/g;
|
|
321
|
+
let match;
|
|
322
|
+
while ((match = markerPattern.exec(value))) {
|
|
323
|
+
const name = normalizeSkillName(match[1]);
|
|
324
|
+
if (name) names.add(name);
|
|
325
|
+
}
|
|
326
|
+
const commandPattern = /<command-name>([^<\n]+)<\/command-name>/g;
|
|
327
|
+
while ((match = commandPattern.exec(value))) {
|
|
328
|
+
const name = normalizeSkillName(match[1]);
|
|
329
|
+
if (name) names.add(name);
|
|
330
|
+
}
|
|
331
|
+
return [...names];
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function skillNamesFromToolCall(toolCall) {
|
|
335
|
+
if (!toolCall || toolCall.category !== "skill") return [];
|
|
336
|
+
const args = toolCall.arguments && typeof toolCall.arguments === "object" ? toolCall.arguments : {};
|
|
337
|
+
const candidates = [args.skill, args.skill_name, args.skillName, args.name, args.command, toolCall.target];
|
|
338
|
+
for (const candidate of candidates) {
|
|
339
|
+
const name = normalizeSkillName(candidate);
|
|
340
|
+
if (name) return [name];
|
|
341
|
+
}
|
|
342
|
+
return [];
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function normalizeSkillName(value) {
|
|
346
|
+
const text = String(value || "").trim().replace(/^[$/]+/, "").trim();
|
|
347
|
+
if (!text || text.length > 120 || /\s{2,}/.test(text)) return "";
|
|
348
|
+
return text;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const MEMORY_PATH_BASES = new Set([
|
|
352
|
+
"agents.md",
|
|
353
|
+
"claude.md",
|
|
354
|
+
"gemini.md",
|
|
355
|
+
"memory.md",
|
|
356
|
+
".cursorrules",
|
|
357
|
+
".windsurfrules",
|
|
358
|
+
"rules.md"
|
|
359
|
+
]);
|
|
360
|
+
|
|
361
|
+
const READ_TOOL_NAMES = new Set(["read", "notebookread", "cat", "sed", "view", "open"]);
|
|
362
|
+
const WRITE_TOOL_NAMES = new Set(["write", "edit", "multiedit", "notebookedit", "apply_patch", "patch", "replace", "update_file"]);
|
|
363
|
+
|
|
364
|
+
function memoryActivityFromToolCall(toolCall) {
|
|
365
|
+
const info = memoryInfoFromToolCall(toolCall);
|
|
366
|
+
if (!info) return null;
|
|
367
|
+
const action = memoryToolAction(toolCall);
|
|
368
|
+
if (!action) return null;
|
|
369
|
+
return { action, ...info };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function memoryActivityFromSystemMessage(message) {
|
|
373
|
+
const metadata = message?.metadata || {};
|
|
374
|
+
const contextKind = String(metadata.contextKind || "").toLowerCase();
|
|
375
|
+
if (contextKind === "remote_control_nested_memory") {
|
|
376
|
+
const attachment = metadata.attachment && typeof metadata.attachment === "object" ? metadata.attachment : {};
|
|
377
|
+
const rawPath = firstString(attachment.path, attachment.contentPath, attachment.displayPath);
|
|
378
|
+
const info = memoryPathInfo(rawPath) || genericMemoryInfo(rawPath || "memory", "remote-control-memory", "remote");
|
|
379
|
+
return {
|
|
380
|
+
action: "load",
|
|
381
|
+
...info,
|
|
382
|
+
contentPreview: firstString(attachment.contentPreview)
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
if (contextKind === "project_instructions") {
|
|
386
|
+
const path = projectInstructionsPathFromContent(message.content);
|
|
387
|
+
const info = memoryPathInfo(path);
|
|
388
|
+
if (info) return { action: "load", ...info, contentPreview: summarize(message.content, 240) };
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function memoryInfoFromToolCall(toolCall) {
|
|
394
|
+
for (const candidate of memoryPathCandidates(toolCall)) {
|
|
395
|
+
const info = memoryPathInfo(candidate);
|
|
396
|
+
if (info) return info;
|
|
397
|
+
}
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function memoryToolAction(toolCall) {
|
|
402
|
+
const name = normalizeToolKey(toolCall?.name || toolCall?.displayName || toolCall?.title);
|
|
403
|
+
const category = normalizeToolKey(toolCall?.category || toolCall?.rawCategory);
|
|
404
|
+
if (category === "read" || READ_TOOL_NAMES.has(name)) return "read";
|
|
405
|
+
if (category === "edit" || WRITE_TOOL_NAMES.has(name)) return "write";
|
|
406
|
+
return "";
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function memoryPathCandidates(toolCall) {
|
|
410
|
+
const out = [];
|
|
411
|
+
appendMemoryPathCandidate(out, toolCall?.target);
|
|
412
|
+
appendMemoryPathCandidate(out, toolCall?.argument);
|
|
413
|
+
appendMemoryPathCandidate(out, toolCall?.rawInputSummary);
|
|
414
|
+
appendMemoryPathCandidate(out, toolCall?.inputPreview);
|
|
415
|
+
collectMemoryPathValues(toolCall?.arguments, "", 0, out);
|
|
416
|
+
return [...new Set(out.map(normalizeMemoryPath).filter(Boolean))];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function collectMemoryPathValues(value, key = "", depth = 0, out = []) {
|
|
420
|
+
if (value == null || depth > 5) return out;
|
|
421
|
+
if (typeof value === "string") {
|
|
422
|
+
if (isPathArgumentKey(key)) appendMemoryPathCandidate(out, value);
|
|
423
|
+
return out;
|
|
424
|
+
}
|
|
425
|
+
if (Array.isArray(value)) {
|
|
426
|
+
for (const item of value) collectMemoryPathValues(item, key, depth + 1, out);
|
|
427
|
+
return out;
|
|
428
|
+
}
|
|
429
|
+
if (typeof value !== "object") return out;
|
|
430
|
+
for (const [childKey, childValue] of Object.entries(value)) collectMemoryPathValues(childValue, childKey, depth + 1, out);
|
|
431
|
+
return out;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function appendMemoryPathCandidate(out, value) {
|
|
435
|
+
if (typeof value !== "string") return;
|
|
436
|
+
const normalized = normalizeMemoryPath(value);
|
|
437
|
+
if (normalized) out.push(normalized);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function memoryPathInfo(value) {
|
|
441
|
+
const normalized = normalizeMemoryPath(value);
|
|
442
|
+
if (!normalized) return null;
|
|
443
|
+
const lower = normalized.toLowerCase();
|
|
444
|
+
const base = lower.split("/").filter(Boolean).pop() || "";
|
|
445
|
+
if (/\/\.claude\/projects\/[^/]+\/memory\/[^/]+\.(md|mdx|txt|json|yaml|yml)$/i.test(normalized)) {
|
|
446
|
+
return genericMemoryInfo(normalized, "claude-code-project-memory", "project");
|
|
447
|
+
}
|
|
448
|
+
if (/\/\.claude\/(?:memory|memories)\//i.test(normalized)) {
|
|
449
|
+
return genericMemoryInfo(normalized, "claude-code-memory", "global");
|
|
450
|
+
}
|
|
451
|
+
if (/\/\.codex\/(?:memory|memories)\//i.test(normalized)) {
|
|
452
|
+
return genericMemoryInfo(normalized, "codex-memory", "global");
|
|
453
|
+
}
|
|
454
|
+
if (/\/\.cursor\/rules\//i.test(normalized)) {
|
|
455
|
+
return genericMemoryInfo(normalized, "cursor-rules", "project");
|
|
456
|
+
}
|
|
457
|
+
if (/\/\.windsurf\/rules\//i.test(normalized)) {
|
|
458
|
+
return genericMemoryInfo(normalized, "windsurf-rules", "project");
|
|
459
|
+
}
|
|
460
|
+
if (MEMORY_PATH_BASES.has(base)) {
|
|
461
|
+
const source = base === "agents.md" ? "project-instructions"
|
|
462
|
+
: base === "claude.md" ? "claude-instructions"
|
|
463
|
+
: base === "gemini.md" ? "gemini-instructions"
|
|
464
|
+
: base === ".cursorrules" ? "cursor-rules"
|
|
465
|
+
: base === ".windsurfrules" ? "windsurf-rules"
|
|
466
|
+
: "memory-file";
|
|
467
|
+
return genericMemoryInfo(normalized, source, projectMemoryScope(lower));
|
|
468
|
+
}
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function genericMemoryInfo(pathValue, source, scope) {
|
|
473
|
+
const normalized = normalizeMemoryPath(pathValue);
|
|
474
|
+
const name = normalized.split("/").filter(Boolean).pop() || normalized || "memory";
|
|
475
|
+
return {
|
|
476
|
+
path: normalized,
|
|
477
|
+
name,
|
|
478
|
+
source,
|
|
479
|
+
scope
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function projectMemoryScope(lowerPath) {
|
|
484
|
+
if (/\/\.(claude|codex|cursor|windsurf)\//.test(lowerPath)) return "project";
|
|
485
|
+
return "project";
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function normalizeMemoryPath(value) {
|
|
489
|
+
const text = String(value || "").trim();
|
|
490
|
+
if (!text || text.length > 4096) return "";
|
|
491
|
+
return text.replace(/\\/g, "/").replace(/\/+/g, "/");
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function projectInstructionsPathFromContent(content) {
|
|
495
|
+
const match = /^# AGENTS\.md instructions for\s+(.+)$/m.exec(String(content || ""));
|
|
496
|
+
if (!match) return "";
|
|
497
|
+
const root = normalizeMemoryPath(match[1]);
|
|
498
|
+
if (!root) return "";
|
|
499
|
+
return root.toLowerCase().endsWith("/agents.md") ? root : `${root.replace(/\/+$/, "")}/AGENTS.md`;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function memoryEventTitle(memory) {
|
|
503
|
+
const action = String(memory?.action || "loaded").toLowerCase();
|
|
504
|
+
if (action === "read") return "Memory read";
|
|
505
|
+
if (action === "write") return "Memory write";
|
|
506
|
+
return "Memory loaded";
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function memoryEventSummary(memory) {
|
|
510
|
+
const label = memoryEventTitle(memory);
|
|
511
|
+
const pathValue = firstString(memory?.path, memory?.name, "memory");
|
|
512
|
+
return `${label}: ${pathValue}`;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function isSuccessfulToolResult(toolResult) {
|
|
516
|
+
const status = String(toolResult?.status || "completed").toLowerCase();
|
|
517
|
+
return !status.includes("error") && !status.includes("fail");
|
|
518
|
+
}
|
|
519
|
+
|
|
232
520
|
function rememberToolCallEvent(state, toolCall, eventId) {
|
|
233
521
|
if (!state || !eventId) return;
|
|
234
522
|
for (const key of toolPairKeys(toolCall)) {
|
|
@@ -236,6 +524,7 @@ function rememberToolCallEvent(state, toolCall, eventId) {
|
|
|
236
524
|
state.toolCallEventIdsByKey.get(key).push(eventId);
|
|
237
525
|
}
|
|
238
526
|
state.unmatchedToolCallEventIds.push(eventId);
|
|
527
|
+
state.unmatchedToolCallEventIdSet.add(eventId);
|
|
239
528
|
}
|
|
240
529
|
|
|
241
530
|
function consumeToolCallEventId(state, toolResult) {
|
|
@@ -247,14 +536,19 @@ function consumeToolCallEventId(state, toolResult) {
|
|
|
247
536
|
if (consumeUnmatchedToolEventId(state, eventId)) return eventId;
|
|
248
537
|
}
|
|
249
538
|
}
|
|
250
|
-
|
|
539
|
+
// FIFO fallback: advance the head pointer past tombstoned (already-consumed)
|
|
540
|
+
// ids and return the oldest one still unmatched.
|
|
541
|
+
const ids = state.unmatchedToolCallEventIds;
|
|
542
|
+
while (state.unmatchedHead < ids.length) {
|
|
543
|
+
const eventId = ids[state.unmatchedHead++];
|
|
544
|
+
if (state.unmatchedToolCallEventIdSet.delete(eventId)) return eventId;
|
|
545
|
+
}
|
|
546
|
+
return "";
|
|
251
547
|
}
|
|
252
548
|
|
|
253
549
|
function consumeUnmatchedToolEventId(state, eventId) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
state.unmatchedToolCallEventIds.splice(index, 1);
|
|
257
|
-
return true;
|
|
550
|
+
// delete() returns true only if the id was present (still unmatched).
|
|
551
|
+
return state.unmatchedToolCallEventIdSet.delete(eventId);
|
|
258
552
|
}
|
|
259
553
|
|
|
260
554
|
function toolPairKeys(tool) {
|
|
@@ -275,7 +569,7 @@ function baseEvent(session, options) {
|
|
|
275
569
|
title: String(options.indexed?.title || ""),
|
|
276
570
|
summary: String(options.indexed?.summary || "")
|
|
277
571
|
};
|
|
278
|
-
for (const key of ["toolName", "toolCategory", "toolIcon", "model", "status", "latencyMs", "target"]) {
|
|
572
|
+
for (const key of ["toolName", "toolCategory", "toolIcon", "model", "status", "latencyMs", "target", "skills", "memoryAction", "memoryPath", "memorySource", "memoryScope"]) {
|
|
279
573
|
if (options.indexed?.[key] !== undefined && options.indexed?.[key] !== "") indexed[key] = options.indexed[key];
|
|
280
574
|
}
|
|
281
575
|
return {
|
|
@@ -301,7 +595,8 @@ function baseEvent(session, options) {
|
|
|
301
595
|
body: {
|
|
302
596
|
text: String(body.text || ""),
|
|
303
597
|
toolCall: body.toolCall || null,
|
|
304
|
-
toolResult: body.toolResult || null
|
|
598
|
+
toolResult: body.toolResult || null,
|
|
599
|
+
memory: body.memory || null
|
|
305
600
|
},
|
|
306
601
|
parentEventId: options.parentEventId || ""
|
|
307
602
|
};
|
|
@@ -336,6 +631,9 @@ function renderEventText(event) {
|
|
|
336
631
|
const text = [event.indexed?.title, result.summary, result.output || event.body?.text].filter(Boolean).join("\n");
|
|
337
632
|
return approxTokenCount(text) > 700 ? [event.indexed?.title, result.summary].filter(Boolean).join(" ") : text;
|
|
338
633
|
}
|
|
634
|
+
if (kind === EVENT_KINDS.MEMORY_READ || kind === EVENT_KINDS.MEMORY_WRITE || kind === EVENT_KINDS.MEMORY_LOADED) {
|
|
635
|
+
return event.body?.text || event.indexed?.summary || "";
|
|
636
|
+
}
|
|
339
637
|
return event.body?.text || event.indexed?.summary || "";
|
|
340
638
|
}
|
|
341
639
|
|
|
@@ -415,7 +713,9 @@ function normalizeToolCall(raw, provider = "") {
|
|
|
415
713
|
const rawInputSummary = firstString(raw.rawInputSummary, argument);
|
|
416
714
|
const inputPreview = firstString(raw.inputPreview, rawInputSummary, summarizeToolInput(parsedArguments));
|
|
417
715
|
const target = firstString(raw.target, targetFromArguments(parsedArguments));
|
|
418
|
-
|
|
716
|
+
const structuredPatch = normalizeStructuredPatch(raw.structuredPatch || raw.structured_patch);
|
|
717
|
+
const argumentPatch = structuredPatch.length ? structuredPatch : structuredPatchFromToolArguments(parsedArguments);
|
|
718
|
+
const normalized = {
|
|
419
719
|
provider: firstString(raw.provider, provider),
|
|
420
720
|
id: firstString(raw.id, raw.callId, raw.call_id, raw.toolCallId, raw.tool_call_id, raw.toolUseId, raw.tool_use_id) || undefined,
|
|
421
721
|
name,
|
|
@@ -432,6 +732,8 @@ function normalizeToolCall(raw, provider = "") {
|
|
|
432
732
|
target,
|
|
433
733
|
arguments: parsedArguments && typeof parsedArguments === "object" && !Array.isArray(parsedArguments) ? parsedArguments : undefined
|
|
434
734
|
};
|
|
735
|
+
if (argumentPatch.length) normalized.structuredPatch = argumentPatch;
|
|
736
|
+
return normalized;
|
|
435
737
|
}
|
|
436
738
|
|
|
437
739
|
function summarizeToolInput(value) {
|
|
@@ -467,7 +769,8 @@ function normalizeToolResult(raw, provider = "") {
|
|
|
467
769
|
const output = raw.trim();
|
|
468
770
|
if (!output) return null;
|
|
469
771
|
const classification = classifyTool("tool_output");
|
|
470
|
-
|
|
772
|
+
const structuredPatch = structuredPatchFromDiffText(output);
|
|
773
|
+
const normalized = {
|
|
471
774
|
provider,
|
|
472
775
|
id: undefined,
|
|
473
776
|
kind: "Tool output",
|
|
@@ -481,6 +784,8 @@ function normalizeToolResult(raw, provider = "") {
|
|
|
481
784
|
collapsed: output.split("\n").length > 18,
|
|
482
785
|
status: "completed"
|
|
483
786
|
};
|
|
787
|
+
if (structuredPatch.length) normalized.structuredPatch = structuredPatch;
|
|
788
|
+
return normalized;
|
|
484
789
|
}
|
|
485
790
|
if (typeof raw !== "object") return null;
|
|
486
791
|
const output = firstString(raw.output, raw.text, raw.content, raw.result);
|
|
@@ -488,7 +793,9 @@ function normalizeToolResult(raw, provider = "") {
|
|
|
488
793
|
const kind = firstString(raw.kind, raw.type, raw.toolName, "Tool output");
|
|
489
794
|
const rawCategory = firstString(raw.rawCategory, raw.category, raw.kind, raw.type);
|
|
490
795
|
const classification = classifyTool(firstString(raw.toolName, raw.name, kind), rawCategory);
|
|
491
|
-
|
|
796
|
+
const structuredPatch = normalizeStructuredPatch(raw.structuredPatch || raw.structured_patch);
|
|
797
|
+
const outputPatch = structuredPatch.length ? structuredPatch : structuredPatchFromDiffText(output);
|
|
798
|
+
const normalized = {
|
|
492
799
|
provider: firstString(raw.provider, provider),
|
|
493
800
|
id: firstString(raw.id, raw.callId, raw.call_id, raw.toolCallId, raw.tool_call_id, raw.toolUseId, raw.tool_use_id) || undefined,
|
|
494
801
|
name: firstString(raw.name, raw.toolName, raw.tool_name) || undefined,
|
|
@@ -504,6 +811,8 @@ function normalizeToolResult(raw, provider = "") {
|
|
|
504
811
|
collapsed: Boolean(raw.collapsed),
|
|
505
812
|
status: firstString(raw.status, "completed")
|
|
506
813
|
};
|
|
814
|
+
if (outputPatch.length) normalized.structuredPatch = outputPatch;
|
|
815
|
+
return normalized;
|
|
507
816
|
}
|
|
508
817
|
|
|
509
818
|
function toolArgumentClauses(toolCall) {
|
|
@@ -614,11 +923,13 @@ module.exports = {
|
|
|
614
923
|
CANONICAL_EVENT_SCHEMA_VERSION,
|
|
615
924
|
EVENT_KINDS,
|
|
616
925
|
isLowSignalToolCall,
|
|
926
|
+
memoryPathInfo,
|
|
617
927
|
messageToCanonicalEvents,
|
|
618
928
|
normalizeSessionEvents,
|
|
619
929
|
normalizeToolCall,
|
|
620
930
|
normalizeToolResult,
|
|
621
931
|
renderEventText,
|
|
622
932
|
renderToolCallText,
|
|
933
|
+
skillInvocationsFromPromptText,
|
|
623
934
|
stableEventId
|
|
624
935
|
};
|