trajectories 0.0.0 → 0.1.2
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/CHANGELOG.md +36 -0
- package/LICENSE +201 -0
- package/README.md +288 -2
- package/dist/cli.js +30210 -0
- package/dist/convert.d.ts +31 -0
- package/dist/convert.js +431 -0
- package/dist/deepagents_checkpoint.py +362 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8402 -0
- package/dist/log-baseline.d.ts +26 -0
- package/dist/log-baseline.js +104 -0
- package/dist/log-content.d.ts +16 -0
- package/dist/log-content.js +80 -0
- package/dist/log-io.d.ts +10 -0
- package/dist/log-io.js +121 -0
- package/dist/log-read.d.ts +24 -0
- package/dist/log-read.js +117 -0
- package/dist/log-reconcile.d.ts +5 -0
- package/dist/log-reconcile.js +38 -0
- package/dist/log-records.d.ts +35 -0
- package/dist/log-records.js +85 -0
- package/dist/log-recovery.d.ts +18 -0
- package/dist/log-recovery.js +123 -0
- package/dist/log-stage.d.ts +14 -0
- package/dist/log-stage.js +138 -0
- package/dist/log-state.d.ts +89 -0
- package/dist/log-state.js +92 -0
- package/dist/log-switch.d.ts +3 -0
- package/dist/log-switch.js +98 -0
- package/dist/log-types.d.ts +129 -0
- package/dist/log-types.js +8 -0
- package/dist/log.d.ts +8 -0
- package/dist/log.js +62 -0
- package/dist/migrate.d.ts +29 -0
- package/dist/migrate.js +173 -0
- package/dist/normalization-runtime.d.ts +1 -0
- package/dist/normalization-runtime.js +3150 -0
- package/dist/portable.d.ts +9 -0
- package/dist/portable.js +26 -0
- package/dist/readers/canonical.d.ts +13 -0
- package/dist/readers/canonical.js +54 -0
- package/dist/readers/cline.d.ts +10 -0
- package/dist/readers/cline.js +107 -0
- package/dist/readers/cursor.d.ts +20 -0
- package/dist/readers/cursor.js +374 -0
- package/dist/readers/deepagents.d.ts +41 -0
- package/dist/readers/deepagents.js +163 -0
- package/dist/readers/fx.d.ts +11 -0
- package/dist/readers/fx.js +573 -0
- package/dist/readers/github-copilot.d.ts +8 -0
- package/dist/readers/github-copilot.js +216 -0
- package/dist/readers/grok-build.d.ts +12 -0
- package/dist/readers/grok-build.js +391 -0
- package/dist/readers/guards.d.ts +4 -0
- package/dist/readers/guards.js +121 -0
- package/dist/readers/pi-compaction.d.ts +7 -0
- package/dist/readers/pi-compaction.js +112 -0
- package/dist/readers/pi-context.d.ts +13 -0
- package/dist/readers/pi-context.js +64 -0
- package/dist/store.d.ts +25 -0
- package/dist/store.js +218 -0
- package/dist/types.d.ts +91 -0
- package/dist/types.js +1 -0
- package/dist/writers/claude-code.d.ts +5 -0
- package/dist/writers/claude-code.js +51 -0
- package/dist/writers/cline.d.ts +3 -0
- package/dist/writers/cline.js +77 -0
- package/dist/writers/codex.d.ts +3 -0
- package/dist/writers/codex.js +32 -0
- package/dist/writers/cursor.d.ts +3 -0
- package/dist/writers/cursor.js +197 -0
- package/dist/writers/deepagents.d.ts +3 -0
- package/dist/writers/deepagents.js +116 -0
- package/dist/writers/entropy.d.ts +5 -0
- package/dist/writers/entropy.js +33 -0
- package/dist/writers/fx.d.ts +3 -0
- package/dist/writers/fx.js +135 -0
- package/dist/writers/github-copilot.d.ts +3 -0
- package/dist/writers/github-copilot.js +71 -0
- package/dist/writers/grok-build.d.ts +3 -0
- package/dist/writers/grok-build.js +43 -0
- package/dist/writers/helpers.d.ts +17 -0
- package/dist/writers/helpers.js +75 -0
- package/dist/writers/omp.d.ts +3 -0
- package/dist/writers/omp.js +7 -0
- package/dist/writers/opencode.d.ts +3 -0
- package/dist/writers/opencode.js +65 -0
- package/dist/writers/pi.d.ts +3 -0
- package/dist/writers/pi.js +45 -0
- package/docs/cline-native-format.md +43 -0
- package/docs/copilot-native-format.md +78 -0
- package/docs/cursor-native-format.md +103 -0
- package/docs/deepagents-native-format.md +98 -0
- package/docs/evidence-api.md +170 -0
- package/docs/fx-native-format.md +87 -0
- package/docs/harness-parity-bootstrap.md +78 -0
- package/docs/harness-support-parity.md +107 -0
- package/docs/inspirations.md +103 -0
- package/docs/ledger-migration.md +141 -0
- package/docs/pi-compaction-context.md +75 -0
- package/docs/pi-provider-context.md +76 -0
- package/docs/research/2026-10-06-huihua-and-oar.md +176 -0
- package/docs/research/ledger/README.md +96 -0
- package/docs/research/ledger/confer/2026-09-13-round-10/README.md +61 -0
- package/docs/research/ledger/confer/2026-09-13-round-2/cass.md +72 -0
- package/docs/research/ledger/confer/2026-09-13-round-3/README.md +70 -0
- package/docs/research/ledger/confer/2026-09-13-round-5/README.md +61 -0
- package/docs/research/ledger/confer/2026-09-13-round-6/README.md +68 -0
- package/docs/research/ledger/confer/2026-09-13-round-7/README.md +64 -0
- package/docs/research/ledger/confer/2026-09-13-round-9/README.md +59 -0
- package/docs/research/ledger/confer/2026-09-14-wake/wake.md +146 -0
- package/docs/research/ledger/docs/inspirations.md +320 -0
- package/docs/research/ledger/docs/pr2-pr6-integration.md +53 -0
- package/docs/research/ledger/docs/research/2026-09-07-confer-inspirations.md +163 -0
- package/docs/research/ledger/docs/research/2026-09-07-letta-continuous-service.md +104 -0
- package/docs/research/ledger/docs/research/2026-09-08-claude-history-retrieval.md +117 -0
- package/docs/research/ledger/docs/research/2026-09-09-agentsview-native-discovery.md +87 -0
- package/docs/research/ledger/docs/research/2026-09-09-daemon-observation.md +231 -0
- package/docs/research/ledger/docs/research/2026-09-09-discovery-pagination.md +114 -0
- package/docs/research/ledger/docs/research/2026-09-09-harness-transcript-contract.md +145 -0
- package/docs/research/ledger/docs/research/2026-09-09-native-history-discovery.md +180 -0
- package/docs/research/ledger/docs/research/2026-09-09-native-history-implementation.md +137 -0
- package/docs/research/ledger/docs/research/2026-09-09-other-inspirations.md +279 -0
- package/docs/research/ledger/docs/research/2026-09-09-trajectory-and-letta-code.md +128 -0
- package/docs/research/ledger/docs/research/2026-09-13-diagnostics-coverage.md +116 -0
- package/docs/research/ledger/docs/research/2026-09-13-fts-rebuild.md +83 -0
- package/docs/research/ledger/docs/research/2026-09-13-read-path-split.md +74 -0
- package/docs/research/ledger/docs/research/2026-09-13-runtime-rollout.md +102 -0
- package/docs/research/ledger/docs/research/2026-09-13-scan-outcomes.md +80 -0
- package/docs/research/ledger/docs/research/2026-09-13-search-quality.md +105 -0
- package/docs/research/ledger/docs/research/2026-09-13-source-coverage.md +64 -0
- package/docs/research/ledger/docs/research/2026-09-13-sync-wall-budget.md +82 -0
- package/docs/research/ledger/docs/research/2026-09-13-typed-read-gate.md +81 -0
- package/docs/research/ledger/docs/research/2026-09-13-writer-lease.md +84 -0
- package/docs/research/ledger/docs/research/2026-09-16-c1-copy-fallback.md +227 -0
- package/docs/research/ledger/docs/research/2026-09-16-c10-kimi.md +414 -0
- package/docs/research/ledger/docs/research/2026-09-16-c2-derive-counter.md +216 -0
- package/docs/research/ledger/docs/research/2026-09-16-c3-echo-filter.md +305 -0
- package/docs/research/ledger/docs/research/2026-09-16-c4-title-index.md +349 -0
- package/docs/research/ledger/docs/research/2026-09-16-c5-trigram.md +268 -0
- package/docs/research/ledger/docs/research/2026-09-16-c6-recency-prior.md +438 -0
- package/docs/research/ledger/docs/research/2026-09-16-c7-tombstones.md +467 -0
- package/docs/research/ledger/docs/research/2026-09-16-c8-remote-truth.md +390 -0
- package/docs/research/ledger/docs/research/2026-09-16-c9-grok.md +380 -0
- package/docs/research/ledger/docs/research/2026-09-16-wake-port-program.md +38 -0
- package/docs/research/ledger/docs/research/2026-09-17-cursor-blobstore.md +157 -0
- package/docs/research/ledger/manifest.json +540 -0
- package/legacy/NOTICE.md +50 -0
- package/legacy/bin/ledger-core.ts +7 -0
- package/legacy/bin/ledger.ts +7 -0
- package/legacy/bin/traj-bridge.ts +7 -0
- package/legacy/scripts/import-claude-history.ts +130 -0
- package/legacy/scripts/native-history-smoke.ts +52 -0
- package/legacy/scripts/observe-daemon.ts +570 -0
- package/legacy/scripts/retitle-sessions.md +19 -0
- package/legacy/scripts/verify-runtime-rollout.ts +151 -0
- package/legacy/src/canonical.ts +108 -0
- package/legacy/src/cli.ts +1293 -0
- package/legacy/src/db.ts +2254 -0
- package/legacy/src/diagnostics.ts +87 -0
- package/legacy/src/discovery.ts +56 -0
- package/legacy/src/embeddings.ts +382 -0
- package/legacy/src/filter.ts +602 -0
- package/legacy/src/gemini_embeddings.ts +103 -0
- package/legacy/src/identity.ts +9 -0
- package/legacy/src/index.ts +10 -0
- package/legacy/src/ingest.ts +791 -0
- package/legacy/src/managed.ts +178 -0
- package/legacy/src/native/common.ts +68 -0
- package/legacy/src/native/cursor.ts +647 -0
- package/legacy/src/native/grok.ts +540 -0
- package/legacy/src/native/kimi.ts +706 -0
- package/legacy/src/native/opencode.ts +470 -0
- package/legacy/src/native/sqlite-ro.ts +281 -0
- package/legacy/src/native.ts +97 -0
- package/legacy/src/normalizer.ts +457 -0
- package/legacy/src/parentage.ts +562 -0
- package/legacy/src/pressure.ts +162 -0
- package/legacy/src/private-storage.ts +74 -0
- package/legacy/src/reader.ts +1255 -0
- package/legacy/src/scanner.ts +591 -0
- package/legacy/src/schema-gate.ts +263 -0
- package/legacy/src/schema.ts +829 -0
- package/legacy/src/semantic-top-k.ts +71 -0
- package/legacy/src/session-hash.ts +49 -0
- package/legacy/src/store-status.ts +218 -0
- package/legacy/src/sync-preparation.ts +45 -0
- package/legacy/src/sync-truth.ts +843 -0
- package/legacy/src/sync.ts +1233 -0
- package/legacy/src/types.ts +436 -0
- package/legacy/src/vocab.txt +30522 -0
- package/legacy/src/watch.ts +673 -0
- package/legacy/src/writer-lease.ts +310 -0
- package/ops/README.md +150 -0
- package/ops/install-cli.sh +63 -0
- package/ops/install-native.sh +35 -0
- package/ops/install-release.sh +49 -0
- package/ops/linux/install-systemd-user.sh +103 -0
- package/ops/macos/install-launchd.sh +72 -0
- package/ops/sync-settings.sh +37 -0
- package/package.json +21 -5
- package/skills/trajectories/SKILL.md +138 -0
- package/skills/trajectories/scripts/trajectories_recent.sh +26 -0
- package/skills/trajectories/scripts/trajectories_search.sh +26 -0
- package/index.js +0 -1
|
@@ -0,0 +1,3150 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/types.js
|
|
3
|
+
class NormalizationError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(code, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "NormalizationError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/shared.js
|
|
13
|
+
function parseJsonLines(transcript, diagnostics) {
|
|
14
|
+
const parsed = [];
|
|
15
|
+
const lines = transcript.split(`
|
|
16
|
+
`);
|
|
17
|
+
let byteOffset = 0;
|
|
18
|
+
for (let index = 0;index < lines.length; index += 1) {
|
|
19
|
+
const raw = lines[index];
|
|
20
|
+
if (raw === undefined)
|
|
21
|
+
continue;
|
|
22
|
+
const lineByteOffset = byteOffset;
|
|
23
|
+
byteOffset += utf8ByteLength(raw) + 1;
|
|
24
|
+
if (!raw.trim())
|
|
25
|
+
continue;
|
|
26
|
+
const line = index + 1;
|
|
27
|
+
let value;
|
|
28
|
+
try {
|
|
29
|
+
value = JSON.parse(raw);
|
|
30
|
+
} catch {
|
|
31
|
+
diagnostics.push({
|
|
32
|
+
code: "invalid_json_line",
|
|
33
|
+
message: `Skipped invalid JSON on line ${line}.`,
|
|
34
|
+
inputLine: line
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (!isObject(value)) {
|
|
39
|
+
diagnostics.push({
|
|
40
|
+
code: "non_object_json_line",
|
|
41
|
+
message: `Skipped non-object JSON on line ${line}.`,
|
|
42
|
+
inputLine: line
|
|
43
|
+
});
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
parsed.push({ value, line, byteOffset: lineByteOffset });
|
|
47
|
+
}
|
|
48
|
+
return parsed;
|
|
49
|
+
}
|
|
50
|
+
function utf8ByteLength(text) {
|
|
51
|
+
return new TextEncoder().encode(text).length;
|
|
52
|
+
}
|
|
53
|
+
function isObject(value) {
|
|
54
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
55
|
+
}
|
|
56
|
+
function nonemptyString(value) {
|
|
57
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
58
|
+
}
|
|
59
|
+
function parseTimestamp(value) {
|
|
60
|
+
if (value instanceof Date && !Number.isNaN(value.getTime()))
|
|
61
|
+
return value;
|
|
62
|
+
if (typeof value === "number" && value > 100000000000) {
|
|
63
|
+
const date = new Date(value);
|
|
64
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
65
|
+
}
|
|
66
|
+
if (typeof value !== "string" || value.length === 0)
|
|
67
|
+
return;
|
|
68
|
+
const withZone = /(Z|[+-]\d{2}:?\d{2})$/.test(value) ? value : `${value}Z`;
|
|
69
|
+
const date = new Date(withZone);
|
|
70
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
71
|
+
}
|
|
72
|
+
function blocksText(content) {
|
|
73
|
+
if (typeof content === "string")
|
|
74
|
+
return content;
|
|
75
|
+
if (!Array.isArray(content))
|
|
76
|
+
return "";
|
|
77
|
+
const parts = [];
|
|
78
|
+
for (const item of content) {
|
|
79
|
+
if (!isObject(item))
|
|
80
|
+
continue;
|
|
81
|
+
const type = item.type;
|
|
82
|
+
if (type === "text" || type === "input_text" || type === "output_text" || type === undefined && "text" in item) {
|
|
83
|
+
if (typeof item.text === "string" && item.text.length > 0) {
|
|
84
|
+
parts.push(item.text);
|
|
85
|
+
}
|
|
86
|
+
} else if (type === "image") {
|
|
87
|
+
parts.push("[image]");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return parts.join(`
|
|
91
|
+
`);
|
|
92
|
+
}
|
|
93
|
+
function jsonString(value) {
|
|
94
|
+
const serialized = JSON.stringify(value ?? {});
|
|
95
|
+
return serialized === undefined ? "{}" : serialized;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/atif/index.js
|
|
99
|
+
var SUPPORTED_SCHEMA_VERSIONS = new Set(Array.from({ length: 8 }, (_, index) => `ATIF-v1.${index}`));
|
|
100
|
+
var atifAdapter = {
|
|
101
|
+
source: "atif",
|
|
102
|
+
decode(transcript) {
|
|
103
|
+
const document = parseAtifDocument(transcript);
|
|
104
|
+
const diagnostics = [];
|
|
105
|
+
const events = [];
|
|
106
|
+
const trajectoryId = nonemptyString(document.trajectory_id);
|
|
107
|
+
const sessionId = nonemptyString(document.session_id);
|
|
108
|
+
const rootModel = nonemptyString(document.agent.model_name);
|
|
109
|
+
let createdAt;
|
|
110
|
+
for (let index = 0;index < document.steps.length; index += 1) {
|
|
111
|
+
const step = document.steps[index];
|
|
112
|
+
if (!isObject(step))
|
|
113
|
+
throw invalidAtifTranscript();
|
|
114
|
+
const expectedStepId = index + 1;
|
|
115
|
+
if (step.step_id !== expectedStepId)
|
|
116
|
+
throw invalidAtifTranscript();
|
|
117
|
+
if (step.source !== "system" && step.source !== "user" && step.source !== "agent") {
|
|
118
|
+
throw invalidAtifTranscript();
|
|
119
|
+
}
|
|
120
|
+
if (typeof step.message !== "string" && !Array.isArray(step.message)) {
|
|
121
|
+
throw invalidAtifTranscript();
|
|
122
|
+
}
|
|
123
|
+
const timestamp = parseTimestamp(step.timestamp);
|
|
124
|
+
createdAt ??= timestamp;
|
|
125
|
+
const model = step.source === "agent" ? nonemptyString(step.model_name) ?? rootModel : undefined;
|
|
126
|
+
const sourceRecordId = trajectoryId ? `trajectory:${trajectoryId}:step:${expectedStepId}` : `step:${expectedStepId}`;
|
|
127
|
+
let componentIndex = 0;
|
|
128
|
+
const emit = (event) => {
|
|
129
|
+
events.push({
|
|
130
|
+
...event,
|
|
131
|
+
sourceRecordId,
|
|
132
|
+
sourceSequence: expectedStepId,
|
|
133
|
+
componentIndex: componentIndex++
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
const shared = {
|
|
137
|
+
...timestamp ? { timestamp } : {},
|
|
138
|
+
...model ? { model } : {}
|
|
139
|
+
};
|
|
140
|
+
if (step.source === "user") {
|
|
141
|
+
emit({
|
|
142
|
+
type: "message",
|
|
143
|
+
role: "user",
|
|
144
|
+
content: atifContent(step.message),
|
|
145
|
+
...shared
|
|
146
|
+
});
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (step.source === "system") {
|
|
150
|
+
emit({
|
|
151
|
+
type: "message",
|
|
152
|
+
role: "system",
|
|
153
|
+
content: atifContent(step.message),
|
|
154
|
+
...shared
|
|
155
|
+
});
|
|
156
|
+
} else {
|
|
157
|
+
if (typeof step.reasoning_content === "string") {
|
|
158
|
+
emit({
|
|
159
|
+
type: "reasoning",
|
|
160
|
+
content: step.reasoning_content,
|
|
161
|
+
...shared
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
emit({
|
|
165
|
+
type: "message",
|
|
166
|
+
role: "assistant",
|
|
167
|
+
content: atifContent(step.message),
|
|
168
|
+
...shared
|
|
169
|
+
});
|
|
170
|
+
if (step.tool_calls != null && !Array.isArray(step.tool_calls)) {
|
|
171
|
+
throw invalidAtifTranscript();
|
|
172
|
+
}
|
|
173
|
+
for (const rawCall of step.tool_calls ?? []) {
|
|
174
|
+
if (!isObject(rawCall))
|
|
175
|
+
throw invalidAtifTranscript();
|
|
176
|
+
const callId = nonemptyString(rawCall.tool_call_id);
|
|
177
|
+
const name = nonemptyString(rawCall.function_name);
|
|
178
|
+
emit({
|
|
179
|
+
type: "tool_call",
|
|
180
|
+
args: jsonString(rawCall.arguments),
|
|
181
|
+
...callId ? { id: callId } : {},
|
|
182
|
+
...name ? { name } : {},
|
|
183
|
+
...shared
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (step.observation == null)
|
|
188
|
+
continue;
|
|
189
|
+
if (!isObject(step.observation) || !Array.isArray(step.observation.results)) {
|
|
190
|
+
throw invalidAtifTranscript();
|
|
191
|
+
}
|
|
192
|
+
for (const rawResult of step.observation.results) {
|
|
193
|
+
if (!isObject(rawResult))
|
|
194
|
+
throw invalidAtifTranscript();
|
|
195
|
+
const callId = nonemptyString(rawResult.source_call_id);
|
|
196
|
+
const content = observationContent(rawResult);
|
|
197
|
+
emit(callId ? { type: "tool_result", callId, content, ...shared } : { type: "observation", content, ...shared });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (Array.isArray(document.subagent_trajectories) && document.subagent_trajectories.length > 0) {
|
|
201
|
+
diagnostics.push({
|
|
202
|
+
code: "noise_record_dropped",
|
|
203
|
+
message: `Did not flatten ${document.subagent_trajectories.length} embedded ATIF subagent trajectory(ies); only root steps are normalized.`,
|
|
204
|
+
count: document.subagent_trajectories.length
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
const sourceGroupId = sessionId ?? trajectoryId;
|
|
208
|
+
return {
|
|
209
|
+
events,
|
|
210
|
+
context: {
|
|
211
|
+
source: "atif",
|
|
212
|
+
...rootModel ? { model: rootModel } : {},
|
|
213
|
+
...createdAt ? { createdAt } : {},
|
|
214
|
+
...sourceGroupId ? { sourceGroupId } : { sourceGroupRequired: true }
|
|
215
|
+
},
|
|
216
|
+
diagnostics
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
function parseAtifDocument(transcript) {
|
|
221
|
+
let parsed;
|
|
222
|
+
try {
|
|
223
|
+
parsed = JSON.parse(transcript);
|
|
224
|
+
} catch {
|
|
225
|
+
throw invalidAtifTranscript();
|
|
226
|
+
}
|
|
227
|
+
if (!isObject(parsed) || typeof parsed.schema_version !== "string" || !SUPPORTED_SCHEMA_VERSIONS.has(parsed.schema_version) || !isObject(parsed.agent) || typeof parsed.agent.name !== "string" || typeof parsed.agent.version !== "string" || !Array.isArray(parsed.steps) || parsed.steps.length === 0) {
|
|
228
|
+
throw invalidAtifTranscript();
|
|
229
|
+
}
|
|
230
|
+
return parsed;
|
|
231
|
+
}
|
|
232
|
+
function atifContent(value) {
|
|
233
|
+
if (typeof value === "string")
|
|
234
|
+
return value;
|
|
235
|
+
if (Array.isArray(value))
|
|
236
|
+
return blocksText(value);
|
|
237
|
+
return jsonString(value);
|
|
238
|
+
}
|
|
239
|
+
function observationContent(result) {
|
|
240
|
+
if (result.content != null)
|
|
241
|
+
return atifContent(result.content);
|
|
242
|
+
if (Array.isArray(result.subagent_trajectory_ref)) {
|
|
243
|
+
return jsonString({ subagent_trajectory_ref: result.subagent_trajectory_ref });
|
|
244
|
+
}
|
|
245
|
+
return "";
|
|
246
|
+
}
|
|
247
|
+
function invalidAtifTranscript() {
|
|
248
|
+
return new NormalizationError("invalid_input", "ATIF transcript must be one ATIF-v1.0 through ATIF-v1.7 JSON trajectory object with agent metadata and sequential steps.");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/claude-code/index.js
|
|
252
|
+
var TRANSPORT_TYPES = new Set([
|
|
253
|
+
"progress",
|
|
254
|
+
"queue-operation",
|
|
255
|
+
"file-history-snapshot",
|
|
256
|
+
"summary",
|
|
257
|
+
"system",
|
|
258
|
+
"pr-link",
|
|
259
|
+
"last-prompt",
|
|
260
|
+
"custom-title",
|
|
261
|
+
"ai-title",
|
|
262
|
+
"agent-name",
|
|
263
|
+
"permission-mode",
|
|
264
|
+
"attachment",
|
|
265
|
+
"mode"
|
|
266
|
+
]);
|
|
267
|
+
var claudeCodeAdapter = {
|
|
268
|
+
source: "claude-code",
|
|
269
|
+
decode(transcript) {
|
|
270
|
+
const diagnostics = [];
|
|
271
|
+
const events = [];
|
|
272
|
+
const rows = [...parseJsonLines(transcript, diagnostics)];
|
|
273
|
+
const standaloneSidechain = rows.some(({ value }) => isConversationalRecord(value) && value.isSidechain === true) && !rows.some(({ value }) => isConversationalRecord(value) && value.isSidechain !== true);
|
|
274
|
+
let cwdCandidate;
|
|
275
|
+
let branchCandidate;
|
|
276
|
+
const sessionIds = new Set;
|
|
277
|
+
const agentIds = new Set;
|
|
278
|
+
for (const { value: record, line, byteOffset } of rows) {
|
|
279
|
+
const recordType = record.type;
|
|
280
|
+
if (record.isSidechain === true && !standaloneSidechain) {
|
|
281
|
+
diagnostics.push({
|
|
282
|
+
code: "sidechain_record_dropped",
|
|
283
|
+
message: `Dropped a Claude Code sidechain record on line ${line}.`,
|
|
284
|
+
inputLine: line
|
|
285
|
+
});
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (typeof recordType === "string" && TRANSPORT_TYPES.has(recordType)) {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const contextKey = {
|
|
292
|
+
ts: parseTimestamp(record.timestamp)?.getTime() ?? Number.POSITIVE_INFINITY,
|
|
293
|
+
tie: typeof record.uuid === "string" && record.uuid ? record.uuid : `@${byteOffset}`
|
|
294
|
+
};
|
|
295
|
+
if (typeof record.cwd === "string" && record.cwd) {
|
|
296
|
+
cwdCandidate = earlier(cwdCandidate, { ...contextKey, value: record.cwd });
|
|
297
|
+
}
|
|
298
|
+
if (typeof record.gitBranch === "string" && record.gitBranch) {
|
|
299
|
+
branchCandidate = earlier(branchCandidate, {
|
|
300
|
+
...contextKey,
|
|
301
|
+
value: record.gitBranch
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (typeof record.sessionId === "string" && record.sessionId) {
|
|
305
|
+
sessionIds.add(record.sessionId);
|
|
306
|
+
}
|
|
307
|
+
if (standaloneSidechain && typeof record.agentId === "string" && record.agentId) {
|
|
308
|
+
agentIds.add(record.agentId);
|
|
309
|
+
}
|
|
310
|
+
if (recordType !== "user" && recordType !== "assistant")
|
|
311
|
+
continue;
|
|
312
|
+
if (!isObject(record.message))
|
|
313
|
+
continue;
|
|
314
|
+
const message = record.message;
|
|
315
|
+
const timestamp = parseTimestamp(record.timestamp);
|
|
316
|
+
const model = typeof message.model === "string" ? message.model : undefined;
|
|
317
|
+
const content = message.content;
|
|
318
|
+
const uuid = typeof record.uuid === "string" && record.uuid ? record.uuid : undefined;
|
|
319
|
+
let componentIndex = 0;
|
|
320
|
+
const emit = (event) => {
|
|
321
|
+
events.push({
|
|
322
|
+
...event,
|
|
323
|
+
...uuid !== undefined ? { sourceRecordId: uuid } : {},
|
|
324
|
+
sourceOffset: byteOffset,
|
|
325
|
+
sourceAnchorKind: "byte",
|
|
326
|
+
componentIndex: componentIndex++
|
|
327
|
+
});
|
|
328
|
+
};
|
|
329
|
+
if (recordType === "user") {
|
|
330
|
+
if (typeof content === "string") {
|
|
331
|
+
emit(messageEvent("user", content, line, timestamp));
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
const textParts = [];
|
|
335
|
+
for (const block of Array.isArray(content) ? content : []) {
|
|
336
|
+
if (!isObject(block))
|
|
337
|
+
continue;
|
|
338
|
+
if (block.type === "tool_result") {
|
|
339
|
+
emit(toolResultEvent(blocksText(block.content), typeof block.tool_use_id === "string" ? block.tool_use_id : undefined, typeof block.is_error === "boolean" ? !block.is_error : undefined, line, timestamp));
|
|
340
|
+
} else if (block.type === "text" && typeof block.text === "string") {
|
|
341
|
+
textParts.push(block.text);
|
|
342
|
+
} else if (block.type === "image") {
|
|
343
|
+
textParts.push("[image]");
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
if (textParts.length > 0) {
|
|
347
|
+
emit(messageEvent("user", textParts.join(`
|
|
348
|
+
`), line, timestamp));
|
|
349
|
+
}
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if (typeof content === "string") {
|
|
353
|
+
if (content.trim()) {
|
|
354
|
+
emit(messageEvent("assistant", content, line, timestamp, model));
|
|
355
|
+
}
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
for (const block of Array.isArray(content) ? content : []) {
|
|
359
|
+
if (!isObject(block))
|
|
360
|
+
continue;
|
|
361
|
+
if (block.type === "thinking") {
|
|
362
|
+
emit(reasoningEvent(typeof block.thinking === "string" ? block.thinking : "", line, timestamp, model));
|
|
363
|
+
} else if (block.type === "text") {
|
|
364
|
+
emit(messageEvent("assistant", typeof block.text === "string" ? block.text : "", line, timestamp, model));
|
|
365
|
+
} else if (block.type === "tool_use") {
|
|
366
|
+
emit(toolCallEvent(typeof block.id === "string" ? block.id : undefined, typeof block.name === "string" ? block.name : undefined, jsonString(block.input), line, timestamp, model));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
if (agentIds.size > 1) {
|
|
371
|
+
throw new NormalizationError("source_group_conflict", `Claude Code subagent transcript contains multiple agent ids: ${[...agentIds].map((id) => JSON.stringify(id)).sort().join(", ")}.`);
|
|
372
|
+
}
|
|
373
|
+
const sessionId = sessionIds.size === 1 ? sessionIds.values().next().value : undefined;
|
|
374
|
+
const [agentId] = agentIds;
|
|
375
|
+
const sourceGroupId = agentId ?? sessionId;
|
|
376
|
+
const sourceGroupAmbiguous = sessionIds.size > 1 && !agentId;
|
|
377
|
+
const cwd = cwdCandidate?.value;
|
|
378
|
+
const gitBranch = branchCandidate?.value;
|
|
379
|
+
return {
|
|
380
|
+
events,
|
|
381
|
+
context: {
|
|
382
|
+
source: "claude-code",
|
|
383
|
+
...cwd ? { cwd } : {},
|
|
384
|
+
...gitBranch ? { gitBranch } : {},
|
|
385
|
+
...sourceGroupId ? { sourceGroupId } : {},
|
|
386
|
+
...sourceGroupAmbiguous ? { sourceGroupAmbiguous: true } : {}
|
|
387
|
+
},
|
|
388
|
+
diagnostics
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
function isConversationalRecord(record) {
|
|
393
|
+
return (record.type === "user" || record.type === "assistant") && isObject(record.message);
|
|
394
|
+
}
|
|
395
|
+
function earlier(current, next) {
|
|
396
|
+
if (current === undefined)
|
|
397
|
+
return next;
|
|
398
|
+
if (next.ts < current.ts)
|
|
399
|
+
return next;
|
|
400
|
+
if (next.ts > current.ts)
|
|
401
|
+
return current;
|
|
402
|
+
return next.tie < current.tie ? next : current;
|
|
403
|
+
}
|
|
404
|
+
function messageEvent(role, content, inputLine, timestamp, model) {
|
|
405
|
+
return {
|
|
406
|
+
type: "message",
|
|
407
|
+
role,
|
|
408
|
+
content,
|
|
409
|
+
inputLine,
|
|
410
|
+
...timestamp ? { timestamp } : {},
|
|
411
|
+
...model ? { model } : {}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function reasoningEvent(content, inputLine, timestamp, model) {
|
|
415
|
+
return {
|
|
416
|
+
type: "reasoning",
|
|
417
|
+
content,
|
|
418
|
+
inputLine,
|
|
419
|
+
...timestamp ? { timestamp } : {},
|
|
420
|
+
...model ? { model } : {}
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
function toolCallEvent(id, name, args, inputLine, timestamp, model) {
|
|
424
|
+
return {
|
|
425
|
+
type: "tool_call",
|
|
426
|
+
args,
|
|
427
|
+
inputLine,
|
|
428
|
+
...id ? { id } : {},
|
|
429
|
+
...name ? { name } : {},
|
|
430
|
+
...timestamp ? { timestamp } : {},
|
|
431
|
+
...model ? { model } : {}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
function toolResultEvent(content, callId, ok, inputLine, timestamp) {
|
|
435
|
+
return {
|
|
436
|
+
type: "tool_result",
|
|
437
|
+
content,
|
|
438
|
+
...typeof ok === "boolean" ? { ok } : {},
|
|
439
|
+
inputLine,
|
|
440
|
+
...callId ? { callId } : {},
|
|
441
|
+
...timestamp ? { timestamp } : {}
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/codex/index.js
|
|
446
|
+
var INJECTED_PREFIXES = [
|
|
447
|
+
"<environment_context>",
|
|
448
|
+
"<user_instructions>",
|
|
449
|
+
"<permissions instructions>",
|
|
450
|
+
"<turn_context>"
|
|
451
|
+
];
|
|
452
|
+
var codexAdapter = {
|
|
453
|
+
source: "codex",
|
|
454
|
+
decode(transcript) {
|
|
455
|
+
const diagnostics = [];
|
|
456
|
+
const events = [];
|
|
457
|
+
let cwd;
|
|
458
|
+
let gitBranch;
|
|
459
|
+
let model;
|
|
460
|
+
let createdAt;
|
|
461
|
+
let sessionId;
|
|
462
|
+
for (const { value: record, line, byteOffset } of parseJsonLines(transcript, diagnostics)) {
|
|
463
|
+
const recordType = record.type;
|
|
464
|
+
const payload = isObject(record.payload) ? record.payload : {};
|
|
465
|
+
const timestamp = parseTimestamp(record.timestamp);
|
|
466
|
+
const payloadType = payload.type;
|
|
467
|
+
const emit = (event) => {
|
|
468
|
+
events.push({
|
|
469
|
+
...event,
|
|
470
|
+
sourceOffset: byteOffset,
|
|
471
|
+
sourceAnchorKind: "byte",
|
|
472
|
+
componentIndex: 0
|
|
473
|
+
});
|
|
474
|
+
};
|
|
475
|
+
if (recordType === "session_meta") {
|
|
476
|
+
if (!cwd && typeof payload.cwd === "string" && payload.cwd)
|
|
477
|
+
cwd = payload.cwd;
|
|
478
|
+
createdAt ??= parseTimestamp(payload.timestamp) ?? timestamp;
|
|
479
|
+
if (!gitBranch && isObject(payload.git) && typeof payload.git.branch === "string") {
|
|
480
|
+
gitBranch = payload.git.branch;
|
|
481
|
+
}
|
|
482
|
+
if (!sessionId && typeof payload.id === "string" && payload.id) {
|
|
483
|
+
sessionId = payload.id;
|
|
484
|
+
}
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
if (recordType === "turn_context") {
|
|
488
|
+
if (!cwd && typeof payload.cwd === "string" && payload.cwd)
|
|
489
|
+
cwd = payload.cwd;
|
|
490
|
+
if (!model && typeof payload.model === "string" && payload.model) {
|
|
491
|
+
model = payload.model;
|
|
492
|
+
}
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (recordType === "event_msg") {
|
|
496
|
+
if (payloadType === "agent_reasoning" && typeof payload.text === "string" && payload.text.trim()) {
|
|
497
|
+
emit({
|
|
498
|
+
type: "reasoning",
|
|
499
|
+
content: payload.text,
|
|
500
|
+
inputLine: line,
|
|
501
|
+
...timestamp ? { timestamp } : {}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
if (recordType !== "response_item")
|
|
507
|
+
continue;
|
|
508
|
+
if (payloadType === "message") {
|
|
509
|
+
const role = payload.role;
|
|
510
|
+
const content = blocksText(payload.content);
|
|
511
|
+
if (role === "system") {
|
|
512
|
+
emit({
|
|
513
|
+
type: "message",
|
|
514
|
+
role: "system",
|
|
515
|
+
content,
|
|
516
|
+
inputLine: line,
|
|
517
|
+
...timestamp ? { timestamp } : {}
|
|
518
|
+
});
|
|
519
|
+
} else if (role === "user") {
|
|
520
|
+
const head = content.trimStart();
|
|
521
|
+
if (INJECTED_PREFIXES.some((prefix) => head.startsWith(prefix))) {
|
|
522
|
+
diagnostics.push({
|
|
523
|
+
code: "injected_context_dropped",
|
|
524
|
+
message: `Dropped Codex system-injected user content on line ${line}.`,
|
|
525
|
+
inputLine: line
|
|
526
|
+
});
|
|
527
|
+
} else {
|
|
528
|
+
emit({
|
|
529
|
+
type: "message",
|
|
530
|
+
role: "user",
|
|
531
|
+
content,
|
|
532
|
+
inputLine: line,
|
|
533
|
+
...timestamp ? { timestamp } : {}
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
} else if (role === "assistant") {
|
|
537
|
+
emit({
|
|
538
|
+
type: "message",
|
|
539
|
+
role: "assistant",
|
|
540
|
+
content,
|
|
541
|
+
inputLine: line,
|
|
542
|
+
...timestamp ? { timestamp } : {}
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
if (payloadType === "function_call") {
|
|
548
|
+
emit({
|
|
549
|
+
type: "tool_call",
|
|
550
|
+
args: typeof payload.arguments === "string" && payload.arguments ? payload.arguments : "{}",
|
|
551
|
+
inputLine: line,
|
|
552
|
+
...typeof payload.call_id === "string" ? { id: payload.call_id } : {},
|
|
553
|
+
...typeof payload.name === "string" ? { name: payload.name } : {},
|
|
554
|
+
...timestamp ? { timestamp } : {}
|
|
555
|
+
});
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
if (payloadType === "custom_tool_call") {
|
|
559
|
+
emit({
|
|
560
|
+
type: "tool_call",
|
|
561
|
+
args: jsonString({ input: payload.input ?? "" }),
|
|
562
|
+
inputLine: line,
|
|
563
|
+
...typeof payload.call_id === "string" ? { id: payload.call_id } : {},
|
|
564
|
+
...typeof payload.name === "string" ? { name: payload.name } : {},
|
|
565
|
+
...timestamp ? { timestamp } : {}
|
|
566
|
+
});
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
if (payloadType === "web_search_call") {
|
|
570
|
+
const args = {};
|
|
571
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
572
|
+
if (key !== "type" && key !== "call_id" && key !== "status") {
|
|
573
|
+
args[key] = value;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
emit({
|
|
577
|
+
type: "tool_call",
|
|
578
|
+
name: "web_search",
|
|
579
|
+
args: jsonString(args),
|
|
580
|
+
inputLine: line,
|
|
581
|
+
...typeof payload.call_id === "string" ? { id: payload.call_id } : {},
|
|
582
|
+
...timestamp ? { timestamp } : {}
|
|
583
|
+
});
|
|
584
|
+
continue;
|
|
585
|
+
}
|
|
586
|
+
if (payloadType === "tool_search_call") {
|
|
587
|
+
emit({
|
|
588
|
+
type: "tool_call",
|
|
589
|
+
name: "tool_search",
|
|
590
|
+
args: typeof payload.arguments === "string" && payload.arguments ? payload.arguments : jsonString(payload.arguments),
|
|
591
|
+
inputLine: line,
|
|
592
|
+
...typeof payload.call_id === "string" ? { id: payload.call_id } : {},
|
|
593
|
+
...timestamp ? { timestamp } : {}
|
|
594
|
+
});
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output" || payloadType === "tool_search_output") {
|
|
598
|
+
emit({
|
|
599
|
+
type: "tool_result",
|
|
600
|
+
content: payloadType === "tool_search_output" ? jsonString(payload.tools ?? []) : outputText(payload.output),
|
|
601
|
+
inputLine: line,
|
|
602
|
+
...typeof payload.call_id === "string" ? { callId: payload.call_id } : {},
|
|
603
|
+
...timestamp ? { timestamp } : {}
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return {
|
|
608
|
+
events,
|
|
609
|
+
context: {
|
|
610
|
+
source: "codex",
|
|
611
|
+
...cwd ? { cwd } : {},
|
|
612
|
+
...gitBranch ? { gitBranch } : {},
|
|
613
|
+
...model ? { model } : {},
|
|
614
|
+
...createdAt ? { createdAt } : {},
|
|
615
|
+
...sessionId ? { sourceGroupId: sessionId } : {}
|
|
616
|
+
},
|
|
617
|
+
diagnostics
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
function outputText(output) {
|
|
622
|
+
if (typeof output === "string")
|
|
623
|
+
return output;
|
|
624
|
+
if (Array.isArray(output))
|
|
625
|
+
return blocksText(output) || jsonString(output);
|
|
626
|
+
if (isObject(output)) {
|
|
627
|
+
return typeof output.content === "string" && output.content ? output.content : jsonString(output);
|
|
628
|
+
}
|
|
629
|
+
return output == null ? "" : String(output);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/copilot-cli/index.js
|
|
633
|
+
var KNOWN_EVENT_TYPES = new Set([
|
|
634
|
+
"abort",
|
|
635
|
+
"assistant.message",
|
|
636
|
+
"assistant.turn_end",
|
|
637
|
+
"assistant.turn_start",
|
|
638
|
+
"hook.end",
|
|
639
|
+
"hook.start",
|
|
640
|
+
"session.compaction_complete",
|
|
641
|
+
"session.compaction_start",
|
|
642
|
+
"session.info",
|
|
643
|
+
"session.mode_changed",
|
|
644
|
+
"session.model_change",
|
|
645
|
+
"session.plan_changed",
|
|
646
|
+
"session.resume",
|
|
647
|
+
"session.shutdown",
|
|
648
|
+
"session.start",
|
|
649
|
+
"session.task_complete",
|
|
650
|
+
"system.notification",
|
|
651
|
+
"tool.execution_complete",
|
|
652
|
+
"tool.execution_start",
|
|
653
|
+
"user.message"
|
|
654
|
+
]);
|
|
655
|
+
var copilotCliAdapter = {
|
|
656
|
+
source: "copilot-cli",
|
|
657
|
+
decode(transcript) {
|
|
658
|
+
const diagnostics = [];
|
|
659
|
+
const rows = parseJsonLines(transcript, diagnostics);
|
|
660
|
+
const events = [];
|
|
661
|
+
let recognizedRows = 0;
|
|
662
|
+
let cwd;
|
|
663
|
+
let gitBranch;
|
|
664
|
+
let model;
|
|
665
|
+
let sourceGroupId;
|
|
666
|
+
let createdAt;
|
|
667
|
+
for (const { value: row } of rows) {
|
|
668
|
+
if (typeof row.type !== "string" || !KNOWN_EVENT_TYPES.has(row.type))
|
|
669
|
+
continue;
|
|
670
|
+
const data = isObject(row.data) ? row.data : {};
|
|
671
|
+
if (row.type === "session.start") {
|
|
672
|
+
sourceGroupId ??= nonemptyString(data.sessionId);
|
|
673
|
+
createdAt ??= parseTimestamp(data.startTime);
|
|
674
|
+
const context = isObject(data.context) ? data.context : {};
|
|
675
|
+
cwd ??= nonemptyString(context.cwd);
|
|
676
|
+
gitBranch ??= nonemptyString(context.branch);
|
|
677
|
+
} else if (row.type === "hook.start" && data.hookType === "userPromptSubmitted") {
|
|
678
|
+
const input = isObject(data.input) ? data.input : {};
|
|
679
|
+
sourceGroupId ??= nonemptyString(input.sessionId);
|
|
680
|
+
cwd ??= nonemptyString(input.cwd);
|
|
681
|
+
} else if (row.type === "tool.execution_complete") {
|
|
682
|
+
model ??= nonemptyString(data.model);
|
|
683
|
+
} else if (row.type === "session.model_change") {
|
|
684
|
+
model ??= nonemptyString(data.newModel);
|
|
685
|
+
} else if (row.type === "session.shutdown") {
|
|
686
|
+
model ??= nonemptyString(data.currentModel);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
for (const { value: row, line, byteOffset } of rows) {
|
|
690
|
+
const rowType = row.type;
|
|
691
|
+
if (typeof rowType !== "string" || !KNOWN_EVENT_TYPES.has(rowType)) {
|
|
692
|
+
diagnostics.push({
|
|
693
|
+
code: "noise_record_dropped",
|
|
694
|
+
message: `Skipped unsupported Copilot CLI event on line ${line}.`,
|
|
695
|
+
inputLine: line
|
|
696
|
+
});
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
recognizedRows += 1;
|
|
700
|
+
const data = isObject(row.data) ? row.data : {};
|
|
701
|
+
const timestamp = parseTimestamp(row.timestamp);
|
|
702
|
+
const sourceRecordId = nonemptyString(row.id);
|
|
703
|
+
let componentIndex = 0;
|
|
704
|
+
const emit = (event) => {
|
|
705
|
+
events.push({
|
|
706
|
+
...event,
|
|
707
|
+
...sourceRecordId ? { sourceRecordId } : { sourceOffset: byteOffset, sourceAnchorKind: "byte" },
|
|
708
|
+
sourceSequence: line - 1,
|
|
709
|
+
componentIndex: componentIndex++,
|
|
710
|
+
inputLine: line
|
|
711
|
+
});
|
|
712
|
+
};
|
|
713
|
+
if (rowType === "hook.start" && data.hookType === "userPromptSubmitted") {
|
|
714
|
+
const input = isObject(data.input) ? data.input : {};
|
|
715
|
+
const promptTimestamp = parseTimestamp(input.timestamp) ?? timestamp;
|
|
716
|
+
emit({
|
|
717
|
+
type: "message",
|
|
718
|
+
role: "user",
|
|
719
|
+
content: typeof input.prompt === "string" ? input.prompt : "",
|
|
720
|
+
...promptTimestamp ? { timestamp: promptTimestamp } : {}
|
|
721
|
+
});
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
if (rowType === "assistant.message") {
|
|
725
|
+
const eventModel = nonemptyString(data.model);
|
|
726
|
+
if (typeof data.reasoningText === "string" && data.reasoningText.trim()) {
|
|
727
|
+
emit({
|
|
728
|
+
type: "reasoning",
|
|
729
|
+
content: data.reasoningText,
|
|
730
|
+
...timestamp ? { timestamp } : {},
|
|
731
|
+
...eventModel ? { model: eventModel } : {}
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
if (typeof data.content === "string" && data.content.trim()) {
|
|
735
|
+
emit({
|
|
736
|
+
type: "message",
|
|
737
|
+
role: "assistant",
|
|
738
|
+
content: data.content,
|
|
739
|
+
...timestamp ? { timestamp } : {},
|
|
740
|
+
...eventModel ? { model: eventModel } : {}
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
if (Array.isArray(data.toolRequests)) {
|
|
744
|
+
for (const request of data.toolRequests) {
|
|
745
|
+
if (!isObject(request))
|
|
746
|
+
continue;
|
|
747
|
+
const callId = nonemptyString(request.toolCallId);
|
|
748
|
+
const name = nonemptyString(request.name);
|
|
749
|
+
emit({
|
|
750
|
+
type: "tool_call",
|
|
751
|
+
args: typeof request.arguments === "string" ? request.arguments : jsonString(request.arguments),
|
|
752
|
+
...callId ? { id: callId } : {},
|
|
753
|
+
...name ? { name } : {},
|
|
754
|
+
...timestamp ? { timestamp } : {},
|
|
755
|
+
...eventModel ? { model: eventModel } : {}
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
761
|
+
if (rowType === "tool.execution_complete") {
|
|
762
|
+
const callId = nonemptyString(data.toolCallId);
|
|
763
|
+
const eventModel = nonemptyString(data.model);
|
|
764
|
+
emit({
|
|
765
|
+
type: "tool_result",
|
|
766
|
+
content: copilotResultContent(data),
|
|
767
|
+
...callId ? { callId } : {},
|
|
768
|
+
...typeof data.success === "boolean" ? { ok: data.success } : {},
|
|
769
|
+
...timestamp ? { timestamp } : {},
|
|
770
|
+
...eventModel ? { model: eventModel } : {}
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
if (recognizedRows === 0)
|
|
775
|
+
throw invalidCopilotTranscript();
|
|
776
|
+
return {
|
|
777
|
+
events,
|
|
778
|
+
context: {
|
|
779
|
+
source: "copilot-cli",
|
|
780
|
+
...cwd ? { cwd } : {},
|
|
781
|
+
...gitBranch ? { gitBranch } : {},
|
|
782
|
+
...model ? { model } : {},
|
|
783
|
+
...sourceGroupId ? { sourceGroupId } : {},
|
|
784
|
+
...createdAt ? { createdAt } : {}
|
|
785
|
+
},
|
|
786
|
+
diagnostics
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
function copilotResultContent(data) {
|
|
791
|
+
if (isObject(data.result)) {
|
|
792
|
+
const content = data.result.content;
|
|
793
|
+
if (typeof content === "string")
|
|
794
|
+
return content;
|
|
795
|
+
if (content !== undefined)
|
|
796
|
+
return stringifyContent(content);
|
|
797
|
+
}
|
|
798
|
+
if (isObject(data.error) && typeof data.error.message === "string") {
|
|
799
|
+
return data.error.message;
|
|
800
|
+
}
|
|
801
|
+
if (data.error !== undefined)
|
|
802
|
+
return stringifyContent(data.error);
|
|
803
|
+
return "";
|
|
804
|
+
}
|
|
805
|
+
function stringifyContent(value) {
|
|
806
|
+
if (typeof value === "string")
|
|
807
|
+
return value;
|
|
808
|
+
if (value === null || value === undefined)
|
|
809
|
+
return "";
|
|
810
|
+
return isObject(value) || Array.isArray(value) ? jsonString(value) : String(value);
|
|
811
|
+
}
|
|
812
|
+
function invalidCopilotTranscript() {
|
|
813
|
+
return new NormalizationError("invalid_input", "Copilot CLI transcript must be native event JSONL with recognized type and data records.");
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/cursor/index.js
|
|
817
|
+
var cursorAdapter = {
|
|
818
|
+
source: "cursor",
|
|
819
|
+
decode(transcript) {
|
|
820
|
+
const diagnostics = [];
|
|
821
|
+
const events = [];
|
|
822
|
+
let recognizedRows = 0;
|
|
823
|
+
for (const { value: row, line, byteOffset } of parseJsonLines(transcript, diagnostics)) {
|
|
824
|
+
if (row.role !== "user" && row.role !== "assistant" || !isObject(row.message)) {
|
|
825
|
+
diagnostics.push({
|
|
826
|
+
code: "noise_record_dropped",
|
|
827
|
+
message: `Skipped unsupported Cursor row on line ${line}.`,
|
|
828
|
+
inputLine: line
|
|
829
|
+
});
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
recognizedRows += 1;
|
|
833
|
+
const role = row.role;
|
|
834
|
+
const model = typeof row.message.model === "string" && row.message.model ? row.message.model : undefined;
|
|
835
|
+
const content = row.message.content;
|
|
836
|
+
const blocks = Array.isArray(content) ? content : [{ type: "text", text: typeof content === "string" ? content : "" }];
|
|
837
|
+
const sourceRecordId = typeof row.id === "string" && row.id ? row.id : undefined;
|
|
838
|
+
let componentIndex = 0;
|
|
839
|
+
const emit = (event) => {
|
|
840
|
+
events.push({
|
|
841
|
+
...event,
|
|
842
|
+
...sourceRecordId ? { sourceRecordId } : { sourceOffset: byteOffset, sourceAnchorKind: "byte" },
|
|
843
|
+
sourceSequence: line - 1,
|
|
844
|
+
componentIndex: componentIndex++,
|
|
845
|
+
inputLine: line
|
|
846
|
+
});
|
|
847
|
+
};
|
|
848
|
+
for (const block of blocks) {
|
|
849
|
+
if (!isObject(block))
|
|
850
|
+
continue;
|
|
851
|
+
if (block.type === "text") {
|
|
852
|
+
emit({
|
|
853
|
+
type: "message",
|
|
854
|
+
role,
|
|
855
|
+
content: typeof block.text === "string" ? block.text : "",
|
|
856
|
+
...model ? { model } : {}
|
|
857
|
+
});
|
|
858
|
+
} else if (block.type === "thinking") {
|
|
859
|
+
emit({
|
|
860
|
+
type: "reasoning",
|
|
861
|
+
content: typeof block.thinking === "string" ? block.thinking : "",
|
|
862
|
+
...model ? { model } : {}
|
|
863
|
+
});
|
|
864
|
+
} else if (block.type === "tool_use") {
|
|
865
|
+
emit({
|
|
866
|
+
type: "tool_call",
|
|
867
|
+
args: jsonString(block.input),
|
|
868
|
+
...typeof block.id === "string" && block.id ? { id: block.id } : {},
|
|
869
|
+
...typeof block.name === "string" && block.name ? { name: block.name } : {},
|
|
870
|
+
...model ? { model } : {}
|
|
871
|
+
});
|
|
872
|
+
} else if (block.type === "tool_result") {
|
|
873
|
+
emit({
|
|
874
|
+
type: "tool_result",
|
|
875
|
+
content: resultContent(block.content),
|
|
876
|
+
...typeof block.tool_use_id === "string" && block.tool_use_id ? { callId: block.tool_use_id } : {},
|
|
877
|
+
...typeof block.is_error === "boolean" ? { ok: !block.is_error } : {},
|
|
878
|
+
...model ? { model } : {}
|
|
879
|
+
});
|
|
880
|
+
} else {
|
|
881
|
+
diagnostics.push({
|
|
882
|
+
code: "noise_record_dropped",
|
|
883
|
+
message: `Skipped unsupported Cursor content block ${JSON.stringify(block.type)} ` + `on line ${line}.`,
|
|
884
|
+
inputLine: line
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
if (recognizedRows === 0)
|
|
890
|
+
throw invalidCursorTranscript();
|
|
891
|
+
return {
|
|
892
|
+
events,
|
|
893
|
+
context: { source: "cursor" },
|
|
894
|
+
diagnostics
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
};
|
|
898
|
+
function resultContent(value) {
|
|
899
|
+
if (typeof value === "string")
|
|
900
|
+
return value;
|
|
901
|
+
if (Array.isArray(value))
|
|
902
|
+
return blocksText(value);
|
|
903
|
+
if (value === null || value === undefined)
|
|
904
|
+
return "";
|
|
905
|
+
return isObject(value) ? jsonString(value) : String(value);
|
|
906
|
+
}
|
|
907
|
+
function invalidCursorTranscript() {
|
|
908
|
+
return new NormalizationError("invalid_input", "Cursor transcript must be JSONL with role and message.content records.");
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/droid/index.js
|
|
912
|
+
var TRANSPORT_TYPES2 = new Set([
|
|
913
|
+
"todo_state",
|
|
914
|
+
"session_end",
|
|
915
|
+
"compaction_state"
|
|
916
|
+
]);
|
|
917
|
+
var droidAdapter = {
|
|
918
|
+
source: "droid",
|
|
919
|
+
decode(transcript) {
|
|
920
|
+
const diagnostics = [];
|
|
921
|
+
const events = [];
|
|
922
|
+
let cwd;
|
|
923
|
+
let sourceGroupId;
|
|
924
|
+
for (const { value: record, line, byteOffset } of parseJsonLines(transcript, diagnostics)) {
|
|
925
|
+
const recordType = record.type;
|
|
926
|
+
if (recordType === "session_start") {
|
|
927
|
+
if (sourceGroupId === undefined && typeof record.id === "string" && record.id) {
|
|
928
|
+
sourceGroupId = record.id;
|
|
929
|
+
}
|
|
930
|
+
if (cwd === undefined && typeof record.cwd === "string" && record.cwd) {
|
|
931
|
+
cwd = record.cwd;
|
|
932
|
+
}
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
if (typeof recordType === "string" && TRANSPORT_TYPES2.has(recordType)) {
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
if (recordType !== "message" || !isObject(record.message))
|
|
939
|
+
continue;
|
|
940
|
+
const role = record.message.role;
|
|
941
|
+
if (role !== "user" && role !== "assistant")
|
|
942
|
+
continue;
|
|
943
|
+
const blocks = record.message.content;
|
|
944
|
+
if (!Array.isArray(blocks))
|
|
945
|
+
continue;
|
|
946
|
+
let componentIndex = 0;
|
|
947
|
+
const emit = (event) => {
|
|
948
|
+
events.push({
|
|
949
|
+
...event,
|
|
950
|
+
sourceOffset: byteOffset,
|
|
951
|
+
sourceAnchorKind: "byte",
|
|
952
|
+
componentIndex: componentIndex++
|
|
953
|
+
});
|
|
954
|
+
};
|
|
955
|
+
for (const block of blocks) {
|
|
956
|
+
if (!isObject(block))
|
|
957
|
+
continue;
|
|
958
|
+
if (block.type === "thinking") {
|
|
959
|
+
emit({
|
|
960
|
+
type: "reasoning",
|
|
961
|
+
content: typeof block.thinking === "string" ? block.thinking : "",
|
|
962
|
+
inputLine: line
|
|
963
|
+
});
|
|
964
|
+
} else if (block.type === "text") {
|
|
965
|
+
emit({
|
|
966
|
+
type: "message",
|
|
967
|
+
role,
|
|
968
|
+
content: typeof block.text === "string" ? block.text : "",
|
|
969
|
+
inputLine: line
|
|
970
|
+
});
|
|
971
|
+
} else if (block.type === "tool_use" && role === "assistant") {
|
|
972
|
+
emit({
|
|
973
|
+
type: "tool_call",
|
|
974
|
+
args: jsonString(block.input),
|
|
975
|
+
inputLine: line,
|
|
976
|
+
...typeof block.id === "string" && block.id ? { id: block.id } : {},
|
|
977
|
+
...typeof block.name === "string" && block.name ? { name: block.name } : {}
|
|
978
|
+
});
|
|
979
|
+
} else if (block.type === "tool_result" && role === "user") {
|
|
980
|
+
emit({
|
|
981
|
+
type: "tool_result",
|
|
982
|
+
content: toolResultContent(block.content, block.is_error === true),
|
|
983
|
+
inputLine: line,
|
|
984
|
+
...typeof block.tool_use_id === "string" && block.tool_use_id ? { callId: block.tool_use_id } : {}
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return {
|
|
990
|
+
events,
|
|
991
|
+
context: {
|
|
992
|
+
source: "droid",
|
|
993
|
+
...cwd ? { cwd } : {},
|
|
994
|
+
...sourceGroupId ? { sourceGroupId } : {}
|
|
995
|
+
},
|
|
996
|
+
diagnostics
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
function toolResultContent(content, isError) {
|
|
1001
|
+
const text = typeof content === "string" ? content : blocksText(content);
|
|
1002
|
+
return isError && !/^error/i.test(text) ? `Error: ${text}` : text;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/gemini-cli/index.js
|
|
1006
|
+
var TERMINAL_TOOL_STATUSES = new Set(["cancelled", "error", "success"]);
|
|
1007
|
+
var geminiCliAdapter = {
|
|
1008
|
+
source: "gemini-cli",
|
|
1009
|
+
decode(transcript) {
|
|
1010
|
+
const document = parseGeminiDocument(transcript);
|
|
1011
|
+
const diagnostics = [];
|
|
1012
|
+
const events = [];
|
|
1013
|
+
for (let messageIndex = 0;messageIndex < document.messages.length; messageIndex += 1) {
|
|
1014
|
+
const message = document.messages[messageIndex];
|
|
1015
|
+
if (!isObject(message))
|
|
1016
|
+
continue;
|
|
1017
|
+
const messageType = message.type;
|
|
1018
|
+
if (messageType === "info")
|
|
1019
|
+
continue;
|
|
1020
|
+
const timestamp = parseTimestamp(message.timestamp);
|
|
1021
|
+
const model = nonemptyString(message.model);
|
|
1022
|
+
const sourceRecordId = nonemptyString(message.id);
|
|
1023
|
+
let componentIndex = 0;
|
|
1024
|
+
const emit = (event) => {
|
|
1025
|
+
events.push({
|
|
1026
|
+
...event,
|
|
1027
|
+
...sourceRecordId ? { sourceRecordId } : { sourceOffset: messageIndex, sourceAnchorKind: "ordinal" },
|
|
1028
|
+
sourceSequence: messageIndex,
|
|
1029
|
+
componentIndex: componentIndex++
|
|
1030
|
+
});
|
|
1031
|
+
};
|
|
1032
|
+
if (messageType === "user") {
|
|
1033
|
+
emit({
|
|
1034
|
+
type: "message",
|
|
1035
|
+
role: "user",
|
|
1036
|
+
content: blocksText(message.content),
|
|
1037
|
+
...timestamp ? { timestamp } : {}
|
|
1038
|
+
});
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
if (messageType !== "gemini") {
|
|
1042
|
+
diagnostics.push({
|
|
1043
|
+
code: "noise_record_dropped",
|
|
1044
|
+
message: `Skipped unsupported Gemini CLI message type ${JSON.stringify(messageType)} ` + `at position ${messageIndex + 1}.`
|
|
1045
|
+
});
|
|
1046
|
+
continue;
|
|
1047
|
+
}
|
|
1048
|
+
if (Array.isArray(message.thoughts)) {
|
|
1049
|
+
for (const thought of message.thoughts) {
|
|
1050
|
+
const content = thoughtContent(thought);
|
|
1051
|
+
if (!content.trim())
|
|
1052
|
+
continue;
|
|
1053
|
+
emit({
|
|
1054
|
+
type: "reasoning",
|
|
1055
|
+
content,
|
|
1056
|
+
...timestamp ? { timestamp } : {},
|
|
1057
|
+
...model ? { model } : {}
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
const content = blocksText(message.content);
|
|
1062
|
+
if (content.trim()) {
|
|
1063
|
+
emit({
|
|
1064
|
+
type: "message",
|
|
1065
|
+
role: "assistant",
|
|
1066
|
+
content,
|
|
1067
|
+
...timestamp ? { timestamp } : {},
|
|
1068
|
+
...model ? { model } : {}
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
if (!Array.isArray(message.toolCalls))
|
|
1072
|
+
continue;
|
|
1073
|
+
for (const rawCall of message.toolCalls) {
|
|
1074
|
+
if (!isObject(rawCall))
|
|
1075
|
+
continue;
|
|
1076
|
+
const callId = nonemptyString(rawCall.id);
|
|
1077
|
+
const name = nonemptyString(rawCall.name);
|
|
1078
|
+
const callTimestamp = parseTimestamp(rawCall.timestamp) ?? timestamp;
|
|
1079
|
+
emit({
|
|
1080
|
+
type: "tool_call",
|
|
1081
|
+
args: jsonString(rawCall.args),
|
|
1082
|
+
...callId ? { id: callId } : {},
|
|
1083
|
+
...name ? { name } : {},
|
|
1084
|
+
...callTimestamp ? { timestamp: callTimestamp } : {},
|
|
1085
|
+
...model ? { model } : {}
|
|
1086
|
+
});
|
|
1087
|
+
const status = nonemptyString(rawCall.status);
|
|
1088
|
+
const outputs = toolOutputs(rawCall.result);
|
|
1089
|
+
if (outputs.length === 0 && (!status || !TERMINAL_TOOL_STATUSES.has(status))) {
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
emit({
|
|
1093
|
+
type: "tool_result",
|
|
1094
|
+
content: outputs.join(`
|
|
1095
|
+
`),
|
|
1096
|
+
...callId ? { callId } : {},
|
|
1097
|
+
...status === "success" ? { ok: true } : status === "error" || status === "cancelled" ? { ok: false } : {},
|
|
1098
|
+
...callTimestamp ? { timestamp: callTimestamp } : {},
|
|
1099
|
+
...model ? { model } : {}
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
const sourceGroupId = nonemptyString(document.sessionId);
|
|
1104
|
+
const sourceGroupRequired = !sourceGroupId && !nonemptyString(document.projectHash);
|
|
1105
|
+
const createdAt = parseTimestamp(document.startTime);
|
|
1106
|
+
return {
|
|
1107
|
+
events,
|
|
1108
|
+
context: {
|
|
1109
|
+
source: "gemini-cli",
|
|
1110
|
+
...sourceGroupId ? { sourceGroupId } : {},
|
|
1111
|
+
...sourceGroupRequired ? { sourceGroupRequired: true } : {},
|
|
1112
|
+
...createdAt ? { createdAt } : {}
|
|
1113
|
+
},
|
|
1114
|
+
diagnostics
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
function parseGeminiDocument(transcript) {
|
|
1119
|
+
let parsed;
|
|
1120
|
+
try {
|
|
1121
|
+
parsed = JSON.parse(transcript);
|
|
1122
|
+
} catch {
|
|
1123
|
+
throw invalidGeminiTranscript();
|
|
1124
|
+
}
|
|
1125
|
+
if (!isObject(parsed) || !Array.isArray(parsed.messages)) {
|
|
1126
|
+
throw invalidGeminiTranscript();
|
|
1127
|
+
}
|
|
1128
|
+
return parsed;
|
|
1129
|
+
}
|
|
1130
|
+
function thoughtContent(value) {
|
|
1131
|
+
if (!isObject(value))
|
|
1132
|
+
return String(value ?? "");
|
|
1133
|
+
return ["subject", "description"].flatMap((key) => typeof value[key] === "string" && value[key] ? [value[key]] : []).join(" \u2014 ");
|
|
1134
|
+
}
|
|
1135
|
+
function toolOutputs(value) {
|
|
1136
|
+
if (!Array.isArray(value))
|
|
1137
|
+
return [];
|
|
1138
|
+
const outputs = [];
|
|
1139
|
+
for (const item of value) {
|
|
1140
|
+
if (!isObject(item) || !isObject(item.functionResponse))
|
|
1141
|
+
continue;
|
|
1142
|
+
const response = item.functionResponse.response;
|
|
1143
|
+
if (!isObject(response))
|
|
1144
|
+
continue;
|
|
1145
|
+
if (response.output !== undefined) {
|
|
1146
|
+
outputs.push(stringContent(response.output));
|
|
1147
|
+
} else if (Object.keys(response).length > 0) {
|
|
1148
|
+
outputs.push(jsonString(response));
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
return outputs;
|
|
1152
|
+
}
|
|
1153
|
+
function stringContent(value) {
|
|
1154
|
+
if (typeof value === "string")
|
|
1155
|
+
return value;
|
|
1156
|
+
if (value === null || value === undefined)
|
|
1157
|
+
return "";
|
|
1158
|
+
return isObject(value) || Array.isArray(value) ? jsonString(value) : String(value);
|
|
1159
|
+
}
|
|
1160
|
+
function invalidGeminiTranscript() {
|
|
1161
|
+
return new NormalizationError("invalid_input", "Gemini CLI transcript must be one native session JSON document with a messages array.");
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/hermes/index.js
|
|
1165
|
+
var CONTENT_JSON_PREFIX = "\x00json:";
|
|
1166
|
+
var hermesAdapter = {
|
|
1167
|
+
source: "hermes",
|
|
1168
|
+
decode(transcript) {
|
|
1169
|
+
const diagnostics = [];
|
|
1170
|
+
const events = [];
|
|
1171
|
+
const parsed = parseTranscript(transcript);
|
|
1172
|
+
const rows = orderRows(parsed.messages.filter((row) => row.active !== 0 && row.active !== false));
|
|
1173
|
+
const callsByRow = planToolCalls(rows, diagnostics);
|
|
1174
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
1175
|
+
const row = rows[index];
|
|
1176
|
+
if (row === undefined)
|
|
1177
|
+
continue;
|
|
1178
|
+
const timestamp = hermesTimestamp(row.timestamp);
|
|
1179
|
+
const id = rowId(row);
|
|
1180
|
+
let componentIndex = 0;
|
|
1181
|
+
const emit = (event) => {
|
|
1182
|
+
events.push({
|
|
1183
|
+
...event,
|
|
1184
|
+
...id !== undefined ? { sourceRecordId: String(id) } : { sourceOffset: index, sourceAnchorKind: "ordinal" },
|
|
1185
|
+
...typeof id === "number" ? { sourceSequence: id } : {},
|
|
1186
|
+
componentIndex: componentIndex++
|
|
1187
|
+
});
|
|
1188
|
+
};
|
|
1189
|
+
if (row.role === "user") {
|
|
1190
|
+
const content = contentText(row.content);
|
|
1191
|
+
if (content) {
|
|
1192
|
+
emit({
|
|
1193
|
+
type: "message",
|
|
1194
|
+
role: "user",
|
|
1195
|
+
content,
|
|
1196
|
+
...timestamp ? { timestamp } : {}
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
continue;
|
|
1200
|
+
}
|
|
1201
|
+
if (row.role === "assistant") {
|
|
1202
|
+
const reasoning = reasoningText(row);
|
|
1203
|
+
if (reasoning) {
|
|
1204
|
+
emit({
|
|
1205
|
+
type: "reasoning",
|
|
1206
|
+
content: reasoning,
|
|
1207
|
+
...timestamp ? { timestamp } : {}
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
const content = contentText(row.content);
|
|
1211
|
+
if (content) {
|
|
1212
|
+
emit({
|
|
1213
|
+
type: "message",
|
|
1214
|
+
role: "assistant",
|
|
1215
|
+
content,
|
|
1216
|
+
...timestamp ? { timestamp } : {}
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
for (const call of callsByRow.get(index) ?? []) {
|
|
1220
|
+
emit({
|
|
1221
|
+
type: "tool_call",
|
|
1222
|
+
args: call.args,
|
|
1223
|
+
...call.id ? { id: call.id } : {},
|
|
1224
|
+
...call.name ? { name: call.name } : {},
|
|
1225
|
+
...timestamp ? { timestamp } : {}
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
continue;
|
|
1229
|
+
}
|
|
1230
|
+
if (row.role === "tool") {
|
|
1231
|
+
emit({
|
|
1232
|
+
type: "tool_result",
|
|
1233
|
+
content: contentText(row.content),
|
|
1234
|
+
...typeof row.tool_call_id === "string" && row.tool_call_id ? { callId: row.tool_call_id } : {},
|
|
1235
|
+
...timestamp ? { timestamp } : {}
|
|
1236
|
+
});
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
const session = parsed.session ?? {};
|
|
1240
|
+
const model = typeof session.model === "string" && session.model ? session.model : undefined;
|
|
1241
|
+
const cwd = typeof session.cwd === "string" && session.cwd ? session.cwd : undefined;
|
|
1242
|
+
const createdAt = hermesTimestamp(session.started_at);
|
|
1243
|
+
const sourceGroupId = resolveGroupId(session, parsed.messages);
|
|
1244
|
+
return {
|
|
1245
|
+
events,
|
|
1246
|
+
context: {
|
|
1247
|
+
source: "hermes",
|
|
1248
|
+
...cwd ? { cwd } : {},
|
|
1249
|
+
...model ? { model } : {},
|
|
1250
|
+
...createdAt ? { createdAt } : {},
|
|
1251
|
+
...sourceGroupId ? { sourceGroupId } : {}
|
|
1252
|
+
},
|
|
1253
|
+
diagnostics
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
function parseTranscript(transcript) {
|
|
1258
|
+
let parsed;
|
|
1259
|
+
try {
|
|
1260
|
+
parsed = JSON.parse(transcript);
|
|
1261
|
+
} catch {
|
|
1262
|
+
throw invalidHermesTranscript();
|
|
1263
|
+
}
|
|
1264
|
+
if (Array.isArray(parsed)) {
|
|
1265
|
+
if (!parsed.every(isObject))
|
|
1266
|
+
throw invalidHermesTranscript();
|
|
1267
|
+
return { messages: parsed };
|
|
1268
|
+
}
|
|
1269
|
+
if (isObject(parsed) && Array.isArray(parsed.messages)) {
|
|
1270
|
+
if (!parsed.messages.every(isObject))
|
|
1271
|
+
throw invalidHermesTranscript();
|
|
1272
|
+
return {
|
|
1273
|
+
messages: parsed.messages,
|
|
1274
|
+
...isObject(parsed.session) ? { session: parsed.session } : {}
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
throw invalidHermesTranscript();
|
|
1278
|
+
}
|
|
1279
|
+
function orderRows(rows) {
|
|
1280
|
+
if (!rows.every((row) => typeof row.id === "number"))
|
|
1281
|
+
return rows;
|
|
1282
|
+
return rows.map((row, index) => ({ row, index })).sort((left, right) => left.row.id - right.row.id || left.index - right.index).map(({ row }) => row);
|
|
1283
|
+
}
|
|
1284
|
+
function planToolCalls(rows, diagnostics) {
|
|
1285
|
+
const plan = new Map;
|
|
1286
|
+
for (let index = 0;index < rows.length; index += 1) {
|
|
1287
|
+
const row = rows[index];
|
|
1288
|
+
if (row === undefined || row.role !== "assistant")
|
|
1289
|
+
continue;
|
|
1290
|
+
const calls = rowToolCalls(row, index, diagnostics);
|
|
1291
|
+
if (calls.length === 0)
|
|
1292
|
+
continue;
|
|
1293
|
+
const idless = calls.filter((call) => !call.id);
|
|
1294
|
+
if (idless.length > 0) {
|
|
1295
|
+
const claimed = new Set(calls.flatMap((call) => call.id ? [call.id] : []));
|
|
1296
|
+
const available = [];
|
|
1297
|
+
for (let cursor = index + 1;cursor < rows.length; cursor += 1) {
|
|
1298
|
+
const next = rows[cursor];
|
|
1299
|
+
if (next === undefined)
|
|
1300
|
+
continue;
|
|
1301
|
+
if (next.role !== "tool")
|
|
1302
|
+
break;
|
|
1303
|
+
if (typeof next.tool_call_id === "string" && next.tool_call_id && !claimed.has(next.tool_call_id)) {
|
|
1304
|
+
available.push(next.tool_call_id);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
if (available.length === idless.length) {
|
|
1308
|
+
for (let position = 0;position < idless.length; position += 1) {
|
|
1309
|
+
const call = idless[position];
|
|
1310
|
+
const adopted = available[position];
|
|
1311
|
+
if (call && adopted !== undefined)
|
|
1312
|
+
call.id = adopted;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
plan.set(index, calls);
|
|
1317
|
+
}
|
|
1318
|
+
return plan;
|
|
1319
|
+
}
|
|
1320
|
+
function rowToolCalls(row, index, diagnostics) {
|
|
1321
|
+
let raw = row.tool_calls;
|
|
1322
|
+
if (typeof raw === "string" && raw) {
|
|
1323
|
+
try {
|
|
1324
|
+
raw = JSON.parse(raw);
|
|
1325
|
+
} catch {
|
|
1326
|
+
diagnostics.push({
|
|
1327
|
+
code: "invalid_json_line",
|
|
1328
|
+
message: `Skipped undecodable tool_calls on message ${index + 1}.`,
|
|
1329
|
+
inputLine: index + 1
|
|
1330
|
+
});
|
|
1331
|
+
return [];
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
if (!Array.isArray(raw))
|
|
1335
|
+
return [];
|
|
1336
|
+
const calls = [];
|
|
1337
|
+
for (const entry of raw) {
|
|
1338
|
+
if (!isObject(entry))
|
|
1339
|
+
continue;
|
|
1340
|
+
const fn = isObject(entry.function) ? entry.function : undefined;
|
|
1341
|
+
const name = firstString(fn?.name, entry.name);
|
|
1342
|
+
const id = firstString(entry.id, entry.call_id);
|
|
1343
|
+
const args = fn !== undefined ? fn.arguments : entry.arguments;
|
|
1344
|
+
calls.push({
|
|
1345
|
+
args: typeof args === "string" && args ? args : jsonString(args),
|
|
1346
|
+
...id ? { id } : {},
|
|
1347
|
+
...name ? { name } : {}
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
return calls;
|
|
1351
|
+
}
|
|
1352
|
+
function contentText(content) {
|
|
1353
|
+
if (typeof content === "string") {
|
|
1354
|
+
if (content.startsWith(CONTENT_JSON_PREFIX)) {
|
|
1355
|
+
const encoded = content.slice(CONTENT_JSON_PREFIX.length);
|
|
1356
|
+
try {
|
|
1357
|
+
return contentText(JSON.parse(encoded));
|
|
1358
|
+
} catch {
|
|
1359
|
+
return encoded;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
return content;
|
|
1363
|
+
}
|
|
1364
|
+
if (Array.isArray(content))
|
|
1365
|
+
return blocksText(content);
|
|
1366
|
+
if (content === null || content === undefined)
|
|
1367
|
+
return "";
|
|
1368
|
+
if (isObject(content))
|
|
1369
|
+
return jsonString(content);
|
|
1370
|
+
return String(content);
|
|
1371
|
+
}
|
|
1372
|
+
function reasoningText(row) {
|
|
1373
|
+
if (typeof row.reasoning_content === "string" && row.reasoning_content.trim()) {
|
|
1374
|
+
return row.reasoning_content;
|
|
1375
|
+
}
|
|
1376
|
+
if (typeof row.reasoning === "string" && row.reasoning.trim()) {
|
|
1377
|
+
return row.reasoning;
|
|
1378
|
+
}
|
|
1379
|
+
return "";
|
|
1380
|
+
}
|
|
1381
|
+
function hermesTimestamp(value) {
|
|
1382
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
1383
|
+
const milliseconds = value > 100000000000 ? value : value * 1000;
|
|
1384
|
+
const date = new Date(Math.round(milliseconds));
|
|
1385
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
1386
|
+
}
|
|
1387
|
+
return parseTimestamp(value);
|
|
1388
|
+
}
|
|
1389
|
+
function rowId(row) {
|
|
1390
|
+
if (typeof row.id === "number" && Number.isFinite(row.id))
|
|
1391
|
+
return row.id;
|
|
1392
|
+
if (typeof row.id === "string" && row.id)
|
|
1393
|
+
return row.id;
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
function resolveGroupId(session, messages) {
|
|
1397
|
+
if (typeof session.id === "string" && session.id)
|
|
1398
|
+
return session.id;
|
|
1399
|
+
for (const row of messages) {
|
|
1400
|
+
if (typeof row.session_id === "string" && row.session_id) {
|
|
1401
|
+
return row.session_id;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
1406
|
+
function firstString(...values) {
|
|
1407
|
+
for (const value of values) {
|
|
1408
|
+
if (typeof value === "string" && value)
|
|
1409
|
+
return value;
|
|
1410
|
+
}
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
function invalidHermesTranscript() {
|
|
1414
|
+
return new NormalizationError("invalid_input", "Hermes transcript must be a JSON array of session-store message rows or an object with a messages array.");
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/letta-code/index.js
|
|
1418
|
+
var SUPPORTED_KINDS = new Set([
|
|
1419
|
+
"user",
|
|
1420
|
+
"assistant",
|
|
1421
|
+
"reasoning",
|
|
1422
|
+
"tool_call",
|
|
1423
|
+
"error"
|
|
1424
|
+
]);
|
|
1425
|
+
var lettaCodeAdapter = {
|
|
1426
|
+
source: "letta-code",
|
|
1427
|
+
decode(transcript) {
|
|
1428
|
+
const diagnostics = [];
|
|
1429
|
+
const rows = parseJsonLines(transcript, diagnostics);
|
|
1430
|
+
const events = [];
|
|
1431
|
+
const reasoningRecordIds = new Set;
|
|
1432
|
+
let recognizedRows = 0;
|
|
1433
|
+
for (const { value: row } of rows) {
|
|
1434
|
+
if (row.kind !== "reasoning")
|
|
1435
|
+
continue;
|
|
1436
|
+
const sourceRecordId = nonemptyString(row.source_message_id) ?? nonemptyString(row.source_line_id);
|
|
1437
|
+
if (sourceRecordId)
|
|
1438
|
+
reasoningRecordIds.add(sourceRecordId);
|
|
1439
|
+
}
|
|
1440
|
+
for (const { value: row, line } of rows) {
|
|
1441
|
+
if (typeof row.kind !== "string" || !SUPPORTED_KINDS.has(row.kind)) {
|
|
1442
|
+
diagnostics.push({
|
|
1443
|
+
code: "noise_record_dropped",
|
|
1444
|
+
message: `Skipped unsupported Letta Code transcript row on line ${line}.`,
|
|
1445
|
+
inputLine: line
|
|
1446
|
+
});
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
recognizedRows += 1;
|
|
1450
|
+
if (row.kind === "error") {
|
|
1451
|
+
diagnostics.push({
|
|
1452
|
+
code: "noise_record_dropped",
|
|
1453
|
+
message: `Skipped Letta Code runtime error row on line ${line}.`,
|
|
1454
|
+
inputLine: line
|
|
1455
|
+
});
|
|
1456
|
+
continue;
|
|
1457
|
+
}
|
|
1458
|
+
const timestamp = parseTimestamp(row.captured_at);
|
|
1459
|
+
const sourceMessageId = nonemptyString(row.source_message_id);
|
|
1460
|
+
const sourceLineId = nonemptyString(row.source_line_id);
|
|
1461
|
+
const sourceRecordId = sourceMessageId ?? sourceLineId;
|
|
1462
|
+
const sourceFields = sourceRecordId ? { sourceRecordId } : {
|
|
1463
|
+
sourceOffset: line - 1,
|
|
1464
|
+
sourceAnchorKind: "ordinal"
|
|
1465
|
+
};
|
|
1466
|
+
if (row.kind === "user" || row.kind === "assistant" || row.kind === "reasoning") {
|
|
1467
|
+
if (typeof row.text !== "string" || row.text.length === 0) {
|
|
1468
|
+
diagnostics.push({
|
|
1469
|
+
code: "noise_record_dropped",
|
|
1470
|
+
message: `Skipped empty Letta Code ${row.kind} row on line ${line}.`,
|
|
1471
|
+
inputLine: line
|
|
1472
|
+
});
|
|
1473
|
+
continue;
|
|
1474
|
+
}
|
|
1475
|
+
const componentIndex = row.kind === "assistant" && sourceRecordId !== undefined && reasoningRecordIds.has(sourceRecordId) ? 1 : 0;
|
|
1476
|
+
if (row.kind === "reasoning") {
|
|
1477
|
+
events.push({
|
|
1478
|
+
type: "reasoning",
|
|
1479
|
+
content: row.text,
|
|
1480
|
+
inputLine: line,
|
|
1481
|
+
...sourceFields,
|
|
1482
|
+
componentIndex,
|
|
1483
|
+
...timestamp ? { timestamp } : {}
|
|
1484
|
+
});
|
|
1485
|
+
} else {
|
|
1486
|
+
events.push({
|
|
1487
|
+
type: "message",
|
|
1488
|
+
role: row.kind,
|
|
1489
|
+
content: row.text,
|
|
1490
|
+
inputLine: line,
|
|
1491
|
+
...sourceFields,
|
|
1492
|
+
componentIndex,
|
|
1493
|
+
...timestamp ? { timestamp } : {}
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
continue;
|
|
1497
|
+
}
|
|
1498
|
+
const callId = sourceLineId ?? sourceMessageId ?? `letta-code-tool-line-${line}`;
|
|
1499
|
+
const name = nonemptyString(row.name);
|
|
1500
|
+
events.push({
|
|
1501
|
+
type: "tool_call",
|
|
1502
|
+
args: nonemptyString(row.argsText) ?? "{}",
|
|
1503
|
+
inputLine: line,
|
|
1504
|
+
...sourceFields,
|
|
1505
|
+
componentIndex: 0,
|
|
1506
|
+
id: callId,
|
|
1507
|
+
...name ? { name } : {},
|
|
1508
|
+
...timestamp ? { timestamp } : {}
|
|
1509
|
+
});
|
|
1510
|
+
if (typeof row.resultText === "string" || typeof row.resultOk === "boolean") {
|
|
1511
|
+
let content = typeof row.resultText === "string" ? row.resultText : "";
|
|
1512
|
+
if (row.resultOk === false && !/^error/i.test(content)) {
|
|
1513
|
+
content = `Error: ${content}`;
|
|
1514
|
+
}
|
|
1515
|
+
events.push({
|
|
1516
|
+
type: "tool_result",
|
|
1517
|
+
content,
|
|
1518
|
+
...typeof row.resultOk === "boolean" ? { ok: row.resultOk } : {},
|
|
1519
|
+
inputLine: line,
|
|
1520
|
+
...sourceFields,
|
|
1521
|
+
componentIndex: 1,
|
|
1522
|
+
callId,
|
|
1523
|
+
...timestamp ? { timestamp } : {}
|
|
1524
|
+
});
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
if (recognizedRows === 0) {
|
|
1528
|
+
throw invalidLettaCodeTranscript();
|
|
1529
|
+
}
|
|
1530
|
+
return {
|
|
1531
|
+
events,
|
|
1532
|
+
context: { source: "letta-code" },
|
|
1533
|
+
diagnostics
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
function invalidLettaCodeTranscript() {
|
|
1538
|
+
return new NormalizationError("invalid_input", "Letta Code transcript must be client-side transcript.jsonl with kind-tagged rows.");
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/pi-session-shared.js
|
|
1542
|
+
function decodePiSessionTranscript(transcript, options) {
|
|
1543
|
+
const diagnostics = [];
|
|
1544
|
+
const events = [];
|
|
1545
|
+
const excludedModels = options.excludedModels ?? [];
|
|
1546
|
+
let cwd;
|
|
1547
|
+
let createdAt;
|
|
1548
|
+
let sessionId;
|
|
1549
|
+
let sawMessageRow = false;
|
|
1550
|
+
for (const { value: row, line, byteOffset } of parseJsonLines(transcript, diagnostics)) {
|
|
1551
|
+
if (row.type === "session") {
|
|
1552
|
+
if (!cwd && typeof row.cwd === "string" && row.cwd)
|
|
1553
|
+
cwd = row.cwd;
|
|
1554
|
+
createdAt ??= parseTimestamp(row.timestamp);
|
|
1555
|
+
if (!sessionId && typeof row.id === "string" && row.id) {
|
|
1556
|
+
sessionId = row.id;
|
|
1557
|
+
}
|
|
1558
|
+
continue;
|
|
1559
|
+
}
|
|
1560
|
+
if (row.type !== "message" || !isObject(row.message))
|
|
1561
|
+
continue;
|
|
1562
|
+
sawMessageRow = true;
|
|
1563
|
+
const message = row.message;
|
|
1564
|
+
const timestamp = parseTimestamp(row.timestamp) ?? messageTimestamp(message.timestamp);
|
|
1565
|
+
const id = typeof row.id === "string" && row.id ? row.id : undefined;
|
|
1566
|
+
const model = typeof message.model === "string" && message.model && !excludedModels.includes(message.model) ? message.model : undefined;
|
|
1567
|
+
let componentIndex = 0;
|
|
1568
|
+
const emit = (event) => {
|
|
1569
|
+
events.push({
|
|
1570
|
+
...event,
|
|
1571
|
+
...id !== undefined ? { sourceRecordId: id } : { sourceOffset: byteOffset, sourceAnchorKind: "byte" },
|
|
1572
|
+
componentIndex: componentIndex++
|
|
1573
|
+
});
|
|
1574
|
+
};
|
|
1575
|
+
if (message.role === "user") {
|
|
1576
|
+
const content = blocksText(message.content);
|
|
1577
|
+
if (content) {
|
|
1578
|
+
emit({
|
|
1579
|
+
type: "message",
|
|
1580
|
+
role: "user",
|
|
1581
|
+
content,
|
|
1582
|
+
inputLine: line,
|
|
1583
|
+
...timestamp ? { timestamp } : {}
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
continue;
|
|
1587
|
+
}
|
|
1588
|
+
if (message.role === "assistant") {
|
|
1589
|
+
if (typeof message.content === "string") {
|
|
1590
|
+
if (message.content) {
|
|
1591
|
+
emit({
|
|
1592
|
+
type: "message",
|
|
1593
|
+
role: "assistant",
|
|
1594
|
+
content: message.content,
|
|
1595
|
+
inputLine: line,
|
|
1596
|
+
...timestamp ? { timestamp } : {},
|
|
1597
|
+
...model ? { model } : {}
|
|
1598
|
+
});
|
|
1599
|
+
}
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
for (const part of Array.isArray(message.content) ? message.content : []) {
|
|
1603
|
+
if (!isObject(part))
|
|
1604
|
+
continue;
|
|
1605
|
+
if (part.type === "thinking" && typeof part.thinking === "string") {
|
|
1606
|
+
emit({
|
|
1607
|
+
type: "reasoning",
|
|
1608
|
+
content: part.thinking,
|
|
1609
|
+
inputLine: line,
|
|
1610
|
+
...timestamp ? { timestamp } : {},
|
|
1611
|
+
...model ? { model } : {}
|
|
1612
|
+
});
|
|
1613
|
+
} else if (part.type === "text" && typeof part.text === "string") {
|
|
1614
|
+
emit({
|
|
1615
|
+
type: "message",
|
|
1616
|
+
role: "assistant",
|
|
1617
|
+
content: part.text,
|
|
1618
|
+
inputLine: line,
|
|
1619
|
+
...timestamp ? { timestamp } : {},
|
|
1620
|
+
...model ? { model } : {}
|
|
1621
|
+
});
|
|
1622
|
+
} else if (part.type === "toolCall") {
|
|
1623
|
+
emit({
|
|
1624
|
+
type: "tool_call",
|
|
1625
|
+
args: toolArguments(part.arguments),
|
|
1626
|
+
inputLine: line,
|
|
1627
|
+
...typeof part.id === "string" && part.id ? { id: part.id } : {},
|
|
1628
|
+
...typeof part.name === "string" && part.name ? { name: part.name } : {},
|
|
1629
|
+
...timestamp ? { timestamp } : {},
|
|
1630
|
+
...model ? { model } : {}
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
continue;
|
|
1635
|
+
}
|
|
1636
|
+
if (message.role === "toolResult" || message.role === "tool") {
|
|
1637
|
+
const content = blocksText(message.content);
|
|
1638
|
+
emit({
|
|
1639
|
+
type: "tool_result",
|
|
1640
|
+
content,
|
|
1641
|
+
...typeof message.isError === "boolean" ? { ok: !message.isError } : {},
|
|
1642
|
+
inputLine: line,
|
|
1643
|
+
...typeof message.toolCallId === "string" && message.toolCallId ? { callId: message.toolCallId } : {},
|
|
1644
|
+
...timestamp ? { timestamp } : {}
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
if (!sawMessageRow && sessionId === undefined) {
|
|
1649
|
+
throw new NormalizationError("invalid_input", `${options.sourceLabel} transcript must be session JSONL containing a session header or message entries.`);
|
|
1650
|
+
}
|
|
1651
|
+
return {
|
|
1652
|
+
events,
|
|
1653
|
+
context: {
|
|
1654
|
+
source: options.source,
|
|
1655
|
+
...cwd ? { cwd } : {},
|
|
1656
|
+
...createdAt ? { createdAt } : {},
|
|
1657
|
+
...sessionId ? { sourceGroupId: sessionId } : {}
|
|
1658
|
+
},
|
|
1659
|
+
diagnostics
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
function messageTimestamp(value) {
|
|
1663
|
+
return parseTimestamp(value);
|
|
1664
|
+
}
|
|
1665
|
+
function toolArguments(value) {
|
|
1666
|
+
if (typeof value === "string" && value)
|
|
1667
|
+
return value;
|
|
1668
|
+
return jsonString(value);
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/openclaw/index.js
|
|
1672
|
+
var DELIVERY_MIRROR_MODEL = "delivery-mirror";
|
|
1673
|
+
var openClawAdapter = {
|
|
1674
|
+
source: "openclaw",
|
|
1675
|
+
decode(transcript) {
|
|
1676
|
+
return decodePiSessionTranscript(transcript, {
|
|
1677
|
+
source: "openclaw",
|
|
1678
|
+
sourceLabel: "OpenClaw",
|
|
1679
|
+
excludedModels: [DELIVERY_MIRROR_MODEL]
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/openhands/index.js
|
|
1685
|
+
var openHandsAdapter = {
|
|
1686
|
+
source: "openhands",
|
|
1687
|
+
decode(transcript) {
|
|
1688
|
+
const diagnostics = [];
|
|
1689
|
+
const events = [];
|
|
1690
|
+
const rawEvents = parseEvents(transcript);
|
|
1691
|
+
const callIdByActionId = new Map;
|
|
1692
|
+
for (const event of rawEvents) {
|
|
1693
|
+
if (isObject(event) && event.kind === "ActionEvent" && typeof event.id === "string" && event.id) {
|
|
1694
|
+
callIdByActionId.set(event.id, actionCallId(event));
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
for (const event of rawEvents) {
|
|
1698
|
+
if (!isObject(event) || typeof event.id !== "string" || !event.id) {
|
|
1699
|
+
continue;
|
|
1700
|
+
}
|
|
1701
|
+
const timestamp = parseTimestamp(event.timestamp);
|
|
1702
|
+
const sourceRecordId = event.id;
|
|
1703
|
+
let componentIndex = 0;
|
|
1704
|
+
const emit = (decoded) => {
|
|
1705
|
+
events.push({ ...decoded, sourceRecordId, componentIndex: componentIndex++ });
|
|
1706
|
+
};
|
|
1707
|
+
if (event.kind === "MessageEvent") {
|
|
1708
|
+
if (event.source !== "user" && event.source !== "agent")
|
|
1709
|
+
continue;
|
|
1710
|
+
const message = isObject(event.llm_message) ? event.llm_message : {};
|
|
1711
|
+
const content = joinTextContent(message.content);
|
|
1712
|
+
if (!content)
|
|
1713
|
+
continue;
|
|
1714
|
+
emit({
|
|
1715
|
+
type: "message",
|
|
1716
|
+
role: event.source === "user" ? "user" : "assistant",
|
|
1717
|
+
content,
|
|
1718
|
+
...timestamp ? { timestamp } : {}
|
|
1719
|
+
});
|
|
1720
|
+
continue;
|
|
1721
|
+
}
|
|
1722
|
+
if (event.kind === "ActionEvent") {
|
|
1723
|
+
const thought = joinTextContent(event.thought);
|
|
1724
|
+
if (thought) {
|
|
1725
|
+
emit({
|
|
1726
|
+
type: "reasoning",
|
|
1727
|
+
content: thought,
|
|
1728
|
+
...timestamp ? { timestamp } : {}
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
const callId = callIdByActionId.get(event.id) ?? actionCallId(event);
|
|
1732
|
+
emit({
|
|
1733
|
+
type: "tool_call",
|
|
1734
|
+
id: callId,
|
|
1735
|
+
args: actionArgsText(event),
|
|
1736
|
+
...typeof event.tool_name === "string" && event.tool_name ? { name: event.tool_name } : {},
|
|
1737
|
+
...timestamp ? { timestamp } : {}
|
|
1738
|
+
});
|
|
1739
|
+
continue;
|
|
1740
|
+
}
|
|
1741
|
+
const result = extractToolResultText(event);
|
|
1742
|
+
if (result === undefined)
|
|
1743
|
+
continue;
|
|
1744
|
+
const callId = typeof event.tool_call_id === "string" && event.tool_call_id ? event.tool_call_id : typeof event.action_id === "string" ? callIdByActionId.get(event.action_id) : undefined;
|
|
1745
|
+
if (callId) {
|
|
1746
|
+
emit({
|
|
1747
|
+
type: "tool_result",
|
|
1748
|
+
content: result,
|
|
1749
|
+
...toolResultStatus(event),
|
|
1750
|
+
callId,
|
|
1751
|
+
...timestamp ? { timestamp } : {}
|
|
1752
|
+
});
|
|
1753
|
+
} else {
|
|
1754
|
+
emit({
|
|
1755
|
+
type: "observation",
|
|
1756
|
+
content: result,
|
|
1757
|
+
...timestamp ? { timestamp } : {}
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
return {
|
|
1762
|
+
events,
|
|
1763
|
+
context: { source: "openhands" },
|
|
1764
|
+
diagnostics
|
|
1765
|
+
};
|
|
1766
|
+
}
|
|
1767
|
+
};
|
|
1768
|
+
function actionCallId(event) {
|
|
1769
|
+
return typeof event.tool_call_id === "string" && event.tool_call_id ? event.tool_call_id : `oh_${String(event.id)}`;
|
|
1770
|
+
}
|
|
1771
|
+
function parseEvents(transcript) {
|
|
1772
|
+
let parsed;
|
|
1773
|
+
try {
|
|
1774
|
+
parsed = JSON.parse(transcript);
|
|
1775
|
+
} catch {
|
|
1776
|
+
throw new NormalizationError("invalid_input", "OpenHands transcript must be a JSON event array or an object with an items array.");
|
|
1777
|
+
}
|
|
1778
|
+
if (Array.isArray(parsed))
|
|
1779
|
+
return parsed;
|
|
1780
|
+
if (isObject(parsed) && Array.isArray(parsed.items))
|
|
1781
|
+
return parsed.items;
|
|
1782
|
+
throw new NormalizationError("invalid_input", "OpenHands transcript must be a JSON event array or an object with an items array.");
|
|
1783
|
+
}
|
|
1784
|
+
function joinTextContent(content) {
|
|
1785
|
+
if (!Array.isArray(content))
|
|
1786
|
+
return "";
|
|
1787
|
+
const parts = [];
|
|
1788
|
+
for (const item of content) {
|
|
1789
|
+
if (isObject(item) && item.type === "text" && typeof item.text === "string") {
|
|
1790
|
+
parts.push(item.text);
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
return parts.join("");
|
|
1794
|
+
}
|
|
1795
|
+
function actionArgsText(event) {
|
|
1796
|
+
if (isObject(event.tool_call)) {
|
|
1797
|
+
const raw = event.tool_call.arguments;
|
|
1798
|
+
if (typeof raw === "string" && raw)
|
|
1799
|
+
return raw;
|
|
1800
|
+
}
|
|
1801
|
+
if (isObject(event.action)) {
|
|
1802
|
+
const args = { ...event.action };
|
|
1803
|
+
delete args.kind;
|
|
1804
|
+
return jsonString(args);
|
|
1805
|
+
}
|
|
1806
|
+
return "{}";
|
|
1807
|
+
}
|
|
1808
|
+
function toolResultStatus(event) {
|
|
1809
|
+
if (event.kind !== "ObservationEvent" || !isObject(event.observation))
|
|
1810
|
+
return {};
|
|
1811
|
+
return typeof event.observation.is_error === "boolean" ? { ok: !event.observation.is_error } : {};
|
|
1812
|
+
}
|
|
1813
|
+
function extractToolResultText(event) {
|
|
1814
|
+
if (event.kind === "ObservationEvent") {
|
|
1815
|
+
const observation = isObject(event.observation) ? event.observation : {};
|
|
1816
|
+
return joinTextContent(observation.content);
|
|
1817
|
+
}
|
|
1818
|
+
if (event.kind === "AgentErrorEvent") {
|
|
1819
|
+
return typeof event.error === "string" ? event.error : "";
|
|
1820
|
+
}
|
|
1821
|
+
if (event.kind === "UserRejectObservation") {
|
|
1822
|
+
return typeof event.rejection_reason === "string" ? event.rejection_reason : "";
|
|
1823
|
+
}
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/opencode/index.js
|
|
1828
|
+
var TRANSPORT_PART_TYPES = new Set([
|
|
1829
|
+
"file",
|
|
1830
|
+
"patch",
|
|
1831
|
+
"snapshot",
|
|
1832
|
+
"step-finish",
|
|
1833
|
+
"step-start",
|
|
1834
|
+
"subtask"
|
|
1835
|
+
]);
|
|
1836
|
+
var openCodeAdapter = {
|
|
1837
|
+
source: "opencode",
|
|
1838
|
+
decode(transcript) {
|
|
1839
|
+
const document = parseOpenCodeDocument(transcript);
|
|
1840
|
+
const diagnostics = [];
|
|
1841
|
+
const events = [];
|
|
1842
|
+
const sessionInfo = isObject(document.info) ? document.info : {};
|
|
1843
|
+
let partOrdinal = 0;
|
|
1844
|
+
for (let messageIndex = 0;messageIndex < document.messages.length; messageIndex += 1) {
|
|
1845
|
+
const message = document.messages[messageIndex];
|
|
1846
|
+
if (!isObject(message))
|
|
1847
|
+
continue;
|
|
1848
|
+
const info = isObject(message.info) ? message.info : {};
|
|
1849
|
+
const role = info.role;
|
|
1850
|
+
const messageId = nonemptyString(info.id);
|
|
1851
|
+
const timestamp = parseTimestamp(isObject(info.time) ? info.time.created : undefined);
|
|
1852
|
+
const model = nonemptyString(info.modelID);
|
|
1853
|
+
const parts = Array.isArray(message.parts) ? message.parts : [];
|
|
1854
|
+
let messageComponentIndex = 0;
|
|
1855
|
+
let latestTimestamp;
|
|
1856
|
+
const orderedTimestamp = (candidate) => {
|
|
1857
|
+
if (!candidate)
|
|
1858
|
+
return latestTimestamp;
|
|
1859
|
+
if (latestTimestamp && candidate.getTime() < latestTimestamp.getTime()) {
|
|
1860
|
+
return latestTimestamp;
|
|
1861
|
+
}
|
|
1862
|
+
latestTimestamp = candidate;
|
|
1863
|
+
return candidate;
|
|
1864
|
+
};
|
|
1865
|
+
for (const part of parts) {
|
|
1866
|
+
const ordinal = partOrdinal++;
|
|
1867
|
+
if (!isObject(part))
|
|
1868
|
+
continue;
|
|
1869
|
+
const partId = nonemptyString(part.id);
|
|
1870
|
+
const sourceRecordId = partId ?? messageId;
|
|
1871
|
+
let partComponentIndex = 0;
|
|
1872
|
+
const emit = (event) => {
|
|
1873
|
+
const componentIndex = partId ? partComponentIndex++ : messageId ? messageComponentIndex++ : partComponentIndex++;
|
|
1874
|
+
events.push({
|
|
1875
|
+
...event,
|
|
1876
|
+
...sourceRecordId ? { sourceRecordId } : { sourceOffset: ordinal, sourceAnchorKind: "ordinal" },
|
|
1877
|
+
sourceSequence: ordinal,
|
|
1878
|
+
componentIndex
|
|
1879
|
+
});
|
|
1880
|
+
};
|
|
1881
|
+
if (part.type === "text") {
|
|
1882
|
+
if (role !== "user" && role !== "assistant")
|
|
1883
|
+
continue;
|
|
1884
|
+
const partTime = isObject(part.time) ? part.time : {};
|
|
1885
|
+
const eventTimestamp = orderedTimestamp(parseTimestamp(partTime.start) ?? timestamp);
|
|
1886
|
+
emit({
|
|
1887
|
+
type: "message",
|
|
1888
|
+
role,
|
|
1889
|
+
content: stringContent2(part.text),
|
|
1890
|
+
...eventTimestamp ? { timestamp: eventTimestamp } : {},
|
|
1891
|
+
...model ? { model } : {}
|
|
1892
|
+
});
|
|
1893
|
+
continue;
|
|
1894
|
+
}
|
|
1895
|
+
if (part.type === "reasoning") {
|
|
1896
|
+
const partTime = isObject(part.time) ? part.time : {};
|
|
1897
|
+
const eventTimestamp = orderedTimestamp(parseTimestamp(partTime.start) ?? timestamp);
|
|
1898
|
+
emit({
|
|
1899
|
+
type: "reasoning",
|
|
1900
|
+
content: stringContent2(part.text),
|
|
1901
|
+
...eventTimestamp ? { timestamp: eventTimestamp } : {},
|
|
1902
|
+
...model ? { model } : {}
|
|
1903
|
+
});
|
|
1904
|
+
continue;
|
|
1905
|
+
}
|
|
1906
|
+
if (part.type === "tool") {
|
|
1907
|
+
const state = isObject(part.state) ? part.state : {};
|
|
1908
|
+
const stateTime = isObject(state.time) ? state.time : {};
|
|
1909
|
+
const callTimestamp = orderedTimestamp(parseTimestamp(stateTime.start) ?? timestamp);
|
|
1910
|
+
const resultTimestamp = orderedTimestamp(parseTimestamp(stateTime.end) ?? callTimestamp);
|
|
1911
|
+
const callId = nonemptyString(part.callID);
|
|
1912
|
+
const name = nonemptyString(part.tool);
|
|
1913
|
+
emit({
|
|
1914
|
+
type: "tool_call",
|
|
1915
|
+
args: jsonString(state.input),
|
|
1916
|
+
...callId ? { id: callId } : {},
|
|
1917
|
+
...name ? { name } : {},
|
|
1918
|
+
...callTimestamp ? { timestamp: callTimestamp } : {},
|
|
1919
|
+
...model ? { model } : {}
|
|
1920
|
+
});
|
|
1921
|
+
const status = nonemptyString(state.status);
|
|
1922
|
+
const output = state.output !== undefined ? stringContent2(state.output) : status === "error" ? errorContent(state.error) : undefined;
|
|
1923
|
+
if (output !== undefined) {
|
|
1924
|
+
emit({
|
|
1925
|
+
type: "tool_result",
|
|
1926
|
+
content: output,
|
|
1927
|
+
...callId ? { callId } : {},
|
|
1928
|
+
...status === "completed" ? { ok: true } : status === "error" ? { ok: false } : {},
|
|
1929
|
+
...resultTimestamp ? { timestamp: resultTimestamp } : {},
|
|
1930
|
+
...model ? { model } : {}
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
if (typeof part.type === "string" && !TRANSPORT_PART_TYPES.has(part.type)) {
|
|
1936
|
+
diagnostics.push({
|
|
1937
|
+
code: "noise_record_dropped",
|
|
1938
|
+
message: `Skipped unsupported OpenCode part type ${JSON.stringify(part.type)} ` + `in message ${messageIndex + 1}.`
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
const cwd = nonemptyString(sessionInfo.directory);
|
|
1944
|
+
const sourceGroupId = nonemptyString(sessionInfo.id);
|
|
1945
|
+
const createdAt = parseTimestamp(isObject(sessionInfo.time) ? sessionInfo.time.created : undefined);
|
|
1946
|
+
return {
|
|
1947
|
+
events,
|
|
1948
|
+
context: {
|
|
1949
|
+
source: "opencode",
|
|
1950
|
+
...cwd ? { cwd } : {},
|
|
1951
|
+
...sourceGroupId ? { sourceGroupId } : {},
|
|
1952
|
+
...createdAt ? { createdAt } : {}
|
|
1953
|
+
},
|
|
1954
|
+
diagnostics
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
function parseOpenCodeDocument(transcript) {
|
|
1959
|
+
let parsed;
|
|
1960
|
+
try {
|
|
1961
|
+
parsed = JSON.parse(transcript);
|
|
1962
|
+
} catch {
|
|
1963
|
+
throw invalidOpenCodeTranscript();
|
|
1964
|
+
}
|
|
1965
|
+
if (!isObject(parsed) || !isObject(parsed.info) || !Array.isArray(parsed.messages)) {
|
|
1966
|
+
throw invalidOpenCodeTranscript();
|
|
1967
|
+
}
|
|
1968
|
+
return parsed;
|
|
1969
|
+
}
|
|
1970
|
+
function stringContent2(value) {
|
|
1971
|
+
if (typeof value === "string")
|
|
1972
|
+
return value;
|
|
1973
|
+
if (value === null || value === undefined)
|
|
1974
|
+
return "";
|
|
1975
|
+
return isObject(value) || Array.isArray(value) ? jsonString(value) : String(value);
|
|
1976
|
+
}
|
|
1977
|
+
function errorContent(value) {
|
|
1978
|
+
if (isObject(value) && typeof value.message === "string")
|
|
1979
|
+
return value.message;
|
|
1980
|
+
return stringContent2(value);
|
|
1981
|
+
}
|
|
1982
|
+
function invalidOpenCodeTranscript() {
|
|
1983
|
+
return new NormalizationError("invalid_input", "OpenCode transcript must be one JSON document with info and messages arrays of message parts.");
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/omp/index.js
|
|
1987
|
+
var ompAdapter = {
|
|
1988
|
+
source: "omp",
|
|
1989
|
+
decode(transcript) {
|
|
1990
|
+
return decodePiSessionTranscript(transcript, {
|
|
1991
|
+
source: "omp",
|
|
1992
|
+
sourceLabel: "omp"
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1995
|
+
};
|
|
1996
|
+
|
|
1997
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/pi/index.js
|
|
1998
|
+
var piAdapter = {
|
|
1999
|
+
source: "pi",
|
|
2000
|
+
decode(transcript) {
|
|
2001
|
+
return decodePiSessionTranscript(transcript, {
|
|
2002
|
+
source: "pi",
|
|
2003
|
+
sourceLabel: "pi"
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
};
|
|
2007
|
+
|
|
2008
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/bounds.js
|
|
2009
|
+
var DEFAULT_NORMALIZATION_BOUNDS = Object.freeze({
|
|
2010
|
+
toolArguments: Object.freeze({ maxCharacters: 20000 }),
|
|
2011
|
+
toolResults: Object.freeze({
|
|
2012
|
+
maxCharacters: 2500,
|
|
2013
|
+
strategy: "head-tail"
|
|
2014
|
+
})
|
|
2015
|
+
});
|
|
2016
|
+
function resolveBounds(bounds) {
|
|
2017
|
+
if (bounds === undefined)
|
|
2018
|
+
return copyDefaults();
|
|
2019
|
+
assertObject(bounds, "bounds");
|
|
2020
|
+
assertKnownKeys(bounds, ["toolArguments", "toolResults"], "bounds");
|
|
2021
|
+
const toolArguments = bounds.toolArguments;
|
|
2022
|
+
if (toolArguments !== undefined) {
|
|
2023
|
+
assertObject(toolArguments, "bounds.toolArguments");
|
|
2024
|
+
assertKnownKeys(toolArguments, ["maxCharacters"], "bounds.toolArguments");
|
|
2025
|
+
}
|
|
2026
|
+
const toolResults = bounds.toolResults;
|
|
2027
|
+
if (toolResults !== undefined) {
|
|
2028
|
+
assertObject(toolResults, "bounds.toolResults");
|
|
2029
|
+
assertKnownKeys(toolResults, ["maxCharacters", "strategy"], "bounds.toolResults");
|
|
2030
|
+
}
|
|
2031
|
+
const argumentLimit = resolveLimit(toolArguments?.maxCharacters, DEFAULT_NORMALIZATION_BOUNDS.toolArguments.maxCharacters, "bounds.toolArguments.maxCharacters");
|
|
2032
|
+
if (argumentLimit !== null && argumentLimit < 2) {
|
|
2033
|
+
throw invalidBounds("bounds.toolArguments.maxCharacters must be at least 2 so arguments can remain a JSON object.");
|
|
2034
|
+
}
|
|
2035
|
+
const resultLimit = resolveLimit(toolResults?.maxCharacters, DEFAULT_NORMALIZATION_BOUNDS.toolResults.maxCharacters, "bounds.toolResults.maxCharacters");
|
|
2036
|
+
const strategy = toolResults?.strategy ?? DEFAULT_NORMALIZATION_BOUNDS.toolResults.strategy;
|
|
2037
|
+
if (strategy !== "head" && strategy !== "head-tail") {
|
|
2038
|
+
throw invalidBounds('bounds.toolResults.strategy must be either "head" or "head-tail".');
|
|
2039
|
+
}
|
|
2040
|
+
return {
|
|
2041
|
+
toolArguments: { maxCharacters: argumentLimit },
|
|
2042
|
+
toolResults: { maxCharacters: resultLimit, strategy }
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
2045
|
+
function copyDefaults() {
|
|
2046
|
+
return {
|
|
2047
|
+
toolArguments: {
|
|
2048
|
+
maxCharacters: DEFAULT_NORMALIZATION_BOUNDS.toolArguments.maxCharacters
|
|
2049
|
+
},
|
|
2050
|
+
toolResults: {
|
|
2051
|
+
maxCharacters: DEFAULT_NORMALIZATION_BOUNDS.toolResults.maxCharacters,
|
|
2052
|
+
strategy: DEFAULT_NORMALIZATION_BOUNDS.toolResults.strategy
|
|
2053
|
+
}
|
|
2054
|
+
};
|
|
2055
|
+
}
|
|
2056
|
+
function resolveLimit(value, fallback, path) {
|
|
2057
|
+
if (value === undefined)
|
|
2058
|
+
return fallback;
|
|
2059
|
+
if (value === null)
|
|
2060
|
+
return null;
|
|
2061
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
2062
|
+
throw invalidBounds(`${path} must be a positive safe integer or null.`);
|
|
2063
|
+
}
|
|
2064
|
+
return value;
|
|
2065
|
+
}
|
|
2066
|
+
function assertObject(value, path) {
|
|
2067
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2068
|
+
throw invalidBounds(`${path} must be an object.`);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
function assertKnownKeys(value, knownKeys, path) {
|
|
2072
|
+
const unknown = Object.keys(value).find((key) => !knownKeys.includes(key));
|
|
2073
|
+
if (unknown !== undefined) {
|
|
2074
|
+
throw invalidBounds(`${path} contains unknown option ${JSON.stringify(unknown)}.`);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
function invalidBounds(message) {
|
|
2078
|
+
return new NormalizationError("invalid_input", message);
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/filters.js
|
|
2082
|
+
var DEFAULT_NORMALIZATION_FILTERS = Object.freeze({ toolResults: "include", systemMessages: "omit" });
|
|
2083
|
+
function resolveFilters(filters) {
|
|
2084
|
+
if (filters === undefined)
|
|
2085
|
+
return { ...DEFAULT_NORMALIZATION_FILTERS };
|
|
2086
|
+
assertObject2(filters, "filters");
|
|
2087
|
+
const unknown = Object.keys(filters).find((key) => key !== "toolResults" && key !== "systemMessages");
|
|
2088
|
+
if (unknown !== undefined) {
|
|
2089
|
+
throw invalidFilters(`filters contains unknown option ${JSON.stringify(unknown)}.`);
|
|
2090
|
+
}
|
|
2091
|
+
const toolResults = filters.toolResults ?? DEFAULT_NORMALIZATION_FILTERS.toolResults;
|
|
2092
|
+
if (toolResults !== "include" && toolResults !== "omit") {
|
|
2093
|
+
throw invalidFilters('filters.toolResults must be either "include" or "omit".');
|
|
2094
|
+
}
|
|
2095
|
+
const systemMessages = filters.systemMessages ?? DEFAULT_NORMALIZATION_FILTERS.systemMessages;
|
|
2096
|
+
if (systemMessages !== "include" && systemMessages !== "omit") {
|
|
2097
|
+
throw invalidFilters('filters.systemMessages must be either "include" or "omit".');
|
|
2098
|
+
}
|
|
2099
|
+
return { toolResults, systemMessages };
|
|
2100
|
+
}
|
|
2101
|
+
function assertObject2(value, path) {
|
|
2102
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2103
|
+
throw invalidFilters(`${path} must be an object.`);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
function invalidFilters(message) {
|
|
2107
|
+
return new NormalizationError("invalid_input", message);
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/canonical.js
|
|
2111
|
+
import { createHash } from "crypto";
|
|
2112
|
+
|
|
2113
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/version.js
|
|
2114
|
+
var NORMALIZER_VERSION = "0.4.3";
|
|
2115
|
+
var CANONICAL_SCHEMA_VERSION = 3;
|
|
2116
|
+
|
|
2117
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/canonical.js
|
|
2118
|
+
var GROUP_SENTINEL = "default";
|
|
2119
|
+
var META_ORDER_TIMESTAMP = "0000-00-00T00:00:00.000Z";
|
|
2120
|
+
var MISSING_TIME_SENTINEL = "0000-00-00T00:00:00.001Z";
|
|
2121
|
+
var SEQUENCE_WIDTH = 20;
|
|
2122
|
+
function buildCanonicalRecords(internal, options) {
|
|
2123
|
+
const sourceType = internal.context.source;
|
|
2124
|
+
const groupId = options.groupId;
|
|
2125
|
+
const projected = options.emitMeta ? internal.records.map((record, index) => ({ record, index })) : internal.records.map((record, index) => ({ record, index })).filter(({ record }) => record.role !== "meta");
|
|
2126
|
+
return projected.map(({ record, index }) => {
|
|
2127
|
+
const basis = internal.bases[index] ?? null;
|
|
2128
|
+
const recordTimestamp = internal.recordTimestamps[index] ?? null;
|
|
2129
|
+
const type = recordType(record);
|
|
2130
|
+
const contentHash = sha256Hex(canonicalJson({ type, content: semanticContent(record, type) }));
|
|
2131
|
+
const identity = deriveIdentity(type, groupId, basis, contentHash, options.baseByteOffset);
|
|
2132
|
+
const componentIndex = basis?.componentIndex ?? 0;
|
|
2133
|
+
const componentKey = componentKeyFor(record, type, basis);
|
|
2134
|
+
const recordJson = canonicalJson(record);
|
|
2135
|
+
const sourceTimestamp = basis?.sourceTimestamp ?? null;
|
|
2136
|
+
const flat = flattenFields(record, type);
|
|
2137
|
+
return {
|
|
2138
|
+
source_type: sourceType,
|
|
2139
|
+
source_group_id: groupId,
|
|
2140
|
+
stable_source_record_id: identity.stableSourceRecordId,
|
|
2141
|
+
source_identity_kind: identity.kind,
|
|
2142
|
+
source_order_id: buildOrderId(type, sourceTimestamp, basis, identity.stableSourceRecordId),
|
|
2143
|
+
component_index: componentIndex,
|
|
2144
|
+
record_type: type,
|
|
2145
|
+
record_id: sha256Hex(canonicalJson([groupId, identity.stableSourceRecordId, componentKey])),
|
|
2146
|
+
record_hash: sha256Hex(recordJson),
|
|
2147
|
+
content_hash: contentHash,
|
|
2148
|
+
source_timestamp: sourceTimestamp,
|
|
2149
|
+
record_timestamp: recordTimestamp,
|
|
2150
|
+
content: flat.content,
|
|
2151
|
+
tool_call_id: flat.toolCallId,
|
|
2152
|
+
tool_name: flat.toolName,
|
|
2153
|
+
tool_arguments_json: flat.toolArgumentsJson,
|
|
2154
|
+
tool_result_json: flat.toolResultJson,
|
|
2155
|
+
tool_result_ok: flat.toolResultOk,
|
|
2156
|
+
record_json: recordJson
|
|
2157
|
+
};
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
function deriveIdentity(type, groupId, basis, contentHash, baseByteOffset) {
|
|
2161
|
+
if (type === "meta") {
|
|
2162
|
+
return { stableSourceRecordId: "meta", kind: "synthetic" };
|
|
2163
|
+
}
|
|
2164
|
+
if (basis?.sourceRecordId !== undefined && basis.sourceRecordId !== "") {
|
|
2165
|
+
return { stableSourceRecordId: basis.sourceRecordId, kind: "native" };
|
|
2166
|
+
}
|
|
2167
|
+
if (basis?.sourceOffset !== undefined) {
|
|
2168
|
+
const anchorKind = basis.sourceAnchorKind ?? "ordinal";
|
|
2169
|
+
const value = anchorKind === "byte" ? basis.sourceOffset + baseByteOffset : basis.sourceOffset;
|
|
2170
|
+
return {
|
|
2171
|
+
stableSourceRecordId: sha256Hex(`${groupId}|${anchorKind}|${value}`),
|
|
2172
|
+
kind: "location"
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
if (basis?.sourceSequence !== undefined) {
|
|
2176
|
+
return {
|
|
2177
|
+
stableSourceRecordId: sha256Hex(`${groupId}|seq|${basis.sourceSequence}`),
|
|
2178
|
+
kind: "location"
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
const componentIndex = basis?.componentIndex ?? 0;
|
|
2182
|
+
return {
|
|
2183
|
+
stableSourceRecordId: sha256Hex(`${groupId}|content|${type}|${contentHash}|${componentIndex}`),
|
|
2184
|
+
kind: "content"
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
function buildOrderId(type, sourceTimestamp, basis, stableSourceRecordId) {
|
|
2188
|
+
const rank = type === "meta" ? "0" : "1";
|
|
2189
|
+
const timestamp = type === "meta" ? META_ORDER_TIMESTAMP : sourceTimestamp ?? MISSING_TIME_SENTINEL;
|
|
2190
|
+
const sequence = basis?.sourceSequence !== undefined ? String(basis.sourceSequence).padStart(SEQUENCE_WIDTH, "0") : "0".repeat(SEQUENCE_WIDTH);
|
|
2191
|
+
return `${rank}|${timestamp}|${sequence}|${stableSourceRecordId}`;
|
|
2192
|
+
}
|
|
2193
|
+
function recordType(record) {
|
|
2194
|
+
switch (record.role) {
|
|
2195
|
+
case "meta":
|
|
2196
|
+
return "meta";
|
|
2197
|
+
case "system":
|
|
2198
|
+
return "system";
|
|
2199
|
+
case "observation":
|
|
2200
|
+
return "observation";
|
|
2201
|
+
case "user":
|
|
2202
|
+
return "user";
|
|
2203
|
+
case "reasoning":
|
|
2204
|
+
return "reasoning";
|
|
2205
|
+
case "tool":
|
|
2206
|
+
return "tool";
|
|
2207
|
+
default:
|
|
2208
|
+
return "tool_calls" in record ? "assistant-tool-call" : "assistant";
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
function componentKeyFor(record, type, basis) {
|
|
2212
|
+
const ordinal = basis?.componentTypeOrdinal ?? 0;
|
|
2213
|
+
switch (type) {
|
|
2214
|
+
case "meta":
|
|
2215
|
+
return "meta";
|
|
2216
|
+
case "system":
|
|
2217
|
+
case "user":
|
|
2218
|
+
case "assistant":
|
|
2219
|
+
return `message:${ordinal}`;
|
|
2220
|
+
case "observation":
|
|
2221
|
+
return `observation:${ordinal}`;
|
|
2222
|
+
case "reasoning":
|
|
2223
|
+
return `reasoning:${ordinal}`;
|
|
2224
|
+
case "assistant-tool-call":
|
|
2225
|
+
return "tool_calls" in record ? `tool-call:${record.tool_calls[0]?.id ?? ""}` : "tool-call";
|
|
2226
|
+
case "tool":
|
|
2227
|
+
return record.role === "tool" ? `tool-result:${record.tool_call_id}` : "tool-result";
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
function semanticContent(record, type) {
|
|
2231
|
+
switch (type) {
|
|
2232
|
+
case "meta":
|
|
2233
|
+
return record.role === "meta" ? {
|
|
2234
|
+
source: record.source,
|
|
2235
|
+
...record.cwd !== undefined ? { cwd: record.cwd } : {},
|
|
2236
|
+
...record.git_branch !== undefined ? { git_branch: record.git_branch } : {},
|
|
2237
|
+
...record.model !== undefined ? { model: record.model } : {}
|
|
2238
|
+
} : {};
|
|
2239
|
+
case "system":
|
|
2240
|
+
case "observation":
|
|
2241
|
+
case "user":
|
|
2242
|
+
case "reasoning":
|
|
2243
|
+
case "assistant":
|
|
2244
|
+
return { content: "content" in record ? record.content : null };
|
|
2245
|
+
case "assistant-tool-call": {
|
|
2246
|
+
if (!("tool_calls" in record))
|
|
2247
|
+
return {};
|
|
2248
|
+
const call = record.tool_calls[0];
|
|
2249
|
+
return { name: call?.name ?? "", args: call?.args ?? "" };
|
|
2250
|
+
}
|
|
2251
|
+
case "tool":
|
|
2252
|
+
return record.role === "tool" ? { content: record.content, ...typeof record.ok === "boolean" ? { ok: record.ok } : {} } : { content: null };
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
function flattenFields(record, type) {
|
|
2256
|
+
const empty = {
|
|
2257
|
+
content: null,
|
|
2258
|
+
toolCallId: null,
|
|
2259
|
+
toolName: null,
|
|
2260
|
+
toolArgumentsJson: null,
|
|
2261
|
+
toolResultJson: null,
|
|
2262
|
+
toolResultOk: null
|
|
2263
|
+
};
|
|
2264
|
+
switch (type) {
|
|
2265
|
+
case "system":
|
|
2266
|
+
case "observation":
|
|
2267
|
+
case "user":
|
|
2268
|
+
case "reasoning":
|
|
2269
|
+
case "assistant":
|
|
2270
|
+
return { ...empty, content: "content" in record ? record.content : null };
|
|
2271
|
+
case "assistant-tool-call": {
|
|
2272
|
+
if (!("tool_calls" in record))
|
|
2273
|
+
return empty;
|
|
2274
|
+
const call = record.tool_calls[0];
|
|
2275
|
+
return {
|
|
2276
|
+
...empty,
|
|
2277
|
+
toolCallId: call?.id ?? null,
|
|
2278
|
+
toolName: call?.name ?? null,
|
|
2279
|
+
toolArgumentsJson: call?.args ?? null
|
|
2280
|
+
};
|
|
2281
|
+
}
|
|
2282
|
+
case "tool":
|
|
2283
|
+
return record.role === "tool" ? {
|
|
2284
|
+
...empty,
|
|
2285
|
+
toolCallId: record.tool_call_id,
|
|
2286
|
+
toolResultJson: record.content,
|
|
2287
|
+
toolResultOk: record.ok ?? null
|
|
2288
|
+
} : empty;
|
|
2289
|
+
case "meta":
|
|
2290
|
+
return empty;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
function canonicalJson(value) {
|
|
2294
|
+
return JSON.stringify(sortKeys(value));
|
|
2295
|
+
}
|
|
2296
|
+
function sortKeys(value) {
|
|
2297
|
+
if (Array.isArray(value))
|
|
2298
|
+
return value.map(sortKeys);
|
|
2299
|
+
if (value !== null && typeof value === "object") {
|
|
2300
|
+
const entries = Object.entries(value).filter(([, item]) => item !== undefined).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
2301
|
+
const sorted = {};
|
|
2302
|
+
for (const [key, item] of entries)
|
|
2303
|
+
sorted[key] = sortKeys(item);
|
|
2304
|
+
return sorted;
|
|
2305
|
+
}
|
|
2306
|
+
return value;
|
|
2307
|
+
}
|
|
2308
|
+
function sha256Hex(input) {
|
|
2309
|
+
return createHash("sha256").update(input, "utf8").digest("hex");
|
|
2310
|
+
}
|
|
2311
|
+
function finalizeCanonical(internal, bounds, options) {
|
|
2312
|
+
return {
|
|
2313
|
+
records: buildCanonicalRecords(internal, options),
|
|
2314
|
+
diagnostics: internal.diagnostics,
|
|
2315
|
+
normalizer_version: NORMALIZER_VERSION,
|
|
2316
|
+
canonical_schema_version: CANONICAL_SCHEMA_VERSION,
|
|
2317
|
+
config: { bounds, filters: internal.filters }
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/validate.js
|
|
2322
|
+
var TIMESTAMP_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})$/;
|
|
2323
|
+
var META_KEYS = new Set(["role", "source", "cwd", "git_branch", "model"]);
|
|
2324
|
+
var CONTENT_KEYS = new Set(["role", "content", "timestamp"]);
|
|
2325
|
+
var ASSISTANT_TOOL_KEYS = new Set(["role", "content", "timestamp", "tool_calls"]);
|
|
2326
|
+
var TOOL_RESULT_KEYS = new Set(["role", "tool_call_id", "content", "ok", "timestamp"]);
|
|
2327
|
+
var TOOL_CALL_KEYS = new Set(["id", "name", "args"]);
|
|
2328
|
+
function validateTranscript(value, options) {
|
|
2329
|
+
const partial = options?.partial ?? false;
|
|
2330
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
2331
|
+
fail("Transcript must be a non-empty array.");
|
|
2332
|
+
const allCallIds = collectCallIds(value);
|
|
2333
|
+
const callIds = new Set;
|
|
2334
|
+
const roles = new Set;
|
|
2335
|
+
let metaSeen = false;
|
|
2336
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
2337
|
+
const record = value[index];
|
|
2338
|
+
if (!isObject2(record) || typeof record.role !== "string") {
|
|
2339
|
+
fail(`Record ${index} must be an object with a role.`);
|
|
2340
|
+
}
|
|
2341
|
+
roles.add(record.role);
|
|
2342
|
+
if (record.role === "meta") {
|
|
2343
|
+
if (index !== 0 || metaSeen)
|
|
2344
|
+
fail(`Record ${index}: meta must appear once at index 0.`);
|
|
2345
|
+
metaSeen = true;
|
|
2346
|
+
exactKeys(record, META_KEYS, index);
|
|
2347
|
+
if (typeof record.source !== "string" || !record.source) {
|
|
2348
|
+
fail(`Record ${index}: meta.source must be a non-empty string.`);
|
|
2349
|
+
}
|
|
2350
|
+
optionalString(record, "cwd", index);
|
|
2351
|
+
optionalString(record, "git_branch", index);
|
|
2352
|
+
optionalString(record, "model", index);
|
|
2353
|
+
continue;
|
|
2354
|
+
}
|
|
2355
|
+
validateTimestamp(record.timestamp, index);
|
|
2356
|
+
if (record.role === "system" || record.role === "observation" || record.role === "user" || record.role === "reasoning") {
|
|
2357
|
+
exactKeys(record, CONTENT_KEYS, index);
|
|
2358
|
+
if (typeof record.content !== "string") {
|
|
2359
|
+
fail(`Record ${index}: ${record.role} content must be a string.`);
|
|
2360
|
+
}
|
|
2361
|
+
continue;
|
|
2362
|
+
}
|
|
2363
|
+
if (record.role === "assistant") {
|
|
2364
|
+
if ("tool_calls" in record) {
|
|
2365
|
+
exactKeys(record, ASSISTANT_TOOL_KEYS, index);
|
|
2366
|
+
if (record.content !== null) {
|
|
2367
|
+
fail(`Record ${index}: assistant tool-call content must be null.`);
|
|
2368
|
+
}
|
|
2369
|
+
if (!Array.isArray(record.tool_calls) || record.tool_calls.length === 0) {
|
|
2370
|
+
fail(`Record ${index}: assistant tool_calls must be a non-empty array.`);
|
|
2371
|
+
}
|
|
2372
|
+
for (const call of record.tool_calls)
|
|
2373
|
+
validateToolCall(call, index, callIds);
|
|
2374
|
+
} else {
|
|
2375
|
+
exactKeys(record, CONTENT_KEYS, index);
|
|
2376
|
+
if (typeof record.content !== "string" || !record.content) {
|
|
2377
|
+
fail(`Record ${index}: assistant content must be a non-empty string.`);
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
continue;
|
|
2381
|
+
}
|
|
2382
|
+
if (record.role === "tool") {
|
|
2383
|
+
exactKeys(record, TOOL_RESULT_KEYS, index);
|
|
2384
|
+
if (typeof record.tool_call_id !== "string" || !record.tool_call_id || !partial && !allCallIds.has(record.tool_call_id)) {
|
|
2385
|
+
fail(`Record ${index}: tool result must reference a tool call.`);
|
|
2386
|
+
}
|
|
2387
|
+
if (typeof record.content !== "string") {
|
|
2388
|
+
fail(`Record ${index}: tool content must be a string.`);
|
|
2389
|
+
}
|
|
2390
|
+
if ("ok" in record && typeof record.ok !== "boolean") {
|
|
2391
|
+
fail(`Record ${index}: tool ok must be boolean when present.`);
|
|
2392
|
+
}
|
|
2393
|
+
continue;
|
|
2394
|
+
}
|
|
2395
|
+
fail(`Record ${index}: unknown role ${JSON.stringify(record.role)}.`);
|
|
2396
|
+
}
|
|
2397
|
+
if (!partial) {
|
|
2398
|
+
if (!roles.has("user"))
|
|
2399
|
+
fail("Transcript must contain at least one user record.");
|
|
2400
|
+
if (!roles.has("assistant")) {
|
|
2401
|
+
fail("Transcript must contain at least one assistant record.");
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
function collectCallIds(records) {
|
|
2406
|
+
const ids = new Set;
|
|
2407
|
+
for (const record of records) {
|
|
2408
|
+
if (!isObject2(record) || record.role !== "assistant")
|
|
2409
|
+
continue;
|
|
2410
|
+
if (!Array.isArray(record.tool_calls))
|
|
2411
|
+
continue;
|
|
2412
|
+
for (const call of record.tool_calls) {
|
|
2413
|
+
if (isObject2(call) && typeof call.id === "string" && call.id) {
|
|
2414
|
+
ids.add(call.id);
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
return ids;
|
|
2419
|
+
}
|
|
2420
|
+
function validateToolCall(call, recordIndex, callIds) {
|
|
2421
|
+
if (!isObject2(call))
|
|
2422
|
+
fail(`Record ${recordIndex}: tool call must be an object.`);
|
|
2423
|
+
exactKeys(call, TOOL_CALL_KEYS, recordIndex, "tool call");
|
|
2424
|
+
if (typeof call.id !== "string" || !call.id) {
|
|
2425
|
+
fail(`Record ${recordIndex}: tool-call ID must be a non-empty string.`);
|
|
2426
|
+
}
|
|
2427
|
+
if (callIds.has(call.id))
|
|
2428
|
+
fail(`Record ${recordIndex}: duplicate tool-call ID ${call.id}.`);
|
|
2429
|
+
if (typeof call.name !== "string" || !call.name) {
|
|
2430
|
+
fail(`Record ${recordIndex}: tool-call name must be a non-empty string.`);
|
|
2431
|
+
}
|
|
2432
|
+
if (typeof call.args !== "string") {
|
|
2433
|
+
fail(`Record ${recordIndex}: tool-call args must be a string.`);
|
|
2434
|
+
}
|
|
2435
|
+
let args;
|
|
2436
|
+
try {
|
|
2437
|
+
args = JSON.parse(call.args);
|
|
2438
|
+
} catch {
|
|
2439
|
+
fail(`Record ${recordIndex}: tool-call args must contain valid JSON.`);
|
|
2440
|
+
}
|
|
2441
|
+
if (!isObject2(args)) {
|
|
2442
|
+
fail(`Record ${recordIndex}: tool-call args must encode a JSON object.`);
|
|
2443
|
+
}
|
|
2444
|
+
callIds.add(call.id);
|
|
2445
|
+
}
|
|
2446
|
+
function validateTimestamp(value, recordIndex) {
|
|
2447
|
+
if (typeof value !== "string" || !TIMESTAMP_PATTERN.test(value)) {
|
|
2448
|
+
fail(`Record ${recordIndex}: timestamp must be an ISO-8601 instant.`);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
function exactKeys(value, allowed, recordIndex, label = "record") {
|
|
2452
|
+
const extra = Object.keys(value).find((key) => !allowed.has(key));
|
|
2453
|
+
if (extra)
|
|
2454
|
+
fail(`Record ${recordIndex}: unexpected ${label} field ${JSON.stringify(extra)}.`);
|
|
2455
|
+
}
|
|
2456
|
+
function optionalString(value, key, recordIndex) {
|
|
2457
|
+
if (key in value && typeof value[key] !== "string") {
|
|
2458
|
+
fail(`Record ${recordIndex}: ${key} must be a string when present.`);
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
function isObject2(value) {
|
|
2462
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2463
|
+
}
|
|
2464
|
+
function fail(message) {
|
|
2465
|
+
throw new NormalizationError("invalid_normalized_transcript", message);
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/core.js
|
|
2469
|
+
var ARGS_LEAF_FLOOR = 2000;
|
|
2470
|
+
var SYNTH_BASE_MS = Date.UTC(2026, 0, 1);
|
|
2471
|
+
var SYNTH_STEP_SECONDS = 15;
|
|
2472
|
+
var NOISE_PREFIXES = [
|
|
2473
|
+
"<local-command-caveat>",
|
|
2474
|
+
"<command-name>",
|
|
2475
|
+
"<command-message>",
|
|
2476
|
+
"<local-command-stdout>",
|
|
2477
|
+
"<local-command-stderr>",
|
|
2478
|
+
"<task-notification"
|
|
2479
|
+
];
|
|
2480
|
+
function semanticBucket(event) {
|
|
2481
|
+
switch (event.type) {
|
|
2482
|
+
case "message":
|
|
2483
|
+
return "message";
|
|
2484
|
+
case "observation":
|
|
2485
|
+
return "observation";
|
|
2486
|
+
case "reasoning":
|
|
2487
|
+
return "reasoning";
|
|
2488
|
+
case "tool_call":
|
|
2489
|
+
return "tool_call";
|
|
2490
|
+
case "tool_result":
|
|
2491
|
+
return "tool_result";
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
function planEvents(events) {
|
|
2495
|
+
const calls = new Map;
|
|
2496
|
+
const openCalls = new Map;
|
|
2497
|
+
const usedIds = new Set;
|
|
2498
|
+
const occOf = [];
|
|
2499
|
+
const bucketOf = [];
|
|
2500
|
+
let occurrence = -1;
|
|
2501
|
+
for (let index = 0;index < events.length; index += 1) {
|
|
2502
|
+
const event = events[index];
|
|
2503
|
+
if (event === undefined) {
|
|
2504
|
+
occOf.push(occurrence);
|
|
2505
|
+
bucketOf.push("");
|
|
2506
|
+
continue;
|
|
2507
|
+
}
|
|
2508
|
+
if ((event.componentIndex ?? 0) === 0)
|
|
2509
|
+
occurrence += 1;
|
|
2510
|
+
const bucket = semanticBucket(event);
|
|
2511
|
+
occOf.push(occurrence);
|
|
2512
|
+
bucketOf.push(bucket);
|
|
2513
|
+
if (event.type === "tool_call") {
|
|
2514
|
+
const sourceId = event.id || `call_${index + 1}`;
|
|
2515
|
+
const synthesized = !event.id;
|
|
2516
|
+
let finalId = sourceId;
|
|
2517
|
+
let renamed = false;
|
|
2518
|
+
if (usedIds.has(finalId)) {
|
|
2519
|
+
let suffix = 2;
|
|
2520
|
+
while (usedIds.has(`${sourceId}__${suffix}`))
|
|
2521
|
+
suffix += 1;
|
|
2522
|
+
finalId = `${sourceId}__${suffix}`;
|
|
2523
|
+
renamed = true;
|
|
2524
|
+
}
|
|
2525
|
+
usedIds.add(finalId);
|
|
2526
|
+
const entries = openCalls.get(sourceId) ?? [];
|
|
2527
|
+
entries.push({ finalId, consumed: false });
|
|
2528
|
+
openCalls.set(sourceId, entries);
|
|
2529
|
+
calls.set(index, { finalId, renamed, synthesized, sourceId });
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
const seen = new Map;
|
|
2533
|
+
const components = [];
|
|
2534
|
+
for (let index = 0;index < events.length; index += 1) {
|
|
2535
|
+
if (events[index] === undefined) {
|
|
2536
|
+
components.push(undefined);
|
|
2537
|
+
continue;
|
|
2538
|
+
}
|
|
2539
|
+
const key = `${occOf[index]}:${bucketOf[index]}`;
|
|
2540
|
+
const ordinal = seen.get(key) ?? 0;
|
|
2541
|
+
seen.set(key, ordinal + 1);
|
|
2542
|
+
components.push({ typeOrdinal: ordinal });
|
|
2543
|
+
}
|
|
2544
|
+
return { calls, openCalls, components };
|
|
2545
|
+
}
|
|
2546
|
+
function normalizeDecodedSession(decoded, bounds, options) {
|
|
2547
|
+
const internal = normalizeDecodedSessionInternal(decoded, bounds, options);
|
|
2548
|
+
return { records: internal.records, diagnostics: internal.diagnostics };
|
|
2549
|
+
}
|
|
2550
|
+
function normalizeDecodedSessionInternal(decoded, bounds, options) {
|
|
2551
|
+
const partial = options?.partial ?? false;
|
|
2552
|
+
const filters = options?.filters ?? DEFAULT_NORMALIZATION_FILTERS;
|
|
2553
|
+
const diagnostics = [...decoded.diagnostics];
|
|
2554
|
+
const body = [];
|
|
2555
|
+
const bodyBases = [];
|
|
2556
|
+
const anchors = new Map;
|
|
2557
|
+
const modelCounts = new Map;
|
|
2558
|
+
const plan = planEvents(decoded.events);
|
|
2559
|
+
for (let eventIndex = 0;eventIndex < decoded.events.length; eventIndex += 1) {
|
|
2560
|
+
const event = decoded.events[eventIndex];
|
|
2561
|
+
if (event === undefined)
|
|
2562
|
+
continue;
|
|
2563
|
+
if (event.model) {
|
|
2564
|
+
modelCounts.set(event.model, (modelCounts.get(event.model) ?? 0) + 1);
|
|
2565
|
+
}
|
|
2566
|
+
const record = normalizeEvent(event, eventIndex, body.length + 1, plan, diagnostics, bounds, filters, partial);
|
|
2567
|
+
if (!record)
|
|
2568
|
+
continue;
|
|
2569
|
+
const hasTimestamp = event.timestamp !== undefined && !Number.isNaN(event.timestamp.getTime());
|
|
2570
|
+
if (hasTimestamp && event.timestamp) {
|
|
2571
|
+
anchors.set(body.length, event.timestamp);
|
|
2572
|
+
}
|
|
2573
|
+
const component = plan.components[eventIndex] ?? { typeOrdinal: 0 };
|
|
2574
|
+
body.push(record);
|
|
2575
|
+
bodyBases.push({
|
|
2576
|
+
componentIndex: event.componentIndex ?? 0,
|
|
2577
|
+
componentTypeOrdinal: component.typeOrdinal,
|
|
2578
|
+
...event.sourceRecordId !== undefined ? { sourceRecordId: event.sourceRecordId } : {},
|
|
2579
|
+
...event.sourceSequence !== undefined ? { sourceSequence: event.sourceSequence } : {},
|
|
2580
|
+
...event.sourceOffset !== undefined ? { sourceOffset: event.sourceOffset } : {},
|
|
2581
|
+
...event.sourceAnchorKind !== undefined ? { sourceAnchorKind: event.sourceAnchorKind } : {},
|
|
2582
|
+
...hasTimestamp && event.timestamp ? { sourceTimestamp: event.timestamp.toISOString() } : {}
|
|
2583
|
+
});
|
|
2584
|
+
}
|
|
2585
|
+
const roles = new Set(body.map((record) => record.role));
|
|
2586
|
+
if (!partial) {
|
|
2587
|
+
if (!roles.has("user")) {
|
|
2588
|
+
throw new NormalizationError("missing_user_records", "Transcript did not contain any normalizable user records.");
|
|
2589
|
+
}
|
|
2590
|
+
if (!roles.has("assistant")) {
|
|
2591
|
+
throw new NormalizationError("missing_assistant_records", "Transcript did not contain any normalizable assistant records.");
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
const timestamps = fillTimestamps(body.length, anchors, decoded.context, diagnostics);
|
|
2595
|
+
const stampedBody = body.map((record, index) => {
|
|
2596
|
+
const timestamp = timestamps[index];
|
|
2597
|
+
if (timestamp === undefined) {
|
|
2598
|
+
throw new NormalizationError("invalid_normalized_transcript", `Could not assign a timestamp to normalized record ${index}.`);
|
|
2599
|
+
}
|
|
2600
|
+
return { ...record, timestamp };
|
|
2601
|
+
});
|
|
2602
|
+
const meta = buildMeta(decoded.context, modelCounts);
|
|
2603
|
+
const records = [meta, ...stampedBody];
|
|
2604
|
+
validateTranscript(records, { partial });
|
|
2605
|
+
const recordTimestamps = [
|
|
2606
|
+
null,
|
|
2607
|
+
...stampedBody.map((record) => record.timestamp)
|
|
2608
|
+
];
|
|
2609
|
+
const bases = [null, ...bodyBases];
|
|
2610
|
+
return {
|
|
2611
|
+
records,
|
|
2612
|
+
bases,
|
|
2613
|
+
recordTimestamps,
|
|
2614
|
+
context: decoded.context,
|
|
2615
|
+
diagnostics,
|
|
2616
|
+
bounds,
|
|
2617
|
+
filters
|
|
2618
|
+
};
|
|
2619
|
+
}
|
|
2620
|
+
function normalizeEvent(event, eventIndex, recordIndex, plan, diagnostics, bounds, filters, partial) {
|
|
2621
|
+
if (event.type === "message") {
|
|
2622
|
+
if (!event.content.trim()) {
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
if (event.role === "system") {
|
|
2626
|
+
if (filters.systemMessages === "omit")
|
|
2627
|
+
return;
|
|
2628
|
+
const record = {
|
|
2629
|
+
role: "system",
|
|
2630
|
+
content: event.content
|
|
2631
|
+
};
|
|
2632
|
+
return record;
|
|
2633
|
+
}
|
|
2634
|
+
if (event.role === "user" && NOISE_PREFIXES.some((prefix) => event.content.trimStart().startsWith(prefix))) {
|
|
2635
|
+
diagnostics.push({
|
|
2636
|
+
code: "noise_record_dropped",
|
|
2637
|
+
message: "Dropped a harness-noise user record.",
|
|
2638
|
+
recordIndex,
|
|
2639
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2640
|
+
});
|
|
2641
|
+
return;
|
|
2642
|
+
}
|
|
2643
|
+
if (event.role === "user") {
|
|
2644
|
+
const record = {
|
|
2645
|
+
role: "user",
|
|
2646
|
+
content: event.content
|
|
2647
|
+
};
|
|
2648
|
+
return record;
|
|
2649
|
+
}
|
|
2650
|
+
const record = {
|
|
2651
|
+
role: "assistant",
|
|
2652
|
+
content: event.content
|
|
2653
|
+
};
|
|
2654
|
+
return record;
|
|
2655
|
+
}
|
|
2656
|
+
if (event.type === "reasoning") {
|
|
2657
|
+
if (!event.content.trim()) {
|
|
2658
|
+
return;
|
|
2659
|
+
}
|
|
2660
|
+
const record = {
|
|
2661
|
+
role: "reasoning",
|
|
2662
|
+
content: event.content
|
|
2663
|
+
};
|
|
2664
|
+
return record;
|
|
2665
|
+
}
|
|
2666
|
+
if (event.type === "observation") {
|
|
2667
|
+
if (!event.content.trim())
|
|
2668
|
+
return;
|
|
2669
|
+
const record = {
|
|
2670
|
+
role: "observation",
|
|
2671
|
+
content: event.content
|
|
2672
|
+
};
|
|
2673
|
+
return record;
|
|
2674
|
+
}
|
|
2675
|
+
if (event.type === "tool_call") {
|
|
2676
|
+
const entry = plan.calls.get(eventIndex);
|
|
2677
|
+
const sourceId = entry?.sourceId ?? (event.id || `call_${eventIndex + 1}`);
|
|
2678
|
+
const finalId = entry?.finalId ?? sourceId;
|
|
2679
|
+
if (entry?.synthesized ?? !event.id) {
|
|
2680
|
+
diagnostics.push({
|
|
2681
|
+
code: "tool_call_id_synthesized",
|
|
2682
|
+
message: `Synthesized tool-call ID ${JSON.stringify(sourceId)}.`,
|
|
2683
|
+
recordIndex,
|
|
2684
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
if (entry?.renamed) {
|
|
2688
|
+
diagnostics.push({
|
|
2689
|
+
code: "duplicate_tool_call_id",
|
|
2690
|
+
message: `Renamed duplicate tool-call ID ${JSON.stringify(sourceId)} to ${JSON.stringify(finalId)}.`,
|
|
2691
|
+
recordIndex,
|
|
2692
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2693
|
+
});
|
|
2694
|
+
}
|
|
2695
|
+
const name = event.name || "unknown_tool";
|
|
2696
|
+
if (!event.name) {
|
|
2697
|
+
diagnostics.push({
|
|
2698
|
+
code: "unknown_tool_name",
|
|
2699
|
+
message: `Substituted ${JSON.stringify(name)} for a missing tool name.`,
|
|
2700
|
+
recordIndex,
|
|
2701
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
const args = shrinkArgs(event.args, bounds.toolArguments.maxCharacters);
|
|
2705
|
+
if (args.reshaped) {
|
|
2706
|
+
diagnostics.push({
|
|
2707
|
+
code: "tool_arguments_reshaped",
|
|
2708
|
+
message: `Reshaped arguments for tool call ${JSON.stringify(finalId)} into a JSON object.`,
|
|
2709
|
+
recordIndex,
|
|
2710
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
2713
|
+
if (args.truncated) {
|
|
2714
|
+
diagnostics.push({
|
|
2715
|
+
code: "tool_arguments_truncated",
|
|
2716
|
+
message: `Truncated arguments for tool call ${JSON.stringify(finalId)} to at most ${bounds.toolArguments.maxCharacters} Unicode code points.`,
|
|
2717
|
+
recordIndex,
|
|
2718
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2719
|
+
});
|
|
2720
|
+
}
|
|
2721
|
+
const record = {
|
|
2722
|
+
role: "assistant",
|
|
2723
|
+
content: null,
|
|
2724
|
+
tool_calls: [{ id: finalId, name, args: args.args }]
|
|
2725
|
+
};
|
|
2726
|
+
return record;
|
|
2727
|
+
}
|
|
2728
|
+
const sourceId = event.callId || "";
|
|
2729
|
+
const entries = plan.openCalls.get(sourceId);
|
|
2730
|
+
const openEntry = entries?.find((entry) => !entry.consumed);
|
|
2731
|
+
const crossChunk = !openEntry && partial && sourceId !== "" && !(entries && entries.length > 0);
|
|
2732
|
+
if (!openEntry && !crossChunk) {
|
|
2733
|
+
const duplicate = Boolean(entries && entries.length > 0);
|
|
2734
|
+
diagnostics.push({
|
|
2735
|
+
code: duplicate ? "duplicate_tool_result" : "orphan_tool_result",
|
|
2736
|
+
message: duplicate ? `Dropped a duplicate result for tool call ${JSON.stringify(sourceId)}.` : `Dropped a tool result without a preceding call for ${JSON.stringify(sourceId)}.`,
|
|
2737
|
+
recordIndex,
|
|
2738
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2739
|
+
});
|
|
2740
|
+
return;
|
|
2741
|
+
}
|
|
2742
|
+
if (openEntry)
|
|
2743
|
+
openEntry.consumed = true;
|
|
2744
|
+
if (filters.toolResults === "omit")
|
|
2745
|
+
return;
|
|
2746
|
+
const finalId = openEntry ? openEntry.finalId : sourceId;
|
|
2747
|
+
const resultLimit = bounds.toolResults.maxCharacters;
|
|
2748
|
+
const content = resultLimit === null ? event.content : truncateText(event.content, resultLimit, bounds.toolResults.strategy);
|
|
2749
|
+
if (content !== event.content) {
|
|
2750
|
+
diagnostics.push({
|
|
2751
|
+
code: "tool_result_truncated",
|
|
2752
|
+
message: `Truncated the result for tool call ${JSON.stringify(finalId)} to at most ${resultLimit} Unicode code points using the ${JSON.stringify(bounds.toolResults.strategy)} strategy.`,
|
|
2753
|
+
recordIndex,
|
|
2754
|
+
...event.inputLine ? { inputLine: event.inputLine } : {}
|
|
2755
|
+
});
|
|
2756
|
+
}
|
|
2757
|
+
const record = {
|
|
2758
|
+
role: "tool",
|
|
2759
|
+
tool_call_id: finalId,
|
|
2760
|
+
content,
|
|
2761
|
+
...typeof event.ok === "boolean" ? { ok: event.ok } : {}
|
|
2762
|
+
};
|
|
2763
|
+
return record;
|
|
2764
|
+
}
|
|
2765
|
+
function buildMeta(context, modelCounts) {
|
|
2766
|
+
let model = context.model;
|
|
2767
|
+
if (!model) {
|
|
2768
|
+
let best;
|
|
2769
|
+
let highestCount = 0;
|
|
2770
|
+
for (const [candidate, count] of modelCounts) {
|
|
2771
|
+
if (count > highestCount || count === highestCount && best !== undefined && candidate < best) {
|
|
2772
|
+
best = candidate;
|
|
2773
|
+
highestCount = count;
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2776
|
+
model = best;
|
|
2777
|
+
}
|
|
2778
|
+
return {
|
|
2779
|
+
role: "meta",
|
|
2780
|
+
source: context.source,
|
|
2781
|
+
...context.cwd ? { cwd: context.cwd } : {},
|
|
2782
|
+
...context.gitBranch ? { git_branch: context.gitBranch } : {},
|
|
2783
|
+
...model ? { model } : {}
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
function fillTimestamps(count, anchors, context, diagnostics) {
|
|
2787
|
+
if (count === 0)
|
|
2788
|
+
return [];
|
|
2789
|
+
if (anchors.size === 0) {
|
|
2790
|
+
const baseMs = (context.createdAt ?? new Date(SYNTH_BASE_MS)).getTime();
|
|
2791
|
+
const stepSeconds = context.durationSeconds && count > 1 ? context.durationSeconds / (count - 1) : SYNTH_STEP_SECONDS;
|
|
2792
|
+
diagnostics.push({
|
|
2793
|
+
code: "timestamps_synthesized",
|
|
2794
|
+
message: `Synthesized timestamps for ${count} normalized records.`,
|
|
2795
|
+
count
|
|
2796
|
+
});
|
|
2797
|
+
return Array.from({ length: count }, (_, index) => new Date(baseMs + stepSeconds * 1000 * index).toISOString());
|
|
2798
|
+
}
|
|
2799
|
+
const output = new Array(count);
|
|
2800
|
+
const indexes = [...anchors.keys()].sort((a, b) => a - b);
|
|
2801
|
+
const first = indexes[0];
|
|
2802
|
+
const last = indexes[indexes.length - 1];
|
|
2803
|
+
if (first === undefined || last === undefined)
|
|
2804
|
+
return output;
|
|
2805
|
+
const anchorMs = (index) => {
|
|
2806
|
+
const anchor = anchors.get(index);
|
|
2807
|
+
if (!anchor) {
|
|
2808
|
+
throw new NormalizationError("invalid_normalized_transcript", `Missing timestamp anchor at record ${index}.`);
|
|
2809
|
+
}
|
|
2810
|
+
return anchor.getTime();
|
|
2811
|
+
};
|
|
2812
|
+
for (let index = 0;index < first; index += 1) {
|
|
2813
|
+
output[index] = new Date(anchorMs(first) - (first - index) * 1000).toISOString();
|
|
2814
|
+
}
|
|
2815
|
+
for (let cursor = 0;cursor + 1 < indexes.length; cursor += 1) {
|
|
2816
|
+
const start = indexes[cursor];
|
|
2817
|
+
const end = indexes[cursor + 1];
|
|
2818
|
+
if (start === undefined || end === undefined)
|
|
2819
|
+
continue;
|
|
2820
|
+
output[start] = new Date(anchorMs(start)).toISOString();
|
|
2821
|
+
const spanMs = anchorMs(end) - anchorMs(start);
|
|
2822
|
+
const gap = end - start;
|
|
2823
|
+
for (let index = start + 1;index < end; index += 1) {
|
|
2824
|
+
output[index] = new Date(anchorMs(start) + spanMs * (index - start) / gap).toISOString();
|
|
2825
|
+
}
|
|
2826
|
+
}
|
|
2827
|
+
output[last] = new Date(anchorMs(last)).toISOString();
|
|
2828
|
+
for (let index = last + 1;index < count; index += 1) {
|
|
2829
|
+
output[index] = new Date(anchorMs(last) + (index - last) * 1000).toISOString();
|
|
2830
|
+
}
|
|
2831
|
+
const interpolatedCount = count - anchors.size;
|
|
2832
|
+
if (interpolatedCount > 0) {
|
|
2833
|
+
diagnostics.push({
|
|
2834
|
+
code: "timestamps_interpolated",
|
|
2835
|
+
message: `Interpolated timestamps for ${interpolatedCount} normalized records.`,
|
|
2836
|
+
count: interpolatedCount
|
|
2837
|
+
});
|
|
2838
|
+
}
|
|
2839
|
+
return output;
|
|
2840
|
+
}
|
|
2841
|
+
function shrinkArgs(rawInput, limit) {
|
|
2842
|
+
const raw = rawInput || "{}";
|
|
2843
|
+
let parsed;
|
|
2844
|
+
try {
|
|
2845
|
+
parsed = JSON.parse(raw);
|
|
2846
|
+
} catch {
|
|
2847
|
+
parsed = undefined;
|
|
2848
|
+
}
|
|
2849
|
+
if (!isPlainObject(parsed)) {
|
|
2850
|
+
const full = JSON.stringify({ _raw: raw });
|
|
2851
|
+
const wrapped = limit === null ? full : wrapRawArgs(raw, limit);
|
|
2852
|
+
return {
|
|
2853
|
+
args: wrapped,
|
|
2854
|
+
reshaped: true,
|
|
2855
|
+
truncated: wrapped !== full
|
|
2856
|
+
};
|
|
2857
|
+
}
|
|
2858
|
+
if (limit === null || codePointLength(raw) <= limit) {
|
|
2859
|
+
return { args: raw, reshaped: false, truncated: false };
|
|
2860
|
+
}
|
|
2861
|
+
const legacy = shrinkObjectArgsLegacy(parsed, limit);
|
|
2862
|
+
if (codePointLength(legacy) <= limit) {
|
|
2863
|
+
return { args: legacy, reshaped: false, truncated: true };
|
|
2864
|
+
}
|
|
2865
|
+
const fresh = JSON.parse(raw);
|
|
2866
|
+
const serialized = shrinkObjectArgsSafely(fresh, limit);
|
|
2867
|
+
if (codePointLength(serialized) > limit) {
|
|
2868
|
+
return {
|
|
2869
|
+
args: wrapRawArgs(raw, limit),
|
|
2870
|
+
reshaped: true,
|
|
2871
|
+
truncated: true
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
return { args: serialized, reshaped: false, truncated: true };
|
|
2875
|
+
}
|
|
2876
|
+
function shrinkObjectArgsLegacy(parsed, limit) {
|
|
2877
|
+
const leaves = [];
|
|
2878
|
+
collectStringLeaves(parsed, leaves);
|
|
2879
|
+
let serialized = JSON.stringify(parsed);
|
|
2880
|
+
const seen = new Set;
|
|
2881
|
+
while (codePointLength(serialized) > limit && leaves.length > 0) {
|
|
2882
|
+
if (seen.has(serialized))
|
|
2883
|
+
break;
|
|
2884
|
+
seen.add(serialized);
|
|
2885
|
+
let largest = leaves[0];
|
|
2886
|
+
if (!largest)
|
|
2887
|
+
break;
|
|
2888
|
+
for (const leaf of leaves) {
|
|
2889
|
+
if (codePointLength(leafValue(leaf)) > codePointLength(leafValue(largest))) {
|
|
2890
|
+
largest = leaf;
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
const value = leafValue(largest);
|
|
2894
|
+
const valueLength = codePointLength(value);
|
|
2895
|
+
if (valueLength <= ARGS_LEAF_FLOOR)
|
|
2896
|
+
break;
|
|
2897
|
+
const keep = Math.max(ARGS_LEAF_FLOOR, Math.floor(valueLength / 2));
|
|
2898
|
+
setLeafValue(largest, sliceCodePoints(value, 0, keep) + truncationMarker(valueLength - keep));
|
|
2899
|
+
serialized = JSON.stringify(parsed);
|
|
2900
|
+
}
|
|
2901
|
+
return serialized;
|
|
2902
|
+
}
|
|
2903
|
+
function shrinkObjectArgsSafely(parsed, limit) {
|
|
2904
|
+
const leaves = [];
|
|
2905
|
+
collectStringLeaves(parsed, leaves);
|
|
2906
|
+
let serialized = JSON.stringify(parsed);
|
|
2907
|
+
while (codePointLength(serialized) > limit && leaves.length > 0) {
|
|
2908
|
+
let largest = leaves.find((leaf) => leaf.currentLength > 0);
|
|
2909
|
+
if (!largest)
|
|
2910
|
+
break;
|
|
2911
|
+
for (const leaf of leaves) {
|
|
2912
|
+
if (leaf.currentLength > largest.currentLength)
|
|
2913
|
+
largest = leaf;
|
|
2914
|
+
}
|
|
2915
|
+
const previousLength = codePointLength(serialized);
|
|
2916
|
+
const overflow = previousLength - limit;
|
|
2917
|
+
let candidate = "";
|
|
2918
|
+
let nextKeep = 0;
|
|
2919
|
+
if (largest.keep > 0) {
|
|
2920
|
+
const preferredFloor = largest.keep > ARGS_LEAF_FLOOR ? ARGS_LEAF_FLOOR : 0;
|
|
2921
|
+
const markerBudget = codePointLength(truncationMarker(codePointLength(largest.original)));
|
|
2922
|
+
nextKeep = Math.max(preferredFloor, Math.min(Math.floor(largest.keep / 2), largest.keep - overflow - markerBudget - 1));
|
|
2923
|
+
nextKeep = Math.max(0, Math.min(nextKeep, largest.keep - 1));
|
|
2924
|
+
candidate = sliceCodePoints(largest.original, 0, nextKeep) + truncationMarker(codePointLength(largest.original) - nextKeep);
|
|
2925
|
+
if (codePointLength(candidate) >= largest.currentLength) {
|
|
2926
|
+
candidate = "";
|
|
2927
|
+
nextKeep = 0;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
setLeafValue(largest, candidate);
|
|
2931
|
+
largest.keep = nextKeep;
|
|
2932
|
+
largest.currentLength = codePointLength(candidate);
|
|
2933
|
+
serialized = JSON.stringify(parsed);
|
|
2934
|
+
if (codePointLength(serialized) >= previousLength && candidate) {
|
|
2935
|
+
setLeafValue(largest, "");
|
|
2936
|
+
largest.keep = 0;
|
|
2937
|
+
largest.currentLength = 0;
|
|
2938
|
+
serialized = JSON.stringify(parsed);
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
return serialized;
|
|
2942
|
+
}
|
|
2943
|
+
function collectStringLeaves(value, leaves) {
|
|
2944
|
+
if (Array.isArray(value)) {
|
|
2945
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
2946
|
+
const child = value[index];
|
|
2947
|
+
if (typeof child === "string") {
|
|
2948
|
+
leaves.push({
|
|
2949
|
+
parent: value,
|
|
2950
|
+
key: index,
|
|
2951
|
+
original: child,
|
|
2952
|
+
keep: codePointLength(child),
|
|
2953
|
+
currentLength: codePointLength(child)
|
|
2954
|
+
});
|
|
2955
|
+
} else if (child !== null && typeof child === "object") {
|
|
2956
|
+
collectStringLeaves(child, leaves);
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
return;
|
|
2960
|
+
}
|
|
2961
|
+
if (!isPlainObject(value))
|
|
2962
|
+
return;
|
|
2963
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2964
|
+
if (typeof child === "string") {
|
|
2965
|
+
leaves.push({
|
|
2966
|
+
parent: value,
|
|
2967
|
+
key,
|
|
2968
|
+
original: child,
|
|
2969
|
+
keep: codePointLength(child),
|
|
2970
|
+
currentLength: codePointLength(child)
|
|
2971
|
+
});
|
|
2972
|
+
} else if (child !== null && typeof child === "object") {
|
|
2973
|
+
collectStringLeaves(child, leaves);
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
function setLeafValue(leaf, value) {
|
|
2978
|
+
if (Array.isArray(leaf.parent))
|
|
2979
|
+
leaf.parent[leaf.key] = value;
|
|
2980
|
+
else
|
|
2981
|
+
leaf.parent[leaf.key] = value;
|
|
2982
|
+
}
|
|
2983
|
+
function leafValue(leaf) {
|
|
2984
|
+
const value = Array.isArray(leaf.parent) ? leaf.parent[leaf.key] : leaf.parent[leaf.key];
|
|
2985
|
+
return typeof value === "string" ? value : "";
|
|
2986
|
+
}
|
|
2987
|
+
function wrapRawArgs(raw, limit) {
|
|
2988
|
+
const full = JSON.stringify({ _raw: raw });
|
|
2989
|
+
if (codePointLength(full) <= limit)
|
|
2990
|
+
return full;
|
|
2991
|
+
let low = 0;
|
|
2992
|
+
const rawLength = codePointLength(raw);
|
|
2993
|
+
let high = Math.min(rawLength, limit);
|
|
2994
|
+
let best = "{}";
|
|
2995
|
+
while (low <= high) {
|
|
2996
|
+
const keep = Math.floor((low + high) / 2);
|
|
2997
|
+
const candidate = JSON.stringify({
|
|
2998
|
+
_raw: sliceCodePoints(raw, 0, keep) + truncationMarker(rawLength - keep)
|
|
2999
|
+
});
|
|
3000
|
+
if (codePointLength(candidate) <= limit) {
|
|
3001
|
+
best = candidate;
|
|
3002
|
+
low = keep + 1;
|
|
3003
|
+
} else {
|
|
3004
|
+
high = keep - 1;
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
return best;
|
|
3008
|
+
}
|
|
3009
|
+
function isPlainObject(value) {
|
|
3010
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3011
|
+
}
|
|
3012
|
+
function truncateText(text, limit, strategy) {
|
|
3013
|
+
const textLength = codePointLength(text);
|
|
3014
|
+
if (textLength <= limit)
|
|
3015
|
+
return text;
|
|
3016
|
+
let low = 0;
|
|
3017
|
+
let high = Math.min(textLength - 1, limit);
|
|
3018
|
+
let keep = -1;
|
|
3019
|
+
let marker = "";
|
|
3020
|
+
while (low <= high) {
|
|
3021
|
+
const candidateKeep = Math.floor((low + high) / 2);
|
|
3022
|
+
const candidateMarker = truncationMarker(textLength - candidateKeep);
|
|
3023
|
+
if (candidateKeep + codePointLength(candidateMarker) <= limit) {
|
|
3024
|
+
keep = candidateKeep;
|
|
3025
|
+
marker = candidateMarker;
|
|
3026
|
+
low = candidateKeep + 1;
|
|
3027
|
+
} else {
|
|
3028
|
+
high = candidateKeep - 1;
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
if (keep < 0) {
|
|
3032
|
+
marker = sliceCodePoints("\u2026", 0, limit);
|
|
3033
|
+
keep = limit - codePointLength(marker);
|
|
3034
|
+
}
|
|
3035
|
+
if (strategy === "head") {
|
|
3036
|
+
return sliceCodePoints(text, 0, keep) + marker;
|
|
3037
|
+
}
|
|
3038
|
+
const headLength = Math.ceil(keep / 2);
|
|
3039
|
+
const tailLength = keep - headLength;
|
|
3040
|
+
return sliceCodePoints(text, 0, headLength) + marker + (tailLength > 0 ? sliceCodePoints(text, textLength - tailLength, textLength) : "");
|
|
3041
|
+
}
|
|
3042
|
+
function truncationMarker(remaining) {
|
|
3043
|
+
return `
|
|
3044
|
+
\u2026 [truncated, ${remaining} more chars]`;
|
|
3045
|
+
}
|
|
3046
|
+
function codePointLength(text) {
|
|
3047
|
+
let length = 0;
|
|
3048
|
+
for (const _character of text)
|
|
3049
|
+
length += 1;
|
|
3050
|
+
return length;
|
|
3051
|
+
}
|
|
3052
|
+
function sliceCodePoints(text, start, end) {
|
|
3053
|
+
const stop = end ?? Number.POSITIVE_INFINITY;
|
|
3054
|
+
let result = "";
|
|
3055
|
+
let index = 0;
|
|
3056
|
+
for (const character of text) {
|
|
3057
|
+
if (index >= stop)
|
|
3058
|
+
break;
|
|
3059
|
+
if (index >= start)
|
|
3060
|
+
result += character;
|
|
3061
|
+
index += 1;
|
|
3062
|
+
}
|
|
3063
|
+
return result;
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/adapters/deepagents/index.js
|
|
3067
|
+
var MAX_HELPER_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
3068
|
+
|
|
3069
|
+
// ../../node_modules/.bun/@letta-ai+trajectory@0.4.3/node_modules/@letta-ai/trajectory/dist/index.js
|
|
3070
|
+
var ADAPTERS = {
|
|
3071
|
+
atif: atifAdapter,
|
|
3072
|
+
"claude-code": claudeCodeAdapter,
|
|
3073
|
+
codex: codexAdapter,
|
|
3074
|
+
"copilot-cli": copilotCliAdapter,
|
|
3075
|
+
cursor: cursorAdapter,
|
|
3076
|
+
droid: droidAdapter,
|
|
3077
|
+
"gemini-cli": geminiCliAdapter,
|
|
3078
|
+
hermes: hermesAdapter,
|
|
3079
|
+
"letta-code": lettaCodeAdapter,
|
|
3080
|
+
openclaw: openClawAdapter,
|
|
3081
|
+
opencode: openCodeAdapter,
|
|
3082
|
+
openhands: openHandsAdapter,
|
|
3083
|
+
pi: piAdapter,
|
|
3084
|
+
omp: ompAdapter
|
|
3085
|
+
};
|
|
3086
|
+
function decodeTranscript(input) {
|
|
3087
|
+
if (!input || typeof input !== "object") {
|
|
3088
|
+
throw new NormalizationError("invalid_input", "Input must be an object.");
|
|
3089
|
+
}
|
|
3090
|
+
if (typeof input.transcript !== "string") {
|
|
3091
|
+
throw new NormalizationError("invalid_input", "Input transcript must be a string containing the source transcript.");
|
|
3092
|
+
}
|
|
3093
|
+
const adapter = ADAPTERS[input.source];
|
|
3094
|
+
if (!adapter) {
|
|
3095
|
+
throw new NormalizationError("unknown_source", `Unknown trajectory source ${JSON.stringify(input.source)}. Supported sources: ${Object.keys(ADAPTERS).join(", ")}.`);
|
|
3096
|
+
}
|
|
3097
|
+
return {
|
|
3098
|
+
decoded: adapter.decode(input.transcript),
|
|
3099
|
+
bounds: resolveBounds(input.bounds),
|
|
3100
|
+
filters: resolveFilters(input.filters)
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
function normalizeTranscript(input) {
|
|
3104
|
+
const { decoded, bounds, filters } = decodeTranscript(input);
|
|
3105
|
+
return normalizeDecodedSession(decoded, bounds, {
|
|
3106
|
+
partial: isPartialTranscript(input),
|
|
3107
|
+
filters
|
|
3108
|
+
});
|
|
3109
|
+
}
|
|
3110
|
+
function normalizeToCanonical(input) {
|
|
3111
|
+
const { decoded, bounds, filters } = decodeTranscript(input);
|
|
3112
|
+
const baseByteOffset = input.sourceContext?.baseByteOffset ?? 0;
|
|
3113
|
+
const partial = isPartialTranscript(input);
|
|
3114
|
+
const internal = normalizeDecodedSessionInternal(decoded, bounds, {
|
|
3115
|
+
partial,
|
|
3116
|
+
filters
|
|
3117
|
+
});
|
|
3118
|
+
const groupId = resolveGroupId2(input.source, internal.context.sourceGroupId, input.sourceContext?.groupId, internal.context.sourceGroupAmbiguous ?? false, internal.context.sourceGroupRequired ?? false);
|
|
3119
|
+
return finalizeCanonical(internal, bounds, {
|
|
3120
|
+
groupId,
|
|
3121
|
+
baseByteOffset,
|
|
3122
|
+
emitMeta: baseByteOffset === 0
|
|
3123
|
+
});
|
|
3124
|
+
}
|
|
3125
|
+
function isPartialTranscript(input) {
|
|
3126
|
+
return (input.sourceContext?.partial ?? false) || (input.sourceContext?.baseByteOffset ?? 0) > 0;
|
|
3127
|
+
}
|
|
3128
|
+
function resolveGroupId2(source, detected, provided, ambiguous, required) {
|
|
3129
|
+
if (ambiguous && !provided) {
|
|
3130
|
+
throw new NormalizationError("source_group_required", `Canonical ${source} normalization found multiple source groups; pass sourceContext.groupId.`);
|
|
3131
|
+
}
|
|
3132
|
+
if (required && !provided) {
|
|
3133
|
+
throw new NormalizationError("source_group_required", `Canonical ${source} normalization has no source group; pass sourceContext.groupId.`);
|
|
3134
|
+
}
|
|
3135
|
+
if (detected && provided && detected !== provided) {
|
|
3136
|
+
throw new NormalizationError("source_group_conflict", `Detected source group ${JSON.stringify(detected)} conflicts with the provided source context group ${JSON.stringify(provided)}.`);
|
|
3137
|
+
}
|
|
3138
|
+
const resolved = detected || provided;
|
|
3139
|
+
if ((source === "codex" || source === "cursor") && !resolved) {
|
|
3140
|
+
const sourceLabel = source === "codex" ? "Codex" : "Cursor";
|
|
3141
|
+
const discoveryHint = source === "codex" ? "include session_meta or " : "";
|
|
3142
|
+
throw new NormalizationError("source_group_required", `Canonical ${sourceLabel} normalization requires a source group: ` + `${discoveryHint}pass sourceContext.groupId.`);
|
|
3143
|
+
}
|
|
3144
|
+
return resolved || GROUP_SENTINEL;
|
|
3145
|
+
}
|
|
3146
|
+
export {
|
|
3147
|
+
NormalizationError,
|
|
3148
|
+
normalizeToCanonical,
|
|
3149
|
+
normalizeTranscript
|
|
3150
|
+
};
|