@getpaseo/server 0.1.98 → 0.1.99

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.
Files changed (48) hide show
  1. package/dist/server/server/agent/agent-manager.js +2 -2
  2. package/dist/server/server/agent/agent-sdk-types.d.ts +11 -6
  3. package/dist/server/server/agent/provider-registry.d.ts +6 -3
  4. package/dist/server/server/agent/provider-registry.js +48 -22
  5. package/dist/server/server/agent/provider-snapshot-manager.js +26 -14
  6. package/dist/server/server/agent/providers/acp-agent.d.ts +5 -3
  7. package/dist/server/server/agent/providers/acp-agent.js +32 -19
  8. package/dist/server/server/agent/providers/claude/agent.d.ts +2 -2
  9. package/dist/server/server/agent/providers/claude/agent.js +5 -25
  10. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +3 -2
  11. package/dist/server/server/agent/providers/codex-app-server-agent.js +6 -25
  12. package/dist/server/server/agent/providers/copilot-acp-agent.js +1 -31
  13. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +0 -1
  14. package/dist/server/server/agent/providers/generic-acp-agent.js +2 -108
  15. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +2 -3
  16. package/dist/server/server/agent/providers/mock-load-test-agent.js +5 -5
  17. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +2 -3
  18. package/dist/server/server/agent/providers/mock-slow-provider.js +2 -5
  19. package/dist/server/server/agent/providers/opencode-agent.d.ts +4 -3
  20. package/dist/server/server/agent/providers/opencode-agent.js +48 -99
  21. package/dist/server/server/agent/providers/pi/agent.d.ts +2 -3
  22. package/dist/server/server/agent/providers/pi/agent.js +8 -73
  23. package/dist/server/server/agent/providers/pi/cli-runtime.js +2 -2
  24. package/dist/server/server/agent/providers/pi/runtime.d.ts +1 -1
  25. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +1 -1
  26. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +1 -1
  27. package/dist/server/server/session/agent-config/agent-config-session.d.ts +50 -0
  28. package/dist/server/server/session/agent-config/agent-config-session.js +98 -0
  29. package/dist/server/server/session/chat/chat-schedule-loop-session.d.ts +120 -0
  30. package/dist/server/server/session/chat/chat-schedule-loop-session.js +489 -0
  31. package/dist/server/server/session/checkout/checkout-session.d.ts +142 -0
  32. package/dist/server/server/session/checkout/checkout-session.js +925 -0
  33. package/dist/server/server/session/daemon/daemon-session.d.ts +50 -0
  34. package/dist/server/server/session/daemon/daemon-session.js +98 -0
  35. package/dist/server/server/session/files/workspace-files-session.d.ts +43 -0
  36. package/dist/server/server/session/files/workspace-files-session.js +218 -0
  37. package/dist/server/server/session/project-config/project-config-session.d.ts +34 -0
  38. package/dist/server/server/session/project-config/project-config-session.js +125 -0
  39. package/dist/server/server/session/provider/provider-catalog-session.d.ts +74 -0
  40. package/dist/server/server/session/provider/provider-catalog-session.js +339 -0
  41. package/dist/server/server/session/voice/voice-session.d.ts +166 -0
  42. package/dist/server/server/session/voice/voice-session.js +893 -0
  43. package/dist/server/server/{voice → session/voice}/voice-turn-controller.d.ts +2 -2
  44. package/dist/server/server/{voice → session/voice}/voice-turn-controller.js +2 -2
  45. package/dist/server/server/session.d.ts +13 -208
  46. package/dist/server/server/session.js +2132 -5105
  47. package/dist/server/utils/checkout-git.d.ts +6 -0
  48. package/package.json +5 -5
@@ -1,10 +1,7 @@
1
- import { homedir } from "node:os";
2
1
  import { z } from "zod";
3
2
  import { checkProviderLaunchAvailable, resolveProviderLaunch } from "../provider-launch-config.js";
4
- import { ACPAgentClient, DEFAULT_ACP_CAPABILITIES, deriveModelDefinitionsFromACP, deriveModesFromACP, } from "./acp-agent.js";
5
- import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
6
- const ACP_DIAGNOSTIC_INITIALIZE_TIMEOUT_MS = 8000;
7
- const ACP_DIAGNOSTIC_SESSION_TIMEOUT_MS = 8000;
3
+ import { ACPAgentClient, DEFAULT_ACP_CAPABILITIES } from "./acp-agent.js";
4
+ import { formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, } from "./diagnostic-utils.js";
8
5
  export const GenericACPProviderParamsSchema = z
9
6
  .object({
10
7
  supportsMcpServers: z.boolean().optional(),
@@ -43,17 +40,7 @@ export class GenericACPAgentClient extends ACPAgentClient {
43
40
  try {
44
41
  const launch = await this.resolveConfiguredLaunch();
45
42
  const availability = await checkProviderLaunchAvailable(launch);
46
- const available = availability.available;
47
43
  const versionProbe = buildVersionProbeCommand(this.command);
48
- const probeResult = available
49
- ? await this.runDiagnosticACPProbe()
50
- : {
51
- status: formatDiagnosticStatus(false),
52
- initialize: "Not checked",
53
- session: "Not checked",
54
- models: "Not checked",
55
- modes: "Not checked",
56
- };
57
44
  return {
58
45
  diagnostic: formatProviderDiagnostic(providerName, [
59
46
  { label: "Provider ID", value: this.providerId ?? "unknown" },
@@ -70,11 +57,6 @@ export class GenericACPAgentClient extends ACPAgentClient {
70
57
  label: "Version command",
71
58
  value: formatCommand(versionProbe.command, versionProbe.args),
72
59
  },
73
- { label: "ACP initialize", value: probeResult.initialize },
74
- { label: "ACP session/new", value: probeResult.session },
75
- { label: "Models", value: probeResult.models },
76
- { label: "Modes", value: probeResult.modes },
77
- { label: "Status", value: probeResult.status },
78
60
  ]),
79
61
  };
80
62
  }
@@ -90,50 +72,6 @@ export class GenericACPAgentClient extends ACPAgentClient {
90
72
  defaultBinary: this.command[0],
91
73
  });
92
74
  }
93
- async runDiagnosticACPProbe() {
94
- let initializeValue = "Not checked";
95
- let sessionValue = "Not checked";
96
- try {
97
- const probe = await this.spawnProcess({
98
- NO_BROWSER: "true",
99
- NO_OPEN_BROWSER: "1",
100
- GEMINI_CLI_NO_BROWSER: "true",
101
- CI: "1",
102
- }, {
103
- initializeTimeoutMs: ACP_DIAGNOSTIC_INITIALIZE_TIMEOUT_MS,
104
- });
105
- try {
106
- initializeValue = formatInitializeResult(probe.initialize);
107
- const response = await withTimeout(probe.connection.newSession({
108
- cwd: homedir(),
109
- mcpServers: [],
110
- }), ACP_DIAGNOSTIC_SESSION_TIMEOUT_MS, "ACP session/new");
111
- sessionValue = response.sessionId ? `ok (${response.sessionId})` : "ok";
112
- const transformed = this.transformSessionResponse(response);
113
- return {
114
- status: formatDiagnosticStatus(true),
115
- initialize: initializeValue,
116
- session: sessionValue,
117
- ...summarizeSessionState(this.provider, transformed),
118
- };
119
- }
120
- finally {
121
- await this.closeProbe(probe);
122
- }
123
- }
124
- catch (error) {
125
- return {
126
- status: formatDiagnosticStatus(true, {
127
- source: "ACP probe",
128
- cause: error,
129
- }),
130
- initialize: formatProbeError(initializeValue, error),
131
- session: initializeValue === "Not checked" ? "Not checked" : formatProbeError(sessionValue, error),
132
- models: "Not checked",
133
- modes: "Not checked",
134
- };
135
- }
136
- }
137
75
  }
138
76
  function buildGenericACPCapabilities(options) {
139
77
  const params = parseGenericACPProviderParams(options.providerParams);
@@ -200,48 +138,4 @@ function takePackageSpecPrefix(args) {
200
138
  }
201
139
  return prefix;
202
140
  }
203
- function formatInitializeResult(initialize) {
204
- const agentInfo = isAgentInfo(initialize.agentInfo)
205
- ? `${initialize.agentInfo.name}${initialize.agentInfo.version ? ` ${initialize.agentInfo.version}` : ""}`
206
- : "ok";
207
- return `ok (protocol ${initialize.protocolVersion}, ${agentInfo})`;
208
- }
209
- function isAgentInfo(value) {
210
- return (typeof value === "object" &&
211
- value !== null &&
212
- "name" in value &&
213
- typeof Reflect.get(value, "name") === "string");
214
- }
215
- function summarizeSessionState(provider, response) {
216
- const models = deriveModelDefinitionsFromACP(provider, response.models, response.configOptions);
217
- const { modes } = deriveModesFromACP([], response.modes, response.configOptions);
218
- return {
219
- models: `${models.length}`,
220
- modes: modes.length > 0 ? modes.map((mode) => mode.label || mode.id).join(", ") : "none reported",
221
- };
222
- }
223
- function formatProbeError(currentValue, error) {
224
- if (currentValue !== "Not checked") {
225
- return currentValue;
226
- }
227
- return `Error - ${toDiagnosticErrorMessage(error)}`;
228
- }
229
- async function withTimeout(promise, timeoutMs, label) {
230
- let timeout = null;
231
- try {
232
- return await Promise.race([
233
- promise,
234
- new Promise((_, reject) => {
235
- timeout = setTimeout(() => {
236
- reject(new Error(`${label} timed out after ${timeoutMs}ms`));
237
- }, timeoutMs);
238
- }),
239
- ]);
240
- }
241
- finally {
242
- if (timeout) {
243
- clearTimeout(timeout);
244
- }
245
- }
246
- }
247
141
  //# sourceMappingURL=generic-acp-agent.js.map
@@ -1,5 +1,5 @@
1
1
  import type { Logger } from "pino";
2
- import type { AgentCapabilityFlags, AgentClient, AgentFeature, AgentLaunchContext, AgentMode, AgentModelDefinition, AgentPersistenceHandle, AgentPermissionRequest, AgentPermissionResponse, AgentPermissionResult, AgentPromptInput, AgentProvider, AgentRunOptions, AgentRunResult, AgentRuntimeInfo, AgentSession, AgentSessionConfig, AgentStreamEvent, ImportableProviderSession, ImportProviderSessionContext, ImportProviderSessionInput, ListModesOptions, ListModelsOptions } from "../agent-sdk-types.js";
2
+ import type { AgentCapabilityFlags, AgentClient, AgentFeature, AgentLaunchContext, AgentMode, AgentPersistenceHandle, AgentPermissionRequest, AgentPermissionResponse, AgentPermissionResult, AgentPromptInput, AgentProvider, AgentRunOptions, AgentRunResult, AgentRuntimeInfo, AgentSession, AgentSessionConfig, AgentStreamEvent, FetchCatalogOptions, ImportableProviderSession, ImportProviderSessionContext, ImportProviderSessionInput, ProviderCatalog } from "../agent-sdk-types.js";
3
3
  export declare const MOCK_LOAD_TEST_PROVIDER_ID = "mock";
4
4
  export declare const MOCK_LOAD_TEST_DEFAULT_MODEL_ID = "five-minute-stream";
5
5
  export declare class MockLoadTestAgentClient implements AgentClient {
@@ -9,8 +9,7 @@ export declare class MockLoadTestAgentClient implements AgentClient {
9
9
  constructor(logger?: Logger | undefined);
10
10
  createSession(config: AgentSessionConfig, _launchContext?: AgentLaunchContext): Promise<AgentSession>;
11
11
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, _launchContext?: AgentLaunchContext): Promise<AgentSession>;
12
- listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
13
- listModes(_options: ListModesOptions): Promise<AgentMode[]>;
12
+ fetchCatalog(_options: FetchCatalogOptions): Promise<ProviderCatalog>;
14
13
  listImportableSessions(): Promise<ImportableProviderSession[]>;
15
14
  importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
16
15
  isAvailable(): Promise<boolean>;
@@ -379,11 +379,11 @@ export class MockLoadTestAgentClient {
379
379
  logger: this.logger,
380
380
  });
381
381
  }
382
- async listModels(_options) {
383
- return MODELS;
384
- }
385
- async listModes(_options) {
386
- return getAgentProviderDefinition(MOCK_LOAD_TEST_PROVIDER_ID).modes;
382
+ async fetchCatalog(_options) {
383
+ return {
384
+ models: MODELS,
385
+ modes: getAgentProviderDefinition(MOCK_LOAD_TEST_PROVIDER_ID).modes,
386
+ };
387
387
  }
388
388
  async listImportableSessions() {
389
389
  return [];
@@ -1,11 +1,10 @@
1
- import type { AgentCapabilityFlags, AgentClient, AgentLaunchContext, AgentMode, AgentModelDefinition, AgentPersistenceHandle, AgentProvider, AgentSession, AgentSessionConfig, ListModelsOptions, ListModesOptions } from "../agent-sdk-types.js";
1
+ import type { AgentCapabilityFlags, AgentClient, AgentLaunchContext, AgentPersistenceHandle, AgentProvider, AgentSession, AgentSessionConfig, FetchCatalogOptions, ProviderCatalog } from "../agent-sdk-types.js";
2
2
  export declare const MOCK_SLOW_PROVIDER_ID = "mock-slow";
3
3
  export declare class MockSlowProviderClient implements AgentClient {
4
4
  readonly provider: AgentProvider;
5
5
  readonly capabilities: AgentCapabilityFlags;
6
6
  isAvailable(): Promise<boolean>;
7
- listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
8
- listModes(_options: ListModesOptions): Promise<AgentMode[]>;
7
+ fetchCatalog(_options: FetchCatalogOptions): Promise<ProviderCatalog>;
9
8
  getDiagnostic(): Promise<{
10
9
  diagnostic: string;
11
10
  }>;
@@ -21,15 +21,12 @@ export class MockSlowProviderClient {
21
21
  async isAvailable() {
22
22
  return process.env.PASEO_ENABLE_MOCK_SLOW === "true";
23
23
  }
24
- listModels(_options) {
25
- return neverResolves();
26
- }
27
- listModes(_options) {
24
+ async fetchCatalog(_options) {
28
25
  return neverResolves();
29
26
  }
30
27
  async getDiagnostic() {
31
28
  return {
32
- diagnostic: "Mock slow provider: dev-only. listModels() never resolves so the snapshot manager will time out.",
29
+ diagnostic: "Mock slow provider: dev-only. fetchCatalog() never resolves so the snapshot manager will time out.",
33
30
  };
34
31
  }
35
32
  createSession(_config, _launchContext) {
@@ -1,6 +1,6 @@
1
1
  import { type AssistantMessage as OpenCodeAssistantMessage, type Event as OpenCodeEvent, type FilePartInput as OpenCodeFilePartInput, type Message as OpenCodeMessage, type OpencodeClient, type Part as OpenCodePart, type TextPartInput as OpenCodeTextPartInput } from "@opencode-ai/sdk/v2/client";
2
2
  import type { Logger } from "pino";
3
- import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentTimelineItem, type AgentUsage, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ResolveAgentCreateConfigInput, type ResolveAgentCreateConfigResult, type ListModelsOptions, type ListModesOptions, type ToolCallTimelineItem } from "../agent-sdk-types.js";
3
+ import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentTimelineItem, type AgentUsage, type FetchCatalogOptions, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ResolveAgentCreateConfigInput, type ResolveAgentCreateConfigResult, type ProviderCatalog, type ToolCallTimelineItem } from "../agent-sdk-types.js";
4
4
  import { isDefaultAgentCreateConfigUnattended } from "../create-agent-mode.js";
5
5
  import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
6
6
  import { type OpenCodeRuntime } from "./opencode/runtime.js";
@@ -118,8 +118,7 @@ export declare class OpenCodeAgentClient implements AgentClient {
118
118
  constructor(logger: Logger, runtimeSettings?: ProviderRuntimeSettings, deps?: OpenCodeAgentClientDeps);
119
119
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext, options?: AgentCreateSessionOptions): Promise<AgentSession>;
120
120
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
121
- listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
122
- listModes(options: ListModesOptions): Promise<AgentMode[]>;
121
+ fetchCatalog(options: FetchCatalogOptions): Promise<ProviderCatalog>;
123
122
  listCommands(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
124
123
  listFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
125
124
  listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
@@ -129,6 +128,8 @@ export declare class OpenCodeAgentClient implements AgentClient {
129
128
  getDiagnostic(): Promise<{
130
129
  diagnostic: string;
131
130
  }>;
131
+ private fetchModelsFromClient;
132
+ private fetchModesFromClient;
132
133
  private assertConfig;
133
134
  private populateModelContextWindowCache;
134
135
  }
@@ -1,4 +1,3 @@
1
- import { homedir } from "node:os";
2
1
  import { createPathEquivalenceMatcher } from "../../../utils/path.js";
3
2
  import pLimit from "p-limit";
4
3
  import { z } from "zod";
@@ -11,7 +10,7 @@ import { execCommand } from "../../../utils/spawn.js";
11
10
  import { buildToolCallDisplayModel } from "@getpaseo/protocol/tool-call-display";
12
11
  import { mapOpencodeToolCall } from "./opencode/tool-call-mapper.js";
13
12
  import { OpenCodeServerManager } from "./opencode/server-manager.js";
14
- import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
13
+ import { formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
15
14
  import { runProviderTurn } from "./provider-runner.js";
16
15
  import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
17
16
  import { composeSystemPromptParts } from "../system-prompt.js";
@@ -940,70 +939,17 @@ export class OpenCodeAgentClient {
940
939
  throw error;
941
940
  }
942
941
  }
943
- async listModels(options) {
944
- const acquisition = await this.runtime.acquireServer({ force: options.force });
945
- const { url } = acquisition.server;
946
- const client = this.runtime.createClient({
947
- baseUrl: url,
948
- directory: options.cwd,
949
- });
950
- try {
951
- // Background model discovery can be legitimately slow while OpenCode refreshes
952
- // provider state, so allow longer than turn execution paths.
953
- const response = await openCodeMetadataLimit(() => withTimeout(client.provider.list({ directory: options.cwd }), OPENCODE_PROVIDER_LIST_TIMEOUT_MS, `OpenCode provider.list timed out after ${OPENCODE_PROVIDER_LIST_TIMEOUT_MS / 1000}s - server may not be authenticated or connected to any providers`));
954
- if (response.error) {
955
- throw new Error(`Failed to fetch OpenCode providers: ${JSON.stringify(response.error)}`);
956
- }
957
- const providers = response.data;
958
- if (!providers) {
959
- return [];
960
- }
961
- const connectedProviderIds = new Set(providers.connected);
962
- // Providers with source "api" are managed by the OpenCode console/subscription (e.g. Pi
963
- // coding agent). They do not appear in `connected` (which only lists env/config providers)
964
- // but are fully usable — OpenCode authenticates them internally via the console session.
965
- const isAccessible = (provider) => connectedProviderIds.has(provider.id) || provider.source === "api";
966
- // Fail fast if no providers are accessible at all
967
- if (!providers.all.some(isAccessible)) {
968
- throw new Error("OpenCode has no connected providers. Please authenticate with at least one provider " +
969
- "(e.g., openai, anthropic), set appropriate environment variables (e.g., OPENAI_API_KEY), " +
970
- "or log in to OpenCode Go via the console.");
971
- }
972
- const models = [];
973
- this.modelContextWindows.clear();
974
- for (const provider of providers.all) {
975
- if (!isAccessible(provider)) {
976
- continue;
977
- }
978
- for (const [modelId, model] of Object.entries(provider.models)) {
979
- const definition = buildOpenCodeModelDefinition(provider, modelId, model);
980
- const contextWindowMaxTokens = extractOpenCodeModelContextWindow(model);
981
- if (contextWindowMaxTokens !== undefined) {
982
- this.modelContextWindows.set(buildOpenCodeModelLookupKey(provider.id, modelId), contextWindowMaxTokens);
983
- }
984
- models.push(definition);
985
- }
986
- }
987
- return models;
988
- }
989
- finally {
990
- acquisition.release();
991
- }
992
- }
993
- async listModes(options) {
942
+ async fetchCatalog(options) {
994
943
  const acquisition = await this.runtime.acquireServer({ force: options.force });
995
944
  const { url } = acquisition.server;
996
945
  const directory = options.cwd;
997
946
  const client = this.runtime.createClient({ baseUrl: url, directory });
998
947
  try {
999
- const response = await openCodeMetadataLimit(() => withTimeout(client.app.agents({ directory }), 10000, "OpenCode app.agents timed out after 10s"));
1000
- if (response.error || !response.data) {
1001
- return DEFAULT_MODES;
1002
- }
1003
- const discovered = response.data
1004
- .filter(isSelectableOpenCodeAgent)
1005
- .map(mapOpenCodeAgentToMode);
1006
- return mergeOpenCodeModes(discovered);
948
+ const [models, modes] = await Promise.all([
949
+ this.fetchModelsFromClient(client, directory),
950
+ this.fetchModesFromClient(client, directory),
951
+ ]);
952
+ return { models, modes };
1007
953
  }
1008
954
  finally {
1009
955
  acquisition.release();
@@ -1094,17 +1040,6 @@ export class OpenCodeAgentClient {
1094
1040
  defaultBinary: "opencode",
1095
1041
  });
1096
1042
  const availability = await checkProviderLaunchAvailable(launch);
1097
- const available = availability.available;
1098
- let serverStatus = "Not running";
1099
- let modelsValue = "Not checked";
1100
- let status = formatDiagnosticStatus(available);
1101
- try {
1102
- const { url } = await this.runtime.ensureServerRunning();
1103
- serverStatus = `Running (${url})`;
1104
- }
1105
- catch (error) {
1106
- serverStatus = `Unavailable (${toDiagnosticErrorMessage(error)})`;
1107
- }
1108
1043
  let authValue = "Not checked";
1109
1044
  const authCommand = availability.available
1110
1045
  ? (availability.resolvedPath ?? launch.command)
@@ -1122,40 +1057,13 @@ export class OpenCodeAgentClient {
1122
1057
  authValue = `Error - ${toDiagnosticErrorMessage(error)}`;
1123
1058
  }
1124
1059
  }
1125
- if (available) {
1126
- try {
1127
- const models = await this.listModels({ cwd: homedir(), force: false });
1128
- modelsValue = String(models.length);
1129
- }
1130
- catch (error) {
1131
- modelsValue = `Error - ${toDiagnosticErrorMessage(error)}`;
1132
- status = formatDiagnosticStatus(available, {
1133
- source: "model fetch",
1134
- cause: error,
1135
- });
1136
- }
1137
- if (!modelsValue.startsWith("Error -")) {
1138
- try {
1139
- await this.listModes({ cwd: homedir(), force: false });
1140
- }
1141
- catch (error) {
1142
- status = formatDiagnosticStatus(available, {
1143
- source: "mode fetch",
1144
- cause: error,
1145
- });
1146
- }
1147
- }
1148
- }
1149
1060
  return {
1150
1061
  diagnostic: formatProviderDiagnostic("OpenCode", [
1151
1062
  ...(await buildCommandResolutionDiagnosticRows(launch, {
1152
1063
  knownBinaryNames: ["opencode"],
1153
1064
  })),
1154
1065
  ...(await buildBinaryDiagnosticRows(launch, availability)),
1155
- { label: "Server", value: serverStatus },
1156
1066
  { label: "Auth", value: authValue },
1157
- { label: "Models", value: modelsValue },
1158
- { label: "Status", value: status },
1159
1067
  ]),
1160
1068
  };
1161
1069
  }
@@ -1165,6 +1073,47 @@ export class OpenCodeAgentClient {
1165
1073
  };
1166
1074
  }
1167
1075
  }
1076
+ async fetchModelsFromClient(client, directory) {
1077
+ const response = await openCodeMetadataLimit(() => withTimeout(client.provider.list({ directory }), OPENCODE_PROVIDER_LIST_TIMEOUT_MS, `OpenCode provider.list timed out after ${OPENCODE_PROVIDER_LIST_TIMEOUT_MS / 1000}s - server may not be authenticated or connected to any providers`));
1078
+ if (response.error) {
1079
+ throw new Error(`Failed to fetch OpenCode providers: ${JSON.stringify(response.error)}`);
1080
+ }
1081
+ const providers = response.data;
1082
+ if (!providers) {
1083
+ return [];
1084
+ }
1085
+ const connectedProviderIds = new Set(providers.connected);
1086
+ const isAccessible = (provider) => connectedProviderIds.has(provider.id) || provider.source === "api";
1087
+ if (!providers.all.some(isAccessible)) {
1088
+ throw new Error("OpenCode has no connected providers. Please authenticate with at least one provider " +
1089
+ "(e.g., openai, anthropic), set appropriate environment variables (e.g., OPENAI_API_KEY), " +
1090
+ "or log in to OpenCode Go via the console.");
1091
+ }
1092
+ const models = [];
1093
+ this.modelContextWindows.clear();
1094
+ for (const provider of providers.all) {
1095
+ if (!isAccessible(provider)) {
1096
+ continue;
1097
+ }
1098
+ for (const [modelId, model] of Object.entries(provider.models)) {
1099
+ const definition = buildOpenCodeModelDefinition(provider, modelId, model);
1100
+ const contextWindowMaxTokens = extractOpenCodeModelContextWindow(model);
1101
+ if (contextWindowMaxTokens !== undefined) {
1102
+ this.modelContextWindows.set(buildOpenCodeModelLookupKey(provider.id, modelId), contextWindowMaxTokens);
1103
+ }
1104
+ models.push(definition);
1105
+ }
1106
+ }
1107
+ return models;
1108
+ }
1109
+ async fetchModesFromClient(client, directory) {
1110
+ const response = await openCodeMetadataLimit(() => withTimeout(client.app.agents({ directory }), 10000, "OpenCode app.agents timed out after 10s"));
1111
+ if (response.error || !response.data) {
1112
+ return DEFAULT_MODES;
1113
+ }
1114
+ const discovered = response.data.filter(isSelectableOpenCodeAgent).map(mapOpenCodeAgentToMode);
1115
+ return mergeOpenCodeModes(discovered);
1116
+ }
1168
1117
  assertConfig(config) {
1169
1118
  if (config.provider !== "opencode") {
1170
1119
  throw new Error(`OpenCodeAgentClient received config for provider '${config.provider}'`);
@@ -1,6 +1,6 @@
1
1
  import type { Logger } from "pino";
2
2
  import { z } from "zod";
3
- import { type AgentCapabilityFlags, type AgentClient, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModesOptions, type ListModelsOptions } from "../../agent-sdk-types.js";
3
+ import { type AgentCapabilityFlags, type AgentClient, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type FetchCatalogOptions, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ProviderCatalog } from "../../agent-sdk-types.js";
4
4
  import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
5
5
  import type { PiRuntime, PiRuntimeSession } from "./runtime.js";
6
6
  import type { PiSessionState } from "./rpc-types.js";
@@ -112,8 +112,7 @@ export declare class PiRpcAgentClient implements AgentClient {
112
112
  constructor(options: PiRpcAgentClientOptions);
113
113
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext): Promise<AgentSession>;
114
114
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, _launchContext?: AgentLaunchContext): Promise<AgentSession>;
115
- listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
116
- listModes(_options: ListModesOptions): Promise<AgentMode[]>;
115
+ fetchCatalog(options: FetchCatalogOptions): Promise<ProviderCatalog>;
117
116
  listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
118
117
  importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../../agent-sdk-types.js").ImportedProviderSession>;
119
118
  isAvailable(): Promise<boolean>;
@@ -3,13 +3,12 @@ import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { homedir, tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { z } from "zod";
6
- import { withTimeout } from "../../../../utils/promise-timeout.js";
7
6
  import { importSessionFromPersistence } from "../../provider-session-import.js";
8
7
  import { runProviderTurn } from "../provider-runner.js";
9
8
  import { checkProviderLaunchAvailable, resolveProviderLaunch, } from "../../provider-launch-config.js";
10
9
  import { renderPromptAttachmentAsText } from "../../prompt-attachments.js";
11
10
  import { composeSystemPromptParts } from "../../system-prompt.js";
12
- import { buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, toDiagnosticErrorMessage, } from "../diagnostic-utils.js";
11
+ import { buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, formatProviderDiagnostic, formatProviderDiagnosticError, toDiagnosticErrorMessage, } from "../diagnostic-utils.js";
13
12
  import { getUserMessageText, streamPiHistory, } from "./history-mapper.js";
14
13
  import { PiCliRuntime } from "./cli-runtime.js";
15
14
  import { revertPiConversation } from "./rewind.js";
@@ -18,6 +17,7 @@ import { mapToolDetail, parseToolArgs, parseToolResult, resolveToolCallName, } f
18
17
  const PI_PROVIDER = "pi";
19
18
  const DEFAULT_PI_THINKING_LEVEL = "medium";
20
19
  const PI_BINARY_COMMAND = process.env.PI_COMMAND ?? process.env.PI_ACP_PI_COMMAND ?? "pi";
20
+ const PI_CATALOG_REQUEST_TIMEOUT_MS = 120000;
21
21
  const PASEO_PI_TREE_EXTENSION_COMMAND = "paseo_tree";
22
22
  const PASEO_PI_CAPTURE_EXTENSION_COMMAND = "paseo_capture_entries";
23
23
  const PASEO_PI_ENTRY_CAPTURE_MARKER = "PASEO_ENTRY_CAPTURE";
@@ -1538,18 +1538,16 @@ export class PiRpcAgentClient {
1538
1538
  throw error;
1539
1539
  }
1540
1540
  }
1541
- async listModels(options) {
1541
+ async fetchCatalog(options) {
1542
1542
  const runtimeSession = await this.runtime.startSession({ cwd: options.cwd });
1543
1543
  try {
1544
- return transformPiModels((await runtimeSession.getAvailableModels()).map(mapPiModel));
1544
+ const models = transformPiModels((await runtimeSession.getAvailableModels(PI_CATALOG_REQUEST_TIMEOUT_MS)).map(mapPiModel));
1545
+ return { models, modes: [] };
1545
1546
  }
1546
1547
  finally {
1547
1548
  await runtimeSession.close();
1548
1549
  }
1549
1550
  }
1550
- async listModes(_options) {
1551
- return [];
1552
- }
1553
1551
  async listImportableSessions(options) {
1554
1552
  return await listPiImportableSessions({
1555
1553
  ...options,
@@ -1569,28 +1567,9 @@ export class PiRpcAgentClient {
1569
1567
  }
1570
1568
  async isAvailable() {
1571
1569
  try {
1572
- return await withTimeout((async () => {
1573
- const launch = await this.resolvePiLaunch();
1574
- const availability = await checkProviderLaunchAvailable(launch);
1575
- if (!availability.available) {
1576
- return false;
1577
- }
1578
- const runtimeSession = await this.runtime
1579
- .startSession({ cwd: homedir() })
1580
- .catch(() => null);
1581
- if (!runtimeSession) {
1582
- return false;
1583
- }
1584
- try {
1585
- return (await runtimeSession.getAvailableModels()).length > 0;
1586
- }
1587
- catch {
1588
- return false;
1589
- }
1590
- finally {
1591
- await runtimeSession.close().catch(() => undefined);
1592
- }
1593
- })(), 2000, "Pi availability check timed out");
1570
+ const launch = await this.resolvePiLaunch();
1571
+ const availability = await checkProviderLaunchAvailable(launch);
1572
+ return availability.available;
1594
1573
  }
1595
1574
  catch {
1596
1575
  return false;
@@ -1600,61 +1579,17 @@ export class PiRpcAgentClient {
1600
1579
  try {
1601
1580
  const launch = await this.resolvePiLaunch();
1602
1581
  const availability = await checkProviderLaunchAvailable(launch);
1603
- const available = availability.available;
1604
1582
  const authConfigPath = join(homedir(), ".pi", "agent", "auth.json");
1605
- let modelsValue = "Not checked";
1606
- let configuredProvidersValue = "none";
1607
- let mcpToolsValue = "Not checked";
1608
- let status = formatDiagnosticStatus(available);
1609
- if (availability.available) {
1610
- const runtimeSession = await this.runtime
1611
- .startSession({ cwd: homedir() })
1612
- .catch((error) => {
1613
- status = formatDiagnosticStatus(false, {
1614
- source: "startup",
1615
- cause: error,
1616
- });
1617
- return null;
1618
- });
1619
- if (runtimeSession) {
1620
- try {
1621
- const models = await runtimeSession.getAvailableModels();
1622
- modelsValue = String(models.length);
1623
- const configuredProviders = Array.from(new Set(models.map((model) => model.provider))).sort();
1624
- configuredProvidersValue =
1625
- configuredProviders.length > 0 ? configuredProviders.join(", ") : "none";
1626
- const commands = await runtimeSession.getCommands();
1627
- mcpToolsValue = commands.some(isPiMcpAdapterCommand)
1628
- ? "yes (pi-mcp-adapter loaded)"
1629
- : "no (install pi-mcp-adapter)";
1630
- }
1631
- catch (error) {
1632
- modelsValue = `Error - ${toDiagnosticErrorMessage(error)}`;
1633
- mcpToolsValue = `Error - ${toDiagnosticErrorMessage(error)}`;
1634
- status = formatDiagnosticStatus(available, {
1635
- source: "model fetch",
1636
- cause: error,
1637
- });
1638
- }
1639
- finally {
1640
- await runtimeSession.close().catch(() => undefined);
1641
- }
1642
- }
1643
- }
1644
1583
  return {
1645
1584
  diagnostic: formatProviderDiagnostic("Pi", [
1646
1585
  ...(await buildCommandResolutionDiagnosticRows(launch, {
1647
1586
  knownBinaryNames: [launch.command],
1648
1587
  })),
1649
1588
  ...(await buildBinaryDiagnosticRows(launch, availability)),
1650
- { label: "Configured providers", value: configuredProvidersValue },
1651
1589
  {
1652
1590
  label: "Auth config (~/.pi/agent/auth.json)",
1653
1591
  value: existsSync(authConfigPath) ? "found" : "not found",
1654
1592
  },
1655
- { label: "Models", value: modelsValue },
1656
- { label: "Paseo MCP tools", value: mcpToolsValue },
1657
- { label: "Status", value: status },
1658
1593
  ]),
1659
1594
  };
1660
1595
  }
@@ -95,8 +95,8 @@ class PiCliRuntimeSession {
95
95
  const data = (await this.request({ type: "get_messages" }));
96
96
  return data.messages ?? [];
97
97
  }
98
- async getAvailableModels() {
99
- const data = (await this.request({ type: "get_available_models" }));
98
+ async getAvailableModels(timeoutMs) {
99
+ const data = (await this.request({ type: "get_available_models" }, timeoutMs));
100
100
  return data.models ?? [];
101
101
  }
102
102
  async setModel(provider, modelId) {
@@ -33,7 +33,7 @@ export interface PiRuntimeSession {
33
33
  abort(): Promise<void>;
34
34
  getState(): Promise<PiSessionState>;
35
35
  getMessages(): Promise<PiAgentMessage[]>;
36
- getAvailableModels(): Promise<PiModel[]>;
36
+ getAvailableModels(timeoutMs?: number): Promise<PiModel[]>;
37
37
  setModel(provider: string, modelId: string): Promise<PiModel>;
38
38
  setThinkingLevel(level: string): Promise<void>;
39
39
  getSessionStats(): Promise<PiSessionStats>;
@@ -61,7 +61,7 @@ export declare class FakePiSession implements PiRuntimeSession {
61
61
  abort(): Promise<void>;
62
62
  getState(): Promise<PiSessionState>;
63
63
  getMessages(): Promise<PiAgentMessage[]>;
64
- getAvailableModels(): Promise<PiModel[]>;
64
+ getAvailableModels(_timeoutMs?: number): Promise<PiModel[]>;
65
65
  setModel(provider: string, modelId: string): Promise<PiModel>;
66
66
  setThinkingLevel(level: string): Promise<void>;
67
67
  getSessionStats(): Promise<PiSessionStats>;
@@ -100,7 +100,7 @@ export class FakePiSession {
100
100
  async getMessages() {
101
101
  return this.messages;
102
102
  }
103
- async getAvailableModels() {
103
+ async getAvailableModels(_timeoutMs) {
104
104
  return this.models;
105
105
  }
106
106
  async setModel(provider, modelId) {