@getpaseo/server 0.1.78 → 0.1.79
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/scripts/dev-runner.js +1 -13
- package/dist/scripts/dev-runner.js.map +1 -1
- package/dist/scripts/supervisor-entrypoint.js +17 -3
- package/dist/scripts/supervisor-entrypoint.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +34 -2
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +138 -1
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +6 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +40 -5
- 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-sdk-types.d.ts +5 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-storage.d.ts +3 -0
- package/dist/server/server/agent/agent-storage.d.ts.map +1 -1
- package/dist/server/server/agent/agent-storage.js +58 -22
- package/dist/server/server/agent/agent-storage.js.map +1 -1
- package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +51 -0
- package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts.map +1 -0
- package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +140 -0
- package/dist/server/server/agent/create-agent-lifecycle-dispatch.js.map +1 -0
- package/dist/server/server/agent/import-sessions.js +2 -2
- package/dist/server/server/agent/import-sessions.js.map +1 -1
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-server.js +202 -99
- package/dist/server/server/agent/mcp-server.js.map +1 -1
- package/dist/server/server/agent/provider-registry.js +2 -2
- package/dist/server/server/agent/provider-registry.js.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.d.ts +3 -0
- package/dist/server/server/agent/providers/acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.js +44 -4
- 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 +17 -9
- package/dist/server/server/agent/providers/claude/agent.js.map +1 -1
- package/dist/server/server/agent/providers/claude/project-dir.d.ts +5 -0
- package/dist/server/server/agent/providers/claude/project-dir.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/project-dir.js +40 -0
- package/dist/server/server/agent/providers/claude/project-dir.js.map +1 -0
- 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 +13 -2
- 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 +4 -0
- 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 +57 -19
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/cursor-acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/cursor-acp-agent.js +11 -1
- package/dist/server/server/agent/providers/cursor-acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +2 -0
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/generic-acp-agent.js +2 -0
- package/dist/server/server/agent/providers/generic-acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/runtime.d.ts +1 -0
- package/dist/server/server/agent/providers/opencode/runtime.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/runtime.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts +4 -0
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/server-manager.js +18 -2
- package/dist/server/server/agent/providers/opencode/server-manager.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/test-server-manager.js +1 -0
- package/dist/server/server/agent/providers/opencode/test-server-manager.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +1 -1
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +7 -2
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/{pi-direct-agent.d.ts → pi/agent.d.ts} +38 -29
- package/dist/server/server/agent/providers/pi/agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/agent.js +829 -0
- package/dist/server/server/agent/providers/pi/agent.js.map +1 -0
- package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +18 -0
- package/dist/server/server/agent/providers/pi/cli-runtime.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/cli-runtime.js +218 -0
- package/dist/server/server/agent/providers/pi/cli-runtime.js.map +1 -0
- package/dist/server/server/agent/providers/pi/history-mapper.d.ts +5 -0
- package/dist/server/server/agent/providers/pi/history-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/history-mapper.js +139 -0
- package/dist/server/server/agent/providers/pi/history-mapper.js.map +1 -0
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +185 -0
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/rpc-types.js +2 -0
- package/dist/server/server/agent/providers/pi/rpc-types.js.map +1 -0
- package/dist/server/server/agent/providers/pi/runtime.d.ts +48 -0
- package/dist/server/server/agent/providers/pi/runtime.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/runtime.js +52 -0
- package/dist/server/server/agent/providers/pi/runtime.js.map +1 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +10 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.js +300 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.js.map +1 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +52 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +109 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js.map +1 -0
- package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts +112 -0
- package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts.map +1 -0
- package/dist/server/server/agent/providers/pi/tool-call-mapper.js +284 -0
- package/dist/server/server/agent/providers/pi/tool-call-mapper.js.map +1 -0
- package/dist/server/server/agent/system-prompt.d.ts +2 -0
- package/dist/server/server/agent/system-prompt.d.ts.map +1 -0
- package/dist/server/server/agent/system-prompt.js +8 -0
- package/dist/server/server/agent/system-prompt.js.map +1 -0
- package/dist/server/server/bootstrap.d.ts +1 -0
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +15 -1
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/config.d.ts.map +1 -1
- package/dist/server/server/config.js +6 -1
- package/dist/server/server/config.js.map +1 -1
- package/dist/server/server/daemon-config-store.js +1 -0
- package/dist/server/server/daemon-config-store.js.map +1 -1
- package/dist/server/server/persisted-config.d.ts +51 -44
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js +1 -0
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/pid-lock.d.ts +2 -2
- package/dist/server/server/session.d.ts +21 -0
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +232 -10
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts +11 -1
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +10 -2
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/server/workspace-git-service.d.ts +5 -1
- package/dist/server/server/workspace-git-service.d.ts.map +1 -1
- package/dist/server/server/workspace-git-service.js +122 -62
- package/dist/server/server/workspace-git-service.js.map +1 -1
- package/dist/server/shared/importable-providers.d.ts +1 -1
- package/dist/server/shared/importable-providers.d.ts.map +1 -1
- package/dist/server/shared/importable-providers.js +1 -1
- package/dist/server/shared/importable-providers.js.map +1 -1
- package/dist/server/shared/messages.d.ts +2187 -24
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +108 -0
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/terminal/terminal-manager.d.ts +1 -0
- package/dist/server/terminal/terminal-manager.d.ts.map +1 -1
- package/dist/server/terminal/terminal-manager.js +8 -0
- package/dist/server/terminal/terminal-manager.js.map +1 -1
- package/dist/server/terminal/terminal-session-controller.d.ts +1 -0
- package/dist/server/terminal/terminal-session-controller.d.ts.map +1 -1
- package/dist/server/terminal/terminal-session-controller.js +26 -0
- package/dist/server/terminal/terminal-session-controller.js.map +1 -1
- package/dist/server/terminal/terminal.d.ts +1 -0
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +32 -10
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/server/terminal/worker-terminal-manager.d.ts.map +1 -1
- package/dist/server/terminal/worker-terminal-manager.js +18 -0
- package/dist/server/terminal/worker-terminal-manager.js.map +1 -1
- package/dist/server/utils/branch-slug.d.ts +14 -0
- package/dist/server/utils/branch-slug.d.ts.map +1 -0
- package/dist/server/utils/branch-slug.js +49 -0
- package/dist/server/utils/branch-slug.js.map +1 -0
- package/dist/server/utils/directory-suggestions.js +2 -2
- package/dist/server/utils/directory-suggestions.js.map +1 -1
- package/dist/server/utils/path.d.ts +1 -0
- package/dist/server/utils/path.d.ts.map +1 -1
- package/dist/server/utils/path.js +31 -0
- package/dist/server/utils/path.js.map +1 -1
- package/dist/server/utils/run-git-command.d.ts.map +1 -1
- package/dist/server/utils/run-git-command.js +3 -1
- package/dist/server/utils/run-git-command.js.map +1 -1
- package/dist/server/utils/worktree.d.ts +1 -12
- package/dist/server/utils/worktree.d.ts.map +1 -1
- package/dist/server/utils/worktree.js +2 -52
- package/dist/server/utils/worktree.js.map +1 -1
- package/dist/src/server/persisted-config.js +1 -0
- package/dist/src/server/persisted-config.js.map +1 -1
- package/dist/src/shared/messages.js +108 -0
- package/dist/src/shared/messages.js.map +1 -1
- package/package.json +13 -11
- package/dist/server/server/agent/orchestrator-instructions.d.ts +0 -7
- package/dist/server/server/agent/orchestrator-instructions.d.ts.map +0 -1
- package/dist/server/server/agent/orchestrator-instructions.js +0 -51
- package/dist/server/server/agent/orchestrator-instructions.js.map +0 -1
- package/dist/server/server/agent/providers/pi-direct-agent.d.ts.map +0 -1
- package/dist/server/server/agent/providers/pi-direct-agent.js +0 -1151
- package/dist/server/server/agent/providers/pi-direct-agent.js.map +0 -1
- package/dist/server/server/agent/providers/pi-session-recovery-policy.d.ts +0 -22
- package/dist/server/server/agent/providers/pi-session-recovery-policy.d.ts.map +0 -1
- package/dist/server/server/agent/providers/pi-session-recovery-policy.js +0 -51
- package/dist/server/server/agent/providers/pi-session-recovery-policy.js.map +0 -1
|
@@ -1,1151 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { homedir } from "node:os";
|
|
5
|
-
import { AuthStorage, ModelRegistry, SessionManager, createAgentSessionFromServices, createAgentSessionRuntime, createAgentSessionServices, getAgentDir, } from "@mariozechner/pi-coding-agent";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
|
|
8
|
-
import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
|
|
9
|
-
import { findExecutable, isCommandAvailable } from "../../../utils/executable.js";
|
|
10
|
-
import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
|
|
11
|
-
import { applyPiSessionRecoveryPolicy } from "./pi-session-recovery-policy.js";
|
|
12
|
-
const PI_PROVIDER = "pi";
|
|
13
|
-
const DEFAULT_PI_THINKING_LEVEL = "medium";
|
|
14
|
-
const PI_BINARY_COMMAND = process.env.PI_COMMAND ?? process.env.PI_ACP_PI_COMMAND ?? "pi";
|
|
15
|
-
const PI_CAPABILITIES = {
|
|
16
|
-
supportsStreaming: true,
|
|
17
|
-
supportsSessionPersistence: true,
|
|
18
|
-
supportsDynamicModes: true,
|
|
19
|
-
supportsMcpServers: false,
|
|
20
|
-
supportsReasoningStream: true,
|
|
21
|
-
supportsToolInvocations: true,
|
|
22
|
-
};
|
|
23
|
-
const PI_THINKING_OPTIONS = [
|
|
24
|
-
{ id: "off", label: "Off", description: "No extra reasoning" },
|
|
25
|
-
{ id: "minimal", label: "Minimal", description: "Light reasoning" },
|
|
26
|
-
{ id: "low", label: "Low", description: "Faster reasoning" },
|
|
27
|
-
{ id: "medium", label: "Medium", description: "Balanced reasoning", isDefault: true },
|
|
28
|
-
{ id: "high", label: "High", description: "Deeper reasoning" },
|
|
29
|
-
{ id: "xhigh", label: "XHigh", description: "Maximum reasoning" },
|
|
30
|
-
];
|
|
31
|
-
const PiPromptTextBlockSchema = z.object({
|
|
32
|
-
type: z.literal("text"),
|
|
33
|
-
text: z.string(),
|
|
34
|
-
});
|
|
35
|
-
const PiToolResultTextContentSchema = z.object({
|
|
36
|
-
type: z.literal("text"),
|
|
37
|
-
text: z.string(),
|
|
38
|
-
});
|
|
39
|
-
const PiToolResultUnknownContentSchema = z
|
|
40
|
-
.object({
|
|
41
|
-
type: z.string(),
|
|
42
|
-
})
|
|
43
|
-
.passthrough();
|
|
44
|
-
const PiToolResultContentSchema = z.union([
|
|
45
|
-
PiToolResultTextContentSchema,
|
|
46
|
-
PiToolResultUnknownContentSchema,
|
|
47
|
-
]);
|
|
48
|
-
const PiToolResultDetailsSchema = z
|
|
49
|
-
.object({
|
|
50
|
-
diff: z.string().optional(),
|
|
51
|
-
})
|
|
52
|
-
.passthrough();
|
|
53
|
-
const PiToolResultObjectSchema = z
|
|
54
|
-
.object({
|
|
55
|
-
output: z.string().optional(),
|
|
56
|
-
stdout: z.string().optional(),
|
|
57
|
-
text: z.string().optional(),
|
|
58
|
-
content: z.array(PiToolResultContentSchema).optional(),
|
|
59
|
-
exitCode: z.number().optional(),
|
|
60
|
-
code: z.number().optional(),
|
|
61
|
-
details: PiToolResultDetailsSchema.optional(),
|
|
62
|
-
})
|
|
63
|
-
.passthrough();
|
|
64
|
-
const PiToolResultSchema = z.union([z.string(), PiToolResultObjectSchema, z.null()]);
|
|
65
|
-
const PiPersistenceMetadataSchema = z
|
|
66
|
-
.object({
|
|
67
|
-
cwd: z.string().optional(),
|
|
68
|
-
})
|
|
69
|
-
.passthrough();
|
|
70
|
-
const BashToolInputSchema = z.object({
|
|
71
|
-
command: z.string(),
|
|
72
|
-
timeout: z.number().optional(),
|
|
73
|
-
});
|
|
74
|
-
const ReadToolInputSchema = z.object({
|
|
75
|
-
path: z.string(),
|
|
76
|
-
offset: z.number().optional(),
|
|
77
|
-
limit: z.number().optional(),
|
|
78
|
-
});
|
|
79
|
-
const EditToolInputSchema = z.object({
|
|
80
|
-
path: z.string(),
|
|
81
|
-
edits: z.array(z.object({
|
|
82
|
-
oldText: z.string(),
|
|
83
|
-
newText: z.string(),
|
|
84
|
-
})),
|
|
85
|
-
});
|
|
86
|
-
const LegacyEditToolInputSchema = z.object({
|
|
87
|
-
path: z.string(),
|
|
88
|
-
old_string: z.string().optional(),
|
|
89
|
-
oldString: z.string().optional(),
|
|
90
|
-
new_string: z.string().optional(),
|
|
91
|
-
newString: z.string().optional(),
|
|
92
|
-
});
|
|
93
|
-
const WriteToolInputSchema = z.object({
|
|
94
|
-
path: z.string(),
|
|
95
|
-
content: z.string(),
|
|
96
|
-
});
|
|
97
|
-
const FindToolInputSchema = z.object({
|
|
98
|
-
pattern: z.string(),
|
|
99
|
-
path: z.string().optional(),
|
|
100
|
-
limit: z.number().optional(),
|
|
101
|
-
});
|
|
102
|
-
const GrepToolInputSchema = z.object({
|
|
103
|
-
pattern: z.string(),
|
|
104
|
-
path: z.string().optional(),
|
|
105
|
-
glob: z.string().optional(),
|
|
106
|
-
ignoreCase: z.boolean().optional(),
|
|
107
|
-
literal: z.boolean().optional(),
|
|
108
|
-
context: z.number().optional(),
|
|
109
|
-
limit: z.number().optional(),
|
|
110
|
-
});
|
|
111
|
-
const LsToolInputSchema = z.object({
|
|
112
|
-
path: z.string().optional(),
|
|
113
|
-
limit: z.number().optional(),
|
|
114
|
-
});
|
|
115
|
-
function normalizePiModelLabel(label) {
|
|
116
|
-
return label.trim().replace(/[_\s]+/g, " ");
|
|
117
|
-
}
|
|
118
|
-
export function transformPiModels(models) {
|
|
119
|
-
return models.map((model) => {
|
|
120
|
-
if (!model.label.includes("/")) {
|
|
121
|
-
return model;
|
|
122
|
-
}
|
|
123
|
-
const segments = model.label.split("/").filter((segment) => segment.length > 0);
|
|
124
|
-
const rawLabel = segments.at(-1);
|
|
125
|
-
if (!rawLabel) {
|
|
126
|
-
return model;
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
...model,
|
|
130
|
-
label: normalizePiModelLabel(rawLabel),
|
|
131
|
-
description: model.description ?? model.label,
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
function isPiThinkingLevel(value) {
|
|
136
|
-
return (value === "off" ||
|
|
137
|
-
value === "minimal" ||
|
|
138
|
-
value === "low" ||
|
|
139
|
-
value === "medium" ||
|
|
140
|
-
value === "high" ||
|
|
141
|
-
value === "xhigh");
|
|
142
|
-
}
|
|
143
|
-
function normalizePiThinkingOption(value) {
|
|
144
|
-
if (!value) {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
return isPiThinkingLevel(value) ? value : null;
|
|
148
|
-
}
|
|
149
|
-
function toAgentUsage(stats) {
|
|
150
|
-
const inputTokens = stats.tokens.input;
|
|
151
|
-
const cachedInputTokens = stats.tokens.cacheRead;
|
|
152
|
-
const outputTokens = stats.tokens.output;
|
|
153
|
-
const totalCostUsd = stats.cost;
|
|
154
|
-
if (inputTokens === 0 && cachedInputTokens === 0 && outputTokens === 0 && totalCostUsd === 0) {
|
|
155
|
-
return undefined;
|
|
156
|
-
}
|
|
157
|
-
return {
|
|
158
|
-
inputTokens,
|
|
159
|
-
cachedInputTokens,
|
|
160
|
-
outputTokens,
|
|
161
|
-
totalCostUsd,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
function convertPromptInput(prompt) {
|
|
165
|
-
if (typeof prompt === "string") {
|
|
166
|
-
return { text: prompt };
|
|
167
|
-
}
|
|
168
|
-
const textParts = [];
|
|
169
|
-
const images = [];
|
|
170
|
-
for (const block of prompt) {
|
|
171
|
-
if (block.type === "text") {
|
|
172
|
-
textParts.push(block.text);
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
if (block.type === "image") {
|
|
176
|
-
images.push({
|
|
177
|
-
type: "image",
|
|
178
|
-
data: block.data,
|
|
179
|
-
mimeType: block.mimeType,
|
|
180
|
-
});
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
textParts.push(renderPromptAttachmentAsText(block));
|
|
184
|
-
}
|
|
185
|
-
const payload = {
|
|
186
|
-
text: textParts.join("\n\n"),
|
|
187
|
-
};
|
|
188
|
-
if (images.length > 0) {
|
|
189
|
-
payload.images = images;
|
|
190
|
-
}
|
|
191
|
-
return payload;
|
|
192
|
-
}
|
|
193
|
-
function parseToolResult(rawResult) {
|
|
194
|
-
const parsed = PiToolResultSchema.safeParse(rawResult);
|
|
195
|
-
if (parsed.success) {
|
|
196
|
-
return parsed.data;
|
|
197
|
-
}
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
function extractTextFromToolResult(result) {
|
|
201
|
-
if (typeof result === "string") {
|
|
202
|
-
return result;
|
|
203
|
-
}
|
|
204
|
-
if (!result) {
|
|
205
|
-
return undefined;
|
|
206
|
-
}
|
|
207
|
-
const directText = result.output ?? result.stdout ?? result.text;
|
|
208
|
-
if (directText) {
|
|
209
|
-
return directText;
|
|
210
|
-
}
|
|
211
|
-
if (!result.content) {
|
|
212
|
-
return undefined;
|
|
213
|
-
}
|
|
214
|
-
const textParts = [];
|
|
215
|
-
for (const block of result.content) {
|
|
216
|
-
if (block.type === "text" && "text" in block) {
|
|
217
|
-
textParts.push(block.text);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
if (textParts.length === 0) {
|
|
221
|
-
return undefined;
|
|
222
|
-
}
|
|
223
|
-
return textParts.join("\n");
|
|
224
|
-
}
|
|
225
|
-
function resolveToolCallOutput(result) {
|
|
226
|
-
if (typeof result === "string") {
|
|
227
|
-
return { output: result };
|
|
228
|
-
}
|
|
229
|
-
if (!result) {
|
|
230
|
-
return {};
|
|
231
|
-
}
|
|
232
|
-
const summary = {
|
|
233
|
-
output: extractTextFromToolResult(result),
|
|
234
|
-
};
|
|
235
|
-
if (typeof result.exitCode === "number") {
|
|
236
|
-
summary.exitCode = result.exitCode;
|
|
237
|
-
return summary;
|
|
238
|
-
}
|
|
239
|
-
if (typeof result.code === "number") {
|
|
240
|
-
summary.exitCode = result.code;
|
|
241
|
-
return summary;
|
|
242
|
-
}
|
|
243
|
-
summary.exitCode = null;
|
|
244
|
-
return summary;
|
|
245
|
-
}
|
|
246
|
-
function normalizeLegacyEditArgs(rawArgs) {
|
|
247
|
-
const parsed = LegacyEditToolInputSchema.safeParse(rawArgs);
|
|
248
|
-
if (!parsed.success) {
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
const oldText = parsed.data.old_string ?? parsed.data.oldString;
|
|
252
|
-
const newText = parsed.data.new_string ?? parsed.data.newString;
|
|
253
|
-
if (!oldText || newText === undefined) {
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
return {
|
|
257
|
-
path: parsed.data.path,
|
|
258
|
-
edits: [{ oldText, newText }],
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
function parseEditToolArgs(rawArgs) {
|
|
262
|
-
const parsed = EditToolInputSchema.safeParse(rawArgs);
|
|
263
|
-
if (parsed.success) {
|
|
264
|
-
return { kind: "edit", toolName: "edit", args: parsed.data };
|
|
265
|
-
}
|
|
266
|
-
const legacyArgs = normalizeLegacyEditArgs(rawArgs);
|
|
267
|
-
if (legacyArgs) {
|
|
268
|
-
return { kind: "edit", toolName: "edit", args: legacyArgs };
|
|
269
|
-
}
|
|
270
|
-
return { kind: "unknown", toolName: "edit", args: rawArgs ?? null };
|
|
271
|
-
}
|
|
272
|
-
const SIMPLE_TOOL_SCHEMAS = {
|
|
273
|
-
bash: BashToolInputSchema,
|
|
274
|
-
read: ReadToolInputSchema,
|
|
275
|
-
write: WriteToolInputSchema,
|
|
276
|
-
find: FindToolInputSchema,
|
|
277
|
-
grep: GrepToolInputSchema,
|
|
278
|
-
ls: LsToolInputSchema,
|
|
279
|
-
};
|
|
280
|
-
function parseToolArgs(toolName, rawArgs) {
|
|
281
|
-
if (toolName === "edit") {
|
|
282
|
-
return parseEditToolArgs(rawArgs);
|
|
283
|
-
}
|
|
284
|
-
const schema = SIMPLE_TOOL_SCHEMAS[toolName];
|
|
285
|
-
if (schema) {
|
|
286
|
-
const parsed = schema.safeParse(rawArgs);
|
|
287
|
-
if (parsed.success) {
|
|
288
|
-
return { kind: toolName, toolName, args: parsed.data };
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return { kind: "unknown", toolName, args: rawArgs ?? null };
|
|
292
|
-
}
|
|
293
|
-
function mapFindToolDetail(args, result) {
|
|
294
|
-
return {
|
|
295
|
-
type: "search",
|
|
296
|
-
query: args.pattern,
|
|
297
|
-
toolName: "search",
|
|
298
|
-
content: typeof result === "string" ? result : undefined,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
function mapGrepToolDetail(args, result) {
|
|
302
|
-
return {
|
|
303
|
-
type: "search",
|
|
304
|
-
query: args.pattern,
|
|
305
|
-
toolName: "grep",
|
|
306
|
-
content: typeof result === "string" ? result : undefined,
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
function mapLsToolDetail(args, result) {
|
|
310
|
-
const query = args.path ?? "ls";
|
|
311
|
-
return {
|
|
312
|
-
type: "search",
|
|
313
|
-
query,
|
|
314
|
-
content: typeof result === "string" ? result : undefined,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
function mapToolDetail(toolCall, result) {
|
|
318
|
-
const parsedResult = result ?? null;
|
|
319
|
-
switch (toolCall.kind) {
|
|
320
|
-
case "bash": {
|
|
321
|
-
const summary = resolveToolCallOutput(parsedResult);
|
|
322
|
-
return {
|
|
323
|
-
type: "shell",
|
|
324
|
-
command: toolCall.args.command,
|
|
325
|
-
output: summary.output,
|
|
326
|
-
exitCode: summary.exitCode,
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
case "read":
|
|
330
|
-
return {
|
|
331
|
-
type: "read",
|
|
332
|
-
filePath: toolCall.args.path,
|
|
333
|
-
content: extractTextFromToolResult(parsedResult),
|
|
334
|
-
offset: toolCall.args.offset,
|
|
335
|
-
limit: toolCall.args.limit,
|
|
336
|
-
};
|
|
337
|
-
case "edit": {
|
|
338
|
-
const firstEdit = toolCall.args.edits[0];
|
|
339
|
-
const unifiedDiff = parsedResult && typeof parsedResult !== "string" ? parsedResult.details?.diff : undefined;
|
|
340
|
-
return {
|
|
341
|
-
type: "edit",
|
|
342
|
-
filePath: toolCall.args.path,
|
|
343
|
-
oldString: firstEdit?.oldText,
|
|
344
|
-
newString: firstEdit?.newText,
|
|
345
|
-
unifiedDiff,
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
case "write":
|
|
349
|
-
return {
|
|
350
|
-
type: "write",
|
|
351
|
-
filePath: toolCall.args.path,
|
|
352
|
-
content: toolCall.args.content,
|
|
353
|
-
};
|
|
354
|
-
case "find":
|
|
355
|
-
return mapFindToolDetail(toolCall.args, parsedResult);
|
|
356
|
-
case "grep":
|
|
357
|
-
return mapGrepToolDetail(toolCall.args, parsedResult);
|
|
358
|
-
case "ls":
|
|
359
|
-
return mapLsToolDetail(toolCall.args, parsedResult);
|
|
360
|
-
default:
|
|
361
|
-
return {
|
|
362
|
-
type: "unknown",
|
|
363
|
-
input: toolCall.args,
|
|
364
|
-
output: parsedResult,
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
function parseModelReference(modelId) {
|
|
369
|
-
if (!modelId) {
|
|
370
|
-
return null;
|
|
371
|
-
}
|
|
372
|
-
if (modelId.includes("/")) {
|
|
373
|
-
const [provider, ...rest] = modelId.split("/");
|
|
374
|
-
const id = rest.join("/");
|
|
375
|
-
if (provider && id) {
|
|
376
|
-
return { provider, id };
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
if (modelId.includes(":")) {
|
|
380
|
-
const [provider, ...rest] = modelId.split(":");
|
|
381
|
-
const id = rest.join(":");
|
|
382
|
-
if (provider && id) {
|
|
383
|
-
return { provider, id };
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return { id: modelId };
|
|
387
|
-
}
|
|
388
|
-
function mapResolvedCommand(command) {
|
|
389
|
-
return {
|
|
390
|
-
name: command.invocationName,
|
|
391
|
-
description: command.description ?? "Extension command",
|
|
392
|
-
argumentHint: "",
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
function mapSkillCommand(skill) {
|
|
396
|
-
return {
|
|
397
|
-
name: `skill:${skill.name}`,
|
|
398
|
-
description: skill.description || "Skill",
|
|
399
|
-
argumentHint: "",
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
function buildSlashCommands(session) {
|
|
403
|
-
const commands = [];
|
|
404
|
-
const extensionCommands = session.extensionRunner?.getRegisteredCommands() ?? [];
|
|
405
|
-
for (const command of extensionCommands) {
|
|
406
|
-
commands.push(mapResolvedCommand(command));
|
|
407
|
-
}
|
|
408
|
-
for (const template of session.promptTemplates) {
|
|
409
|
-
commands.push({
|
|
410
|
-
name: template.name,
|
|
411
|
-
description: template.description ?? "Prompt template",
|
|
412
|
-
argumentHint: "",
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
const resourceLoader = session.resourceLoader;
|
|
416
|
-
const skills = resourceLoader.getSkills().skills;
|
|
417
|
-
for (const skill of skills) {
|
|
418
|
-
commands.push(mapSkillCommand(skill));
|
|
419
|
-
}
|
|
420
|
-
return commands;
|
|
421
|
-
}
|
|
422
|
-
function applySystemPrompt(session, systemPrompt) {
|
|
423
|
-
const trimmed = systemPrompt?.trim();
|
|
424
|
-
if (!trimmed) {
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
// Pi does not expose a public setter for composing an additional system prompt,
|
|
428
|
-
// so this escape hatch is isolated to one typed boundary.
|
|
429
|
-
const sessionObject = session;
|
|
430
|
-
const baseSystemPrompt = Reflect.get(sessionObject, "_baseSystemPrompt");
|
|
431
|
-
const currentBase = typeof baseSystemPrompt === "string" ? baseSystemPrompt : session.agent.state.systemPrompt;
|
|
432
|
-
const combinedPrompt = currentBase ? `${currentBase}\n\n${trimmed}` : trimmed;
|
|
433
|
-
Reflect.set(sessionObject, "_baseSystemPrompt", combinedPrompt);
|
|
434
|
-
session.agent.state.systemPrompt = combinedPrompt;
|
|
435
|
-
}
|
|
436
|
-
function isTextContentBlock(block) {
|
|
437
|
-
return PiPromptTextBlockSchema.safeParse(block).success;
|
|
438
|
-
}
|
|
439
|
-
function getUserMessageText(content) {
|
|
440
|
-
if (typeof content === "string") {
|
|
441
|
-
return content;
|
|
442
|
-
}
|
|
443
|
-
const textParts = [];
|
|
444
|
-
for (const block of content) {
|
|
445
|
-
if (isTextContentBlock(block)) {
|
|
446
|
-
textParts.push(block.text);
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
return textParts.join("\n\n");
|
|
450
|
-
}
|
|
451
|
-
function parsePersistenceMetadata(metadata) {
|
|
452
|
-
const parsed = PiPersistenceMetadataSchema.safeParse(metadata);
|
|
453
|
-
if (parsed.success) {
|
|
454
|
-
return parsed.data;
|
|
455
|
-
}
|
|
456
|
-
return {};
|
|
457
|
-
}
|
|
458
|
-
function isPiRequestAbortError(error) {
|
|
459
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
460
|
-
return true;
|
|
461
|
-
}
|
|
462
|
-
return /\brequest was aborted\b/i.test(toDiagnosticErrorMessage(error));
|
|
463
|
-
}
|
|
464
|
-
function resolveThinkingOptionId(cachedThinkingOptionId, sessionThinkingLevel) {
|
|
465
|
-
const currentThinking = cachedThinkingOptionId ?? sessionThinkingLevel;
|
|
466
|
-
return normalizePiThinkingOption(currentThinking);
|
|
467
|
-
}
|
|
468
|
-
function mapThinkingOption(option) {
|
|
469
|
-
const mappedOption = {
|
|
470
|
-
id: option.id,
|
|
471
|
-
label: option.label,
|
|
472
|
-
description: option.description,
|
|
473
|
-
};
|
|
474
|
-
if (option.isDefault) {
|
|
475
|
-
return {
|
|
476
|
-
...mappedOption,
|
|
477
|
-
isDefault: true,
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
return mappedOption;
|
|
481
|
-
}
|
|
482
|
-
function findModelInRegistry(registry, parsedReference) {
|
|
483
|
-
if (parsedReference.provider) {
|
|
484
|
-
return (registry.find(parsedReference.provider, parsedReference.id) ??
|
|
485
|
-
createProviderModelFallback(registry, {
|
|
486
|
-
provider: parsedReference.provider,
|
|
487
|
-
id: parsedReference.id,
|
|
488
|
-
}));
|
|
489
|
-
}
|
|
490
|
-
return registry.getAll().find((entry) => {
|
|
491
|
-
if (entry.id === parsedReference.id) {
|
|
492
|
-
return true;
|
|
493
|
-
}
|
|
494
|
-
return `${entry.provider}/${entry.id}` === parsedReference.id;
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
function createProviderModelFallback(registry, parsedReference) {
|
|
498
|
-
const providerDefault = registry
|
|
499
|
-
.getAll()
|
|
500
|
-
.find((model) => model.provider === parsedReference.provider);
|
|
501
|
-
if (!providerDefault) {
|
|
502
|
-
return undefined;
|
|
503
|
-
}
|
|
504
|
-
return {
|
|
505
|
-
id: parsedReference.id,
|
|
506
|
-
name: parsedReference.id,
|
|
507
|
-
api: providerDefault.api,
|
|
508
|
-
provider: parsedReference.provider,
|
|
509
|
-
baseUrl: providerDefault.baseUrl,
|
|
510
|
-
reasoning: false,
|
|
511
|
-
input: ["text"],
|
|
512
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
513
|
-
contextWindow: 128000,
|
|
514
|
-
maxTokens: 16384,
|
|
515
|
-
compat: providerDefault.compat,
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
export class PiDirectAgentSession {
|
|
519
|
-
constructor(runtime, modelRegistry, config) {
|
|
520
|
-
this.runtime = runtime;
|
|
521
|
-
this.modelRegistry = modelRegistry;
|
|
522
|
-
this.config = config;
|
|
523
|
-
this.provider = PI_PROVIDER;
|
|
524
|
-
this.capabilities = PI_CAPABILITIES;
|
|
525
|
-
this.subscribers = new Set();
|
|
526
|
-
this.activeToolCalls = new Map();
|
|
527
|
-
this.activeTurnId = null;
|
|
528
|
-
const session = this.session;
|
|
529
|
-
this.lastKnownThinkingOptionId =
|
|
530
|
-
normalizePiThinkingOption(config.thinkingOptionId) ?? session.thinkingLevel ?? null;
|
|
531
|
-
session.subscribe((event) => {
|
|
532
|
-
this.handleSessionEvent(event);
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
get session() {
|
|
536
|
-
return this.runtime.session;
|
|
537
|
-
}
|
|
538
|
-
get id() {
|
|
539
|
-
return this.session.sessionId;
|
|
540
|
-
}
|
|
541
|
-
emit(event) {
|
|
542
|
-
for (const subscriber of this.subscribers) {
|
|
543
|
-
subscriber(event);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
currentTurnIdForEvent() {
|
|
547
|
-
return this.activeTurnId ?? undefined;
|
|
548
|
-
}
|
|
549
|
-
emitToolCallEvent(toolCallId, toolCall, status, result, error) {
|
|
550
|
-
const turnId = this.currentTurnIdForEvent();
|
|
551
|
-
const detail = mapToolDetail(toolCall, result);
|
|
552
|
-
const baseItem = {
|
|
553
|
-
type: "tool_call",
|
|
554
|
-
callId: toolCallId,
|
|
555
|
-
name: toolCall.toolName,
|
|
556
|
-
detail,
|
|
557
|
-
};
|
|
558
|
-
const item = status === "failed" ? { ...baseItem, status, error } : { ...baseItem, status, error: null };
|
|
559
|
-
this.emit({
|
|
560
|
-
type: "timeline",
|
|
561
|
-
provider: PI_PROVIDER,
|
|
562
|
-
turnId,
|
|
563
|
-
item,
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
handleMessageUpdate(event, turnId) {
|
|
567
|
-
if (event.message.role !== "assistant") {
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
if (event.assistantMessageEvent.type === "text_delta") {
|
|
571
|
-
this.emit({
|
|
572
|
-
type: "timeline",
|
|
573
|
-
provider: PI_PROVIDER,
|
|
574
|
-
turnId,
|
|
575
|
-
item: {
|
|
576
|
-
type: "assistant_message",
|
|
577
|
-
text: event.assistantMessageEvent.delta ?? "",
|
|
578
|
-
},
|
|
579
|
-
});
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
if (event.assistantMessageEvent.type === "thinking_delta") {
|
|
583
|
-
this.emit({
|
|
584
|
-
type: "timeline",
|
|
585
|
-
provider: PI_PROVIDER,
|
|
586
|
-
turnId,
|
|
587
|
-
item: {
|
|
588
|
-
type: "reasoning",
|
|
589
|
-
text: event.assistantMessageEvent.delta ?? "",
|
|
590
|
-
},
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
handleSessionEvent(event) {
|
|
595
|
-
const turnId = this.currentTurnIdForEvent();
|
|
596
|
-
switch (event.type) {
|
|
597
|
-
case "agent_start":
|
|
598
|
-
this.emit({
|
|
599
|
-
type: "thread_started",
|
|
600
|
-
provider: PI_PROVIDER,
|
|
601
|
-
sessionId: this.session.sessionId,
|
|
602
|
-
});
|
|
603
|
-
return;
|
|
604
|
-
case "turn_start":
|
|
605
|
-
this.emit({
|
|
606
|
-
type: "turn_started",
|
|
607
|
-
provider: PI_PROVIDER,
|
|
608
|
-
turnId,
|
|
609
|
-
});
|
|
610
|
-
return;
|
|
611
|
-
case "message_update":
|
|
612
|
-
this.handleMessageUpdate(event, turnId);
|
|
613
|
-
return;
|
|
614
|
-
case "tool_execution_start": {
|
|
615
|
-
const toolCall = parseToolArgs(event.toolName, event.args);
|
|
616
|
-
this.activeToolCalls.set(event.toolCallId, toolCall);
|
|
617
|
-
this.emitToolCallEvent(event.toolCallId, toolCall, "running", null, null);
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
case "tool_execution_update": {
|
|
621
|
-
const toolCall = this.activeToolCalls.get(event.toolCallId);
|
|
622
|
-
if (!toolCall) {
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
const partialResult = parseToolResult(event.partialResult);
|
|
626
|
-
this.emitToolCallEvent(event.toolCallId, toolCall, "running", partialResult, null);
|
|
627
|
-
return;
|
|
628
|
-
}
|
|
629
|
-
case "tool_execution_end": {
|
|
630
|
-
const toolCall = this.activeToolCalls.get(event.toolCallId) ?? parseToolArgs(event.toolName, null);
|
|
631
|
-
this.activeToolCalls.delete(event.toolCallId);
|
|
632
|
-
const result = parseToolResult(event.result);
|
|
633
|
-
const error = event.isError ? event.result : null;
|
|
634
|
-
const status = event.isError ? "failed" : "completed";
|
|
635
|
-
this.emitToolCallEvent(event.toolCallId, toolCall, status, result, error);
|
|
636
|
-
return;
|
|
637
|
-
}
|
|
638
|
-
case "turn_end":
|
|
639
|
-
return;
|
|
640
|
-
case "compaction_start":
|
|
641
|
-
this.emit({
|
|
642
|
-
type: "timeline",
|
|
643
|
-
provider: PI_PROVIDER,
|
|
644
|
-
turnId,
|
|
645
|
-
item: {
|
|
646
|
-
type: "compaction",
|
|
647
|
-
status: "loading",
|
|
648
|
-
trigger: event.reason === "manual" ? "manual" : "auto",
|
|
649
|
-
},
|
|
650
|
-
});
|
|
651
|
-
return;
|
|
652
|
-
case "compaction_end":
|
|
653
|
-
this.emit({
|
|
654
|
-
type: "timeline",
|
|
655
|
-
provider: PI_PROVIDER,
|
|
656
|
-
turnId,
|
|
657
|
-
item: {
|
|
658
|
-
type: "compaction",
|
|
659
|
-
status: "completed",
|
|
660
|
-
},
|
|
661
|
-
});
|
|
662
|
-
return;
|
|
663
|
-
case "agent_end": {
|
|
664
|
-
this.latestUsage = toAgentUsage(this.session.getSessionStats());
|
|
665
|
-
const currentTurnId = turnId;
|
|
666
|
-
this.activeTurnId = null;
|
|
667
|
-
if (this.session.agent.state.errorMessage) {
|
|
668
|
-
this.emit({
|
|
669
|
-
type: "turn_failed",
|
|
670
|
-
provider: PI_PROVIDER,
|
|
671
|
-
turnId: currentTurnId,
|
|
672
|
-
error: this.session.agent.state.errorMessage,
|
|
673
|
-
});
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
676
|
-
this.emit({
|
|
677
|
-
type: "turn_completed",
|
|
678
|
-
provider: PI_PROVIDER,
|
|
679
|
-
turnId: currentTurnId,
|
|
680
|
-
usage: this.latestUsage,
|
|
681
|
-
});
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
default:
|
|
685
|
-
return;
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
async run(prompt, options) {
|
|
689
|
-
const timeline = [];
|
|
690
|
-
let finalText = "";
|
|
691
|
-
let usage;
|
|
692
|
-
let turnId = null;
|
|
693
|
-
const bufferedEvents = [];
|
|
694
|
-
let settled = false;
|
|
695
|
-
let resolveCompletion;
|
|
696
|
-
let rejectCompletion;
|
|
697
|
-
function processEvent(event) {
|
|
698
|
-
if (settled) {
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
const eventTurnId = getAgentStreamEventTurnId(event);
|
|
702
|
-
if (turnId && eventTurnId && eventTurnId !== turnId) {
|
|
703
|
-
return;
|
|
704
|
-
}
|
|
705
|
-
if (event.type === "timeline") {
|
|
706
|
-
timeline.push(event.item);
|
|
707
|
-
if (event.item.type === "assistant_message") {
|
|
708
|
-
finalText += event.item.text;
|
|
709
|
-
}
|
|
710
|
-
return;
|
|
711
|
-
}
|
|
712
|
-
if (event.type === "turn_completed") {
|
|
713
|
-
usage = event.usage;
|
|
714
|
-
settled = true;
|
|
715
|
-
resolveCompletion();
|
|
716
|
-
return;
|
|
717
|
-
}
|
|
718
|
-
if (event.type === "turn_failed") {
|
|
719
|
-
settled = true;
|
|
720
|
-
rejectCompletion(new Error(event.error));
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
const completion = new Promise((resolve, reject) => {
|
|
724
|
-
resolveCompletion = resolve;
|
|
725
|
-
rejectCompletion = reject;
|
|
726
|
-
});
|
|
727
|
-
const unsubscribe = this.subscribe((event) => {
|
|
728
|
-
if (!turnId) {
|
|
729
|
-
bufferedEvents.push(event);
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
processEvent(event);
|
|
733
|
-
});
|
|
734
|
-
try {
|
|
735
|
-
const result = await this.startTurn(prompt, options);
|
|
736
|
-
turnId = result.turnId;
|
|
737
|
-
for (const event of bufferedEvents) {
|
|
738
|
-
processEvent(event);
|
|
739
|
-
}
|
|
740
|
-
if (!settled) {
|
|
741
|
-
await completion;
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
finally {
|
|
745
|
-
unsubscribe();
|
|
746
|
-
}
|
|
747
|
-
return {
|
|
748
|
-
sessionId: this.session.sessionId,
|
|
749
|
-
finalText,
|
|
750
|
-
usage,
|
|
751
|
-
timeline,
|
|
752
|
-
};
|
|
753
|
-
}
|
|
754
|
-
async startTurn(prompt, _options) {
|
|
755
|
-
if (this.activeTurnId) {
|
|
756
|
-
throw new Error("A Pi turn is already active");
|
|
757
|
-
}
|
|
758
|
-
const payload = convertPromptInput(prompt);
|
|
759
|
-
const turnId = randomUUID();
|
|
760
|
-
this.activeTurnId = turnId;
|
|
761
|
-
try {
|
|
762
|
-
await applyPiSessionRecoveryPolicy(this.session);
|
|
763
|
-
}
|
|
764
|
-
catch (error) {
|
|
765
|
-
this.activeTurnId = null;
|
|
766
|
-
this.emit({
|
|
767
|
-
type: "turn_failed",
|
|
768
|
-
provider: PI_PROVIDER,
|
|
769
|
-
turnId,
|
|
770
|
-
error: toDiagnosticErrorMessage(error),
|
|
771
|
-
});
|
|
772
|
-
return { turnId };
|
|
773
|
-
}
|
|
774
|
-
void this.session
|
|
775
|
-
.prompt(payload.text, payload.images ? { images: payload.images } : undefined)
|
|
776
|
-
.catch((error) => {
|
|
777
|
-
const failedTurnId = this.activeTurnId ?? turnId;
|
|
778
|
-
this.activeTurnId = null;
|
|
779
|
-
if (isPiRequestAbortError(error)) {
|
|
780
|
-
this.emit({
|
|
781
|
-
type: "turn_canceled",
|
|
782
|
-
provider: PI_PROVIDER,
|
|
783
|
-
turnId: failedTurnId,
|
|
784
|
-
reason: toDiagnosticErrorMessage(error),
|
|
785
|
-
});
|
|
786
|
-
return;
|
|
787
|
-
}
|
|
788
|
-
this.emit({
|
|
789
|
-
type: "turn_failed",
|
|
790
|
-
provider: PI_PROVIDER,
|
|
791
|
-
turnId: failedTurnId,
|
|
792
|
-
error: toDiagnosticErrorMessage(error),
|
|
793
|
-
});
|
|
794
|
-
});
|
|
795
|
-
return { turnId };
|
|
796
|
-
}
|
|
797
|
-
subscribe(callback) {
|
|
798
|
-
this.subscribers.add(callback);
|
|
799
|
-
return () => {
|
|
800
|
-
this.subscribers.delete(callback);
|
|
801
|
-
};
|
|
802
|
-
}
|
|
803
|
-
async *streamHistory() {
|
|
804
|
-
const pendingToolCalls = new Map();
|
|
805
|
-
let userIndex = 0;
|
|
806
|
-
for (const message of this.session.messages) {
|
|
807
|
-
if (message.role === "user") {
|
|
808
|
-
const text = getUserMessageText(message.content);
|
|
809
|
-
if (text) {
|
|
810
|
-
yield {
|
|
811
|
-
type: "timeline",
|
|
812
|
-
provider: PI_PROVIDER,
|
|
813
|
-
item: {
|
|
814
|
-
type: "user_message",
|
|
815
|
-
text,
|
|
816
|
-
messageId: `pi-user-${userIndex}`,
|
|
817
|
-
},
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
userIndex += 1;
|
|
821
|
-
continue;
|
|
822
|
-
}
|
|
823
|
-
if (message.role === "assistant") {
|
|
824
|
-
for (const content of message.content) {
|
|
825
|
-
if (content.type === "text" && content.text) {
|
|
826
|
-
yield {
|
|
827
|
-
type: "timeline",
|
|
828
|
-
provider: PI_PROVIDER,
|
|
829
|
-
item: { type: "assistant_message", text: content.text },
|
|
830
|
-
};
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
if (content.type === "thinking" && content.thinking) {
|
|
834
|
-
yield {
|
|
835
|
-
type: "timeline",
|
|
836
|
-
provider: PI_PROVIDER,
|
|
837
|
-
item: { type: "reasoning", text: content.thinking },
|
|
838
|
-
};
|
|
839
|
-
continue;
|
|
840
|
-
}
|
|
841
|
-
if (content.type === "toolCall") {
|
|
842
|
-
const tracked = parseToolArgs(content.name, content.arguments);
|
|
843
|
-
pendingToolCalls.set(content.id, tracked);
|
|
844
|
-
yield {
|
|
845
|
-
type: "timeline",
|
|
846
|
-
provider: PI_PROVIDER,
|
|
847
|
-
item: {
|
|
848
|
-
type: "tool_call",
|
|
849
|
-
callId: content.id,
|
|
850
|
-
name: tracked.toolName,
|
|
851
|
-
status: "running",
|
|
852
|
-
detail: mapToolDetail(tracked, null),
|
|
853
|
-
error: null,
|
|
854
|
-
},
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
continue;
|
|
859
|
-
}
|
|
860
|
-
if (message.role === "toolResult") {
|
|
861
|
-
const tracked = pendingToolCalls.get(message.toolCallId) ?? parseToolArgs(message.toolName, null);
|
|
862
|
-
pendingToolCalls.delete(message.toolCallId);
|
|
863
|
-
const result = parseToolResult({ content: message.content });
|
|
864
|
-
const detail = mapToolDetail(tracked, result);
|
|
865
|
-
if (message.isError) {
|
|
866
|
-
const errorText = extractTextFromToolResult(result) ?? "Tool call failed";
|
|
867
|
-
yield {
|
|
868
|
-
type: "timeline",
|
|
869
|
-
provider: PI_PROVIDER,
|
|
870
|
-
item: {
|
|
871
|
-
type: "tool_call",
|
|
872
|
-
callId: message.toolCallId,
|
|
873
|
-
name: tracked.toolName,
|
|
874
|
-
status: "failed",
|
|
875
|
-
detail,
|
|
876
|
-
error: errorText,
|
|
877
|
-
},
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
else {
|
|
881
|
-
yield {
|
|
882
|
-
type: "timeline",
|
|
883
|
-
provider: PI_PROVIDER,
|
|
884
|
-
item: {
|
|
885
|
-
type: "tool_call",
|
|
886
|
-
callId: message.toolCallId,
|
|
887
|
-
name: tracked.toolName,
|
|
888
|
-
status: "completed",
|
|
889
|
-
detail,
|
|
890
|
-
error: null,
|
|
891
|
-
},
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
continue;
|
|
895
|
-
}
|
|
896
|
-
if (message.role === "bashExecution") {
|
|
897
|
-
const callId = `pi-bash-${message.timestamp}`;
|
|
898
|
-
const exitCode = message.exitCode ?? null;
|
|
899
|
-
const detail = {
|
|
900
|
-
type: "shell",
|
|
901
|
-
command: message.command,
|
|
902
|
-
output: message.output,
|
|
903
|
-
exitCode,
|
|
904
|
-
};
|
|
905
|
-
yield {
|
|
906
|
-
type: "timeline",
|
|
907
|
-
provider: PI_PROVIDER,
|
|
908
|
-
item: {
|
|
909
|
-
type: "tool_call",
|
|
910
|
-
callId,
|
|
911
|
-
name: "bash",
|
|
912
|
-
status: message.cancelled ? "canceled" : "completed",
|
|
913
|
-
detail,
|
|
914
|
-
error: null,
|
|
915
|
-
},
|
|
916
|
-
};
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
async getRuntimeInfo() {
|
|
921
|
-
const thinkingOptionId = resolveThinkingOptionId(this.lastKnownThinkingOptionId, this.session.thinkingLevel);
|
|
922
|
-
return {
|
|
923
|
-
provider: PI_PROVIDER,
|
|
924
|
-
sessionId: this.session.sessionId,
|
|
925
|
-
model: this.session.model ? `${this.session.model.provider}/${this.session.model.id}` : null,
|
|
926
|
-
thinkingOptionId,
|
|
927
|
-
modeId: null,
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
async getAvailableModes() {
|
|
931
|
-
return [];
|
|
932
|
-
}
|
|
933
|
-
async getCurrentMode() {
|
|
934
|
-
return null;
|
|
935
|
-
}
|
|
936
|
-
async setMode(modeId) {
|
|
937
|
-
void modeId;
|
|
938
|
-
throw new Error("Pi does not expose selectable modes");
|
|
939
|
-
}
|
|
940
|
-
getPendingPermissions() {
|
|
941
|
-
return [];
|
|
942
|
-
}
|
|
943
|
-
async respondToPermission(requestId, response) {
|
|
944
|
-
void requestId;
|
|
945
|
-
void response;
|
|
946
|
-
}
|
|
947
|
-
describePersistence() {
|
|
948
|
-
return {
|
|
949
|
-
provider: PI_PROVIDER,
|
|
950
|
-
sessionId: this.session.sessionId,
|
|
951
|
-
nativeHandle: this.session.sessionManager.getSessionFile(),
|
|
952
|
-
metadata: {
|
|
953
|
-
cwd: this.session.sessionManager.getCwd(),
|
|
954
|
-
},
|
|
955
|
-
};
|
|
956
|
-
}
|
|
957
|
-
async interrupt() {
|
|
958
|
-
await this.session.abort();
|
|
959
|
-
}
|
|
960
|
-
async close() {
|
|
961
|
-
await this.runtime.dispose();
|
|
962
|
-
}
|
|
963
|
-
async listCommands() {
|
|
964
|
-
return buildSlashCommands(this.session);
|
|
965
|
-
}
|
|
966
|
-
async setModel(modelId) {
|
|
967
|
-
const parsedReference = parseModelReference(modelId);
|
|
968
|
-
if (!parsedReference) {
|
|
969
|
-
return;
|
|
970
|
-
}
|
|
971
|
-
const model = findModelInRegistry(this.modelRegistry, parsedReference);
|
|
972
|
-
if (!model) {
|
|
973
|
-
throw new Error(`Unknown Pi model: ${modelId}`);
|
|
974
|
-
}
|
|
975
|
-
await this.session.setModel(model);
|
|
976
|
-
this.config.model = `${model.provider}/${model.id}`;
|
|
977
|
-
}
|
|
978
|
-
async setThinkingOption(thinkingOptionId) {
|
|
979
|
-
const thinkingLevel = normalizePiThinkingOption(thinkingOptionId) ?? DEFAULT_PI_THINKING_LEVEL;
|
|
980
|
-
this.session.setThinkingLevel(thinkingLevel);
|
|
981
|
-
this.lastKnownThinkingOptionId = thinkingLevel;
|
|
982
|
-
this.config.thinkingOptionId = thinkingLevel;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
export class PiDirectAgentClient {
|
|
986
|
-
constructor(options) {
|
|
987
|
-
this.provider = PI_PROVIDER;
|
|
988
|
-
this.capabilities = PI_CAPABILITIES;
|
|
989
|
-
this.modelRegistry = null;
|
|
990
|
-
this.logger = options.logger;
|
|
991
|
-
this.runtimeSettings = options.runtimeSettings;
|
|
992
|
-
}
|
|
993
|
-
async getSessionServices(cwd, agentDir) {
|
|
994
|
-
return createAgentSessionServices({
|
|
995
|
-
cwd,
|
|
996
|
-
...(agentDir ? { agentDir } : {}),
|
|
997
|
-
...(this.modelRegistry ? { modelRegistry: this.modelRegistry } : {}),
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
resolveConfiguredModel(registry, modelId) {
|
|
1001
|
-
const parsedReference = parseModelReference(modelId ?? null);
|
|
1002
|
-
if (!parsedReference) {
|
|
1003
|
-
return undefined;
|
|
1004
|
-
}
|
|
1005
|
-
return findModelInRegistry(registry, parsedReference);
|
|
1006
|
-
}
|
|
1007
|
-
async createSdkRuntime(config, sessionManager, options = {}) {
|
|
1008
|
-
const createRuntime = async ({ cwd, agentDir, sessionManager: runtimeSessionManager, sessionStartEvent, }) => {
|
|
1009
|
-
const thinkingLevel = normalizePiThinkingOption(config.thinkingOptionId) ?? options.defaultThinkingLevel;
|
|
1010
|
-
const services = await this.getSessionServices(cwd, agentDir);
|
|
1011
|
-
const model = this.resolveConfiguredModel(services.modelRegistry, config.model);
|
|
1012
|
-
return {
|
|
1013
|
-
...(await createAgentSessionFromServices({
|
|
1014
|
-
services,
|
|
1015
|
-
sessionManager: runtimeSessionManager,
|
|
1016
|
-
sessionStartEvent,
|
|
1017
|
-
...(thinkingLevel ? { thinkingLevel } : {}),
|
|
1018
|
-
...(model ? { model } : {}),
|
|
1019
|
-
})),
|
|
1020
|
-
services,
|
|
1021
|
-
diagnostics: services.diagnostics,
|
|
1022
|
-
};
|
|
1023
|
-
};
|
|
1024
|
-
const runtime = await createAgentSessionRuntime(createRuntime, {
|
|
1025
|
-
cwd: sessionManager.getCwd(),
|
|
1026
|
-
agentDir: getAgentDir(),
|
|
1027
|
-
sessionManager,
|
|
1028
|
-
});
|
|
1029
|
-
await runtime.session.bindExtensions({});
|
|
1030
|
-
applySystemPrompt(runtime.session, config.systemPrompt);
|
|
1031
|
-
return { runtime, modelRegistry: runtime.services.modelRegistry };
|
|
1032
|
-
}
|
|
1033
|
-
async createSession(config, _launchContext) {
|
|
1034
|
-
const { runtime, modelRegistry } = await this.createSdkRuntime(config, SessionManager.create(config.cwd), {
|
|
1035
|
-
defaultThinkingLevel: DEFAULT_PI_THINKING_LEVEL,
|
|
1036
|
-
});
|
|
1037
|
-
return new PiDirectAgentSession(runtime, modelRegistry, config);
|
|
1038
|
-
}
|
|
1039
|
-
async resumeSession(handle, overrides, _launchContext) {
|
|
1040
|
-
const sessionFile = handle.nativeHandle;
|
|
1041
|
-
if (!sessionFile) {
|
|
1042
|
-
throw new Error("Pi resume requires a native session file handle");
|
|
1043
|
-
}
|
|
1044
|
-
const initialManager = SessionManager.open(sessionFile);
|
|
1045
|
-
const persistenceMetadata = parsePersistenceMetadata(handle.metadata);
|
|
1046
|
-
const cwd = overrides?.cwd ?? persistenceMetadata.cwd ?? initialManager.getCwd();
|
|
1047
|
-
const resumedManager = SessionManager.open(sessionFile, undefined, cwd);
|
|
1048
|
-
const mergedConfig = {
|
|
1049
|
-
provider: PI_PROVIDER,
|
|
1050
|
-
cwd,
|
|
1051
|
-
model: overrides?.model,
|
|
1052
|
-
thinkingOptionId: overrides?.thinkingOptionId,
|
|
1053
|
-
systemPrompt: overrides?.systemPrompt,
|
|
1054
|
-
featureValues: overrides?.featureValues,
|
|
1055
|
-
title: overrides?.title,
|
|
1056
|
-
approvalPolicy: overrides?.approvalPolicy,
|
|
1057
|
-
sandboxMode: overrides?.sandboxMode,
|
|
1058
|
-
networkAccess: overrides?.networkAccess,
|
|
1059
|
-
webSearch: overrides?.webSearch,
|
|
1060
|
-
extra: overrides?.extra,
|
|
1061
|
-
mcpServers: overrides?.mcpServers,
|
|
1062
|
-
internal: overrides?.internal,
|
|
1063
|
-
modeId: overrides?.modeId,
|
|
1064
|
-
};
|
|
1065
|
-
const { runtime, modelRegistry } = await this.createSdkRuntime(mergedConfig, resumedManager);
|
|
1066
|
-
return new PiDirectAgentSession(runtime, modelRegistry, mergedConfig);
|
|
1067
|
-
}
|
|
1068
|
-
async listModels(options) {
|
|
1069
|
-
const services = await this.getSessionServices(options.cwd);
|
|
1070
|
-
const models = services.modelRegistry.getAvailable().map((model) => ({
|
|
1071
|
-
provider: PI_PROVIDER,
|
|
1072
|
-
id: `${model.provider}/${model.id}`,
|
|
1073
|
-
label: `${model.provider}/${model.name}`,
|
|
1074
|
-
description: `${model.provider}/${model.id}`,
|
|
1075
|
-
metadata: {
|
|
1076
|
-
provider: model.provider,
|
|
1077
|
-
modelId: model.id,
|
|
1078
|
-
},
|
|
1079
|
-
thinkingOptions: model.reasoning ? PI_THINKING_OPTIONS.map(mapThinkingOption) : undefined,
|
|
1080
|
-
defaultThinkingOptionId: model.reasoning ? DEFAULT_PI_THINKING_LEVEL : undefined,
|
|
1081
|
-
}));
|
|
1082
|
-
return transformPiModels(models);
|
|
1083
|
-
}
|
|
1084
|
-
async listModes(_options) {
|
|
1085
|
-
return [];
|
|
1086
|
-
}
|
|
1087
|
-
async isAvailable() {
|
|
1088
|
-
const command = this.runtimeSettings?.command;
|
|
1089
|
-
if (command?.mode === "replace" && command.argv[0]) {
|
|
1090
|
-
if (!existsSync(command.argv[0])) {
|
|
1091
|
-
return false;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
else if (!(await isCommandAvailable(PI_BINARY_COMMAND))) {
|
|
1095
|
-
return false;
|
|
1096
|
-
}
|
|
1097
|
-
const registry = ModelRegistry.create(AuthStorage.create());
|
|
1098
|
-
return registry.getAvailable().length > 0;
|
|
1099
|
-
}
|
|
1100
|
-
async getDiagnostic() {
|
|
1101
|
-
try {
|
|
1102
|
-
const available = await this.isAvailable();
|
|
1103
|
-
const binaryOverride = this.runtimeSettings?.command;
|
|
1104
|
-
const binary = binaryOverride?.mode === "replace" && binaryOverride.argv[0]
|
|
1105
|
-
? binaryOverride.argv[0]
|
|
1106
|
-
: await findExecutable(PI_BINARY_COMMAND);
|
|
1107
|
-
const version = binary ? await resolveBinaryVersion(binary) : "unknown";
|
|
1108
|
-
const authConfigPath = join(homedir(), ".pi", "agent", "auth.json");
|
|
1109
|
-
let modelsValue = "Not checked";
|
|
1110
|
-
let status = formatDiagnosticStatus(available);
|
|
1111
|
-
const registry = ModelRegistry.create(AuthStorage.create());
|
|
1112
|
-
const configuredProviders = Array.from(new Set(registry.getAvailable().map((model) => model.provider))).sort();
|
|
1113
|
-
if (available) {
|
|
1114
|
-
try {
|
|
1115
|
-
const models = await this.listModels({ cwd: homedir(), force: false });
|
|
1116
|
-
modelsValue = String(models.length);
|
|
1117
|
-
}
|
|
1118
|
-
catch (error) {
|
|
1119
|
-
modelsValue = `Error - ${toDiagnosticErrorMessage(error)}`;
|
|
1120
|
-
status = formatDiagnosticStatus(available, {
|
|
1121
|
-
source: "model fetch",
|
|
1122
|
-
cause: error,
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
return {
|
|
1127
|
-
diagnostic: formatProviderDiagnostic("Pi", [
|
|
1128
|
-
{ label: "Binary", value: binary ?? "not found" },
|
|
1129
|
-
{ label: "Version", value: version },
|
|
1130
|
-
{
|
|
1131
|
-
label: "Configured providers",
|
|
1132
|
-
value: configuredProviders.length > 0 ? configuredProviders.join(", ") : "none",
|
|
1133
|
-
},
|
|
1134
|
-
{
|
|
1135
|
-
label: "Auth config (~/.pi/agent/auth.json)",
|
|
1136
|
-
value: existsSync(authConfigPath) ? "found" : "not found",
|
|
1137
|
-
},
|
|
1138
|
-
{ label: "Models", value: modelsValue },
|
|
1139
|
-
{ label: "Status", value: status },
|
|
1140
|
-
]),
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
catch (error) {
|
|
1144
|
-
this.logger.debug({ err: error }, "Pi diagnostic lookup failed");
|
|
1145
|
-
return {
|
|
1146
|
-
diagnostic: formatProviderDiagnosticError("Pi", error),
|
|
1147
|
-
};
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
//# sourceMappingURL=pi-direct-agent.js.map
|