@pasko70/pibo 3.0.0 → 3.0.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/README.md +20 -6
- package/dist/agent-runtime/context-build.js +26 -2
- package/dist/agent-runtime/routed-session.js +108 -9
- package/dist/agent-runtimes/codex-native/adapter.js +12 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +35 -7
- package/dist/agent-runtimes/omp/adapter.js +3 -7
- package/dist/agent-runtimes/pi/adapter.js +5 -3
- package/dist/agent-runtimes/pi/routed-session.js +49 -8
- package/dist/agent-runtimes/pi/runtime.js +6 -0
- package/dist/apps/chat/agent-profiles.js +31 -2
- package/dist/apps/chat/agent-store.js +43 -3
- package/dist/apps/chat/chat-request-normalizers.js +31 -0
- package/dist/apps/chat/data/chat-data-mappers.js +61 -11
- package/dist/apps/chat/data/session-query-service.js +33 -10
- package/dist/apps/chat/data/timeline-query-service.js +60 -35
- package/dist/apps/chat/output-compactor.js +144 -21
- package/dist/apps/chat/output-event-policy.js +179 -2
- package/dist/apps/chat/stream.js +16 -7
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/web-app.js +236 -64
- package/dist/apps/chat-ui/assets/{dist-BBDMeU5-.js → dist-B6GZgWSj.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-mqCviI-c.js → dist-BPotHecb.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-JnW4v8UE.js → dist-BzqQKeVO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BDIATCQt.js → dist-CvaPTBTN.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-lRiLP9rr.js → dist-paagejNj.js} +1 -1
- package/dist/apps/chat-ui/assets/index-6JJV-eic.js +228 -0
- package/dist/apps/chat-ui/assets/index-CeL9JPP5.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/{index-Dtw2Z7jz.js → index-U-MSErGa.js} +4 -4
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/cli-ui/cliSessionsCommand.js +34 -8
- package/dist/cli-session/localSessionSource.js +153 -161
- package/dist/cli.js +7 -11
- package/dist/core/context-build.js +7 -16
- package/dist/core/output-persistence-retry.js +484 -0
- package/dist/core/output-render-sequence.js +331 -0
- package/dist/core/profiles.js +24 -0
- package/dist/core/provider-recovery.js +7 -1
- package/dist/core/session-model.js +37 -1
- package/dist/core/session-router.js +67 -20
- package/dist/data/ingest-service.js +91 -9
- package/dist/data/navigation-store.js +5 -5
- package/dist/data/schema.js +122 -2
- package/dist/data/session-store.js +3 -3
- package/dist/debug/index.js +44 -2
- package/dist/gateway/web.js +8 -8
- package/dist/local/client.js +3 -2
- package/dist/plugins/context-files-store.js +30 -0
- package/dist/plugins/context-files.js +52 -1
- package/dist/plugins/registry.js +2 -0
- package/dist/plugins/user-profile-resources.js +22 -0
- package/dist/reliability/store.js +246 -37
- package/dist/session-ui/terminalRows.js +6 -3
- package/dist/sessions/pibo-data-store.js +145 -0
- package/dist/sessions/store.js +42 -0
- package/dist/setup/cli.js +422 -6
- package/dist/setup/installation-profiles.js +464 -0
- package/dist/shared/deterministic-digest.js +94 -0
- package/dist/shared/trace-engine.js +54 -0
- package/dist/shared/trace-event-projection.js +124 -67
- package/dist/shared/trace-history.js +47 -12
- package/dist/shared/trace-live-reducer.js +23 -4
- package/dist/shared/trace-nodes.js +17 -28
- package/dist/shared/trace-order.js +41 -5
- package/dist/shared/trace-page-merge.js +44 -14
- package/dist/shared/trace-patch-nodes.js +2 -0
- package/dist/shared/trace-subagent-links.js +4 -1
- package/dist/shared/trace-tool-identity.js +15 -8
- package/dist/signals/projector.js +28 -6
- package/dist/subagents/tool.js +7 -3
- package/docs/ops/vscode-extension-release.md +9 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
- package/dist/apps/chat-ui/assets/index-0XOOVxLP.js +0 -228
- package/dist/apps/chat-ui/assets/index-DV7_CgsC.css +0 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-3.0.0.vsix +0 -0
|
@@ -79,6 +79,7 @@ function storedEventFromStreamEvent(event, piboSessionId, nextSequence, now) {
|
|
|
79
79
|
eventId: typeof event.runId === "string" ? event.runId : undefined,
|
|
80
80
|
toolCallId: event.toolCallId,
|
|
81
81
|
toolName: event.toolName,
|
|
82
|
+
toolInvocationOrdinal: validOrdinal(event.toolInvocationOrdinal) ? event.toolInvocationOrdinal : undefined,
|
|
82
83
|
args: event.args,
|
|
83
84
|
...(event.intent ? { intent: event.intent } : {}),
|
|
84
85
|
};
|
|
@@ -94,6 +95,7 @@ function storedEventFromStreamEvent(event, piboSessionId, nextSequence, now) {
|
|
|
94
95
|
eventId,
|
|
95
96
|
toolCallId: event.toolCallId,
|
|
96
97
|
toolName: event.toolName,
|
|
98
|
+
toolInvocationOrdinal: validOrdinal(event.toolInvocationOrdinal) ? event.toolInvocationOrdinal : undefined,
|
|
97
99
|
args: event.args,
|
|
98
100
|
partialResult: event.partialResult,
|
|
99
101
|
...(event.intent ? { intent: event.intent } : {}),
|
|
@@ -104,6 +106,7 @@ function storedEventFromStreamEvent(event, piboSessionId, nextSequence, now) {
|
|
|
104
106
|
eventId,
|
|
105
107
|
toolCallId: event.toolCallId,
|
|
106
108
|
toolName: event.toolName,
|
|
109
|
+
toolInvocationOrdinal: validOrdinal(event.toolInvocationOrdinal) ? event.toolInvocationOrdinal : undefined,
|
|
107
110
|
args: event.args,
|
|
108
111
|
argsComplete: Boolean(event.argsComplete),
|
|
109
112
|
...(event.intent ? { intent: event.intent } : {}),
|
|
@@ -117,6 +120,7 @@ function storedEventFromStreamEvent(event, piboSessionId, nextSequence, now) {
|
|
|
117
120
|
eventId: typeof event.runId === "string" ? event.runId : undefined,
|
|
118
121
|
toolCallId: event.toolCallId,
|
|
119
122
|
toolName: event.toolName,
|
|
123
|
+
toolInvocationOrdinal: validOrdinal(event.toolInvocationOrdinal) ? event.toolInvocationOrdinal : undefined,
|
|
120
124
|
result: event.result,
|
|
121
125
|
isError: Boolean(event.isError),
|
|
122
126
|
...(event.intent ? { intent: event.intent } : {}),
|
|
@@ -140,6 +144,12 @@ function makeStored(streamEvent, piboSessionId, type, payload, nextSequence, now
|
|
|
140
144
|
const streamFrameIndex = typeof streamEvent.streamFrameIndex === "number" ? streamEvent.streamFrameIndex : undefined;
|
|
141
145
|
const liveReplayId = typeof streamEvent.liveReplayId === "number" && Number.isFinite(streamEvent.liveReplayId) ? streamEvent.liveReplayId : undefined;
|
|
142
146
|
const sequence = nextSequence();
|
|
147
|
+
const renderSequence = validSequence(streamEvent.renderSequence)
|
|
148
|
+
? streamEvent.renderSequence
|
|
149
|
+
: validSequence(payload.renderSequence) ? payload.renderSequence : undefined;
|
|
150
|
+
const positionedPayload = renderSequence !== undefined && payload.renderSequence === undefined
|
|
151
|
+
? { ...payload, renderSequence }
|
|
152
|
+
: payload;
|
|
143
153
|
return {
|
|
144
154
|
id: typeof streamEvent.streamId === "number"
|
|
145
155
|
? `stream:${streamEvent.streamId}:${streamFrameIndex ?? "raw"}:${type}`
|
|
@@ -150,15 +160,22 @@ function makeStored(streamEvent, piboSessionId, type, payload, nextSequence, now
|
|
|
150
160
|
: `live:${sequence}:${type}`,
|
|
151
161
|
piboSessionId,
|
|
152
162
|
eventSequence: sequence,
|
|
163
|
+
renderSequence,
|
|
153
164
|
streamId: typeof streamEvent.streamId === "number" ? streamEvent.streamId : undefined,
|
|
154
165
|
streamFrameIndex,
|
|
155
166
|
traceSource: "live",
|
|
156
|
-
eventId: typeof
|
|
167
|
+
eventId: typeof positionedPayload.eventId === "string" ? positionedPayload.eventId : undefined,
|
|
157
168
|
type,
|
|
158
169
|
createdAt: streamEventCreatedAt(streamEvent) ?? now(),
|
|
159
|
-
payload,
|
|
170
|
+
payload: positionedPayload,
|
|
160
171
|
};
|
|
161
172
|
}
|
|
173
|
+
function validSequence(value) {
|
|
174
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
175
|
+
}
|
|
176
|
+
function validOrdinal(value) {
|
|
177
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
178
|
+
}
|
|
162
179
|
function streamEventCreatedAt(event) {
|
|
163
180
|
if (typeof event.createdAt !== "string" || !Number.isFinite(Date.parse(event.createdAt)))
|
|
164
181
|
return undefined;
|
|
@@ -180,8 +197,10 @@ function eventGroupKey(event) {
|
|
|
180
197
|
const payload = isRecord(event.payload) ? event.payload : {};
|
|
181
198
|
const piboSessionId = typeof payload.piboSessionId === "string" ? payload.piboSessionId : event.piboSessionId ?? "";
|
|
182
199
|
const eventId = typeof payload.eventId === "string" ? payload.eventId : event.eventId ?? "";
|
|
183
|
-
if (typeof payload.toolCallId === "string")
|
|
184
|
-
|
|
200
|
+
if (typeof payload.toolCallId === "string") {
|
|
201
|
+
const ordinal = typeof payload.toolInvocationOrdinal === "number" ? payload.toolInvocationOrdinal : 0;
|
|
202
|
+
return `${piboSessionId}:${eventId}:tool:${payload.toolCallId}:${ordinal}`;
|
|
203
|
+
}
|
|
185
204
|
const assistantIndex = typeof payload.assistantIndex === "number" ? payload.assistantIndex : undefined;
|
|
186
205
|
const thinkingIndex = typeof payload.thinkingIndex === "number" ? payload.thinkingIndex : undefined;
|
|
187
206
|
const contentIndex = typeof payload.contentIndex === "number" ? payload.contentIndex : 0;
|
|
@@ -19,41 +19,30 @@ function areTraceNodesSorted(nodes) {
|
|
|
19
19
|
return true;
|
|
20
20
|
}
|
|
21
21
|
export function compareTraceNodes(left, right) {
|
|
22
|
-
if (left.orderKey && right.orderKey
|
|
23
|
-
|
|
24
|
-
if (bySameSourceOrder !== 0)
|
|
25
|
-
return bySameSourceOrder;
|
|
22
|
+
if (!left.orderKey && !right.orderKey) {
|
|
23
|
+
return compareLegacyNodeFallback(left, right);
|
|
26
24
|
}
|
|
27
|
-
else {
|
|
28
|
-
const bySameTurnPhase = compareSameTurnPhase(left, right);
|
|
29
|
-
if (bySameTurnPhase !== 0)
|
|
30
|
-
return bySameTurnPhase;
|
|
31
|
-
}
|
|
32
|
-
const byStartTime = compareOptionalIsoTime(left.startedAt, right.startedAt);
|
|
33
|
-
if (byStartTime !== 0)
|
|
34
|
-
return byStartTime;
|
|
35
25
|
const byOrder = compareTraceOrder(left.orderKey, right.orderKey);
|
|
36
26
|
if (byOrder !== 0)
|
|
37
27
|
return byOrder;
|
|
38
28
|
return left.id.localeCompare(right.id);
|
|
39
29
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
30
|
+
function compareLegacyNodeFallback(left, right) {
|
|
31
|
+
const leftTime = validIsoTime(left.startedAt);
|
|
32
|
+
const rightTime = validIsoTime(right.startedAt);
|
|
33
|
+
if (leftTime !== rightTime) {
|
|
34
|
+
if (leftTime === undefined)
|
|
35
|
+
return 1;
|
|
36
|
+
if (rightTime === undefined)
|
|
37
|
+
return -1;
|
|
38
|
+
const byTime = leftTime.localeCompare(rightTime);
|
|
39
|
+
if (byTime !== 0)
|
|
40
|
+
return byTime;
|
|
41
|
+
}
|
|
42
|
+
return left.id.localeCompare(right.id);
|
|
48
43
|
}
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
return 0;
|
|
52
|
-
if (!left)
|
|
53
|
-
return 1;
|
|
54
|
-
if (!right)
|
|
55
|
-
return -1;
|
|
56
|
-
return left.localeCompare(right);
|
|
44
|
+
function validIsoTime(value) {
|
|
45
|
+
return value !== undefined && Number.isFinite(Date.parse(value)) ? value : undefined;
|
|
57
46
|
}
|
|
58
47
|
export function flattenTraceNodes(nodes) {
|
|
59
48
|
const flattened = [];
|
|
@@ -18,12 +18,14 @@ export const TRACE_PHASE_RANK = {
|
|
|
18
18
|
"assistant.message": 8,
|
|
19
19
|
error: 9,
|
|
20
20
|
};
|
|
21
|
-
export function historyTraceOrder(historyIndex, contentPartIndex, type, source) {
|
|
21
|
+
export function historyTraceOrder(historyIndex, contentPartIndex, type, source, createdAt) {
|
|
22
22
|
return {
|
|
23
23
|
sourceRank: TRACE_SOURCE_RANK[source],
|
|
24
24
|
turnSeq: historyIndex,
|
|
25
25
|
transcriptIndex: historyIndex,
|
|
26
|
+
eventSequence: source === "product-history" ? historyIndex : undefined,
|
|
26
27
|
contentPartIndex,
|
|
28
|
+
chronologyMs: parseChronologyMs(createdAt),
|
|
27
29
|
phaseRank: TRACE_PHASE_RANK[type],
|
|
28
30
|
};
|
|
29
31
|
}
|
|
@@ -78,12 +80,46 @@ export function compareTraceOrder(left, right) {
|
|
|
78
80
|
return 1;
|
|
79
81
|
if (!right)
|
|
80
82
|
return -1;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
const leftPosition = canonicalTracePosition(left);
|
|
84
|
+
const rightPosition = canonicalTracePosition(right);
|
|
85
|
+
return (compareOptionalChronology(left.chronologyMs, right.chronologyMs) ||
|
|
86
|
+
leftPosition - rightPosition ||
|
|
87
|
+
left.phaseRank - right.phaseRank ||
|
|
88
|
+
(left.contentPartIndex ?? 0) - (right.contentPartIndex ?? 0) ||
|
|
89
|
+
left.sourceRank - right.sourceRank ||
|
|
83
90
|
(left.transcriptIndex ?? Number.MAX_SAFE_INTEGER) - (right.transcriptIndex ?? Number.MAX_SAFE_INTEGER) ||
|
|
84
91
|
(left.eventSequence ?? Number.MAX_SAFE_INTEGER) - (right.eventSequence ?? Number.MAX_SAFE_INTEGER) ||
|
|
92
|
+
(left.renderSequence ?? Number.MAX_SAFE_INTEGER) - (right.renderSequence ?? Number.MAX_SAFE_INTEGER) ||
|
|
85
93
|
(left.streamId ?? Number.MAX_SAFE_INTEGER) - (right.streamId ?? Number.MAX_SAFE_INTEGER) ||
|
|
86
94
|
(left.streamFrameIndex ?? Number.MAX_SAFE_INTEGER) - (right.streamFrameIndex ?? Number.MAX_SAFE_INTEGER) ||
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
left.turnSeq - right.turnSeq);
|
|
96
|
+
}
|
|
97
|
+
function parseChronologyMs(value) {
|
|
98
|
+
if (!value)
|
|
99
|
+
return undefined;
|
|
100
|
+
const parsed = Date.parse(value);
|
|
101
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
102
|
+
}
|
|
103
|
+
function compareOptionalChronology(left, right) {
|
|
104
|
+
if (left === right)
|
|
105
|
+
return 0;
|
|
106
|
+
if (left === undefined)
|
|
107
|
+
return 1;
|
|
108
|
+
if (right === undefined)
|
|
109
|
+
return -1;
|
|
110
|
+
return left - right;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* chronologyMs is the common cross-source domain; renderSequence supplies its
|
|
114
|
+
* immutable first-visible time for modern stream segments. This canonical
|
|
115
|
+
* position is the deterministic tie-break domain for equal/missing chronology.
|
|
116
|
+
* The comparator never selects a field based on the other operand, keeping the
|
|
117
|
+
* relation total and transitive.
|
|
118
|
+
*/
|
|
119
|
+
function canonicalTracePosition(order) {
|
|
120
|
+
return order.renderSequence
|
|
121
|
+
?? order.eventSequence
|
|
122
|
+
?? order.transcriptIndex
|
|
123
|
+
?? order.streamId
|
|
124
|
+
?? order.turnSeq;
|
|
89
125
|
}
|
|
@@ -3,14 +3,7 @@ import { compareTraceOrder } from "./trace-order.js";
|
|
|
3
3
|
export function mergeOlderTracePage(current, older) {
|
|
4
4
|
if (current.piboSessionId !== older.piboSessionId)
|
|
5
5
|
return current;
|
|
6
|
-
const
|
|
7
|
-
const rawEvents = [...older.rawEvents, ...current.rawEvents].filter((event) => {
|
|
8
|
-
const key = event.id || `${event.eventSequence ?? ""}:${event.type}:${event.createdAt}`;
|
|
9
|
-
if (seenRawEvents.has(key))
|
|
10
|
-
return false;
|
|
11
|
-
seenRawEvents.add(key);
|
|
12
|
-
return true;
|
|
13
|
-
});
|
|
6
|
+
const rawEvents = mergeTraceRawEvents(older.rawEvents, current.rawEvents, false);
|
|
14
7
|
return {
|
|
15
8
|
...current,
|
|
16
9
|
version: current.version,
|
|
@@ -30,7 +23,7 @@ export function mergeRefreshedTracePage(current, refreshed) {
|
|
|
30
23
|
return {
|
|
31
24
|
...refreshed,
|
|
32
25
|
nodes: mergeRefreshedTraceNodes(current.nodes, refreshed),
|
|
33
|
-
rawEvents: mergeTraceRawEvents(current.rawEvents, refreshed.rawEvents),
|
|
26
|
+
rawEvents: mergeTraceRawEvents(current.rawEvents, refreshed.rawEvents, true),
|
|
34
27
|
beforeCursor: current.beforeCursor,
|
|
35
28
|
firstEventSequence: current.firstEventSequence ?? refreshed.firstEventSequence,
|
|
36
29
|
nextBeforeSequence: current.nextBeforeSequence,
|
|
@@ -121,14 +114,14 @@ function parseTimestamp(value) {
|
|
|
121
114
|
const parsed = Date.parse(value);
|
|
122
115
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
123
116
|
}
|
|
124
|
-
function mergeTraceRawEvents(currentEvents, refreshedEvents) {
|
|
117
|
+
function mergeTraceRawEvents(currentEvents, refreshedEvents, replaceCoveredTail) {
|
|
125
118
|
if (!refreshedEvents.length)
|
|
126
|
-
return currentEvents;
|
|
127
|
-
const firstRefreshedSequence = refreshedEvents.reduce((first, event) => {
|
|
119
|
+
return [...currentEvents].sort(compareTraceRawEvents);
|
|
120
|
+
const firstRefreshedSequence = replaceCoveredTail ? refreshedEvents.reduce((first, event) => {
|
|
128
121
|
if (event.eventSequence === undefined)
|
|
129
122
|
return first;
|
|
130
123
|
return first === undefined ? event.eventSequence : Math.min(first, event.eventSequence);
|
|
131
|
-
}, undefined);
|
|
124
|
+
}, undefined) : undefined;
|
|
132
125
|
const byKey = new Map();
|
|
133
126
|
for (const event of currentEvents) {
|
|
134
127
|
if (firstRefreshedSequence !== undefined && event.eventSequence !== undefined && event.eventSequence >= firstRefreshedSequence)
|
|
@@ -137,7 +130,44 @@ function mergeTraceRawEvents(currentEvents, refreshedEvents) {
|
|
|
137
130
|
}
|
|
138
131
|
for (const event of refreshedEvents)
|
|
139
132
|
byKey.set(traceRawEventKey(event), event);
|
|
140
|
-
return [...byKey.values()];
|
|
133
|
+
return [...byKey.values()].sort(compareTraceRawEvents);
|
|
134
|
+
}
|
|
135
|
+
function compareTraceRawEvents(left, right) {
|
|
136
|
+
const leftSequenceDomain = left.eventSequence === undefined ? 0 : 1;
|
|
137
|
+
const rightSequenceDomain = right.eventSequence === undefined ? 0 : 1;
|
|
138
|
+
return leftSequenceDomain - rightSequenceDomain
|
|
139
|
+
|| (left.eventSequence !== undefined && right.eventSequence !== undefined
|
|
140
|
+
? left.eventSequence - right.eventSequence
|
|
141
|
+
: 0)
|
|
142
|
+
|| compareOptionalString(validTimestamp(left.createdAt), validTimestamp(right.createdAt))
|
|
143
|
+
|| compareOptionalNumber(left.streamId, right.streamId)
|
|
144
|
+
|| compareOptionalNumber(left.streamFrameIndex, right.streamFrameIndex)
|
|
145
|
+
|| (left.eventSequence === undefined && right.eventSequence === undefined
|
|
146
|
+
? compareOptionalNumber(left.renderSequence, right.renderSequence)
|
|
147
|
+
: 0)
|
|
148
|
+
|| left.id.localeCompare(right.id)
|
|
149
|
+
|| left.type.localeCompare(right.type);
|
|
150
|
+
}
|
|
151
|
+
function compareOptionalNumber(left, right) {
|
|
152
|
+
if (left === right)
|
|
153
|
+
return 0;
|
|
154
|
+
if (left === undefined)
|
|
155
|
+
return 1;
|
|
156
|
+
if (right === undefined)
|
|
157
|
+
return -1;
|
|
158
|
+
return left - right;
|
|
159
|
+
}
|
|
160
|
+
function compareOptionalString(left, right) {
|
|
161
|
+
if (left === right)
|
|
162
|
+
return 0;
|
|
163
|
+
if (left === undefined)
|
|
164
|
+
return 1;
|
|
165
|
+
if (right === undefined)
|
|
166
|
+
return -1;
|
|
167
|
+
return left.localeCompare(right);
|
|
168
|
+
}
|
|
169
|
+
function validTimestamp(value) {
|
|
170
|
+
return Number.isFinite(Date.parse(value)) ? value : undefined;
|
|
141
171
|
}
|
|
142
172
|
function traceRawEventKey(event) {
|
|
143
173
|
return event.id || `${event.eventSequence ?? ""}:${event.type}:${event.createdAt}`;
|
|
@@ -51,6 +51,7 @@ function traceNodeShallowEqual(left, right) {
|
|
|
51
51
|
left.piboSessionId === right.piboSessionId &&
|
|
52
52
|
left.eventId === right.eventId &&
|
|
53
53
|
left.toolCallId === right.toolCallId &&
|
|
54
|
+
left.toolInvocationOrdinal === right.toolInvocationOrdinal &&
|
|
54
55
|
left.runId === right.runId &&
|
|
55
56
|
left.intent === right.intent &&
|
|
56
57
|
left.type === right.type &&
|
|
@@ -75,6 +76,7 @@ function traceOrderKeyEqual(left, right) {
|
|
|
75
76
|
return false;
|
|
76
77
|
return (left.sourceRank === right.sourceRank &&
|
|
77
78
|
left.turnSeq === right.turnSeq &&
|
|
79
|
+
left.renderSequence === right.renderSequence &&
|
|
78
80
|
left.transcriptIndex === right.transcriptIndex &&
|
|
79
81
|
left.contentPartIndex === right.contentPartIndex &&
|
|
80
82
|
left.eventSequence === right.eventSequence &&
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { qualifiedToolNodeId } from "./trace-tool-identity.js";
|
|
1
2
|
export function mapTraceChildSessionsByParent(sessions) {
|
|
2
3
|
const result = new Map();
|
|
3
4
|
for (const session of sessions) {
|
|
@@ -15,7 +16,9 @@ export function mapTraceSubagentSessionLinks(events) {
|
|
|
15
16
|
const event = storedEvent.payload;
|
|
16
17
|
if (event.type !== "subagent_session" || !event.toolCallId)
|
|
17
18
|
continue;
|
|
18
|
-
|
|
19
|
+
const eventId = event.eventId
|
|
20
|
+
?? (event.renderSequence !== undefined ? `render:${event.renderSequence}` : "unscoped");
|
|
21
|
+
result.set(qualifiedToolNodeId(event.toolCallId, eventId, event.toolInvocationOrdinal ?? 0), event.childPiboSessionId);
|
|
19
22
|
}
|
|
20
23
|
return result;
|
|
21
24
|
}
|
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
1
|
+
const QUALIFIED_TOOL_PREFIX = "tool-invocation:";
|
|
2
|
+
const LEGACY_QUALIFIED_TOOL_PREFIX = "history-tool:";
|
|
3
3
|
const TOOL_PREFIX = "tool:";
|
|
4
4
|
const TOOL_INVOCATION_TAG = "event-tool";
|
|
5
|
-
export function
|
|
5
|
+
export function qualifiedToolNodeId(toolCallId, eventId, invocationOrdinal) {
|
|
6
6
|
const projectionIdentity = JSON.stringify([TOOL_INVOCATION_TAG, eventId, invocationOrdinal]);
|
|
7
7
|
return `${QUALIFIED_TOOL_PREFIX}${encodeURIComponent(JSON.stringify([toolCallId, projectionIdentity]))}`;
|
|
8
8
|
}
|
|
9
|
+
/** @deprecated Use qualifiedToolNodeId for every projection source. */
|
|
10
|
+
export const qualifiedHistoryToolNodeId = qualifiedToolNodeId;
|
|
9
11
|
export function parseTraceToolNodeIdentity(nodeId) {
|
|
10
12
|
if (nodeId.startsWith(TOOL_PREFIX)) {
|
|
11
13
|
const toolCallId = nodeId.slice(TOOL_PREFIX.length);
|
|
12
14
|
return toolCallId ? { toolCallId } : undefined;
|
|
13
15
|
}
|
|
14
|
-
|
|
16
|
+
const qualifiedPrefix = nodeId.startsWith(QUALIFIED_TOOL_PREFIX)
|
|
17
|
+
? QUALIFIED_TOOL_PREFIX
|
|
18
|
+
: nodeId.startsWith(LEGACY_QUALIFIED_TOOL_PREFIX) ? LEGACY_QUALIFIED_TOOL_PREFIX : undefined;
|
|
19
|
+
if (!qualifiedPrefix)
|
|
15
20
|
return undefined;
|
|
16
21
|
try {
|
|
17
|
-
const decoded = JSON.parse(decodeURIComponent(nodeId.slice(
|
|
22
|
+
const decoded = JSON.parse(decodeURIComponent(nodeId.slice(qualifiedPrefix.length)));
|
|
18
23
|
if (!Array.isArray(decoded)
|
|
19
24
|
|| decoded.length !== 2
|
|
20
25
|
|| typeof decoded[0] !== "string"
|
|
@@ -28,14 +33,16 @@ export function parseTraceToolNodeIdentity(nodeId) {
|
|
|
28
33
|
|| typeof qualifier[1] !== "string"
|
|
29
34
|
|| qualifier[1].length === 0
|
|
30
35
|
|| !Number.isSafeInteger(qualifier[2])
|
|
31
|
-
|| Number(qualifier[2]) < 0
|
|
32
|
-
|| Number(qualifier[2]) >= TRACE_RECONCILIATION_ENTRY_CAP)
|
|
36
|
+
|| Number(qualifier[2]) < 0)
|
|
33
37
|
return undefined;
|
|
34
38
|
const identity = {
|
|
35
39
|
toolCallId: decoded[0],
|
|
36
40
|
qualifier: { eventId: qualifier[1], invocationOrdinal: Number(qualifier[2]) },
|
|
37
41
|
};
|
|
38
|
-
|
|
42
|
+
const canonicalId = qualifiedToolNodeId(identity.toolCallId, identity.qualifier.eventId, identity.qualifier.invocationOrdinal);
|
|
43
|
+
return canonicalId === nodeId || canonicalId.replace(QUALIFIED_TOOL_PREFIX, LEGACY_QUALIFIED_TOOL_PREFIX) === nodeId
|
|
44
|
+
? identity
|
|
45
|
+
: undefined;
|
|
39
46
|
}
|
|
40
47
|
catch {
|
|
41
48
|
return undefined;
|
|
@@ -16,9 +16,22 @@ function runStatus(status) {
|
|
|
16
16
|
return "error";
|
|
17
17
|
return status;
|
|
18
18
|
}
|
|
19
|
-
function
|
|
19
|
+
function nodeBelongsToTurn(node, turnNodeId, context) {
|
|
20
|
+
let current = node;
|
|
21
|
+
const visited = new Set();
|
|
22
|
+
while (current && !visited.has(current.id)) {
|
|
23
|
+
if (current.id === turnNodeId || current.parentNodeId === turnNodeId)
|
|
24
|
+
return true;
|
|
25
|
+
visited.add(current.id);
|
|
26
|
+
current = current.parentNodeId ? context.getNode(current.parentNodeId) : undefined;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
function settleActiveSessionNodes(piboSessionId, context, status, terminalSource, eventId) {
|
|
31
|
+
const turnNodeId = eventId ? `turn:${piboSessionId}:${eventId}` : undefined;
|
|
20
32
|
return context.getSessionNodes(piboSessionId)
|
|
21
33
|
.filter((node) => node.kind !== "session" && node.kind !== "yielded_run" && isActiveSignalStatus(node.status))
|
|
34
|
+
.filter((node) => !turnNodeId || nodeBelongsToTurn(node, turnNodeId, context))
|
|
22
35
|
.filter((node) => terminalSource !== "processing_stopped" || node.kind !== "turn" || node.metadata?.accepted !== true)
|
|
23
36
|
.map((node) => ({
|
|
24
37
|
type: "patch_node",
|
|
@@ -210,12 +223,21 @@ export const outputSignalProducer = {
|
|
|
210
223
|
mutations.push(...settleActiveSessionNodes(piboSessionId, context, "done", "message_finished"));
|
|
211
224
|
}
|
|
212
225
|
if (event.type === "session_error") {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
226
|
+
const turnNodeId = event.eventId ? `turn:${piboSessionId}:${event.eventId}` : undefined;
|
|
227
|
+
const hasUnrelatedActiveTurn = Boolean(turnNodeId && context.getSessionNodes(piboSessionId)
|
|
228
|
+
.some((candidate) => candidate.kind === "turn" && candidate.id !== turnNodeId && isActiveSignalStatus(candidate.status)));
|
|
229
|
+
const error = { message: event.error, source: "pi" };
|
|
230
|
+
if (!hasUnrelatedActiveTurn)
|
|
231
|
+
mutations.push({ type: "set_session_queue", piboSessionId, queuedMessages: 0 });
|
|
232
|
+
mutations.push(...settleActiveSessionNodes(piboSessionId, context, "error", "session_error", hasUnrelatedActiveTurn ? event.eventId : undefined));
|
|
233
|
+
mutations.push({
|
|
234
|
+
type: "patch_node",
|
|
235
|
+
nodeId: `session:${piboSessionId}`,
|
|
236
|
+
patch: hasUnrelatedActiveTurn ? { error } : { status: "error", completedAt: context.now(), error },
|
|
237
|
+
});
|
|
216
238
|
if (event.eventId) {
|
|
217
|
-
mutations.push({ type: "patch_node", nodeId: `message:${piboSessionId}:${event.eventId}`, patch: { status: "error", completedAt: context.now(), error
|
|
218
|
-
mutations.push({ type: "patch_node", nodeId: `turn:${piboSessionId}:${event.eventId}`, patch: { status: "error", completedAt: context.now(), error
|
|
239
|
+
mutations.push({ type: "patch_node", nodeId: `message:${piboSessionId}:${event.eventId}`, patch: { status: "error", completedAt: context.now(), error } });
|
|
240
|
+
mutations.push({ type: "patch_node", nodeId: `turn:${piboSessionId}:${event.eventId}`, patch: { status: "error", completedAt: context.now(), error, metadata: { ...eventTurn?.metadata, terminalSource: "session_error" } } });
|
|
219
241
|
}
|
|
220
242
|
}
|
|
221
243
|
return mutations;
|
package/dist/subagents/tool.js
CHANGED
|
@@ -77,7 +77,10 @@ export function formatAgentObservationsForModel(result) {
|
|
|
77
77
|
const event = observation.kind === "tool"
|
|
78
78
|
? `${observation.eventType}${observation.toolName ? ` ${observation.toolName}` : ""}`
|
|
79
79
|
: observation.eventType;
|
|
80
|
-
|
|
80
|
+
const toolCall = observation.kind === "tool" && observation.toolCallId
|
|
81
|
+
? `; toolCallId=${observation.toolCallId}`
|
|
82
|
+
: "";
|
|
83
|
+
lines.push("", `#${observation.sequence} ${scope} — ${event}${toolCall}${observation.isError ? " [error]" : ""}`);
|
|
81
84
|
if (observation.text)
|
|
82
85
|
lines.push(observation.text);
|
|
83
86
|
}
|
|
@@ -186,13 +189,14 @@ export function createAgentToolDefinitions(subagents, controller) {
|
|
|
186
189
|
description: [
|
|
187
190
|
"Read completed delegated-agent messages with bounded cursor, identity, event, time, text, order, and limit filters.",
|
|
188
191
|
"Default: the newest 20 completed assistant messages, with streaming deltas and tools hidden.",
|
|
189
|
-
"Set includeTools=true to add compact tool calls and terminal results
|
|
192
|
+
"Set includeTools=true to add compact tool calls and terminal results, or pass toolCallIds to retrieve only those exact tool observations. Set toolDetail=full only for bounded diagnostic inspection.",
|
|
190
193
|
].join("\n"),
|
|
191
|
-
promptSnippet: "Observe child-agent progress through completed assistant messages. Defaults: newest 20 messages, no streaming deltas, no duplicate tool progress events, no tools. Set includeTools=true for compact tool call/result summaries, toolDetail=full for bounded raw tool text, or eventTypes/kinds for explicit progress diagnostics. Pass afterSequence from the previous result for cursor polling; cursor pages consume the oldest unseen matches even when order is desc.",
|
|
194
|
+
promptSnippet: "Observe child-agent progress through completed assistant messages. Defaults: newest 20 messages, no streaming deltas, no duplicate tool progress events, no tools. Set includeTools=true for compact tool call/result summaries, pass up to 50 exact toolCallIds to retrieve only those tool observations, use toolDetail=full for bounded raw tool text, or eventTypes/kinds for explicit progress diagnostics. Compact tool entries expose their toolCallId for follow-up queries. Pass afterSequence from the previous result for cursor polling; cursor pages consume the oldest unseen matches even when order is desc.",
|
|
192
195
|
executionMode: "parallel",
|
|
193
196
|
annotations: { readOnly: true },
|
|
194
197
|
inputSchema: Type.Object({
|
|
195
198
|
requestIds: Type.Optional(Type.Array(Type.String({ description: "Exact yielded run/request ID" }), { maxItems: 50 })),
|
|
199
|
+
toolCallIds: Type.Optional(Type.Array(Type.String({ description: "Exact existing toolCallId. Multiple values use OR semantics and return only matching tool observations." }), { maxItems: 50 })),
|
|
196
200
|
agentIds: Type.Optional(Type.Array(Type.String({ description: "Owned child agentId" }), { maxItems: 50 })),
|
|
197
201
|
names: Type.Optional(Type.Array(piboStringEnum(names), { maxItems: 50 })),
|
|
198
202
|
threadKeys: Type.Optional(Type.Array(Type.String(), { maxItems: 50 })),
|
|
@@ -151,7 +151,15 @@ The `files` whitelist in `package.json` controls what is published:
|
|
|
151
151
|
- `docs/ops/**` — operator runbooks.
|
|
152
152
|
- `README.md` and `src/mcp/LICENSE.mcp-cli`.
|
|
153
153
|
|
|
154
|
-
The `.vsix` is **not** in the npm package.
|
|
154
|
+
The `.vsix` is **not** in the npm package. The `package.json#files` whitelist explicitly excludes `dist/apps/vscode-artifacts/**` even when the release workflow creates the versioned VSIX and `latest.vsix` before `npm publish`. Those files remain in the workspace for GitHub Release and Marketplace upload.
|
|
155
|
+
|
|
156
|
+
Verify the package boundary before publishing:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm pack --dry-run --json --ignore-scripts | node -e 'let input=""; process.stdin.on("data", chunk => input += chunk).on("end", () => { const files = JSON.parse(input)[0].files.map(file => file.path); if (files.some(file => file.startsWith("dist/apps/vscode-artifacts/"))) process.exit(1); })'
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The VSIX lives on the GitHub Release and (after the maintainer uploads it) on the VS Code Marketplace.
|
|
155
163
|
|
|
156
164
|
## Why the WebView bundle is in the npm package
|
|
157
165
|
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pasko70/pibo",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@pasko70/pibo",
|
|
9
|
-
"version": "3.0.
|
|
9
|
+
"version": "3.0.2",
|
|
10
10
|
"workspaces": [
|
|
11
11
|
"packages/workflows"
|
|
12
12
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pasko70/pibo",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
"packages/workflows"
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"description": "Minimal TypeScript wrapper around Pi Coding Agent.",
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
|
+
"!dist/apps/vscode-artifacts/**",
|
|
11
12
|
"context",
|
|
12
13
|
"skills/builtin/**",
|
|
13
14
|
"docs/ops/**",
|