@pasko70/pibo 3.4.3 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-runtime/routed-session.js +39 -12
- package/dist/agent-runtimes/codex-native/adapter.js +14 -1
- package/dist/agent-runtimes/codex-native/models.js +4 -4
- package/dist/agent-runtimes/codex-native/process.js +32 -13
- package/dist/agent-runtimes/codex-native/provider-usage.js +115 -0
- package/dist/agent-runtimes/pi/adapter.js +1 -0
- package/dist/agent-runtimes/pi/routed-session.js +4 -2
- package/dist/apps/chat/bounded-event-stream.js +98 -0
- package/dist/apps/chat/chat-settings-routes.js +3 -3
- package/dist/apps/chat/data/chat-data-mappers.js +32 -13
- package/dist/apps/chat/data/event-command-service.js +30 -21
- package/dist/apps/chat/data/history-query-service.js +34 -25
- package/dist/apps/chat/data/read-state-service.js +13 -0
- package/dist/apps/chat/data/session-query-service.js +19 -11
- package/dist/apps/chat/data/timeline-query-service.js +19 -7
- package/dist/apps/chat/message-command-dispatcher.js +134 -0
- package/dist/apps/chat/output-compactor.js +9 -0
- package/dist/apps/chat/output-event-policy.js +9 -1
- package/dist/apps/chat/stream.js +21 -3
- package/dist/apps/chat/telemetry-retention-service.js +113 -8
- package/dist/apps/chat/trace-response-cache.js +46 -0
- package/dist/apps/chat/trace-v2.js +12 -6
- package/dist/apps/chat/trace.js +1 -1
- package/dist/apps/chat/web-app.js +608 -281
- package/dist/apps/chat-ui/assets/{dist-DeMKnZR8.js → dist-BG0n7zLd.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C8GzUMPk.js → dist-D6TjFhAm.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BkUu8WPA.js → dist-D79vyxSX.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-B4YhOxh0.js → dist-DFZ8cwh0.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Cyb4rVa6.js → dist-cOjokPrK.js} +1 -1
- package/dist/apps/chat-ui/assets/index-RMHUTJ62.js +229 -0
- package/dist/apps/chat-ui/assets/{index-BOceJ0jM.css → index-hEkrlRk-.css} +1 -1
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-xacbCyTx.js +44 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/compute/pool/seeds.js +25 -3
- package/dist/core/events.js +4 -0
- package/dist/core/output-render-sequence.js +2 -0
- package/dist/core/provider-capacity.js +33 -0
- package/dist/core/provider-telemetry.js +21 -6
- package/dist/core/runtime-capacity.js +174 -0
- package/dist/core/runtime-telemetry.js +40 -12
- package/dist/core/session-router.js +79 -2
- package/dist/data/async-chat-reads.js +38 -0
- package/dist/data/async-chat-storage.js +91 -0
- package/dist/data/async-telemetry-maintenance.js +9 -0
- package/dist/data/bounded-worker-client.js +256 -0
- package/dist/data/chat-read-projections.js +159 -0
- package/dist/data/chat-read-worker.js +73 -0
- package/dist/data/chat-storage-worker.js +146 -0
- package/dist/data/ingest-service.js +79 -14
- package/dist/data/message-command-store.js +148 -0
- package/dist/data/payload-store.js +92 -11
- package/dist/data/pibo-store.js +10 -8
- package/dist/data/schema.js +16 -2
- package/dist/data/session-store.js +3 -1
- package/dist/data/storage-backup.js +278 -0
- package/dist/data/telemetry-capture.js +188 -0
- package/dist/data/telemetry-command.js +3 -0
- package/dist/data/telemetry-maintenance-worker.js +40 -0
- package/dist/data/telemetry-maintenance.js +110 -0
- package/dist/data/telemetry-retention.js +16 -7
- package/dist/data/telemetry-worker.js +111 -0
- package/dist/data/telemetry-writer.js +150 -83
- package/dist/data/telemetry.js +5 -0
- package/dist/debug/index.js +52 -0
- package/dist/debug/storage-backup.js +33 -0
- package/dist/debug/telemetry-capture.js +66 -0
- package/dist/gateway/cli.js +104 -16
- package/dist/gateway/server.js +2 -0
- package/dist/providers/openai-gpt56.js +11 -6
- package/dist/session-ui/terminalRows.js +55 -13
- package/dist/sessions/pibo-data-store.js +30 -10
- package/dist/shared/debug-features.js +4 -0
- package/dist/shared/model-inference-metrics.js +23 -0
- package/dist/shared/trace-event-projection.js +59 -2
- package/dist/shared/trace-history.js +9 -0
- package/dist/shared/trace-live-reducer.js +1 -0
- package/dist/shared/trace-patch-nodes.js +19 -0
- package/dist/web/channel.js +8 -2
- package/dist/web/http.js +36 -3
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-Dk4mbXAB.js +0 -228
- package/dist/apps/chat-vscode-web/assets/index-0oTGFHni.js +0 -43
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AsyncTelemetryMaintenance } from "../../data/async-telemetry-maintenance.js";
|
|
2
|
+
import { TelemetryMaintenance } from "../../data/telemetry-maintenance.js";
|
|
1
3
|
import { telemetryRetentionCutoff, } from "../../core/telemetry-retention-settings.js";
|
|
2
4
|
export const TELEMETRY_RETENTION_CLASSES = [
|
|
3
5
|
"live",
|
|
@@ -7,14 +9,33 @@ export const TELEMETRY_RETENTION_CLASSES = [
|
|
|
7
9
|
"incident",
|
|
8
10
|
];
|
|
9
11
|
export const DEFAULT_TELEMETRY_RETENTION_MAINTENANCE_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
12
|
+
/** Bounded recovery: back off a failing maintenance job, then leave it visible instead of respawning. */
|
|
13
|
+
export const TELEMETRY_RETENTION_MAINTENANCE_FAILURE_LIMIT = 8;
|
|
14
|
+
export const TELEMETRY_RETENTION_MAINTENANCE_MAX_RETRY_MS = 30_000;
|
|
15
|
+
export async function disposeTelemetryRetentionMaintenance(state) {
|
|
16
|
+
state.disposed = true;
|
|
17
|
+
if (state.timer)
|
|
18
|
+
clearTimeout(state.timer);
|
|
19
|
+
state.timer = undefined;
|
|
20
|
+
state.running = false;
|
|
21
|
+
await state.worker?.close();
|
|
22
|
+
state.worker = undefined;
|
|
23
|
+
}
|
|
10
24
|
export function pruneTelemetryOlderThan(input) {
|
|
11
25
|
const cutoff = telemetryRetentionCutoff(input.days, input.now);
|
|
12
|
-
const results =
|
|
26
|
+
const results = [];
|
|
27
|
+
for (const retentionClass of TELEMETRY_RETENTION_CLASSES) {
|
|
28
|
+
const result = input.dataStore.telemetry.prune({ retentionClass, before: cutoff, apply: input.apply });
|
|
29
|
+
results.push(result);
|
|
30
|
+
if (result.completed === false)
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
13
33
|
return {
|
|
14
34
|
cutoff,
|
|
15
35
|
days: input.days,
|
|
16
36
|
applied: input.apply === true,
|
|
17
37
|
results,
|
|
38
|
+
completed: results.every(result => result.completed !== false),
|
|
18
39
|
rowsDeleted: results.reduce((sum, result) => sum + result.rowsDeleted, 0),
|
|
19
40
|
bytesMatched: results.reduce((sum, result) => sum + result.bytesMatched, 0),
|
|
20
41
|
};
|
|
@@ -27,6 +48,8 @@ export function isTelemetryRetentionMaintenanceDue(input) {
|
|
|
27
48
|
return !(input.state.lastCheckedAt && now.getTime() - input.state.lastCheckedAt < intervalMs);
|
|
28
49
|
}
|
|
29
50
|
export function maybeRunTelemetryRetentionMaintenance(input) {
|
|
51
|
+
if (input.state.disposed)
|
|
52
|
+
return;
|
|
30
53
|
if (!input.settings.enabled)
|
|
31
54
|
return;
|
|
32
55
|
if (input.state.running)
|
|
@@ -39,19 +62,70 @@ export function maybeRunTelemetryRetentionMaintenance(input) {
|
|
|
39
62
|
input.state.lastCheckedAt = now.getTime();
|
|
40
63
|
return;
|
|
41
64
|
}
|
|
42
|
-
if (hasActiveRuntimeWork(input.context))
|
|
43
|
-
return;
|
|
44
65
|
input.state.lastCheckedAt = now.getTime();
|
|
45
66
|
input.state.running = true;
|
|
46
|
-
|
|
67
|
+
const cutoff = telemetryRetentionCutoff(input.settings.days, now);
|
|
68
|
+
const local = input.dataStore.path === ":memory:" ? new TelemetryMaintenance(input.dataStore.db) : undefined;
|
|
69
|
+
let consecutiveFailures = 0;
|
|
70
|
+
const run = async () => {
|
|
71
|
+
let failed = false;
|
|
47
72
|
try {
|
|
48
|
-
|
|
49
|
-
|
|
73
|
+
if (input.state.disposed)
|
|
74
|
+
return;
|
|
75
|
+
if (local) {
|
|
76
|
+
if (!local.status() || local.status()?.status === "completed" || local.status()?.status === "cancelled")
|
|
77
|
+
local.start(cutoff);
|
|
78
|
+
local.step();
|
|
79
|
+
}
|
|
80
|
+
else if (!input.state.worker) {
|
|
81
|
+
input.state.worker = new AsyncTelemetryMaintenance(input.dataStore.path);
|
|
82
|
+
await input.state.worker.command("start", cutoff);
|
|
83
|
+
}
|
|
84
|
+
const status = local?.status() ?? await input.state.worker.command("status");
|
|
85
|
+
if (input.state.disposed)
|
|
86
|
+
return;
|
|
87
|
+
if (status?.status === "completed") {
|
|
88
|
+
input.onPruned?.(now.toISOString());
|
|
89
|
+
input.state.running = false;
|
|
90
|
+
await input.state.worker?.close();
|
|
91
|
+
input.state.worker = undefined;
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (status?.status === "cancelled" || status?.status === "paused") {
|
|
95
|
+
input.state.running = false;
|
|
96
|
+
await input.state.worker?.close();
|
|
97
|
+
input.state.worker = undefined;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
failed = true;
|
|
103
|
+
input.state.failures = (input.state.failures ?? 0) + 1;
|
|
104
|
+
await input.state.worker?.close();
|
|
105
|
+
input.state.worker = undefined;
|
|
106
|
+
}
|
|
107
|
+
if (input.state.disposed)
|
|
108
|
+
return;
|
|
109
|
+
if (!failed) {
|
|
110
|
+
consecutiveFailures = 0;
|
|
111
|
+
input.state.timer = setTimeout(() => { input.state.timer = undefined; void run(); }, local ? 25 : 250);
|
|
112
|
+
input.state.timer.unref?.();
|
|
113
|
+
return;
|
|
50
114
|
}
|
|
51
|
-
|
|
115
|
+
// A persistent failure must not respawn a worker thread every 250 ms forever. Back off, then stop
|
|
116
|
+
// with the failure count visible so a later due check retries instead of burning one worker per attempt.
|
|
117
|
+
consecutiveFailures++;
|
|
118
|
+
if (consecutiveFailures >= TELEMETRY_RETENTION_MAINTENANCE_FAILURE_LIMIT) {
|
|
52
119
|
input.state.running = false;
|
|
120
|
+
input.state.timer = undefined;
|
|
121
|
+
return;
|
|
53
122
|
}
|
|
54
|
-
|
|
123
|
+
const backoffMs = Math.min(TELEMETRY_RETENTION_MAINTENANCE_MAX_RETRY_MS, 250 * 2 ** (consecutiveFailures - 1));
|
|
124
|
+
input.state.timer = setTimeout(() => { input.state.timer = undefined; void run(); }, backoffMs);
|
|
125
|
+
input.state.timer.unref?.();
|
|
126
|
+
};
|
|
127
|
+
input.state.timer = setTimeout(() => { input.state.timer = undefined; void run(); }, 0);
|
|
128
|
+
input.state.timer.unref?.();
|
|
55
129
|
}
|
|
56
130
|
export function isPersistentRetentionDue(lastPrunedAt, now, intervalMs) {
|
|
57
131
|
if (!lastPrunedAt)
|
|
@@ -67,3 +141,34 @@ export function hasActiveRuntimeWork(context) {
|
|
|
67
141
|
?? [];
|
|
68
142
|
return statuses.some((status) => Boolean(status?.processing || status?.streaming || (status?.queuedMessages ?? 0) > 0));
|
|
69
143
|
}
|
|
144
|
+
/** Explicit HTTP maintenance keeps SQL off the gateway and yields between every bounded batch. */
|
|
145
|
+
export async function pruneTelemetryOlderThanAsync(input) {
|
|
146
|
+
if (input.dataStore.path === ":memory:")
|
|
147
|
+
return pruneTelemetryOlderThan(input);
|
|
148
|
+
const cutoff = telemetryRetentionCutoff(input.days), worker = new AsyncTelemetryMaintenance(input.dataStore.path);
|
|
149
|
+
const abort = () => { void worker.close(); };
|
|
150
|
+
input.signal?.addEventListener("abort", abort, { once: true });
|
|
151
|
+
try {
|
|
152
|
+
if (input.signal?.aborted)
|
|
153
|
+
throw Error("Maintenance request cancelled");
|
|
154
|
+
if (!input.apply) {
|
|
155
|
+
const results = await worker.preview(cutoff);
|
|
156
|
+
return { cutoff, days: input.days, applied: false, results, rowsDeleted: 0, bytesMatched: results.reduce((n, r) => n + r.bytesMatched, 0), completed: true };
|
|
157
|
+
}
|
|
158
|
+
let status = await worker.command("start", cutoff);
|
|
159
|
+
if (status?.status === "paused")
|
|
160
|
+
status = await worker.command("resume");
|
|
161
|
+
const until = Date.now() + 30000;
|
|
162
|
+
while (status?.status === "running" && Date.now() < until) {
|
|
163
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
164
|
+
status = await worker.command("status");
|
|
165
|
+
}
|
|
166
|
+
if (status?.status === "running")
|
|
167
|
+
status = await worker.command("pause");
|
|
168
|
+
return { cutoff: status?.cutoff ?? cutoff, days: input.days, applied: true, results: [], rowsDeleted: status?.deleted ?? 0, bytesMatched: 0, completed: status?.status === "completed" };
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
input.signal?.removeEventListener("abort", abort);
|
|
172
|
+
await worker.close();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Exact encoded responses; bounded independently from reconstructed trace caches. */
|
|
2
|
+
export class TraceResponseCache {
|
|
3
|
+
maximumBytes;
|
|
4
|
+
maximumEntries;
|
|
5
|
+
entries = new Map();
|
|
6
|
+
bytes = 0;
|
|
7
|
+
constructor(maximumBytes = 8 * 1024 * 1024, maximumEntries = 32) {
|
|
8
|
+
this.maximumBytes = maximumBytes;
|
|
9
|
+
this.maximumEntries = maximumEntries;
|
|
10
|
+
}
|
|
11
|
+
get(key, request) {
|
|
12
|
+
const entry = this.entries.get(key);
|
|
13
|
+
if (!entry)
|
|
14
|
+
return;
|
|
15
|
+
this.entries.delete(key);
|
|
16
|
+
this.entries.set(key, entry);
|
|
17
|
+
const headers = new Headers(entry.headers);
|
|
18
|
+
headers.set("server-timing", 'trace_cache;desc="watermark-hit"');
|
|
19
|
+
const etag = headers.get("etag");
|
|
20
|
+
const requested = request.headers.get("if-none-match");
|
|
21
|
+
if (etag && requested?.split(',').some(v => v.trim() === '*' || v.trim() === etag || v.trim() === 'W/' + etag))
|
|
22
|
+
return new Response(null, { status: 304, headers });
|
|
23
|
+
return new Response(entry.body.slice(), { status: entry.status, headers });
|
|
24
|
+
}
|
|
25
|
+
async set(key, response) {
|
|
26
|
+
if (response.status !== 200 || !response.headers.get("content-type")?.includes("json"))
|
|
27
|
+
return;
|
|
28
|
+
const body = new Uint8Array(await response.clone().arrayBuffer());
|
|
29
|
+
const bytes = body.byteLength + Buffer.byteLength(key);
|
|
30
|
+
if (bytes > Math.min(this.maximumBytes, 1024 * 1024))
|
|
31
|
+
return;
|
|
32
|
+
const previous = this.entries.get(key);
|
|
33
|
+
if (previous)
|
|
34
|
+
this.bytes -= previous.bytes;
|
|
35
|
+
this.entries.delete(key);
|
|
36
|
+
this.entries.set(key, { body, headers: [...response.headers.entries()], status: response.status, bytes });
|
|
37
|
+
this.bytes += bytes;
|
|
38
|
+
while (this.bytes > this.maximumBytes || this.entries.size > this.maximumEntries) {
|
|
39
|
+
const oldest = this.entries.keys().next().value;
|
|
40
|
+
this.bytes -= this.entries.get(oldest).bytes;
|
|
41
|
+
this.entries.delete(oldest);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
clear() { this.entries.clear(); this.bytes = 0; }
|
|
45
|
+
status() { return { entries: this.entries.size, bytes: this.bytes, maximumBytes: this.maximumBytes, maximumEntries: this.maximumEntries }; }
|
|
46
|
+
}
|
|
@@ -148,17 +148,21 @@ export function looksLikeImagePayloadPreview(value) {
|
|
|
148
148
|
return /"type"\s*:\s*"(?:image|input_image|output_image|image_url)"/i.test(value)
|
|
149
149
|
|| /"mime(?:Type|_type)"\s*:\s*"image\//i.test(value);
|
|
150
150
|
}
|
|
151
|
-
export function readTracePayloadChunk(input) {
|
|
151
|
+
export async function readTracePayloadChunk(input) {
|
|
152
152
|
const parsed = parseTracePayloadRef(input.ref);
|
|
153
153
|
if (!parsed)
|
|
154
154
|
return undefined;
|
|
155
155
|
const payload = input.payloadStore.getPayload(parsed.payloadId);
|
|
156
156
|
if (!payload)
|
|
157
157
|
return undefined;
|
|
158
|
-
const
|
|
159
|
-
const offset = Math.max(0, Math.min(input.offset, bytes.byteLength));
|
|
158
|
+
const offset = Math.max(0, Math.min(input.offset, payload.byteSize));
|
|
160
159
|
const limit = Math.max(1, Math.min(input.limit, TRACE_V2_PAYLOAD_MAX_LIMIT_BYTES));
|
|
161
|
-
const
|
|
160
|
+
const bytes = await input.payloadStore.readPayloadRange(parsed.payloadId, offset, limit + 3);
|
|
161
|
+
let length = Math.min(limit, bytes.length);
|
|
162
|
+
// Include a complete UTF-8 code point at the boundary; cursors remain byte offsets.
|
|
163
|
+
while (length < bytes.length && (bytes[length] & 0xc0) === 0x80)
|
|
164
|
+
length++;
|
|
165
|
+
const chunk = bytes.subarray(0, length);
|
|
162
166
|
const preview = payload.previewText ?? "";
|
|
163
167
|
const traceRef = {
|
|
164
168
|
ref: input.ref,
|
|
@@ -168,7 +172,7 @@ export function readTracePayloadChunk(input) {
|
|
|
168
172
|
truncatedPreview: Buffer.byteLength(preview, "utf8") < payload.byteSize,
|
|
169
173
|
hash: payload.sha256,
|
|
170
174
|
};
|
|
171
|
-
const nextOffset = offset + chunk.byteLength <
|
|
175
|
+
const nextOffset = offset + chunk.byteLength < payload.byteSize ? offset + chunk.byteLength : undefined;
|
|
172
176
|
return {
|
|
173
177
|
ref: traceRef,
|
|
174
178
|
offset,
|
|
@@ -248,6 +252,8 @@ function compactTraceNode(node, payloadStore, piboSessionId, depth) {
|
|
|
248
252
|
completedAt: node.completedAt,
|
|
249
253
|
durationMs: node.durationMs,
|
|
250
254
|
toolMetrics: node.toolMetrics,
|
|
255
|
+
modelInferences: node.modelInferences,
|
|
256
|
+
compactionStats: node.compactionStats,
|
|
251
257
|
orderKey: node.orderKey,
|
|
252
258
|
depth,
|
|
253
259
|
hasChildren: node.children.length > 0,
|
|
@@ -268,7 +274,7 @@ function compactTraceNode(node, payloadStore, piboSessionId, depth) {
|
|
|
268
274
|
});
|
|
269
275
|
}
|
|
270
276
|
function inlinePayloadForNodeValue(node, kind, value) {
|
|
271
|
-
return inlinePayloadForValue(value, inlinePayloadByteLimit(node, kind));
|
|
277
|
+
return node.payloadRefs?.[kind] ? undefined : inlinePayloadForValue(value, inlinePayloadByteLimit(node, kind));
|
|
272
278
|
}
|
|
273
279
|
function inlinePayloadByteLimit(node, kind) {
|
|
274
280
|
if ((node.type === "user.message" || node.type === "assistant.message" || node.type === "model.reasoning") && kind !== "error") {
|
package/dist/apps/chat/trace.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isBuiltInHistoryReconciliationProof } from "../../agent-runtimes/histor
|
|
|
5
5
|
import { buildTraceViewFromEvents, traceNodesFromHistoryEntries } from "../../shared/trace-engine.js";
|
|
6
6
|
import { chatWebSessionSidebarOrder, isChatWebSessionArchived, isChatWebSessionPinned } from "./session-metadata.js";
|
|
7
7
|
import { workflowSessionKindFromMetadata } from "../../sessions/workflow-session-kind.js";
|
|
8
|
-
export const TRACE_PROJECTION_VERSION = "runtime-history-v2-
|
|
8
|
+
export const TRACE_PROJECTION_VERSION = "runtime-history-v2-debug-metrics";
|
|
9
9
|
export { compareTraceNodes, sortTraceNodes, nestTraceNodes, flattenTraceNodes, mapTraceNodesById, buildTraceViewFromEvents, traceNodesFromHistoryEntries, } from "../../shared/trace-engine.js";
|
|
10
10
|
export const TRACE_TRANSCRIPT_TAIL_MAX_BYTES = PI_HISTORY_TAIL_MAX_BYTES;
|
|
11
11
|
export const TRACE_TRANSCRIPT_HISTORY_PAGE_MAX_BYTES = PI_HISTORY_PAGE_MAX_BYTES;
|