@pasko70/pibo 3.4.0 → 3.4.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/dist/agent-runtime/routed-session.js +7 -1
- package/dist/agent-runtimes/pi/adapter.js +4 -1
- package/dist/agent-runtimes/pi/history.js +55 -1
- package/dist/apps/chat/data/chat-data-mappers.js +1 -1
- package/dist/apps/chat/stream.js +1 -1
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/web-app.js +2 -1
- package/dist/apps/chat-ui/assets/{dist-jVaiGXFD.js → dist-B7Ju7u08.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Dyp6sLQn.js → dist-BDnWOTcs.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-t25moyJS.js → dist-CAiO6h6z.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-AhtdAETR.js → dist-CCR1HsaR.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Bk_L1qbJ.js → dist-CXWLhBio.js} +1 -1
- package/dist/apps/chat-ui/assets/index-0cCGS0o3.js +228 -0
- package/dist/apps/chat-ui/assets/index-BMJGoyM8.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-BD3Ogz9Z.js +43 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/auth/openai-codex-usage.js +34 -5
- package/dist/core/session-router.js +100 -11
- package/dist/data/ingest-service.js +1 -1
- package/dist/data/schema.js +10 -1
- package/dist/debug/agents.js +5 -3
- package/dist/gateway/server.js +1 -1
- package/dist/previews/web-app.js +85 -0
- package/dist/session-ui/terminalRows.js +3 -1
- package/dist/sessions/pibo-data-store.js +38 -1
- package/dist/sessions/store.js +38 -0
- package/dist/shared/tool-call-metrics.js +77 -0
- package/dist/shared/trace-event-projection.js +2 -0
- package/dist/shared/trace-live-reducer.js +1 -0
- package/dist/shared/trace-patch-nodes.js +4 -0
- package/dist/subagents/context.js +2 -2
- package/dist/subagents/observation-query.js +28 -1
- package/dist/subagents/observations.js +8 -0
- package/dist/subagents/tool.js +12 -8
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-CZjNw-aK.js +0 -228
- package/dist/apps/chat-ui/assets/index-CcEjFITM.css +0 -1
- package/dist/apps/chat-vscode-web/assets/index-Spj6M0tn.js +0 -43
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Bounded structural walk; never tokenize, copy or scan large strings. */
|
|
2
|
+
export function estimateToolPayloadTokens(payload) {
|
|
3
|
+
let budget = 10_000;
|
|
4
|
+
const seen = new WeakSet();
|
|
5
|
+
function size(value, depth) {
|
|
6
|
+
if (--budget < 0 || depth > 64)
|
|
7
|
+
return NaN;
|
|
8
|
+
if (typeof value === "string")
|
|
9
|
+
return value.length;
|
|
10
|
+
if (value === null)
|
|
11
|
+
return 4;
|
|
12
|
+
if (typeof value === "boolean")
|
|
13
|
+
return value ? 4 : 5;
|
|
14
|
+
if (typeof value === "number")
|
|
15
|
+
return String(value).length;
|
|
16
|
+
if (typeof value !== "object" || seen.has(value))
|
|
17
|
+
return NaN;
|
|
18
|
+
seen.add(value);
|
|
19
|
+
let chars = 2;
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
for (const item of value) {
|
|
22
|
+
chars += size(item, depth + 1) + 1;
|
|
23
|
+
if (!Number.isFinite(chars))
|
|
24
|
+
return NaN;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
const record = value;
|
|
29
|
+
// Binary/media payloads have no meaningful character-based token count.
|
|
30
|
+
if (["image", "audio", "document", "resource", "image_url"].includes(String(record.type)))
|
|
31
|
+
return NaN;
|
|
32
|
+
for (const key in record) {
|
|
33
|
+
if (--budget < 0)
|
|
34
|
+
return NaN;
|
|
35
|
+
if (!Object.hasOwn(record, key) || record[key] === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
chars += key.length + 3 + size(record[key], depth + 1) + 1;
|
|
38
|
+
if (!Number.isFinite(chars))
|
|
39
|
+
return NaN;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
seen.delete(value);
|
|
43
|
+
return chars;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const chars = size(payload, 0);
|
|
47
|
+
return Number.isFinite(chars) ? Math.ceil(chars / 4) : undefined;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Diagnostics must not turn an otherwise successful tool into a failure.
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export class ToolCallMetricsCollector {
|
|
55
|
+
active = new Map();
|
|
56
|
+
start(id, args, now = performance.now()) {
|
|
57
|
+
if (this.active.has(id))
|
|
58
|
+
return;
|
|
59
|
+
this.active.set(id, { startedAt: now, inputTokens: estimateToolPayloadTokens(args) });
|
|
60
|
+
}
|
|
61
|
+
finish(id, result, now = performance.now()) {
|
|
62
|
+
const started = this.active.get(id);
|
|
63
|
+
this.active.delete(id);
|
|
64
|
+
// Harness result metadata is not model-visible tool output.
|
|
65
|
+
const output = result && typeof result === "object" && "content" in result
|
|
66
|
+
? result.content : result;
|
|
67
|
+
return {
|
|
68
|
+
tokenBasis: "chars/4",
|
|
69
|
+
durationMs: started ? Math.max(0, now - started.startedAt) : undefined,
|
|
70
|
+
inputTokens: started?.inputTokens,
|
|
71
|
+
outputTokens: estimateToolPayloadTokens(output),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
clear() {
|
|
75
|
+
this.active.clear();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -626,6 +626,7 @@ function traceNodeFromEvent(piboSessionId, event, childByParent, linkedChildByTo
|
|
|
626
626
|
toolCallId: event.toolCallId,
|
|
627
627
|
toolInvocationOrdinal: event.toolInvocationOrdinal ?? 0,
|
|
628
628
|
intent: event.intent,
|
|
629
|
+
toolMetrics: event.type === "tool_execution_finished" ? event.toolMetrics : undefined,
|
|
629
630
|
type: subagentTool ? "agent.delegation" : "tool.call",
|
|
630
631
|
title: event.toolName,
|
|
631
632
|
status: event.type === "tool_execution_finished"
|
|
@@ -1102,6 +1103,7 @@ function thinkingEventNodeId(event) {
|
|
|
1102
1103
|
function mergeToolEvent(target, update) {
|
|
1103
1104
|
target.status = update.status;
|
|
1104
1105
|
target.intent = update.intent ?? target.intent;
|
|
1106
|
+
target.toolMetrics = update.toolMetrics ?? target.toolMetrics;
|
|
1105
1107
|
target.summary = update.summary ?? target.summary;
|
|
1106
1108
|
target.input = mergeDelegationInput(target, update);
|
|
1107
1109
|
target.output = update.output ?? target.output;
|
|
@@ -122,6 +122,7 @@ function storedEventFromStreamEvent(event, piboSessionId, nextSequence, now) {
|
|
|
122
122
|
toolName: event.toolName,
|
|
123
123
|
toolInvocationOrdinal: validOrdinal(event.toolInvocationOrdinal) ? event.toolInvocationOrdinal : undefined,
|
|
124
124
|
result: event.result,
|
|
125
|
+
toolMetrics: event.toolMetrics,
|
|
125
126
|
isError: Boolean(event.isError),
|
|
126
127
|
...(event.intent ? { intent: event.intent } : {}),
|
|
127
128
|
};
|
|
@@ -60,6 +60,10 @@ function traceNodeShallowEqual(left, right) {
|
|
|
60
60
|
left.startedAt === right.startedAt &&
|
|
61
61
|
left.completedAt === right.completedAt &&
|
|
62
62
|
left.durationMs === right.durationMs &&
|
|
63
|
+
left.toolMetrics?.durationMs === right.toolMetrics?.durationMs &&
|
|
64
|
+
left.toolMetrics?.inputTokens === right.toolMetrics?.inputTokens &&
|
|
65
|
+
left.toolMetrics?.outputTokens === right.toolMetrics?.outputTokens &&
|
|
66
|
+
left.toolMetrics?.tokenBasis === right.toolMetrics?.tokenBasis &&
|
|
63
67
|
left.summary === right.summary &&
|
|
64
68
|
left.input === right.input &&
|
|
65
69
|
left.output === right.output &&
|
|
@@ -33,14 +33,14 @@ export function getDelegatedAgentContextFile(subagents) {
|
|
|
33
33
|
"",
|
|
34
34
|
"pibo_run_wait({ runId, timeoutMs? }) # bounded wait only; expiry does not stop the child",
|
|
35
35
|
"pibo_run_status({ runId }) # compact lifecycle state",
|
|
36
|
-
"pibo_agents_observe({ requestIds?: [runId], textContains?, textRegex?, afterSequence?, limit?, includeTools?, toolDetail?, ... })",
|
|
36
|
+
"pibo_agents_observe({ requestIds?: [runId], cursorMode?: \"auto\"|\"history\", textContains?, textRegex?, afterSequence?, limit?, includeTools?, toolDetail?, ... })",
|
|
37
37
|
"pibo_run_read({ runId }) # terminal result, including the complete final agent message",
|
|
38
38
|
"pibo_run_cancel({ runId }) # explicit request cancellation",
|
|
39
39
|
"pibo_agents_list_agents({}) # available definitions and persistent child instances",
|
|
40
40
|
"pibo_agents_kill({ agentId }) # terminate one persistent child session subtree",
|
|
41
41
|
"```",
|
|
42
42
|
"",
|
|
43
|
-
"Set `sessionName` on every send to a nonblank human-readable child title of at most 40 Unicode code points. Pibo trims surrounding whitespace and rejects missing, blank, non-string, or oversized names before creating a yielded run or child session. Reuse a stable `threadKey` to continue the same child Pibo Session; a new `sessionName` updates its title without changing identity. A wait timeout
|
|
43
|
+
"Set `sessionName` on every send to a nonblank human-readable child title of at most 40 Unicode code points. Pibo trims surrounding whitespace and rejects missing, blank, non-string, or oversized names before creating a yielded run or child session. Reuse a stable `threadKey` to continue the same child Pibo Session; a new `sessionName` updates its title without changing identity. A wait timeout only wakes the orchestrator. Observe uses `cursorMode: \"auto\"` by default: the first equivalent query returns the newest completed assistant messages, and later calls return only unread messages. Use `cursorMode: \"history\"` only to reread earlier observations. Streaming deltas, duplicate tool progress events, and tools are hidden by default. Inspect tools only when a child stalls, reports an error, or needs targeted diagnosis; prefer exact `toolCallIds`, then `includeTools: true`, and use `toolDetail: \"full\"` only when summaries are insufficient. Use `textContains` for case-insensitive substring matching or `textRegex` for rg/Rust-regex matching; both must match when supplied together. Text, regex, identity, and event filters create separate automatic query cursors; an explicit `afterSequence` overrides and advances the matching automatic cursor.",
|
|
44
44
|
"",
|
|
45
45
|
"Observe progress and decide whether to continue waiting, steer through a new message after the current turn, cancel the request, or kill the child session.",
|
|
46
46
|
"",
|
|
@@ -1,6 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { PIBO_AGENT_OBSERVATION_DEFAULT_EVENT_TYPES, PIBO_AGENT_OBSERVATION_DEFAULT_TOOL_EVENT_TYPES, normalizePiboAgentObservationCursor, normalizePiboAgentObservationCursorMode, normalizePiboAgentObservationLimit, normalizePiboAgentObservationOrder, normalizePiboAgentObservationToolDetail, parsePiboAgentObservationTimestamp, piboAgentObservationKind, piboAgentObservationToolSummary, } from "./observations.js";
|
|
2
3
|
import { PIBO_AGENT_TEXT_REGEX_BATCH_MAX_ITEMS, PIBO_AGENT_TEXT_REGEX_BATCH_TARGET_BYTES, matchPiboAgentObservationTextRegex, preparePiboAgentObservationTextRegex, } from "./observation-text-regex.js";
|
|
4
|
+
function sortedUnique(values) {
|
|
5
|
+
return values ? [...new Set(values)].sort() : undefined;
|
|
6
|
+
}
|
|
7
|
+
export function piboAgentObservationCursorScopeKey(input) {
|
|
8
|
+
const scope = {
|
|
9
|
+
requestIds: sortedUnique(input.requestIds),
|
|
10
|
+
toolCallIds: sortedUnique(input.toolCallIds),
|
|
11
|
+
agentIds: sortedUnique(input.agentIds),
|
|
12
|
+
names: sortedUnique(input.names),
|
|
13
|
+
threadKeys: sortedUnique(input.threadKeys),
|
|
14
|
+
eventTypes: sortedUnique(input.eventTypes),
|
|
15
|
+
kinds: input.kinds ? [...new Set(input.kinds)].sort() : undefined,
|
|
16
|
+
roles: sortedUnique(input.roles),
|
|
17
|
+
since: input.since,
|
|
18
|
+
until: input.until,
|
|
19
|
+
textContains: input.textContains?.toLowerCase(),
|
|
20
|
+
textRegex: input.textRegex,
|
|
21
|
+
includeTools: input.includeTools === true,
|
|
22
|
+
toolDetail: input.toolDetail ?? "summary",
|
|
23
|
+
includeDetails: input.includeDetails === true,
|
|
24
|
+
};
|
|
25
|
+
return `v1:${createHash("sha256").update(JSON.stringify(scope)).digest("hex")}`;
|
|
26
|
+
}
|
|
3
27
|
export function preparePiboAgentObservationQuery(input = {}) {
|
|
28
|
+
const cursorMode = normalizePiboAgentObservationCursorMode(input.cursorMode);
|
|
4
29
|
const order = normalizePiboAgentObservationOrder(input.order);
|
|
5
30
|
const limit = normalizePiboAgentObservationLimit(input.limit);
|
|
6
31
|
const toolDetail = normalizePiboAgentObservationToolDetail(input.toolDetail);
|
|
@@ -40,6 +65,7 @@ export function preparePiboAgentObservationQuery(input = {}) {
|
|
|
40
65
|
return {
|
|
41
66
|
filters: {
|
|
42
67
|
...input,
|
|
68
|
+
cursorMode,
|
|
43
69
|
...(defaultMessageView ? { eventTypes: defaultEventTypes } : {}),
|
|
44
70
|
...(afterSequence !== undefined ? { afterSequence } : {}),
|
|
45
71
|
order,
|
|
@@ -49,6 +75,7 @@ export function preparePiboAgentObservationQuery(input = {}) {
|
|
|
49
75
|
includeDetails: input.includeDetails === true,
|
|
50
76
|
},
|
|
51
77
|
...(afterSequence !== undefined ? { afterSequence } : {}),
|
|
78
|
+
cursorMode,
|
|
52
79
|
order,
|
|
53
80
|
scanOrder: afterSequence !== undefined ? "asc" : order,
|
|
54
81
|
limit,
|
|
@@ -212,6 +212,14 @@ export function normalizePiboAgentObservationOrder(value) {
|
|
|
212
212
|
throw new Error(`Agent observation order must be "asc" or "desc".`);
|
|
213
213
|
return value;
|
|
214
214
|
}
|
|
215
|
+
export function normalizePiboAgentObservationCursorMode(value) {
|
|
216
|
+
if (value === undefined)
|
|
217
|
+
return "auto";
|
|
218
|
+
if (value !== "auto" && value !== "history") {
|
|
219
|
+
throw new Error(`Agent observation cursorMode must be "auto" or "history".`);
|
|
220
|
+
}
|
|
221
|
+
return value;
|
|
222
|
+
}
|
|
215
223
|
export function normalizePiboAgentObservationToolDetail(value) {
|
|
216
224
|
if (value === undefined)
|
|
217
225
|
return "summary";
|
package/dist/subagents/tool.js
CHANGED
|
@@ -60,12 +60,15 @@ function preparePiboDeprecatedSubagentToolInput(input) {
|
|
|
60
60
|
export function formatAgentObservationsForModel(result) {
|
|
61
61
|
const includeTools = result.filters.includeTools === true;
|
|
62
62
|
const toolDetail = result.filters.toolDetail ?? "summary";
|
|
63
|
+
const cursorMode = result.filters.cursorMode ?? "auto";
|
|
63
64
|
const lines = [
|
|
64
|
-
`Agent observations (${result.observations.length}; tools=${includeTools ? toolDetail : "hidden"}; order=${result.filters.order ?? "desc"}; limit=${result.filters.limit ?? 20})`,
|
|
65
|
-
`nextAfterSequence=${result.nextAfterSequence}; truncated=${result.truncated}`,
|
|
65
|
+
`Agent observations (${result.observations.length}; cursor=${cursorMode}; tools=${includeTools ? toolDetail : "hidden"}; order=${result.filters.order ?? "desc"}; limit=${result.filters.limit ?? 20})`,
|
|
66
|
+
`afterSequence=${result.filters.afterSequence ?? "initial"}; nextAfterSequence=${result.nextAfterSequence}${result.autoCursorSequence === undefined ? "" : `; autoCursorSequence=${result.autoCursorSequence}`}; truncated=${result.truncated}`,
|
|
66
67
|
];
|
|
67
68
|
if (result.observations.length === 0) {
|
|
68
|
-
lines.push("",
|
|
69
|
+
lines.push("", cursorMode === "auto"
|
|
70
|
+
? "No new delegated-agent messages matched since the automatic cursor. Use cursorMode=\"history\" only when you need to reread earlier observations."
|
|
71
|
+
: "No historical delegated-agent observations matched the filters.");
|
|
69
72
|
return lines.join("\n");
|
|
70
73
|
}
|
|
71
74
|
for (const observation of result.observations) {
|
|
@@ -188,10 +191,10 @@ export function createAgentToolDefinitions(subagents, controller) {
|
|
|
188
191
|
title: "Pibo Agents Observe",
|
|
189
192
|
description: [
|
|
190
193
|
"Read completed delegated-agent messages with bounded cursor, identity, event, time, substring, regex, order, and limit filters.",
|
|
191
|
-
"Default: the newest 20 completed assistant messages
|
|
192
|
-
"
|
|
194
|
+
"Default cursorMode=auto: the first equivalent query returns the newest 20 completed assistant messages; later calls return only unread messages. Streaming deltas, duplicate tool progress events, and tools stay hidden.",
|
|
195
|
+
"Use cursorMode=history only to reread earlier observations. Inspect tools only when an agent appears stuck, reports a problem, or needs targeted diagnosis; prefer exact toolCallIds, then includeTools=true, and use toolDetail=full only when compact summaries are insufficient.",
|
|
193
196
|
].join("\n"),
|
|
194
|
-
promptSnippet: "Observe child
|
|
197
|
+
promptSnippet: "Observe child progress through completed assistant messages. cursorMode=auto is the default and remembers each equivalent query, so repeated calls return only unread messages; use cursorMode=history to reread earlier observations. Streaming deltas, duplicate tool progress events, and tools are hidden by default. Inspect tools only for stalls, errors, or targeted diagnosis: prefer exact toolCallIds, use includeTools=true only when broader context is needed, and use toolDetail=full only when summaries are insufficient. Use textContains or textRegex for focused matching; different filters use separate automatic cursors. An explicit afterSequence overrides the stored cursor and advances that automatic query cursor.",
|
|
195
198
|
executionMode: "parallel",
|
|
196
199
|
annotations: { readOnly: true },
|
|
197
200
|
inputSchema: Type.Object({
|
|
@@ -207,10 +210,11 @@ export function createAgentToolDefinitions(subagents, controller) {
|
|
|
207
210
|
until: Type.Optional(Type.String({ description: "Inclusive ISO-8601 upper timestamp bound" })),
|
|
208
211
|
textContains: Type.Optional(Type.String({ description: "Case-insensitive substring match against normalized observation text" })),
|
|
209
212
|
textRegex: Type.Optional(Type.String({ description: "Case-sensitive rg/Rust-regex match against normalized observation text. Use inline flags such as (?i) to change case behavior. Combines with textContains using AND semantics. NUL text and literal or escaped NUL patterns are rejected; regex use requires the optional rg platform binary." })),
|
|
210
|
-
|
|
213
|
+
cursorMode: Type.Optional(piboStringEnum(["auto", "history"], { default: "auto", description: "auto remembers this normalized query and returns only unread observations after its first newest-message snapshot. history ignores and does not change the saved cursor, allowing deliberate rereads." })),
|
|
214
|
+
afterSequence: Type.Optional(Type.Integer({ description: "Explicit exclusive cursor override. In auto mode it replaces and advances the saved cursor for this normalized query; cursor pages consume the oldest unseen matches and desc reverses only the returned page.", minimum: 0 })),
|
|
211
215
|
order: Type.Optional(piboStringEnum(["asc", "desc"], { default: "desc", description: "Newest first by default when no cursor is supplied" })),
|
|
212
216
|
limit: Type.Optional(Type.Integer({ description: "Maximum completed messages or activity records to return. Use 50 explicitly when needed.", minimum: 1, maximum: 200, default: 20 })),
|
|
213
|
-
includeTools: Type.Optional(Type.Boolean({ description: "Include
|
|
217
|
+
includeTools: Type.Optional(Type.Boolean({ description: "Include compact tool calls and terminal results. Default false; enable only for stalls, errors, or targeted diagnosis. Prefer exact toolCallIds when known.", default: false })),
|
|
214
218
|
toolDetail: Type.Optional(piboStringEnum(["summary", "full"], { default: "summary", description: "Tool text detail when tools are included. summary is compact; full remains bounded to the observation text limit." })),
|
|
215
219
|
includeDetails: Type.Optional(Type.Boolean({ description: "Include the normalized source event in structured details. Default false; use only for diagnostics.", default: false })),
|
|
216
220
|
}),
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pasko70/pibo",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@pasko70/pibo",
|
|
9
|
-
"version": "3.4.
|
|
9
|
+
"version": "3.4.2",
|
|
10
10
|
"workspaces": [
|
|
11
11
|
"packages/workflows"
|
|
12
12
|
],
|