@freesyntax/notch-cli 0.5.20 → 0.5.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-443G6HCC.js +543 -0
- package/dist/chunk-GFVLHUSS.js +155 -0
- package/dist/chunk-MMBFNIKE.js +509 -0
- package/dist/chunk-OSWUX6TC.js +167 -0
- package/dist/{chunk-6M6CXXWR.js → chunk-PKZKVOAN.js} +209 -1
- package/dist/chunk-QKM27RHS.js +198 -0
- package/dist/{chunk-YBYF7L4A.js → chunk-TU465P2P.js} +1830 -1331
- package/dist/compression-SQAIQ2UU.js +32 -0
- package/dist/index.js +2346 -822
- package/dist/ollama-bench-QQHBIG2D.js +190 -0
- package/dist/ollama-launch-2ASVER3S.js +18 -0
- package/dist/ollama-usage-2WPCZJJI.js +69 -0
- package/dist/{server-W7FRCVRZ.js → server-7UQKCB2Z.js} +1 -1
- package/dist/session-index-SSGOOZXK.js +21 -0
- package/dist/{tools-Q7CDHB4K.js → tools-7WAWS6V4.js} +3 -1
- package/package.json +2 -1
- package/dist/compression-UTB2Y4BB.js +0 -16
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/agent/compression.ts
|
|
2
2
|
import { generateText } from "ai";
|
|
3
|
+
import { createHash } from "crypto";
|
|
3
4
|
function estimateTokens(messages) {
|
|
4
5
|
let chars = 0;
|
|
5
6
|
for (const msg of messages) {
|
|
@@ -15,6 +16,112 @@ function estimateTokens(messages) {
|
|
|
15
16
|
}
|
|
16
17
|
return Math.ceil(chars / 4);
|
|
17
18
|
}
|
|
19
|
+
var InMemoryArtifactStore = class {
|
|
20
|
+
map = /* @__PURE__ */ new Map();
|
|
21
|
+
put(key, value) {
|
|
22
|
+
this.map.set(key, value);
|
|
23
|
+
}
|
|
24
|
+
get(key) {
|
|
25
|
+
return this.map.get(key);
|
|
26
|
+
}
|
|
27
|
+
has(key) {
|
|
28
|
+
return this.map.has(key);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var globalArtifactStore = new InMemoryArtifactStore();
|
|
32
|
+
function setArtifactStore(store) {
|
|
33
|
+
const prev = globalArtifactStore;
|
|
34
|
+
globalArtifactStore = store;
|
|
35
|
+
return () => {
|
|
36
|
+
globalArtifactStore = prev;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function getArtifactStore() {
|
|
40
|
+
return globalArtifactStore;
|
|
41
|
+
}
|
|
42
|
+
var ARTIFACT_URI_PREFIX = "notch-artifact://";
|
|
43
|
+
function artifactKey(content) {
|
|
44
|
+
return createHash("sha1").update(content).digest("hex").slice(0, 16);
|
|
45
|
+
}
|
|
46
|
+
function makeArtifactUri(key) {
|
|
47
|
+
return `${ARTIFACT_URI_PREFIX}${key}`;
|
|
48
|
+
}
|
|
49
|
+
function parseArtifactUri(text) {
|
|
50
|
+
const match = text.match(/notch-artifact:\/\/([a-f0-9]{8,64})/);
|
|
51
|
+
return match ? match[1] : null;
|
|
52
|
+
}
|
|
53
|
+
var BUDGET_TOOL_RESULT_MAX = 3e3;
|
|
54
|
+
var BUDGET_PREVIEW_CHARS = 400;
|
|
55
|
+
function budgetReduce(messages, opts = {}) {
|
|
56
|
+
const maxChars = opts.maxToolResultChars ?? BUDGET_TOOL_RESULT_MAX;
|
|
57
|
+
const previewChars = opts.previewChars ?? BUDGET_PREVIEW_CHARS;
|
|
58
|
+
const keepLastN = opts.keepLastN ?? 4;
|
|
59
|
+
const store = opts.store ?? globalArtifactStore;
|
|
60
|
+
const toolIdx = [];
|
|
61
|
+
for (let i = 0; i < messages.length; i++) {
|
|
62
|
+
if (messages[i].role === "tool") toolIdx.push(i);
|
|
63
|
+
}
|
|
64
|
+
const eligibleUpTo = toolIdx.length - keepLastN;
|
|
65
|
+
if (eligibleUpTo <= 0) return { messages, stashed: 0, savedChars: 0 };
|
|
66
|
+
const eligible = new Set(toolIdx.slice(0, eligibleUpTo));
|
|
67
|
+
let stashed = 0;
|
|
68
|
+
let savedChars = 0;
|
|
69
|
+
const out = messages.map((msg, idx) => {
|
|
70
|
+
if (msg.role !== "tool" || !eligible.has(idx)) return msg;
|
|
71
|
+
if (!Array.isArray(msg.content)) return msg;
|
|
72
|
+
let touched = false;
|
|
73
|
+
const newContent = msg.content.map((block) => {
|
|
74
|
+
const b = block;
|
|
75
|
+
if (b.type !== "tool-result") return block;
|
|
76
|
+
const resultStr = typeof b.result === "string" ? b.result : JSON.stringify(b.result ?? "");
|
|
77
|
+
if (resultStr.length <= maxChars) return block;
|
|
78
|
+
const key = artifactKey(resultStr);
|
|
79
|
+
try {
|
|
80
|
+
void store.put(key, resultStr);
|
|
81
|
+
} catch {
|
|
82
|
+
return block;
|
|
83
|
+
}
|
|
84
|
+
const preview = resultStr.slice(0, previewChars);
|
|
85
|
+
const replacement = `${preview}
|
|
86
|
+
... [+${resultStr.length - previewChars} chars stashed at ${makeArtifactUri(key)}]`;
|
|
87
|
+
savedChars += resultStr.length - replacement.length;
|
|
88
|
+
stashed++;
|
|
89
|
+
touched = true;
|
|
90
|
+
return {
|
|
91
|
+
...b,
|
|
92
|
+
result: replacement
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
if (!touched) return msg;
|
|
96
|
+
return { ...msg, content: newContent };
|
|
97
|
+
});
|
|
98
|
+
return { messages: out, stashed, savedChars };
|
|
99
|
+
}
|
|
100
|
+
function snip(messages, opts = {}) {
|
|
101
|
+
const keepStart = opts.keepStart ?? 1;
|
|
102
|
+
const keepRecent = opts.keepRecent ?? 6;
|
|
103
|
+
const trigger = opts.triggerMiddleCount ?? 40;
|
|
104
|
+
const snipCount = opts.snipCount ?? 10;
|
|
105
|
+
if (messages.length < keepStart + keepRecent + trigger) {
|
|
106
|
+
return { messages, snipped: 0 };
|
|
107
|
+
}
|
|
108
|
+
const head = messages.slice(0, keepStart);
|
|
109
|
+
const tail = messages.slice(-keepRecent);
|
|
110
|
+
const middle = messages.slice(keepStart, messages.length - keepRecent);
|
|
111
|
+
let cut = Math.min(snipCount, middle.length);
|
|
112
|
+
while (cut < middle.length && middle[cut].role === "tool") cut++;
|
|
113
|
+
const dropped = middle.slice(0, cut);
|
|
114
|
+
const kept = middle.slice(cut);
|
|
115
|
+
if (dropped.length === 0) return { messages, snipped: 0 };
|
|
116
|
+
const marker = {
|
|
117
|
+
role: "user",
|
|
118
|
+
content: `[snip: ${dropped.length} older messages removed by age]`
|
|
119
|
+
};
|
|
120
|
+
return {
|
|
121
|
+
messages: [...head, marker, ...kept, ...tail],
|
|
122
|
+
snipped: dropped.length
|
|
123
|
+
};
|
|
124
|
+
}
|
|
18
125
|
var TEXT_BLOCK_MAX = 8e3;
|
|
19
126
|
function microCompact(messages) {
|
|
20
127
|
const result = [];
|
|
@@ -35,6 +142,48 @@ function microCompact(messages) {
|
|
|
35
142
|
}
|
|
36
143
|
return result;
|
|
37
144
|
}
|
|
145
|
+
function contextCollapse(messages, opts = {}) {
|
|
146
|
+
const keepStart = opts.keepStart ?? 1;
|
|
147
|
+
const keepRecent = opts.keepRecent ?? 4;
|
|
148
|
+
const trigger = opts.triggerMiddleCount ?? 12;
|
|
149
|
+
const store = opts.store ?? globalArtifactStore;
|
|
150
|
+
if (messages.length < keepStart + keepRecent + trigger) {
|
|
151
|
+
return { messages, collapsed: false };
|
|
152
|
+
}
|
|
153
|
+
const head = messages.slice(0, keepStart);
|
|
154
|
+
const middle = messages.slice(keepStart, messages.length - keepRecent);
|
|
155
|
+
const tail = messages.slice(-keepRecent);
|
|
156
|
+
if (middle.length === 0) return { messages, collapsed: false };
|
|
157
|
+
let key;
|
|
158
|
+
try {
|
|
159
|
+
const serialized = JSON.stringify(middle);
|
|
160
|
+
key = artifactKey(serialized);
|
|
161
|
+
void store.put(key, serialized);
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
const summaryText = buildDeterministicSummary(middle);
|
|
165
|
+
const ref = key ? ` (originals at ${makeArtifactUri(key)})` : "";
|
|
166
|
+
const summaryMarker = {
|
|
167
|
+
role: "user",
|
|
168
|
+
content: `[Context collapsed \u2014 ${middle.length} messages summarized${ref}]
|
|
169
|
+
${summaryText}`
|
|
170
|
+
};
|
|
171
|
+
return {
|
|
172
|
+
messages: [...head, summaryMarker, ...tail],
|
|
173
|
+
collapsed: true,
|
|
174
|
+
artifactKey: key
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
async function restoreCollapsedSpan(artifactKeyOrUri, store = globalArtifactStore) {
|
|
178
|
+
const key = artifactKeyOrUri.startsWith(ARTIFACT_URI_PREFIX) ? artifactKeyOrUri.slice(ARTIFACT_URI_PREFIX.length) : artifactKeyOrUri;
|
|
179
|
+
const raw = await store.get(key);
|
|
180
|
+
if (!raw) return null;
|
|
181
|
+
try {
|
|
182
|
+
return JSON.parse(raw);
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
38
187
|
var RESERVE_BUFFER_TOKENS = 13e3;
|
|
39
188
|
var MAX_SUMMARY_TOKENS = 2e4;
|
|
40
189
|
var MAX_COMPRESSION_FAILURES = 3;
|
|
@@ -180,10 +329,19 @@ ${firstContent}`
|
|
|
180
329
|
return { messages: compressed, compressed: true };
|
|
181
330
|
}
|
|
182
331
|
async function autoCompress(messages, model, contextWindow, onCompress) {
|
|
183
|
-
let result = microCompact(messages);
|
|
184
332
|
const threshold = (contextWindow - RESERVE_BUFFER_TOKENS) * 0.75;
|
|
333
|
+
let result = budgetReduce(messages).messages;
|
|
334
|
+
result = snip(result).messages;
|
|
335
|
+
result = microCompact(result);
|
|
185
336
|
let tokens = estimateTokens(result);
|
|
186
337
|
if (tokens < threshold) return result;
|
|
338
|
+
const collapsed = contextCollapse(result);
|
|
339
|
+
if (collapsed.collapsed) {
|
|
340
|
+
onCompress?.();
|
|
341
|
+
result = collapsed.messages;
|
|
342
|
+
tokens = estimateTokens(result);
|
|
343
|
+
}
|
|
344
|
+
if (tokens < threshold) return result;
|
|
187
345
|
const auto = await autoCompactSummarize(result, { model, contextWindow });
|
|
188
346
|
if (auto.compressed) {
|
|
189
347
|
onCompress?.();
|
|
@@ -198,6 +356,48 @@ async function autoCompress(messages, model, contextWindow, onCompress) {
|
|
|
198
356
|
}
|
|
199
357
|
return result;
|
|
200
358
|
}
|
|
359
|
+
async function autoCompressWithStats(messages, model, contextWindow) {
|
|
360
|
+
const stats = {
|
|
361
|
+
budgetStashed: 0,
|
|
362
|
+
snipped: 0,
|
|
363
|
+
collapsed: false,
|
|
364
|
+
autoCompacted: false,
|
|
365
|
+
fullCompacted: false
|
|
366
|
+
};
|
|
367
|
+
const threshold = (contextWindow - RESERVE_BUFFER_TOKENS) * 0.75;
|
|
368
|
+
const br = budgetReduce(messages);
|
|
369
|
+
let result = br.messages;
|
|
370
|
+
stats.budgetStashed = br.stashed;
|
|
371
|
+
const sn = snip(result);
|
|
372
|
+
result = sn.messages;
|
|
373
|
+
stats.snipped = sn.snipped;
|
|
374
|
+
result = microCompact(result);
|
|
375
|
+
let tokens = estimateTokens(result);
|
|
376
|
+
if (tokens >= threshold) {
|
|
377
|
+
const collapsed = contextCollapse(result);
|
|
378
|
+
if (collapsed.collapsed) {
|
|
379
|
+
result = collapsed.messages;
|
|
380
|
+
stats.collapsed = true;
|
|
381
|
+
tokens = estimateTokens(result);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (tokens >= threshold) {
|
|
385
|
+
const auto = await autoCompactSummarize(result, { model, contextWindow });
|
|
386
|
+
if (auto.compressed) {
|
|
387
|
+
result = auto.messages;
|
|
388
|
+
stats.autoCompacted = true;
|
|
389
|
+
tokens = estimateTokens(result);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
if (tokens >= threshold) {
|
|
393
|
+
const full = await fullCompact(result, model);
|
|
394
|
+
if (full.compressed) {
|
|
395
|
+
result = full.messages;
|
|
396
|
+
stats.fullCompacted = true;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return { messages: result, stats };
|
|
400
|
+
}
|
|
201
401
|
async function compressHistory(messages, opts) {
|
|
202
402
|
const result = await autoCompactSummarize(messages, opts);
|
|
203
403
|
return result;
|
|
@@ -205,9 +405,17 @@ async function compressHistory(messages, opts) {
|
|
|
205
405
|
|
|
206
406
|
export {
|
|
207
407
|
estimateTokens,
|
|
408
|
+
setArtifactStore,
|
|
409
|
+
getArtifactStore,
|
|
410
|
+
parseArtifactUri,
|
|
411
|
+
budgetReduce,
|
|
412
|
+
snip,
|
|
208
413
|
microCompact,
|
|
414
|
+
contextCollapse,
|
|
415
|
+
restoreCollapsedSpan,
|
|
209
416
|
autoCompactSummarize,
|
|
210
417
|
fullCompact,
|
|
211
418
|
autoCompress,
|
|
419
|
+
autoCompressWithStats,
|
|
212
420
|
compressHistory
|
|
213
421
|
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// src/session/rollout.ts
|
|
2
|
+
import fsp from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import os from "os";
|
|
5
|
+
import crypto from "crypto";
|
|
6
|
+
var ROLLOUT_DIR = path.join(os.homedir(), ".notch", "rollouts");
|
|
7
|
+
async function ensureDir() {
|
|
8
|
+
await fsp.mkdir(ROLLOUT_DIR, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
function rolloutPath(id) {
|
|
11
|
+
return path.join(ROLLOUT_DIR, `${id}.jsonl`);
|
|
12
|
+
}
|
|
13
|
+
function indexPath(id) {
|
|
14
|
+
return path.join(ROLLOUT_DIR, `${id}.idx.json`);
|
|
15
|
+
}
|
|
16
|
+
function generateSessionId() {
|
|
17
|
+
const d = /* @__PURE__ */ new Date();
|
|
18
|
+
const stamp = d.toISOString().slice(0, 10).replace(/-/g, "") + "-" + d.toISOString().slice(11, 16).replace(":", "");
|
|
19
|
+
const rand = crypto.randomBytes(3).toString("hex");
|
|
20
|
+
return `${stamp}-${rand}`;
|
|
21
|
+
}
|
|
22
|
+
var Rollout = class {
|
|
23
|
+
constructor(id) {
|
|
24
|
+
this.id = id;
|
|
25
|
+
}
|
|
26
|
+
id;
|
|
27
|
+
fd = null;
|
|
28
|
+
seq = 0;
|
|
29
|
+
idx = {
|
|
30
|
+
lastSeq: -1,
|
|
31
|
+
messageCount: 0,
|
|
32
|
+
branches: {},
|
|
33
|
+
activeStream: null
|
|
34
|
+
};
|
|
35
|
+
async openNew(header) {
|
|
36
|
+
await ensureDir();
|
|
37
|
+
this.fd = await fsp.open(rolloutPath(this.id), "a");
|
|
38
|
+
await this.writeRecord({
|
|
39
|
+
type: "header",
|
|
40
|
+
payload: { id: this.id, project: header.project, model: header.model, createdAt: (/* @__PURE__ */ new Date()).toISOString(), schema: 1 }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async openExisting() {
|
|
44
|
+
await ensureDir();
|
|
45
|
+
this.idx = await readIndex(this.id);
|
|
46
|
+
this.seq = this.idx.lastSeq + 1;
|
|
47
|
+
this.fd = await fsp.open(rolloutPath(this.id), "a");
|
|
48
|
+
}
|
|
49
|
+
async close() {
|
|
50
|
+
await this.saveIndex();
|
|
51
|
+
if (this.fd) {
|
|
52
|
+
await this.fd.close();
|
|
53
|
+
this.fd = null;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
const { upsertSessionIndexEntry } = await import("./session-index-SSGOOZXK.js");
|
|
57
|
+
await upsertSessionIndexEntry(this.id);
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async writeRecord(partial) {
|
|
62
|
+
if (!this.fd) throw new Error("rollout not open");
|
|
63
|
+
const rec = { seq: this.seq++, ts: Date.now(), ...partial };
|
|
64
|
+
const line = JSON.stringify(rec) + "\n";
|
|
65
|
+
await this.fd.write(line);
|
|
66
|
+
this.idx.lastSeq = rec.seq;
|
|
67
|
+
if (rec.type === "user-message" || rec.type === "assistant-message") {
|
|
68
|
+
this.idx.messageCount++;
|
|
69
|
+
if (rec.parent && rec.msgId) {
|
|
70
|
+
(this.idx.branches[rec.parent] ??= []).push(rec.msgId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (rec.type === "active-stream") {
|
|
74
|
+
this.idx.activeStream = rec.streamId ?? null;
|
|
75
|
+
} else if (rec.type === "turn-end" || rec.type === "error") {
|
|
76
|
+
this.idx.activeStream = null;
|
|
77
|
+
}
|
|
78
|
+
return rec;
|
|
79
|
+
}
|
|
80
|
+
append(record) {
|
|
81
|
+
return this.writeRecord(record);
|
|
82
|
+
}
|
|
83
|
+
async flush() {
|
|
84
|
+
if (this.fd) await this.fd.sync();
|
|
85
|
+
await this.saveIndex();
|
|
86
|
+
}
|
|
87
|
+
async saveIndex() {
|
|
88
|
+
await fsp.writeFile(indexPath(this.id), JSON.stringify(this.idx, null, 2));
|
|
89
|
+
}
|
|
90
|
+
get activeStream() {
|
|
91
|
+
return this.idx.activeStream;
|
|
92
|
+
}
|
|
93
|
+
get index() {
|
|
94
|
+
return this.idx;
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
async function readRollout(id) {
|
|
98
|
+
const raw = await fsp.readFile(rolloutPath(id), "utf-8");
|
|
99
|
+
const out = [];
|
|
100
|
+
for (const line of raw.split("\n")) {
|
|
101
|
+
if (!line.trim()) continue;
|
|
102
|
+
try {
|
|
103
|
+
out.push(JSON.parse(line));
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
async function readIndex(id) {
|
|
110
|
+
try {
|
|
111
|
+
const raw = await fsp.readFile(indexPath(id), "utf-8");
|
|
112
|
+
return JSON.parse(raw);
|
|
113
|
+
} catch {
|
|
114
|
+
const records = await readRollout(id);
|
|
115
|
+
const idx = { lastSeq: -1, messageCount: 0, branches: {}, activeStream: null };
|
|
116
|
+
for (const r of records) {
|
|
117
|
+
idx.lastSeq = r.seq;
|
|
118
|
+
if (r.type === "user-message" || r.type === "assistant-message") {
|
|
119
|
+
idx.messageCount++;
|
|
120
|
+
if (r.parent && r.msgId) (idx.branches[r.parent] ??= []).push(r.msgId);
|
|
121
|
+
}
|
|
122
|
+
if (r.type === "active-stream") idx.activeStream = r.streamId ?? null;
|
|
123
|
+
else if (r.type === "turn-end" || r.type === "error") idx.activeStream = null;
|
|
124
|
+
}
|
|
125
|
+
await fsp.writeFile(indexPath(id), JSON.stringify(idx, null, 2)).catch(() => {
|
|
126
|
+
});
|
|
127
|
+
return idx;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function listRollouts() {
|
|
131
|
+
try {
|
|
132
|
+
const entries = await fsp.readdir(ROLLOUT_DIR);
|
|
133
|
+
const files = entries.filter((e) => e.endsWith(".jsonl"));
|
|
134
|
+
const out = [];
|
|
135
|
+
for (const f of files) {
|
|
136
|
+
const id = f.replace(/\.jsonl$/, "");
|
|
137
|
+
const stat = await fsp.stat(path.join(ROLLOUT_DIR, f));
|
|
138
|
+
const idx = await readIndex(id).catch(() => ({ messageCount: 0 }));
|
|
139
|
+
let project;
|
|
140
|
+
let model;
|
|
141
|
+
try {
|
|
142
|
+
const first = (await fsp.readFile(path.join(ROLLOUT_DIR, f), "utf-8")).split("\n", 1)[0];
|
|
143
|
+
if (first) {
|
|
144
|
+
const header = JSON.parse(first);
|
|
145
|
+
project = header.payload?.project;
|
|
146
|
+
model = header.payload?.model;
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
out.push({ id, updated: stat.mtimeMs, messageCount: idx.messageCount, project, model });
|
|
151
|
+
}
|
|
152
|
+
return out.sort((a, b) => b.updated - a.updated);
|
|
153
|
+
} catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function rebuildMessagesFromRollout(records) {
|
|
158
|
+
const msgs = [];
|
|
159
|
+
let current = null;
|
|
160
|
+
for (const r of records) {
|
|
161
|
+
if (r.type === "user-message") {
|
|
162
|
+
if (current) {
|
|
163
|
+
msgs.push(current);
|
|
164
|
+
current = null;
|
|
165
|
+
}
|
|
166
|
+
msgs.push({ role: "user", content: r.payload?.content ?? "" });
|
|
167
|
+
} else if (r.type === "text-delta") {
|
|
168
|
+
const delta = r.payload?.content ?? "";
|
|
169
|
+
if (!current) current = { role: "assistant", content: "" };
|
|
170
|
+
current.content += delta;
|
|
171
|
+
} else if (r.type === "assistant-message") {
|
|
172
|
+
if (current) {
|
|
173
|
+
msgs.push(current);
|
|
174
|
+
current = null;
|
|
175
|
+
}
|
|
176
|
+
msgs.push({ role: "assistant", content: r.payload?.content ?? "" });
|
|
177
|
+
} else if (r.type === "turn-end" && current) {
|
|
178
|
+
msgs.push(current);
|
|
179
|
+
current = null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (current) msgs.push(current);
|
|
183
|
+
return msgs;
|
|
184
|
+
}
|
|
185
|
+
function hasActiveStream(idx) {
|
|
186
|
+
return !!idx.activeStream;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
rolloutPath,
|
|
191
|
+
generateSessionId,
|
|
192
|
+
Rollout,
|
|
193
|
+
readRollout,
|
|
194
|
+
readIndex,
|
|
195
|
+
listRollouts,
|
|
196
|
+
rebuildMessagesFromRollout,
|
|
197
|
+
hasActiveStream
|
|
198
|
+
};
|