@pasko70/pibo 1.9.10 → 1.9.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/apps/chat/data/timeline-query-service.js +11 -0
  2. package/dist/apps/chat/trace.js +2 -0
  3. package/dist/apps/chat/web-app.js +70 -7
  4. package/dist/apps/chat-ui/assets/{dist-BH4dS5wk.js → dist-BCB6zezO.js} +1 -1
  5. package/dist/apps/chat-ui/assets/{dist-ZN6fdzpB.js → dist-BHa-kcGl.js} +1 -1
  6. package/dist/apps/chat-ui/assets/{dist-qwl4CNfF.js → dist-BNMu92bb.js} +1 -1
  7. package/dist/apps/chat-ui/assets/{dist-BCqTb13C.js → dist-BZ2eTC4f.js} +1 -1
  8. package/dist/apps/chat-ui/assets/{dist-Ds5VZTeC.js → dist-CnVsqwSG.js} +1 -1
  9. package/dist/apps/chat-ui/assets/{dist-BXmdj7mb.js → dist-CzE6k3F3.js} +1 -1
  10. package/dist/apps/chat-ui/assets/{dist-CdhJkLlg.js → dist-D811wJeV.js} +1 -1
  11. package/dist/apps/chat-ui/assets/{dist-CDTTlyfG.js → dist-Dq4GxJi3.js} +1 -1
  12. package/dist/apps/chat-ui/assets/{dist-D7FSg1x8.js → dist-HqTN67dc.js} +1 -1
  13. package/dist/apps/chat-ui/assets/{dist-4VdcCJgh.js → dist-WyXdYl-w.js} +1 -1
  14. package/dist/apps/chat-ui/assets/{dist--Sb99Zop.js → dist-yCYNNb5d.js} +1 -1
  15. package/dist/apps/chat-ui/assets/{index-Gf-Zb-P-.js → index-DwHJfmiF.js} +81 -81
  16. package/dist/apps/chat-ui/index.html +1 -1
  17. package/dist/apps/vscode-artifacts/latest.vsix +0 -0
  18. package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.9.13.vsix +0 -0
  19. package/dist/core/session-router.js +7 -0
  20. package/dist/data/ingest-service.js +7 -0
  21. package/dist/data/message-store.js +11 -0
  22. package/dist/data/schema.js +2 -0
  23. package/dist/gateway/server.js +2 -0
  24. package/dist/resources/lifecycle.js +4 -6
  25. package/dist/resources/reaper-state.js +30 -3
  26. package/dist/resources/reaper.js +43 -15
  27. package/dist/shared/trace-engine.js +3 -2
  28. package/dist/shared/trace-event-projection.js +26 -0
  29. package/dist/signals/registry.js +24 -1
  30. package/dist/signals/status.js +12 -0
  31. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { messageTurnTimingsFromEvents } from "../../../shared/trace-event-projection.js";
1
2
  import { storedChatEventFromV2Row, storedPiboEventFromV2Row } from "./chat-data-mappers.js";
2
3
  export class ChatTimelineQueryService {
3
4
  store;
@@ -30,6 +31,16 @@ export class ChatTimelineQueryService {
30
31
  listAllSessionEvents(piboSessionId) {
31
32
  return this.listTraceEvents({ piboSessionId, limit: 10000, includeLive: true });
32
33
  }
34
+ listMessageTurnTimings(piboSessionId) {
35
+ const rows = this.store.db.prepare(`
36
+ SELECT * FROM event_log
37
+ WHERE session_id = ?
38
+ AND type IN ('message_started', 'message_finished')
39
+ ORDER BY session_sequence ASC, stream_id ASC
40
+ `).all(piboSessionId);
41
+ const events = rows.map(storedPiboEventFromV2Row).filter((event) => event !== undefined);
42
+ return messageTurnTimingsFromEvents(events);
43
+ }
33
44
  listTraceEvents(input) {
34
45
  const piboSessionId = typeof input === "string" ? input : input.piboSessionId;
35
46
  const limit = Math.max(1, Math.min((typeof input === "string" ? undefined : input.limit) ?? 2000, 10000));
@@ -126,6 +126,7 @@ export async function buildTraceView(input) {
126
126
  title: createSessionTitle(input.session, metadata),
127
127
  },
128
128
  events: input.events,
129
+ turnTimings: input.turnTimings,
129
130
  transcriptEntries: allEntries,
130
131
  sessions: input.sessions.map((s) => ({
131
132
  id: s.id,
@@ -175,6 +176,7 @@ export function createTraceViewVersion(input) {
175
176
  const eventTail = input.events.at(-1);
176
177
  return createHash("sha1")
177
178
  .update(JSON.stringify({
179
+ traceProjection: "turn-timing-v2",
178
180
  session: {
179
181
  id: input.session.id,
180
182
  piSessionId: input.session.piSessionId,
@@ -1,6 +1,7 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import os from "node:os";
3
3
  import { monitorEventLoopDelay } from "node:perf_hooks";
4
+ import { summarizeSessionSignalStatus } from "../../signals/status.js";
4
5
  import { PiboWebHttpError, readJsonBody, responseJson } from "../../web/http.js";
5
6
  import { OutputCompactor } from "./output-compactor.js";
6
7
  import { isLiveOnlyOutputEvent, isPersistableOutputEvent } from "./output-event-policy.js";
@@ -112,6 +113,25 @@ function writeJsonSse(controller, event, payload, id) {
112
113
  controller.enqueue(encoder.encode(`event: ${event}\n`));
113
114
  controller.enqueue(encoder.encode(`data: ${JSON.stringify(payload)}\n\n`));
114
115
  }
116
+ function compactSignalStatusPatch(patch) {
117
+ return {
118
+ type: "signal_status_patch",
119
+ rootPiboSessionId: patch.rootPiboSessionId,
120
+ fromVersion: patch.fromVersion,
121
+ toVersion: patch.toVersion,
122
+ generatedAt: patch.generatedAt,
123
+ sessionStatuses: patch.sessionSnapshots.map(summarizeSessionSignalStatus),
124
+ };
125
+ }
126
+ function signalSseHeaders() {
127
+ return {
128
+ "content-type": "text/event-stream; charset=utf-8",
129
+ "cache-control": "no-cache, no-transform",
130
+ "content-encoding": "identity",
131
+ "x-accel-buffering": "no",
132
+ connection: "keep-alive",
133
+ };
134
+ }
115
135
  function requireSameOriginJsonRequest(request) {
116
136
  requireSameOriginRequest(request, "application/json");
117
137
  }
@@ -303,6 +323,7 @@ function createFastTraceV2Version(input) {
303
323
  .sort((left, right) => left.id.localeCompare(right.id));
304
324
  return createHash("sha1")
305
325
  .update(JSON.stringify({
326
+ traceProjection: "turn-timing-v2",
306
327
  session: {
307
328
  id: input.session.id,
308
329
  piSessionId: input.session.piSessionId,
@@ -3511,6 +3532,48 @@ export function createChatWebApp(options = {}) {
3511
3532
  const projectSession = archived === undefined ? state.projectService.getProjectSession(selectedSession.id) : state.projectService.setProjectSessionArchived(selectedSession.id, archived);
3512
3533
  return responseJson({ session: updated, projectSession });
3513
3534
  }
3535
+ if (url.pathname === `${CHAT_WEB_API_PREFIX}/signals/statuses` && request.method === "GET") {
3536
+ await requireSession(request, context);
3537
+ if (!context.channelContext.snapshotSignalStatuses) {
3538
+ throw new PiboWebHttpError("Signal registry is not available", 503);
3539
+ }
3540
+ return responseJson(context.channelContext.snapshotSignalStatuses());
3541
+ }
3542
+ if (url.pathname === `${CHAT_WEB_API_PREFIX}/signals/status-events` && request.method === "GET") {
3543
+ await requireSession(request, context);
3544
+ if (!context.channelContext.snapshotSignalStatuses || !context.channelContext.subscribeSignalStatuses) {
3545
+ throw new PiboWebHttpError("Signal registry is not available", 503);
3546
+ }
3547
+ let unsubscribe;
3548
+ let heartbeat;
3549
+ let closed = false;
3550
+ const stream = new ReadableStream({
3551
+ start: (controller) => {
3552
+ writeJsonSse(controller, "signal_status_snapshot", context.channelContext.snapshotSignalStatuses());
3553
+ unsubscribe = context.channelContext.subscribeSignalStatuses((patch) => {
3554
+ if (closed)
3555
+ return;
3556
+ const statusPatch = compactSignalStatusPatch(patch);
3557
+ writeJsonSse(controller, "signal_status_patch", statusPatch, `${patch.rootPiboSessionId}:${patch.toVersion}`);
3558
+ });
3559
+ heartbeat = setInterval(() => {
3560
+ if (!closed)
3561
+ writeSseComment(controller, "heartbeat");
3562
+ }, 25_000);
3563
+ },
3564
+ cancel: () => {
3565
+ closed = true;
3566
+ unsubscribe?.();
3567
+ unsubscribe = undefined;
3568
+ if (heartbeat)
3569
+ clearInterval(heartbeat);
3570
+ heartbeat = undefined;
3571
+ },
3572
+ });
3573
+ return new Response(stream, {
3574
+ headers: signalSseHeaders(),
3575
+ });
3576
+ }
3514
3577
  const requestedSignal = signalResource(url.pathname);
3515
3578
  if (requestedSignal && request.method === "GET") {
3516
3579
  const webSession = await requireSession(request, context);
@@ -3550,13 +3613,7 @@ export function createChatWebApp(options = {}) {
3550
3613
  },
3551
3614
  });
3552
3615
  return new Response(stream, {
3553
- headers: {
3554
- "content-type": "text/event-stream; charset=utf-8",
3555
- "cache-control": "no-cache, no-transform",
3556
- "content-encoding": "identity",
3557
- "x-accel-buffering": "no",
3558
- connection: "keep-alive",
3559
- },
3616
+ headers: signalSseHeaders(),
3560
3617
  });
3561
3618
  }
3562
3619
  if (url.pathname === `${CHAT_WEB_API_PREFIX}/workflows` && request.method === "GET") {
@@ -4210,6 +4267,7 @@ export function createChatWebApp(options = {}) {
4210
4267
  let metadataMs = 0;
4211
4268
  const lastEventSequence = state.timelineQuery.getLatestEventSequence(selectedSession.id);
4212
4269
  const latestStreamId = state.timelineQuery.getLatestStreamId({ piboSessionId: selectedSession.id });
4270
+ const turnTimings = state.timelineQuery.listMessageTurnTimings(selectedSession.id);
4213
4271
  const liveSnapshots = timelineCursor.kind === "tail" ? state.outputCompactor.snapshotsForSession(selectedSession.id) : [];
4214
4272
  const metadataStartedAt = performance.now();
4215
4273
  const transcriptMetadata = timelineCursor.kind === "tail" || timelineCursor.kind === "transcript"
@@ -4272,6 +4330,7 @@ export function createChatWebApp(options = {}) {
4272
4330
  metadata: transcriptMetadata ?? {},
4273
4331
  transcriptEntries: history.entries,
4274
4332
  transcriptOrderOffset: history.startByte,
4333
+ turnTimings,
4275
4334
  includeRawEvents: false,
4276
4335
  latestStreamId,
4277
4336
  });
@@ -4304,6 +4363,7 @@ export function createChatWebApp(options = {}) {
4304
4363
  status: indexedSession?.status,
4305
4364
  metadata: transcriptMetadata ?? {},
4306
4365
  transcriptEntries,
4366
+ turnTimings,
4307
4367
  includeRawEvents: false,
4308
4368
  latestStreamId,
4309
4369
  });
@@ -4418,6 +4478,7 @@ export function createChatWebApp(options = {}) {
4418
4478
  const metadataMs = performance.now() - metadataStartedAt;
4419
4479
  const lastEventSequence = state.timelineQuery.getLatestEventSequence(selectedSession.id);
4420
4480
  const latestStreamId = state.timelineQuery.getLatestStreamId({ piboSessionId: selectedSession.id });
4481
+ const turnTimings = state.timelineQuery.listMessageTurnTimings(selectedSession.id);
4421
4482
  const liveSnapshots = beforeSequence === undefined ? state.outputCompactor.snapshotsForSession(selectedSession.id) : [];
4422
4483
  const baseVersion = createTraceViewVersion({
4423
4484
  session: selectedSession,
@@ -4461,6 +4522,7 @@ export function createChatWebApp(options = {}) {
4461
4522
  events,
4462
4523
  status: indexedSession?.status,
4463
4524
  metadata,
4525
+ turnTimings,
4464
4526
  includeRawEvents: false,
4465
4527
  latestStreamId,
4466
4528
  });
@@ -4522,6 +4584,7 @@ export function createChatWebApp(options = {}) {
4522
4584
  sessions: ownedSessions,
4523
4585
  events: state.timelineQuery.listTraceEvents({ piboSessionId, beforeOrAtSequence: eventSequence, limit: DEFAULT_TRACE_EVENTS_PAGE_SIZE }),
4524
4586
  status: indexedSession?.status,
4587
+ turnTimings: state.timelineQuery.listMessageTurnTimings(piboSessionId),
4525
4588
  });
4526
4589
  return responseJson(trace);
4527
4590
  }