@getpaseo/server 0.1.81 → 0.1.83
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/server/client/daemon-client.d.ts +2 -1
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +29 -0
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +9 -7
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +78 -92
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.js +1 -1
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
- package/dist/server/server/agent/agent-projections.js +4 -4
- package/dist/server/server/agent/agent-projections.js.map +1 -1
- package/dist/server/server/agent/agent-prompt.d.ts +13 -10
- package/dist/server/server/agent/agent-prompt.d.ts.map +1 -1
- package/dist/server/server/agent/agent-prompt.js +38 -18
- package/dist/server/server/agent/agent-prompt.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +13 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.js.map +1 -1
- package/dist/server/server/agent/agent-storage.d.ts +2 -7
- package/dist/server/server/agent/agent-storage.d.ts.map +1 -1
- package/dist/server/server/agent/agent-storage.js +2 -16
- package/dist/server/server/agent/agent-storage.js.map +1 -1
- package/dist/server/server/agent/agent-timeline-store-types.d.ts +0 -4
- package/dist/server/server/agent/agent-timeline-store-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-timeline-store.d.ts +0 -5
- package/dist/server/server/agent/agent-timeline-store.d.ts.map +1 -1
- package/dist/server/server/agent/agent-timeline-store.js +0 -33
- package/dist/server/server/agent/agent-timeline-store.js.map +1 -1
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-server.js +42 -28
- package/dist/server/server/agent/mcp-server.js.map +1 -1
- package/dist/server/server/agent/provider-launch-config.d.ts.map +1 -1
- package/dist/server/server/agent/provider-launch-config.js +0 -1
- package/dist/server/server/agent/provider-launch-config.js.map +1 -1
- package/dist/server/server/agent/provider-manifest.d.ts +1 -1
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -1
- package/dist/server/server/agent/provider-registry.d.ts +2 -1
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -1
- package/dist/server/server/agent/provider-registry.js +5 -1
- package/dist/server/server/agent/provider-registry.js.map +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +2 -2
- package/dist/server/server/agent/provider-snapshot-manager.d.ts.map +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.js +60 -26
- package/dist/server/server/agent/provider-snapshot-manager.js.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.js +3 -0
- package/dist/server/server/agent/providers/acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/claude/agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/agent.js +275 -85
- package/dist/server/server/agent/providers/claude/agent.js.map +1 -1
- package/dist/server/server/agent/providers/claude/rewind.d.ts +30 -0
- package/dist/server/server/agent/providers/claude/rewind.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/rewind.js +30 -0
- package/dist/server/server/agent/providers/claude/rewind.js.map +1 -0
- package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.d.ts +24 -0
- package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.js +23 -0
- package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.js.map +1 -0
- package/dist/server/server/agent/providers/codex/app-server-transport.d.ts +168 -0
- package/dist/server/server/agent/providers/codex/app-server-transport.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/app-server-transport.js +48 -0
- package/dist/server/server/agent/providers/codex/app-server-transport.js.map +1 -1
- package/dist/server/server/agent/providers/codex/rewind.d.ts +21 -0
- package/dist/server/server/agent/providers/codex/rewind.d.ts.map +1 -0
- package/dist/server/server/agent/providers/codex/rewind.js +46 -0
- package/dist/server/server/agent/providers/codex/rewind.js.map +1 -0
- package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.d.ts +5 -0
- package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.js +45 -0
- package/dist/server/server/agent/providers/codex/test-utils/fake-app-server.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +11 -11
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +32 -34
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +206 -60
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/copilot-acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/copilot-acp-agent.js +3 -0
- package/dist/server/server/agent/providers/copilot-acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +13 -0
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.js +55 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/rewind.d.ts +18 -0
- package/dist/server/server/agent/providers/opencode/rewind.d.ts.map +1 -0
- package/dist/server/server/agent/providers/opencode/rewind.js +14 -0
- package/dist/server/server/agent/providers/opencode/rewind.js.map +1 -0
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +110 -2
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts +18 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +265 -38
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/pi/agent.d.ts +21 -1
- package/dist/server/server/agent/providers/pi/agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/pi/agent.js +355 -13
- package/dist/server/server/agent/providers/pi/agent.js.map +1 -1
- package/dist/server/server/agent/providers/pi/history-mapper.d.ts +5 -1
- package/dist/server/server/agent/providers/pi/history-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/pi/history-mapper.js +3 -2
- package/dist/server/server/agent/providers/pi/history-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/pi/rewind.d.ts +8 -0
- package/dist/server/server/agent/providers/pi/rewind.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/rewind.js +8 -0
- package/dist/server/server/agent/providers/pi/rewind.js.map +1 -0
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +10 -0
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts.map +1 -1
- package/dist/server/server/agent/providers/pi/runtime.d.ts +2 -0
- package/dist/server/server/agent/providers/pi/runtime.d.ts.map +1 -1
- package/dist/server/server/agent/providers/pi/runtime.js +4 -0
- package/dist/server/server/agent/providers/pi/runtime.js.map +1 -1
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +10 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts.map +1 -1
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +49 -1
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +4 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +57 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
- package/dist/server/server/agent/rewind/rewind.d.ts +10 -0
- package/dist/server/server/agent/rewind/rewind.d.ts.map +1 -0
- package/dist/server/server/agent/rewind/rewind.js +29 -0
- package/dist/server/server/agent/rewind/rewind.js.map +1 -0
- package/dist/server/server/agent/rewind/test-rewind-session.d.ts +48 -0
- package/dist/server/server/agent/rewind/test-rewind-session.d.ts.map +1 -0
- package/dist/server/server/agent/rewind/test-rewind-session.js +88 -0
- package/dist/server/server/agent/rewind/test-rewind-session.js.map +1 -0
- package/dist/server/server/persistence-hooks.d.ts.map +1 -1
- package/dist/server/server/persistence-hooks.js +0 -2
- package/dist/server/server/persistence-hooks.js.map +1 -1
- package/dist/server/server/session.d.ts +2 -0
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +56 -25
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +2 -0
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/shared/messages.d.ts +281 -0
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +27 -0
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +14 -0
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/src/server/agent/agent-sdk-types.js.map +1 -1
- package/dist/src/server/agent/provider-launch-config.js +0 -1
- package/dist/src/server/agent/provider-launch-config.js.map +1 -1
- package/dist/src/shared/messages.js +27 -0
- package/dist/src/shared/messages.js.map +1 -1
- package/package.json +3 -3
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts +0 -9
- package/dist/server/server/agent/providers/codex-rollout-timeline.d.ts.map +0 -1
- package/dist/server/server/agent/providers/codex-rollout-timeline.js +0 -555
- package/dist/server/server/agent/providers/codex-rollout-timeline.js.map +0 -1
- package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +0 -10
- package/dist/server/server/agent/providers/pi/session-descriptor.d.ts.map +0 -1
- package/dist/server/server/agent/providers/pi/session-descriptor.js +0 -300
- package/dist/server/server/agent/providers/pi/session-descriptor.js.map +0 -1
|
@@ -7,13 +7,18 @@ import { renderPromptAttachmentAsText } from "../../prompt-attachments.js";
|
|
|
7
7
|
import { composeSystemPromptParts } from "../../system-prompt.js";
|
|
8
8
|
import { findExecutable } from "../../../../utils/executable.js";
|
|
9
9
|
import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "../diagnostic-utils.js";
|
|
10
|
-
import { streamPiHistory } from "./history-mapper.js";
|
|
10
|
+
import { getUserMessageText, streamPiHistory, } from "./history-mapper.js";
|
|
11
11
|
import { PiCliRuntime } from "./cli-runtime.js";
|
|
12
|
-
import {
|
|
12
|
+
import { revertPiConversation } from "./rewind.js";
|
|
13
13
|
import { mapToolDetail, parseToolArgs, parseToolResult, resolveToolCallName, } from "./tool-call-mapper.js";
|
|
14
14
|
const PI_PROVIDER = "pi";
|
|
15
15
|
const DEFAULT_PI_THINKING_LEVEL = "medium";
|
|
16
16
|
const PI_BINARY_COMMAND = process.env.PI_COMMAND ?? process.env.PI_ACP_PI_COMMAND ?? "pi";
|
|
17
|
+
const PASEO_PI_TREE_EXTENSION_COMMAND = "paseo_tree";
|
|
18
|
+
const PASEO_PI_CAPTURE_EXTENSION_COMMAND = "paseo_capture_entries";
|
|
19
|
+
const PASEO_PI_ENTRY_CAPTURE_MARKER = "PASEO_ENTRY_CAPTURE";
|
|
20
|
+
const PASEO_PI_COMMAND_RESULT_MARKER = "PASEO_COMMAND_RESULT";
|
|
21
|
+
const PASEO_PI_EXTENSION_RESULT_TIMEOUT_MS = 10000;
|
|
17
22
|
const PI_CAPABILITIES = {
|
|
18
23
|
supportsStreaming: true,
|
|
19
24
|
supportsSessionPersistence: true,
|
|
@@ -21,6 +26,9 @@ const PI_CAPABILITIES = {
|
|
|
21
26
|
supportsMcpServers: false,
|
|
22
27
|
supportsReasoningStream: true,
|
|
23
28
|
supportsToolInvocations: true,
|
|
29
|
+
supportsRewindConversation: true,
|
|
30
|
+
supportsRewindFiles: false,
|
|
31
|
+
supportsRewindBoth: false,
|
|
24
32
|
};
|
|
25
33
|
const PI_THINKING_OPTIONS = [
|
|
26
34
|
{ id: "off", label: "Off", description: "No extra reasoning" },
|
|
@@ -211,6 +219,103 @@ function createPiMcpConfigFile(servers) {
|
|
|
211
219
|
cleanup: () => rmSync(dir, { recursive: true, force: true }),
|
|
212
220
|
};
|
|
213
221
|
}
|
|
222
|
+
function createPiPaseoExtensionFile() {
|
|
223
|
+
const dir = mkdtempSync(join(tmpdir(), "paseo-pi-extension-"));
|
|
224
|
+
const filePath = join(dir, "paseo-integration.mjs");
|
|
225
|
+
writeFileSync(filePath, `
|
|
226
|
+
function decodePayload(encoded) {
|
|
227
|
+
return JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function readTextContent(content) {
|
|
231
|
+
if (typeof content === "string") {
|
|
232
|
+
return content;
|
|
233
|
+
}
|
|
234
|
+
if (!Array.isArray(content)) {
|
|
235
|
+
return "";
|
|
236
|
+
}
|
|
237
|
+
return content
|
|
238
|
+
.filter((part) => part && part.type === "text" && typeof part.text === "string")
|
|
239
|
+
.map((part) => part.text)
|
|
240
|
+
.join("\\n\\n");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function getCapturedUserEntries(ctx) {
|
|
244
|
+
return ctx.sessionManager
|
|
245
|
+
.getEntries()
|
|
246
|
+
.filter((entry) => entry.type === "message" && entry.message?.role === "user")
|
|
247
|
+
.map((entry) => ({
|
|
248
|
+
id: entry.id,
|
|
249
|
+
parentId: entry.parentId ?? null,
|
|
250
|
+
text: readTextContent(entry.message.content),
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function emitEntryCapture(ctx, reason, requestId) {
|
|
255
|
+
ctx.ui.notify(
|
|
256
|
+
"${PASEO_PI_ENTRY_CAPTURE_MARKER} " +
|
|
257
|
+
JSON.stringify({ reason, requestId, entries: getCapturedUserEntries(ctx) }),
|
|
258
|
+
"info",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function emitCommandResult(ctx, requestId, result) {
|
|
263
|
+
ctx.ui.notify(
|
|
264
|
+
"${PASEO_PI_COMMAND_RESULT_MARKER} " + JSON.stringify({ requestId, ...result }),
|
|
265
|
+
result.ok ? "info" : "error",
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export default function paseoIntegration(pi) {
|
|
270
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
271
|
+
emitEntryCapture(ctx, "session_start");
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
pi.on("turn_end", async (_event, ctx) => {
|
|
275
|
+
emitEntryCapture(ctx, "turn_end");
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
pi.registerCommand("${PASEO_PI_CAPTURE_EXTENSION_COMMAND}", {
|
|
279
|
+
description: "Internal Paseo entry capture bridge",
|
|
280
|
+
handler: async (args, ctx) => {
|
|
281
|
+
const payload = decodePayload(args.trim());
|
|
282
|
+
emitEntryCapture(ctx, "command", payload.requestId);
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
pi.registerCommand("${PASEO_PI_TREE_EXTENSION_COMMAND}", {
|
|
287
|
+
description: "Internal Paseo tree navigation bridge",
|
|
288
|
+
handler: async (args, ctx) => {
|
|
289
|
+
const payload = decodePayload(args.trim());
|
|
290
|
+
try {
|
|
291
|
+
const result = await ctx.navigateTree(payload.targetId, { summarize: false });
|
|
292
|
+
emitEntryCapture(ctx, "tree_navigation");
|
|
293
|
+
emitCommandResult(ctx, payload.requestId, { ok: true, result });
|
|
294
|
+
} catch (error) {
|
|
295
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
296
|
+
emitCommandResult(ctx, payload.requestId, { ok: false, error: message });
|
|
297
|
+
throw error;
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
`.trimStart(), "utf8");
|
|
303
|
+
return {
|
|
304
|
+
path: filePath,
|
|
305
|
+
cleanup: () => rmSync(dir, { recursive: true, force: true }),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
function combineCleanup(cleanups) {
|
|
309
|
+
const activeCleanups = cleanups.filter((cleanup) => Boolean(cleanup));
|
|
310
|
+
if (activeCleanups.length === 0) {
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
return () => {
|
|
314
|
+
for (const cleanup of activeCleanups) {
|
|
315
|
+
cleanup();
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
214
319
|
function isPiMcpAdapterCommand(command) {
|
|
215
320
|
if (command.source !== "extension" || !/^mcp(?::\d+)?$/.test(command.name)) {
|
|
216
321
|
return false;
|
|
@@ -239,11 +344,41 @@ function resolveThinkingOptionId(cachedThinkingOptionId, sessionThinkingLevel) {
|
|
|
239
344
|
function modelToId(model) {
|
|
240
345
|
return model?.provider && model.id ? `${model.provider}/${model.id}` : null;
|
|
241
346
|
}
|
|
347
|
+
function piAssistantText(message) {
|
|
348
|
+
const text = message.content
|
|
349
|
+
.flatMap((part) => {
|
|
350
|
+
if (part.type === "text") {
|
|
351
|
+
return [part.text];
|
|
352
|
+
}
|
|
353
|
+
if (part.type === "thinking") {
|
|
354
|
+
return [part.thinking];
|
|
355
|
+
}
|
|
356
|
+
return [];
|
|
357
|
+
})
|
|
358
|
+
.join("\n\n")
|
|
359
|
+
.trim();
|
|
360
|
+
return text.length > 0 ? text : null;
|
|
361
|
+
}
|
|
362
|
+
function formatPiErrorMessage(message) {
|
|
363
|
+
const headline = message.errorMessage?.trim() || "Pi turn failed";
|
|
364
|
+
const details = [
|
|
365
|
+
message.stopReason ? `stopReason=${message.stopReason}` : null,
|
|
366
|
+
message.provider && message.model ? `model=${message.provider}/${message.model}` : null,
|
|
367
|
+
message.responseModel ? `responseModel=${message.responseModel}` : null,
|
|
368
|
+
message.responseId ? `responseId=${message.responseId}` : null,
|
|
369
|
+
].filter((detail) => detail !== null);
|
|
370
|
+
const partialText = piAssistantText(message);
|
|
371
|
+
if (partialText) {
|
|
372
|
+
details.push(`partial=${JSON.stringify(partialText.slice(0, 500))}`);
|
|
373
|
+
}
|
|
374
|
+
return details.length > 0 ? `${headline} (${details.join(", ")})` : headline;
|
|
375
|
+
}
|
|
242
376
|
function latestPiErrorMessage(messages) {
|
|
243
377
|
const latestAssistant = messages.findLast((message) => message.role === "assistant");
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
378
|
+
if (!latestAssistant || !latestAssistant.errorMessage?.trim()) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
return formatPiErrorMessage(latestAssistant);
|
|
247
382
|
}
|
|
248
383
|
function isRecord(value) {
|
|
249
384
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -251,6 +386,42 @@ function isRecord(value) {
|
|
|
251
386
|
function optionalString(value) {
|
|
252
387
|
return typeof value === "string" ? value : undefined;
|
|
253
388
|
}
|
|
389
|
+
function parseExtensionMarkerPayload(message, marker) {
|
|
390
|
+
const prefix = `${marker} `;
|
|
391
|
+
if (!message.startsWith(prefix)) {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
const parsed = JSON.parse(message.slice(prefix.length));
|
|
396
|
+
return isRecord(parsed) ? parsed : null;
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function parseCapturedEntries(value) {
|
|
403
|
+
if (!Array.isArray(value)) {
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
return value.flatMap((entry) => {
|
|
407
|
+
if (!isRecord(entry)) {
|
|
408
|
+
return [];
|
|
409
|
+
}
|
|
410
|
+
const id = optionalString(entry.id)?.trim();
|
|
411
|
+
const text = optionalString(entry.text);
|
|
412
|
+
if (!id || text === undefined) {
|
|
413
|
+
return [];
|
|
414
|
+
}
|
|
415
|
+
const parentId = entry.parentId === null ? null : optionalString(entry.parentId)?.trim();
|
|
416
|
+
return [
|
|
417
|
+
{
|
|
418
|
+
id,
|
|
419
|
+
parentId: parentId || null,
|
|
420
|
+
text,
|
|
421
|
+
},
|
|
422
|
+
];
|
|
423
|
+
});
|
|
424
|
+
}
|
|
254
425
|
function mapExtensionUiRequestToPermission(event) {
|
|
255
426
|
switch (event.method) {
|
|
256
427
|
case "select":
|
|
@@ -355,6 +526,11 @@ export class PiRpcAgentSession {
|
|
|
355
526
|
this.activeToolCalls = new Map();
|
|
356
527
|
this.pendingExtensionUiRequests = new Map();
|
|
357
528
|
this.activeTurnId = null;
|
|
529
|
+
this.capturedUserEntries = [];
|
|
530
|
+
this.capturedUserEntriesById = new Map();
|
|
531
|
+
this.seenUserEntryIds = new Set();
|
|
532
|
+
this.pendingUserMessages = [];
|
|
533
|
+
this.pendingExtensionResults = new Map();
|
|
358
534
|
this.closed = false;
|
|
359
535
|
this.runtimeSession = options.runtimeSession;
|
|
360
536
|
this.config = options.config;
|
|
@@ -417,7 +593,8 @@ export class PiRpcAgentSession {
|
|
|
417
593
|
};
|
|
418
594
|
}
|
|
419
595
|
async *streamHistory() {
|
|
420
|
-
|
|
596
|
+
await this.requestEntryCapture("history");
|
|
597
|
+
yield* streamPiHistory(PI_PROVIDER, await this.runtimeSession.getMessages(), this.capturedUserEntries);
|
|
421
598
|
}
|
|
422
599
|
async getRuntimeInfo() {
|
|
423
600
|
await this.refreshState();
|
|
@@ -472,6 +649,33 @@ export class PiRpcAgentSession {
|
|
|
472
649
|
async interrupt() {
|
|
473
650
|
await this.runtimeSession.abort();
|
|
474
651
|
}
|
|
652
|
+
async revertConversation(input) {
|
|
653
|
+
if (this.activeTurnId) {
|
|
654
|
+
throw new Error("Cannot rewind the Pi conversation while a Pi turn is active");
|
|
655
|
+
}
|
|
656
|
+
await this.refreshState().catch(() => undefined);
|
|
657
|
+
await this.requestEntryCapture("rewind");
|
|
658
|
+
const targetEntry = this.capturedUserEntriesById.get(input.messageId);
|
|
659
|
+
if (!targetEntry) {
|
|
660
|
+
throw new Error(`Pi rewind target ${input.messageId} was not found in captured tree entries`);
|
|
661
|
+
}
|
|
662
|
+
await revertPiConversation({
|
|
663
|
+
messageId: input.messageId,
|
|
664
|
+
navigator: {
|
|
665
|
+
navigateTree: (treeEntryId) => this.runPiTreeExtensionCommand(treeEntryId),
|
|
666
|
+
},
|
|
667
|
+
});
|
|
668
|
+
// Pi keeps all tree nodes, so selecting the previous leaf later reverses this rewind.
|
|
669
|
+
this.currentLeafOverrideId = targetEntry.parentId;
|
|
670
|
+
this.activeToolCalls.clear();
|
|
671
|
+
}
|
|
672
|
+
async runPiTreeExtensionCommand(targetId) {
|
|
673
|
+
const requestId = randomUUID();
|
|
674
|
+
const resultPromise = this.waitForExtensionResult(requestId);
|
|
675
|
+
const payload = Buffer.from(JSON.stringify({ targetId, requestId })).toString("base64url");
|
|
676
|
+
await this.runtimeSession.prompt(`/${PASEO_PI_TREE_EXTENSION_COMMAND} ${payload}`);
|
|
677
|
+
return await resultPromise;
|
|
678
|
+
}
|
|
475
679
|
async close() {
|
|
476
680
|
if (this.closed) {
|
|
477
681
|
return;
|
|
@@ -481,6 +685,7 @@ export class PiRpcAgentSession {
|
|
|
481
685
|
await this.runtimeSession.close();
|
|
482
686
|
}
|
|
483
687
|
finally {
|
|
688
|
+
this.rejectAllExtensionResults(new Error("Pi session closed"));
|
|
484
689
|
this.cleanup?.();
|
|
485
690
|
}
|
|
486
691
|
}
|
|
@@ -525,7 +730,114 @@ export class PiRpcAgentSession {
|
|
|
525
730
|
currentTurnIdForEvent() {
|
|
526
731
|
return this.activeTurnId ?? undefined;
|
|
527
732
|
}
|
|
733
|
+
async requestEntryCapture(reason) {
|
|
734
|
+
const requestId = randomUUID();
|
|
735
|
+
const resultPromise = this.waitForExtensionResult(requestId);
|
|
736
|
+
const payload = Buffer.from(JSON.stringify({ requestId, reason })).toString("base64url");
|
|
737
|
+
await this.runtimeSession.prompt(`/${PASEO_PI_CAPTURE_EXTENSION_COMMAND} ${payload}`);
|
|
738
|
+
await resultPromise;
|
|
739
|
+
}
|
|
740
|
+
waitForExtensionResult(requestId) {
|
|
741
|
+
return new Promise((resolve, reject) => {
|
|
742
|
+
const timer = setTimeout(() => {
|
|
743
|
+
this.pendingExtensionResults.delete(requestId);
|
|
744
|
+
reject(new Error(`Pi extension result timed out for request ${requestId}`));
|
|
745
|
+
}, PASEO_PI_EXTENSION_RESULT_TIMEOUT_MS);
|
|
746
|
+
this.pendingExtensionResults.set(requestId, { resolve, reject, timer });
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
resolveExtensionResult(requestId, result) {
|
|
750
|
+
const pending = this.pendingExtensionResults.get(requestId);
|
|
751
|
+
if (!pending) {
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
clearTimeout(pending.timer);
|
|
755
|
+
this.pendingExtensionResults.delete(requestId);
|
|
756
|
+
pending.resolve(result);
|
|
757
|
+
}
|
|
758
|
+
rejectExtensionResult(requestId, error) {
|
|
759
|
+
const pending = this.pendingExtensionResults.get(requestId);
|
|
760
|
+
if (!pending) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
clearTimeout(pending.timer);
|
|
764
|
+
this.pendingExtensionResults.delete(requestId);
|
|
765
|
+
pending.reject(error);
|
|
766
|
+
}
|
|
767
|
+
rejectAllExtensionResults(error) {
|
|
768
|
+
for (const requestId of this.pendingExtensionResults.keys()) {
|
|
769
|
+
this.rejectExtensionResult(requestId, error);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
recordCapturedUserEntries(entries) {
|
|
773
|
+
const previouslySeenEntryIds = new Set(this.seenUserEntryIds);
|
|
774
|
+
this.capturedUserEntries.splice(0, this.capturedUserEntries.length, ...entries);
|
|
775
|
+
this.capturedUserEntriesById.clear();
|
|
776
|
+
for (const entry of entries) {
|
|
777
|
+
this.capturedUserEntriesById.set(entry.id, entry);
|
|
778
|
+
}
|
|
779
|
+
this.flushPendingUserMessages(previouslySeenEntryIds);
|
|
780
|
+
for (const entry of entries) {
|
|
781
|
+
this.seenUserEntryIds.add(entry.id);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
flushPendingUserMessages(previouslySeenEntryIds) {
|
|
785
|
+
for (let index = 0; index < this.pendingUserMessages.length; index += 1) {
|
|
786
|
+
const pending = this.pendingUserMessages[index];
|
|
787
|
+
const entry = this.capturedUserEntries.find((candidate) => !previouslySeenEntryIds.has(candidate.id));
|
|
788
|
+
if (!entry) {
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
previouslySeenEntryIds.add(entry.id);
|
|
792
|
+
this.pendingUserMessages.splice(index, 1);
|
|
793
|
+
index -= 1;
|
|
794
|
+
this.emit({
|
|
795
|
+
type: "timeline",
|
|
796
|
+
provider: PI_PROVIDER,
|
|
797
|
+
turnId: pending.turnId,
|
|
798
|
+
item: {
|
|
799
|
+
type: "user_message",
|
|
800
|
+
text: pending.text,
|
|
801
|
+
messageId: entry.id,
|
|
802
|
+
},
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
handleEntryCaptureMarker(message) {
|
|
807
|
+
const payload = parseExtensionMarkerPayload(message, PASEO_PI_ENTRY_CAPTURE_MARKER);
|
|
808
|
+
if (!payload) {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
const entries = parseCapturedEntries(payload.entries);
|
|
812
|
+
this.recordCapturedUserEntries(entries);
|
|
813
|
+
if (typeof payload.requestId === "string") {
|
|
814
|
+
this.resolveExtensionResult(payload.requestId, entries);
|
|
815
|
+
}
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
818
|
+
handleCommandResultMarker(message) {
|
|
819
|
+
const payload = parseExtensionMarkerPayload(message, PASEO_PI_COMMAND_RESULT_MARKER);
|
|
820
|
+
if (!payload) {
|
|
821
|
+
return false;
|
|
822
|
+
}
|
|
823
|
+
if (typeof payload.requestId !== "string") {
|
|
824
|
+
return true;
|
|
825
|
+
}
|
|
826
|
+
if (payload.ok === true) {
|
|
827
|
+
this.resolveExtensionResult(payload.requestId, payload.result);
|
|
828
|
+
return true;
|
|
829
|
+
}
|
|
830
|
+
const error = typeof payload.error === "string" ? payload.error : "Pi extension command failed";
|
|
831
|
+
this.rejectExtensionResult(payload.requestId, new Error(error));
|
|
832
|
+
return true;
|
|
833
|
+
}
|
|
528
834
|
handleExtensionUiRequest(event) {
|
|
835
|
+
const message = optionalString(event.message);
|
|
836
|
+
if (event.method === "notify" && message) {
|
|
837
|
+
if (this.handleEntryCaptureMarker(message) || this.handleCommandResultMarker(message)) {
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
529
841
|
const request = mapExtensionUiRequestToPermission(event);
|
|
530
842
|
if (!request) {
|
|
531
843
|
return;
|
|
@@ -550,6 +862,7 @@ export class PiRpcAgentSession {
|
|
|
550
862
|
this.handleSessionEvent(event);
|
|
551
863
|
}
|
|
552
864
|
handleProcessExit(error) {
|
|
865
|
+
this.rejectAllExtensionResults(new Error(error));
|
|
553
866
|
if (!this.activeTurnId) {
|
|
554
867
|
return;
|
|
555
868
|
}
|
|
@@ -579,6 +892,11 @@ export class PiRpcAgentSession {
|
|
|
579
892
|
turnId,
|
|
580
893
|
});
|
|
581
894
|
return;
|
|
895
|
+
case "message_start":
|
|
896
|
+
return;
|
|
897
|
+
case "message_end":
|
|
898
|
+
this.handleMessageEnd(event, turnId);
|
|
899
|
+
return;
|
|
582
900
|
case "message_update":
|
|
583
901
|
this.handleMessageUpdate(event, turnId);
|
|
584
902
|
return;
|
|
@@ -664,6 +982,25 @@ export class PiRpcAgentSession {
|
|
|
664
982
|
});
|
|
665
983
|
}
|
|
666
984
|
}
|
|
985
|
+
handleMessageEnd(event, turnId) {
|
|
986
|
+
if (event.message.role !== "user") {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
const text = getUserMessageText(event.message.content);
|
|
990
|
+
if (!text) {
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
this.pendingUserMessages.push({ text, turnId });
|
|
994
|
+
void this.requestEntryCapture("message_end").catch((error) => {
|
|
995
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
996
|
+
this.emit({
|
|
997
|
+
type: "turn_failed",
|
|
998
|
+
provider: PI_PROVIDER,
|
|
999
|
+
turnId,
|
|
1000
|
+
error: message,
|
|
1001
|
+
});
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
667
1004
|
emitToolCallEvent(toolCallId, toolCall, status, result, error) {
|
|
668
1005
|
const turnId = this.currentTurnIdForEvent();
|
|
669
1006
|
const detail = mapToolDetail(toolCall, result);
|
|
@@ -729,6 +1066,7 @@ export class PiRpcAgentClient {
|
|
|
729
1066
|
}
|
|
730
1067
|
async createSession(config, launchContext) {
|
|
731
1068
|
const mcpConfig = await this.prepareMcpConfig(config.cwd, config.mcpServers);
|
|
1069
|
+
const paseoExtension = createPiPaseoExtensionFile();
|
|
732
1070
|
let runtimeSession;
|
|
733
1071
|
try {
|
|
734
1072
|
runtimeSession = await this.runtime.startSession({
|
|
@@ -738,10 +1076,12 @@ export class PiRpcAgentClient {
|
|
|
738
1076
|
systemPrompt: composeSystemPromptParts(config.systemPrompt, config.daemonAppendSystemPrompt),
|
|
739
1077
|
env: launchContext?.env,
|
|
740
1078
|
mcpConfigPath: mcpConfig?.path,
|
|
1079
|
+
extensionPaths: [paseoExtension.path],
|
|
741
1080
|
});
|
|
742
1081
|
}
|
|
743
1082
|
catch (error) {
|
|
744
1083
|
mcpConfig?.cleanup();
|
|
1084
|
+
paseoExtension.cleanup();
|
|
745
1085
|
throw error;
|
|
746
1086
|
}
|
|
747
1087
|
try {
|
|
@@ -750,12 +1090,13 @@ export class PiRpcAgentClient {
|
|
|
750
1090
|
config,
|
|
751
1091
|
initialState: await runtimeSession.getState(),
|
|
752
1092
|
capabilities: withPiMcpCapability(mcpConfig !== null),
|
|
753
|
-
cleanup: mcpConfig?.cleanup,
|
|
1093
|
+
cleanup: combineCleanup([mcpConfig?.cleanup, paseoExtension.cleanup]),
|
|
754
1094
|
});
|
|
755
1095
|
}
|
|
756
1096
|
catch (error) {
|
|
757
1097
|
await runtimeSession.close().catch(() => undefined);
|
|
758
1098
|
mcpConfig?.cleanup();
|
|
1099
|
+
paseoExtension.cleanup();
|
|
759
1100
|
throw error;
|
|
760
1101
|
}
|
|
761
1102
|
}
|
|
@@ -767,6 +1108,7 @@ export class PiRpcAgentClient {
|
|
|
767
1108
|
const persistenceMetadata = parsePersistenceMetadata(handle.metadata);
|
|
768
1109
|
const resumeConfig = buildResumeConfig(persistenceMetadata, overrides);
|
|
769
1110
|
const mcpConfig = await this.prepareMcpConfig(resumeConfig.cwd, resumeConfig.config.mcpServers);
|
|
1111
|
+
const paseoExtension = createPiPaseoExtensionFile();
|
|
770
1112
|
let runtimeSession;
|
|
771
1113
|
try {
|
|
772
1114
|
runtimeSession = await this.runtime.startSession({
|
|
@@ -776,10 +1118,12 @@ export class PiRpcAgentClient {
|
|
|
776
1118
|
thinkingOptionId: normalizePiThinkingOption(resumeConfig.thinkingOptionId) ?? undefined,
|
|
777
1119
|
systemPrompt: composeSystemPromptParts(resumeConfig.config.systemPrompt, resumeConfig.config.daemonAppendSystemPrompt),
|
|
778
1120
|
mcpConfigPath: mcpConfig?.path,
|
|
1121
|
+
extensionPaths: [paseoExtension.path],
|
|
779
1122
|
});
|
|
780
1123
|
}
|
|
781
1124
|
catch (error) {
|
|
782
1125
|
mcpConfig?.cleanup();
|
|
1126
|
+
paseoExtension.cleanup();
|
|
783
1127
|
throw error;
|
|
784
1128
|
}
|
|
785
1129
|
try {
|
|
@@ -788,12 +1132,13 @@ export class PiRpcAgentClient {
|
|
|
788
1132
|
config: resumeConfig.config,
|
|
789
1133
|
initialState: await runtimeSession.getState(),
|
|
790
1134
|
capabilities: withPiMcpCapability(mcpConfig !== null),
|
|
791
|
-
cleanup: mcpConfig?.cleanup,
|
|
1135
|
+
cleanup: combineCleanup([mcpConfig?.cleanup, paseoExtension.cleanup]),
|
|
792
1136
|
});
|
|
793
1137
|
}
|
|
794
1138
|
catch (error) {
|
|
795
1139
|
await runtimeSession.close().catch(() => undefined);
|
|
796
1140
|
mcpConfig?.cleanup();
|
|
1141
|
+
paseoExtension.cleanup();
|
|
797
1142
|
throw error;
|
|
798
1143
|
}
|
|
799
1144
|
}
|
|
@@ -809,11 +1154,8 @@ export class PiRpcAgentClient {
|
|
|
809
1154
|
async listModes(_options) {
|
|
810
1155
|
return [];
|
|
811
1156
|
}
|
|
812
|
-
async listPersistedAgents(
|
|
813
|
-
return
|
|
814
|
-
...options,
|
|
815
|
-
runtimeSettings: this.runtimeSettings,
|
|
816
|
-
});
|
|
1157
|
+
async listPersistedAgents(_options) {
|
|
1158
|
+
return [];
|
|
817
1159
|
}
|
|
818
1160
|
async isAvailable() {
|
|
819
1161
|
const binary = await this.resolvePiBinary();
|