@pasko70/pibo 3.1.0 → 3.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.
|
@@ -3,6 +3,7 @@ const RENDER_SEQUENCE_SLOTS_PER_MILLISECOND = 1_000;
|
|
|
3
3
|
const MAX_TRACKED_SESSIONS = 1_024;
|
|
4
4
|
const MAX_RECENT_SEGMENTS_PER_SESSION = 1_024;
|
|
5
5
|
const MAX_RECENT_TOOL_INVOCATIONS_PER_SESSION = 1_024;
|
|
6
|
+
const MAX_RECENT_OUTPUT_PARTS_PER_SESSION = 1_024;
|
|
6
7
|
export function outputRenderHighWaterStore(value) {
|
|
7
8
|
if (!value || typeof value !== "object")
|
|
8
9
|
return undefined;
|
|
@@ -32,7 +33,8 @@ export class OutputRenderSequencer {
|
|
|
32
33
|
position(event) {
|
|
33
34
|
const state = this.sessionState(event.piboSessionId);
|
|
34
35
|
this.trackActiveTurn(state, event);
|
|
35
|
-
const
|
|
36
|
+
const eventWithPartIdentity = this.positionOutputPart(state, event);
|
|
37
|
+
const eventWithToolIdentity = this.positionToolInvocation(state, eventWithPartIdentity);
|
|
36
38
|
const key = outputRenderSegmentKey(eventWithToolIdentity, state.activeEventId);
|
|
37
39
|
const supplied = validRenderSequence(eventWithToolIdentity.renderSequence)
|
|
38
40
|
? eventWithToolIdentity.renderSequence
|
|
@@ -90,11 +92,61 @@ export class OutputRenderSequencer {
|
|
|
90
92
|
activeSegments: new Set(),
|
|
91
93
|
completedSegments: new Set(),
|
|
92
94
|
toolInvocations: new Map(),
|
|
95
|
+
outputParts: new Map(),
|
|
93
96
|
lastSequence: 0,
|
|
94
97
|
};
|
|
95
98
|
this.sessions.set(piboSessionId, state);
|
|
96
99
|
return state;
|
|
97
100
|
}
|
|
101
|
+
positionOutputPart(state, event) {
|
|
102
|
+
const transition = outputPartTransition(event, state.activeEventId);
|
|
103
|
+
if (!transition)
|
|
104
|
+
return event;
|
|
105
|
+
const key = outputPartCounterKey(transition.eventId, transition.kind);
|
|
106
|
+
const parts = state.outputParts.get(key) ?? [];
|
|
107
|
+
if (!state.outputParts.has(key))
|
|
108
|
+
state.outputParts.set(key, parts);
|
|
109
|
+
const exact = parts.find((part) => part.fingerprints.has(transition.fingerprint));
|
|
110
|
+
const latestOpen = [...parts].reverse().find((part) => !part.closed);
|
|
111
|
+
const localMaximum = parts.reduce((maximum, part) => Math.max(maximum, part.index), -1);
|
|
112
|
+
const localIndex = exact?.index
|
|
113
|
+
?? latestOpen?.index
|
|
114
|
+
?? (transition.proposedIndex > localMaximum ? transition.proposedIndex : localMaximum + 1);
|
|
115
|
+
const index = validRenderSequence(event.renderSequence) || exact || latestOpen
|
|
116
|
+
? localIndex
|
|
117
|
+
: this.highWaterStore?.claimOrAttachOutputPart?.({ ...transition, proposedIndex: localIndex }) ?? localIndex;
|
|
118
|
+
let part = parts.find((candidate) => candidate.index === index);
|
|
119
|
+
if (!part) {
|
|
120
|
+
part = { index, fingerprints: new Set(), closed: false };
|
|
121
|
+
parts.push(part);
|
|
122
|
+
}
|
|
123
|
+
part.fingerprints.add(transition.fingerprint);
|
|
124
|
+
if (transition.terminal)
|
|
125
|
+
part.closed = true;
|
|
126
|
+
this.trimOutputParts(state);
|
|
127
|
+
return withOutputPartIndex(event, transition.kind, index);
|
|
128
|
+
}
|
|
129
|
+
trimOutputParts(state) {
|
|
130
|
+
let total = 0;
|
|
131
|
+
for (const parts of state.outputParts.values())
|
|
132
|
+
total += parts.length;
|
|
133
|
+
while (total > MAX_RECENT_OUTPUT_PARTS_PER_SESSION) {
|
|
134
|
+
let removed = false;
|
|
135
|
+
for (const [key, parts] of state.outputParts) {
|
|
136
|
+
const closedIndex = parts.findIndex((part) => part.closed);
|
|
137
|
+
if (closedIndex === -1)
|
|
138
|
+
continue;
|
|
139
|
+
parts.splice(closedIndex, 1);
|
|
140
|
+
total -= 1;
|
|
141
|
+
if (!parts.length)
|
|
142
|
+
state.outputParts.delete(key);
|
|
143
|
+
removed = true;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
if (!removed)
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
98
150
|
positionToolInvocation(state, event) {
|
|
99
151
|
if (!isToolIdentityEvent(event) || !event.toolCallId)
|
|
100
152
|
return event;
|
|
@@ -130,7 +182,7 @@ export class OutputRenderSequencer {
|
|
|
130
182
|
if (!latest) {
|
|
131
183
|
invocation = this.createToolInvocation(invocations, event.piboSessionId, eventId, event.toolCallId, transition);
|
|
132
184
|
}
|
|
133
|
-
else if (event.type === "tool_call" && (latest
|
|
185
|
+
else if (event.type === "tool_call" && toolCallStartsNewInvocation(latest, transition?.callFingerprint)) {
|
|
134
186
|
invocation = this.createToolInvocation(invocations, event.piboSessionId, eventId, event.toolCallId, transition);
|
|
135
187
|
}
|
|
136
188
|
else if (event.type === "tool_execution_started" && latest.closed && latest.seen.has("tool_execution_started")) {
|
|
@@ -143,6 +195,8 @@ export class OutputRenderSequencer {
|
|
|
143
195
|
}
|
|
144
196
|
}
|
|
145
197
|
invocation.seen.add(event.type);
|
|
198
|
+
if (event.type === "tool_call" && transition?.callFingerprint)
|
|
199
|
+
invocation.callFingerprint = transition.callFingerprint;
|
|
146
200
|
if (event.type === "tool_execution_finished")
|
|
147
201
|
invocation.closed = true;
|
|
148
202
|
this.trimToolInvocations(state);
|
|
@@ -243,6 +297,110 @@ function createInvocation(invocations, ordinal) {
|
|
|
243
297
|
invocations.push(invocation);
|
|
244
298
|
return invocation;
|
|
245
299
|
}
|
|
300
|
+
function toolCallStartsNewInvocation(invocation, callFingerprint) {
|
|
301
|
+
if (!invocation.seen.has("tool_call"))
|
|
302
|
+
return invocation.closed && invocation.persistedIdentity;
|
|
303
|
+
if (invocation.closed)
|
|
304
|
+
return true;
|
|
305
|
+
if (invocation.callFingerprint === undefined)
|
|
306
|
+
return false;
|
|
307
|
+
return callFingerprint === undefined || invocation.callFingerprint !== callFingerprint;
|
|
308
|
+
}
|
|
309
|
+
function outputPartTransition(event, activeEventId) {
|
|
310
|
+
const eventId = ("eventId" in event ? event.eventId : undefined) ?? activeEventId;
|
|
311
|
+
if (!eventId)
|
|
312
|
+
return undefined;
|
|
313
|
+
if (event.type === "assistant_delta" || event.type === "assistant_message") {
|
|
314
|
+
return {
|
|
315
|
+
piboSessionId: event.piboSessionId,
|
|
316
|
+
eventId,
|
|
317
|
+
kind: "assistant",
|
|
318
|
+
proposedIndex: event.assistantIndex ?? event.contentIndex ?? 0,
|
|
319
|
+
fingerprint: outputPartFingerprint(event),
|
|
320
|
+
identityFingerprint: outputIdentityFingerprint(event),
|
|
321
|
+
terminal: event.type === "assistant_message",
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (event.type === "thinking_started" || event.type === "thinking_delta" || event.type === "thinking_finished") {
|
|
325
|
+
return {
|
|
326
|
+
piboSessionId: event.piboSessionId,
|
|
327
|
+
eventId,
|
|
328
|
+
kind: "thinking",
|
|
329
|
+
proposedIndex: event.thinkingIndex ?? event.contentIndex ?? 0,
|
|
330
|
+
fingerprint: outputPartFingerprint(event),
|
|
331
|
+
identityFingerprint: outputIdentityFingerprint(event),
|
|
332
|
+
terminal: event.type === "thinking_finished",
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
if (event.type === "assistant_usage") {
|
|
336
|
+
return {
|
|
337
|
+
piboSessionId: event.piboSessionId,
|
|
338
|
+
eventId,
|
|
339
|
+
kind: "usage",
|
|
340
|
+
proposedIndex: event.usageIndex ?? 0,
|
|
341
|
+
fingerprint: outputPartFingerprint(event),
|
|
342
|
+
identityFingerprint: outputIdentityFingerprint(event),
|
|
343
|
+
terminal: true,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
if (event.type === "compaction_start" || event.type === "compaction_end") {
|
|
347
|
+
return {
|
|
348
|
+
piboSessionId: event.piboSessionId,
|
|
349
|
+
eventId,
|
|
350
|
+
kind: "compaction",
|
|
351
|
+
proposedIndex: event.compactionIndex ?? 0,
|
|
352
|
+
fingerprint: outputPartFingerprint(event),
|
|
353
|
+
identityFingerprint: outputIdentityFingerprint(event),
|
|
354
|
+
terminal: event.type === "compaction_end",
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
export function outputIdentityFingerprint(event) {
|
|
360
|
+
const payload = { ...event };
|
|
361
|
+
delete payload.renderSequence;
|
|
362
|
+
return createHash("sha256").update(stableJson(payload)).digest("hex");
|
|
363
|
+
}
|
|
364
|
+
export function outputPartFingerprint(event) {
|
|
365
|
+
const payload = { ...event };
|
|
366
|
+
delete payload.renderSequence;
|
|
367
|
+
delete payload.assistantIndex;
|
|
368
|
+
delete payload.thinkingIndex;
|
|
369
|
+
delete payload.usageIndex;
|
|
370
|
+
delete payload.compactionIndex;
|
|
371
|
+
delete payload.contentIndex;
|
|
372
|
+
return createHash("sha256").update(stableJson(payload)).digest("hex");
|
|
373
|
+
}
|
|
374
|
+
function stableJson(value) {
|
|
375
|
+
if (Array.isArray(value))
|
|
376
|
+
return `[${value.map(stableJson).join(",")}]`;
|
|
377
|
+
if (value && typeof value === "object") {
|
|
378
|
+
return `{${Object.entries(value)
|
|
379
|
+
.filter(([, entry]) => entry !== undefined)
|
|
380
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
381
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
|
|
382
|
+
.join(",")}}`;
|
|
383
|
+
}
|
|
384
|
+
return JSON.stringify(value) ?? "null";
|
|
385
|
+
}
|
|
386
|
+
function outputPartCounterKey(eventId, kind) {
|
|
387
|
+
return JSON.stringify([eventId, kind]);
|
|
388
|
+
}
|
|
389
|
+
function withOutputPartIndex(event, kind, index) {
|
|
390
|
+
if (kind === "assistant" && (event.type === "assistant_delta" || event.type === "assistant_message")) {
|
|
391
|
+
return event.assistantIndex === index ? event : { ...event, assistantIndex: index };
|
|
392
|
+
}
|
|
393
|
+
if (kind === "thinking" && (event.type === "thinking_started" || event.type === "thinking_delta" || event.type === "thinking_finished")) {
|
|
394
|
+
return event.thinkingIndex === index ? event : { ...event, thinkingIndex: index };
|
|
395
|
+
}
|
|
396
|
+
if (kind === "usage" && event.type === "assistant_usage") {
|
|
397
|
+
return event.usageIndex === index ? event : { ...event, usageIndex: index };
|
|
398
|
+
}
|
|
399
|
+
if (kind === "compaction" && (event.type === "compaction_start" || event.type === "compaction_end")) {
|
|
400
|
+
return event.compactionIndex === index ? event : { ...event, compactionIndex: index };
|
|
401
|
+
}
|
|
402
|
+
return event;
|
|
403
|
+
}
|
|
246
404
|
function segmentRemainsActive(event) {
|
|
247
405
|
return event.type === "message_started"
|
|
248
406
|
|| event.type === "assistant_delta"
|
|
@@ -278,6 +436,8 @@ function toolInvocationCounterKey(eventId, toolCallId) {
|
|
|
278
436
|
return JSON.stringify([eventId ?? "unscoped", toolCallId]);
|
|
279
437
|
}
|
|
280
438
|
function toolCallFingerprint(event) {
|
|
439
|
+
if (!event.argsComplete)
|
|
440
|
+
return undefined;
|
|
281
441
|
return createHash("sha256")
|
|
282
442
|
.update(JSON.stringify([event.toolName, event.argsComplete, event.args]))
|
|
283
443
|
.digest("hex");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { outputIdentityFingerprint, outputPartFingerprint } from "../core/output-render-sequence.js";
|
|
2
3
|
import { rootSessionId } from "./session-store.js";
|
|
3
4
|
export class PiboOutputIdentityCollisionError extends Error {
|
|
4
5
|
idempotencyKey;
|
|
@@ -89,7 +90,8 @@ export class ChatDataIngestService {
|
|
|
89
90
|
ingestOutputEvent(input) {
|
|
90
91
|
const event = input.event;
|
|
91
92
|
const idempotencyKey = outputIdempotencyKey(event);
|
|
92
|
-
const identityFingerprint =
|
|
93
|
+
const identityFingerprint = outputIdentityFingerprint(event);
|
|
94
|
+
const partFingerprint = isOutputPartEvent(event) ? outputPartFingerprint(event) : undefined;
|
|
93
95
|
if (idempotencyKey) {
|
|
94
96
|
const existing = this.store.eventLog.findByIdempotencyKey(idempotencyKey);
|
|
95
97
|
if (existing) {
|
|
@@ -156,6 +158,7 @@ export class ChatDataIngestService {
|
|
|
156
158
|
previewText: previewTextForOutputEvent(event),
|
|
157
159
|
attributes: compactObject({
|
|
158
160
|
identityFingerprint,
|
|
161
|
+
outputPartFingerprint: partFingerprint,
|
|
159
162
|
eventIdentityScoped: eventIdForOutputEvent(event) !== undefined,
|
|
160
163
|
semanticEventId: eventIdForOutputEvent(event),
|
|
161
164
|
legacyStreamId: input.legacyStreamId,
|
|
@@ -270,11 +273,6 @@ function deterministicId(prefix, value) {
|
|
|
270
273
|
function hashJson(value) {
|
|
271
274
|
return createHash("sha256").update(canonicalJson(value)).digest("hex").slice(0, 16);
|
|
272
275
|
}
|
|
273
|
-
function outputEventFingerprint(event) {
|
|
274
|
-
const identity = { ...event };
|
|
275
|
-
delete identity.renderSequence;
|
|
276
|
-
return createHash("sha256").update(canonicalJson(identity)).digest("hex");
|
|
277
|
-
}
|
|
278
276
|
function canonicalJson(value) {
|
|
279
277
|
if (value === null || typeof value !== "object")
|
|
280
278
|
return JSON.stringify(value) ?? "null";
|
|
@@ -470,6 +468,16 @@ function observationStatusForOutputEvent(event) {
|
|
|
470
468
|
return "error";
|
|
471
469
|
return "completed";
|
|
472
470
|
}
|
|
471
|
+
function isOutputPartEvent(event) {
|
|
472
|
+
return event.type === "assistant_delta"
|
|
473
|
+
|| event.type === "assistant_message"
|
|
474
|
+
|| event.type === "thinking_started"
|
|
475
|
+
|| event.type === "thinking_delta"
|
|
476
|
+
|| event.type === "thinking_finished"
|
|
477
|
+
|| event.type === "assistant_usage"
|
|
478
|
+
|| event.type === "compaction_start"
|
|
479
|
+
|| event.type === "compaction_end";
|
|
480
|
+
}
|
|
473
481
|
function isTerminalOutputEvent(event) {
|
|
474
482
|
return !event.type.endsWith("_started") && event.type !== "tool_call" && event.type !== "assistant_delta" && event.type !== "thinking_delta" && event.type !== "tool_execution_updated";
|
|
475
483
|
}
|
package/dist/data/schema.js
CHANGED
|
@@ -199,6 +199,16 @@ function applyPiboDataSchemaInTransaction(db, hooks, previousVersion, tablesToRe
|
|
|
199
199
|
FOREIGN KEY (pibo_session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
200
200
|
);
|
|
201
201
|
|
|
202
|
+
CREATE TABLE IF NOT EXISTS session_output_part_counters (
|
|
203
|
+
pibo_session_id TEXT NOT NULL,
|
|
204
|
+
event_id TEXT NOT NULL,
|
|
205
|
+
part_kind TEXT NOT NULL CHECK(part_kind IN ('assistant', 'thinking', 'usage', 'compaction')),
|
|
206
|
+
next_index INTEGER NOT NULL CHECK(next_index >= 0),
|
|
207
|
+
updated_at TEXT NOT NULL,
|
|
208
|
+
PRIMARY KEY (pibo_session_id, event_id, part_kind),
|
|
209
|
+
FOREIGN KEY (pibo_session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
210
|
+
);
|
|
211
|
+
|
|
202
212
|
CREATE TABLE IF NOT EXISTS session_tool_invocation_counters (
|
|
203
213
|
pibo_session_id TEXT NOT NULL,
|
|
204
214
|
event_id TEXT NOT NULL,
|
|
@@ -147,6 +147,65 @@ export class PiboDataSessionStore {
|
|
|
147
147
|
`).run(sequence, new Date().toISOString(), piboSessionId);
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
|
+
claimOrAttachOutputPart(input) {
|
|
151
|
+
return this.dataStore.transaction(() => {
|
|
152
|
+
const indexAttribute = outputPartIndexAttribute(input.kind);
|
|
153
|
+
const eventTypes = outputPartEventTypes(input.kind);
|
|
154
|
+
const placeholders = eventTypes.map(() => "?").join(", ");
|
|
155
|
+
const rows = this.db.prepare(`
|
|
156
|
+
SELECT type, attributes_json
|
|
157
|
+
FROM event_log
|
|
158
|
+
WHERE session_id = ? AND event_id = ? AND type IN (${placeholders})
|
|
159
|
+
ORDER BY stream_id ASC
|
|
160
|
+
`).all(input.piboSessionId, input.eventId, ...eventTypes);
|
|
161
|
+
let maximum = -1;
|
|
162
|
+
const latestTypeByIndex = new Map();
|
|
163
|
+
for (const row of rows) {
|
|
164
|
+
const attributes = parseJsonObject(row.attributes_json);
|
|
165
|
+
const index = attributes[indexAttribute];
|
|
166
|
+
if (typeof index !== "number" || !Number.isSafeInteger(index) || index < 0)
|
|
167
|
+
continue;
|
|
168
|
+
maximum = Math.max(maximum, index);
|
|
169
|
+
if (attributes.outputPartFingerprint === input.fingerprint
|
|
170
|
+
|| attributes.identityFingerprint === input.identityFingerprint) {
|
|
171
|
+
this.observeOutputPartIndex(input, index);
|
|
172
|
+
return index;
|
|
173
|
+
}
|
|
174
|
+
latestTypeByIndex.set(index, row.type);
|
|
175
|
+
}
|
|
176
|
+
const latestOpen = [...latestTypeByIndex.entries()]
|
|
177
|
+
.filter(([, eventType]) => !outputPartEventIsTerminal(eventType))
|
|
178
|
+
.sort(([left], [right]) => right - left)[0]?.[0];
|
|
179
|
+
if (latestOpen !== undefined) {
|
|
180
|
+
this.observeOutputPartIndex(input, latestOpen);
|
|
181
|
+
return latestOpen;
|
|
182
|
+
}
|
|
183
|
+
const minimum = Math.max(input.proposedIndex, maximum + 1);
|
|
184
|
+
const row = this.db.prepare(`
|
|
185
|
+
INSERT INTO session_output_part_counters (
|
|
186
|
+
pibo_session_id, event_id, part_kind, next_index, updated_at
|
|
187
|
+
) VALUES (?, ?, ?, ? + 1, ?)
|
|
188
|
+
ON CONFLICT(pibo_session_id, event_id, part_kind) DO UPDATE SET
|
|
189
|
+
next_index = MAX(session_output_part_counters.next_index, ?) + 1,
|
|
190
|
+
updated_at = excluded.updated_at
|
|
191
|
+
RETURNING next_index - 1 AS part_index
|
|
192
|
+
`).get(input.piboSessionId, input.eventId, input.kind, minimum, new Date().toISOString(), minimum);
|
|
193
|
+
return row.part_index;
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
observeOutputPartIndex(input, index) {
|
|
197
|
+
this.db.prepare(`
|
|
198
|
+
INSERT INTO session_output_part_counters (
|
|
199
|
+
pibo_session_id, event_id, part_kind, next_index, updated_at
|
|
200
|
+
) VALUES (?, ?, ?, ?, ?)
|
|
201
|
+
ON CONFLICT(pibo_session_id, event_id, part_kind) DO UPDATE SET
|
|
202
|
+
next_index = MAX(session_output_part_counters.next_index, excluded.next_index),
|
|
203
|
+
updated_at = CASE
|
|
204
|
+
WHEN excluded.next_index > session_output_part_counters.next_index THEN excluded.updated_at
|
|
205
|
+
ELSE session_output_part_counters.updated_at
|
|
206
|
+
END
|
|
207
|
+
`).run(input.piboSessionId, input.eventId, input.kind, index + 1, new Date().toISOString());
|
|
208
|
+
}
|
|
150
209
|
claimOutputToolInvocationOrdinal(piboSessionId, eventId, toolCallId) {
|
|
151
210
|
return this.dataStore.transaction(() => {
|
|
152
211
|
const durable = this.db.prepare(`
|
|
@@ -196,7 +255,9 @@ export class PiboDataSessionStore {
|
|
|
196
255
|
let ordinal;
|
|
197
256
|
if (input.eventType === "tool_call"
|
|
198
257
|
&& latestOpen
|
|
199
|
-
&& (latestOpen.seen_call === 0
|
|
258
|
+
&& (latestOpen.seen_call === 0
|
|
259
|
+
|| latestOpen.call_fingerprint === null
|
|
260
|
+
|| latestOpen.call_fingerprint === input.callFingerprint)) {
|
|
200
261
|
ordinal = latestOpen.invocation_ordinal;
|
|
201
262
|
}
|
|
202
263
|
else if (input.eventType !== "tool_call" && latestOpen) {
|
|
@@ -562,6 +623,28 @@ function runtimeBindingFromRow(row) {
|
|
|
562
623
|
function isRuntimeBindingState(value) {
|
|
563
624
|
return value === "unbound" || value === "bound" || value === "missing" || value === "error";
|
|
564
625
|
}
|
|
626
|
+
function outputPartIndexAttribute(kind) {
|
|
627
|
+
switch (kind) {
|
|
628
|
+
case "assistant": return "assistantIndex";
|
|
629
|
+
case "thinking": return "thinkingIndex";
|
|
630
|
+
case "usage": return "usageIndex";
|
|
631
|
+
case "compaction": return "compactionIndex";
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function outputPartEventTypes(kind) {
|
|
635
|
+
switch (kind) {
|
|
636
|
+
case "assistant": return ["assistant_delta", "assistant_message"];
|
|
637
|
+
case "thinking": return ["thinking_started", "thinking_delta", "thinking_finished"];
|
|
638
|
+
case "usage": return ["assistant_usage"];
|
|
639
|
+
case "compaction": return ["compaction_start", "compaction_end"];
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
function outputPartEventIsTerminal(eventType) {
|
|
643
|
+
return eventType === "assistant_message"
|
|
644
|
+
|| eventType === "thinking_finished"
|
|
645
|
+
|| eventType === "assistant_usage"
|
|
646
|
+
|| eventType === "compaction_end";
|
|
647
|
+
}
|
|
565
648
|
function parseJsonObject(json) {
|
|
566
649
|
if (!json)
|
|
567
650
|
return {};
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pasko70/pibo",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@pasko70/pibo",
|
|
9
|
-
"version": "3.1.
|
|
9
|
+
"version": "3.1.2",
|
|
10
10
|
"workspaces": [
|
|
11
11
|
"packages/workflows"
|
|
12
12
|
],
|