@getpaseo/server 0.1.98 → 0.1.100

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 (59) 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 +49 -22
  5. package/dist/server/server/agent/provider-snapshot-manager.js +26 -14
  6. package/dist/server/server/agent/providers/acp-agent.d.ts +23 -3
  7. package/dist/server/server/agent/providers/acp-agent.js +139 -9
  8. package/dist/server/server/agent/providers/claude/agent.d.ts +2 -2
  9. package/dist/server/server/agent/providers/claude/agent.js +41 -77
  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.d.ts +2 -1
  13. package/dist/server/server/agent/providers/copilot-acp-agent.js +11 -31
  14. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +0 -1
  15. package/dist/server/server/agent/providers/generic-acp-agent.js +2 -108
  16. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +2 -3
  17. package/dist/server/server/agent/providers/mock-load-test-agent.js +5 -5
  18. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +2 -3
  19. package/dist/server/server/agent/providers/mock-slow-provider.js +2 -5
  20. package/dist/server/server/agent/providers/opencode/server-manager.d.ts +14 -11
  21. package/dist/server/server/agent/providers/opencode/server-manager.js +149 -91
  22. package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +6 -5
  23. package/dist/server/server/agent/providers/opencode/test-server-manager.js +13 -3
  24. package/dist/server/server/agent/providers/opencode/test-utils/{test-opencode-runtime.d.ts → test-opencode-harness.d.ts} +11 -11
  25. package/dist/server/server/agent/providers/opencode/test-utils/{test-opencode-runtime.js → test-opencode-harness.js} +23 -10
  26. package/dist/server/server/agent/providers/opencode-agent.d.ts +13 -6
  27. package/dist/server/server/agent/providers/opencode-agent.js +74 -137
  28. package/dist/server/server/agent/providers/pi/agent.d.ts +4 -4
  29. package/dist/server/server/agent/providers/pi/agent.js +13 -76
  30. package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +3 -0
  31. package/dist/server/server/agent/providers/pi/cli-runtime.js +8 -5
  32. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +2 -1
  33. package/dist/server/server/agent/providers/pi/runtime.d.ts +1 -1
  34. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +1 -1
  35. package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +1 -1
  36. package/dist/server/server/session/agent-config/agent-config-session.d.ts +50 -0
  37. package/dist/server/server/session/agent-config/agent-config-session.js +98 -0
  38. package/dist/server/server/session/chat/chat-schedule-loop-session.d.ts +120 -0
  39. package/dist/server/server/session/chat/chat-schedule-loop-session.js +489 -0
  40. package/dist/server/server/session/checkout/checkout-session.d.ts +142 -0
  41. package/dist/server/server/session/checkout/checkout-session.js +925 -0
  42. package/dist/server/server/session/daemon/daemon-session.d.ts +50 -0
  43. package/dist/server/server/session/daemon/daemon-session.js +98 -0
  44. package/dist/server/server/session/files/workspace-files-session.d.ts +43 -0
  45. package/dist/server/server/session/files/workspace-files-session.js +218 -0
  46. package/dist/server/server/session/project-config/project-config-session.d.ts +34 -0
  47. package/dist/server/server/session/project-config/project-config-session.js +125 -0
  48. package/dist/server/server/session/provider/provider-catalog-session.d.ts +74 -0
  49. package/dist/server/server/session/provider/provider-catalog-session.js +339 -0
  50. package/dist/server/server/session/voice/voice-session.d.ts +166 -0
  51. package/dist/server/server/session/voice/voice-session.js +893 -0
  52. package/dist/server/server/{voice → session/voice}/voice-turn-controller.d.ts +2 -2
  53. package/dist/server/server/{voice → session/voice}/voice-turn-controller.js +2 -2
  54. package/dist/server/server/session.d.ts +13 -208
  55. package/dist/server/server/session.js +2132 -5105
  56. package/dist/server/utils/checkout-git.d.ts +6 -0
  57. package/package.json +5 -5
  58. package/dist/server/server/agent/providers/opencode/runtime.d.ts +0 -28
  59. package/dist/server/server/agent/providers/opencode/runtime.js +0 -5
@@ -1,4 +1,4 @@
1
- import { homedir } from "node:os";
1
+ import { createOpencodeClient, } from "@opencode-ai/sdk/v2/client";
2
2
  import { createPathEquivalenceMatcher } from "../../../utils/path.js";
3
3
  import pLimit from "p-limit";
4
4
  import { z } from "zod";
@@ -10,12 +10,11 @@ import { withTimeout } from "../../../utils/promise-timeout.js";
10
10
  import { execCommand } from "../../../utils/spawn.js";
11
11
  import { buildToolCallDisplayModel } from "@getpaseo/protocol/tool-call-display";
12
12
  import { mapOpencodeToolCall } from "./opencode/tool-call-mapper.js";
13
- import { OpenCodeServerManager } from "./opencode/server-manager.js";
14
- import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
13
+ import { OpenCodeServerManager, } from "./opencode/server-manager.js";
14
+ import { formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
15
15
  import { runProviderTurn } from "./provider-runner.js";
16
16
  import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
17
17
  import { composeSystemPromptParts } from "../system-prompt.js";
18
- import { createSdkOpenCodeClient, } from "./opencode/runtime.js";
19
18
  import { normalizeProviderReplayTimestamp } from "../provider-history-timestamps.js";
20
19
  import { revertOpenCodeConversationAndFiles } from "./opencode/rewind.js";
21
20
  const OPENCODE_CAPABILITIES = {
@@ -852,22 +851,8 @@ export const __openCodeInternals = {
852
851
  return OpenCodeAgentSession;
853
852
  },
854
853
  };
855
- class ProductionOpenCodeRuntime {
856
- constructor(serverManager) {
857
- this.serverManager = serverManager;
858
- }
859
- async acquireServer(options) {
860
- return this.serverManager.acquire(options);
861
- }
862
- async ensureServerRunning() {
863
- return this.serverManager.ensureRunning();
864
- }
865
- createClient(options) {
866
- return createSdkOpenCodeClient(options);
867
- }
868
- async shutdown() {
869
- await this.serverManager.shutdown();
870
- }
854
+ function createSdkOpenCodeClient(options) {
855
+ return createOpencodeClient(options);
871
856
  }
872
857
  export class OpenCodeAgentClient {
873
858
  constructor(logger, runtimeSettings, deps = {}) {
@@ -878,20 +863,20 @@ export class OpenCodeAgentClient {
878
863
  this.modelContextWindows = new Map();
879
864
  this.logger = logger.child({ module: "agent", provider: "opencode" });
880
865
  this.runtimeSettings = runtimeSettings;
881
- this.runtime =
882
- deps.runtime ??
883
- new ProductionOpenCodeRuntime(OpenCodeServerManager.getInstance(this.logger, runtimeSettings, {
866
+ this.serverManager =
867
+ deps.serverManager ??
868
+ OpenCodeServerManager.getInstance(this.logger, runtimeSettings, {
884
869
  managedProcesses: deps.managedProcesses,
885
- }));
870
+ });
871
+ this.createOpenCodeClient = deps.createClient ?? createSdkOpenCodeClient;
886
872
  }
887
873
  async createSession(config, launchContext, options) {
888
874
  const openCodeConfig = this.assertConfig(config);
889
- const acquisition = await this.runtime.acquireServer({
890
- force: false,
891
- env: launchContext?.env,
892
- });
875
+ const acquisition = launchContext?.env
876
+ ? await this.serverManager.acquireDedicated(launchContext.env)
877
+ : await this.serverManager.acquireCurrent();
893
878
  const { url } = acquisition.server;
894
- const client = this.runtime.createClient({
879
+ const client = this.createOpenCodeClient({
895
880
  baseUrl: url,
896
881
  directory: openCodeConfig.cwd,
897
882
  });
@@ -925,9 +910,9 @@ export class OpenCodeAgentClient {
925
910
  cwd,
926
911
  };
927
912
  const openCodeConfig = this.assertConfig(config);
928
- const acquisition = await this.runtime.acquireServer({ force: false });
913
+ const acquisition = await this.serverManager.acquireCurrent();
929
914
  const { url } = acquisition.server;
930
- const client = this.runtime.createClient({
915
+ const client = this.createOpenCodeClient({
931
916
  baseUrl: url,
932
917
  directory: openCodeConfig.cwd,
933
918
  });
@@ -940,70 +925,19 @@ export class OpenCodeAgentClient {
940
925
  throw error;
941
926
  }
942
927
  }
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) {
994
- const acquisition = await this.runtime.acquireServer({ force: options.force });
928
+ async fetchCatalog(options) {
929
+ const acquisition = options.force
930
+ ? await this.serverManager.acquireNew()
931
+ : await this.serverManager.acquireCurrent();
995
932
  const { url } = acquisition.server;
996
933
  const directory = options.cwd;
997
- const client = this.runtime.createClient({ baseUrl: url, directory });
934
+ const client = this.createOpenCodeClient({ baseUrl: url, directory });
998
935
  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);
936
+ const [models, modes] = await Promise.all([
937
+ this.fetchModelsFromClient(client, directory),
938
+ this.fetchModesFromClient(client, directory),
939
+ ]);
940
+ return { models, modes };
1007
941
  }
1008
942
  finally {
1009
943
  acquisition.release();
@@ -1011,9 +945,9 @@ export class OpenCodeAgentClient {
1011
945
  }
1012
946
  async listCommands(config) {
1013
947
  const openCodeConfig = this.assertConfig(config);
1014
- const acquisition = await this.runtime.acquireServer({ force: false });
948
+ const acquisition = await this.serverManager.acquireCurrent();
1015
949
  const { url } = acquisition.server;
1016
- const client = this.runtime.createClient({
950
+ const client = this.createOpenCodeClient({
1017
951
  baseUrl: url,
1018
952
  directory: openCodeConfig.cwd,
1019
953
  });
@@ -1028,9 +962,9 @@ export class OpenCodeAgentClient {
1028
962
  return [buildOpenCodeAutoAcceptFeature(this.assertConfig(config))];
1029
963
  }
1030
964
  async listImportableSessions(options) {
1031
- const acquisition = await this.runtime.acquireServer({ force: false });
965
+ const acquisition = await this.serverManager.acquireCurrent();
1032
966
  const { url } = acquisition.server;
1033
- const client = this.runtime.createClient({
967
+ const client = this.createOpenCodeClient({
1034
968
  baseUrl: url,
1035
969
  directory: options?.cwd ?? "",
1036
970
  });
@@ -1042,9 +976,9 @@ export class OpenCodeAgentClient {
1042
976
  }
1043
977
  }
1044
978
  async importSession(input, context) {
1045
- const acquisition = await this.runtime.acquireServer({ force: false });
979
+ const acquisition = await this.serverManager.acquireCurrent();
1046
980
  const { url } = acquisition.server;
1047
- const client = this.runtime.createClient({
981
+ const client = this.createOpenCodeClient({
1048
982
  baseUrl: url,
1049
983
  directory: input.cwd,
1050
984
  });
@@ -1085,7 +1019,7 @@ export class OpenCodeAgentClient {
1085
1019
  return availability.available;
1086
1020
  }
1087
1021
  async shutdown() {
1088
- await this.runtime.shutdown();
1022
+ await this.serverManager.shutdown();
1089
1023
  }
1090
1024
  async getDiagnostic() {
1091
1025
  try {
@@ -1094,17 +1028,6 @@ export class OpenCodeAgentClient {
1094
1028
  defaultBinary: "opencode",
1095
1029
  });
1096
1030
  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
1031
  let authValue = "Not checked";
1109
1032
  const authCommand = availability.available
1110
1033
  ? (availability.resolvedPath ?? launch.command)
@@ -1122,40 +1045,13 @@ export class OpenCodeAgentClient {
1122
1045
  authValue = `Error - ${toDiagnosticErrorMessage(error)}`;
1123
1046
  }
1124
1047
  }
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
1048
  return {
1150
1049
  diagnostic: formatProviderDiagnostic("OpenCode", [
1151
1050
  ...(await buildCommandResolutionDiagnosticRows(launch, {
1152
1051
  knownBinaryNames: ["opencode"],
1153
1052
  })),
1154
1053
  ...(await buildBinaryDiagnosticRows(launch, availability)),
1155
- { label: "Server", value: serverStatus },
1156
1054
  { label: "Auth", value: authValue },
1157
- { label: "Models", value: modelsValue },
1158
- { label: "Status", value: status },
1159
1055
  ]),
1160
1056
  };
1161
1057
  }
@@ -1165,6 +1061,47 @@ export class OpenCodeAgentClient {
1165
1061
  };
1166
1062
  }
1167
1063
  }
1064
+ async fetchModelsFromClient(client, directory) {
1065
+ 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`));
1066
+ if (response.error) {
1067
+ throw new Error(`Failed to fetch OpenCode providers: ${JSON.stringify(response.error)}`);
1068
+ }
1069
+ const providers = response.data;
1070
+ if (!providers) {
1071
+ return [];
1072
+ }
1073
+ const connectedProviderIds = new Set(providers.connected);
1074
+ const isAccessible = (provider) => connectedProviderIds.has(provider.id) || provider.source === "api";
1075
+ if (!providers.all.some(isAccessible)) {
1076
+ throw new Error("OpenCode has no connected providers. Please authenticate with at least one provider " +
1077
+ "(e.g., openai, anthropic), set appropriate environment variables (e.g., OPENAI_API_KEY), " +
1078
+ "or log in to OpenCode Go via the console.");
1079
+ }
1080
+ const models = [];
1081
+ this.modelContextWindows.clear();
1082
+ for (const provider of providers.all) {
1083
+ if (!isAccessible(provider)) {
1084
+ continue;
1085
+ }
1086
+ for (const [modelId, model] of Object.entries(provider.models)) {
1087
+ const definition = buildOpenCodeModelDefinition(provider, modelId, model);
1088
+ const contextWindowMaxTokens = extractOpenCodeModelContextWindow(model);
1089
+ if (contextWindowMaxTokens !== undefined) {
1090
+ this.modelContextWindows.set(buildOpenCodeModelLookupKey(provider.id, modelId), contextWindowMaxTokens);
1091
+ }
1092
+ models.push(definition);
1093
+ }
1094
+ }
1095
+ return models;
1096
+ }
1097
+ async fetchModesFromClient(client, directory) {
1098
+ const response = await openCodeMetadataLimit(() => withTimeout(client.app.agents({ directory }), 10000, "OpenCode app.agents timed out after 10s"));
1099
+ if (response.error || !response.data) {
1100
+ return DEFAULT_MODES;
1101
+ }
1102
+ const discovered = response.data.filter(isSelectableOpenCodeAgent).map(mapOpenCodeAgentToMode);
1103
+ return mergeOpenCodeModes(discovered);
1104
+ }
1168
1105
  assertConfig(config) {
1169
1106
  if (config.provider !== "opencode") {
1170
1107
  throw new Error(`OpenCodeAgentClient received config for provider '${config.provider}'`);
@@ -1,9 +1,9 @@
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
- import type { PiSessionState } from "./rpc-types.js";
6
+ import type { PiCommandsRpcType, PiSessionState } from "./rpc-types.js";
7
7
  export declare const PiProviderParamsSchema: z.ZodObject<{
8
8
  sessionDir: z.ZodOptional<z.ZodString>;
9
9
  }, z.core.$strict>;
@@ -11,6 +11,7 @@ interface PiRpcAgentClientOptions {
11
11
  logger: Logger;
12
12
  runtimeSettings?: ProviderRuntimeSettings;
13
13
  providerParams?: unknown;
14
+ commandsRpcType?: PiCommandsRpcType;
14
15
  runtime?: PiRuntime;
15
16
  }
16
17
  interface StartTurnResult {
@@ -112,8 +113,7 @@ export declare class PiRpcAgentClient implements AgentClient {
112
113
  constructor(options: PiRpcAgentClientOptions);
113
114
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext): Promise<AgentSession>;
114
115
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, _launchContext?: AgentLaunchContext): Promise<AgentSession>;
115
- listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
116
- listModes(_options: ListModesOptions): Promise<AgentMode[]>;
116
+ fetchCatalog(options: FetchCatalogOptions): Promise<ProviderCatalog>;
117
117
  listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
118
118
  importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../../agent-sdk-types.js").ImportedProviderSession>;
119
119
  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";
@@ -685,8 +685,8 @@ function mapPiModel(model) {
685
685
  defaultThinkingOptionId: model.reasoning ? DEFAULT_PI_THINKING_LEVEL : undefined,
686
686
  };
687
687
  }
688
- function createRuntime(logger, runtimeSettings) {
689
- return new PiCliRuntime({ logger, runtimeSettings });
688
+ function createRuntime(logger, runtimeSettings, commandsRpcType) {
689
+ return new PiCliRuntime({ logger, runtimeSettings, commandsRpcType });
690
690
  }
691
691
  export class PiRpcAgentSession {
692
692
  constructor(options) {
@@ -1458,7 +1458,9 @@ export class PiRpcAgentClient {
1458
1458
  this.logger = options.logger;
1459
1459
  this.runtimeSettings = options.runtimeSettings;
1460
1460
  this.providerParams = PiProviderParamsSchema.parse(options.providerParams ?? {});
1461
- this.runtime = options.runtime ?? createRuntime(options.logger, options.runtimeSettings);
1461
+ this.runtime =
1462
+ options.runtime ??
1463
+ createRuntime(options.logger, options.runtimeSettings, options.commandsRpcType);
1462
1464
  }
1463
1465
  async createSession(config, launchContext) {
1464
1466
  const mcpConfig = await this.prepareMcpConfig(config.cwd, config.mcpServers);
@@ -1538,18 +1540,16 @@ export class PiRpcAgentClient {
1538
1540
  throw error;
1539
1541
  }
1540
1542
  }
1541
- async listModels(options) {
1543
+ async fetchCatalog(options) {
1542
1544
  const runtimeSession = await this.runtime.startSession({ cwd: options.cwd });
1543
1545
  try {
1544
- return transformPiModels((await runtimeSession.getAvailableModels()).map(mapPiModel));
1546
+ const models = transformPiModels((await runtimeSession.getAvailableModels(PI_CATALOG_REQUEST_TIMEOUT_MS)).map(mapPiModel));
1547
+ return { models, modes: [] };
1545
1548
  }
1546
1549
  finally {
1547
1550
  await runtimeSession.close();
1548
1551
  }
1549
1552
  }
1550
- async listModes(_options) {
1551
- return [];
1552
- }
1553
1553
  async listImportableSessions(options) {
1554
1554
  return await listPiImportableSessions({
1555
1555
  ...options,
@@ -1569,28 +1569,9 @@ export class PiRpcAgentClient {
1569
1569
  }
1570
1570
  async isAvailable() {
1571
1571
  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");
1572
+ const launch = await this.resolvePiLaunch();
1573
+ const availability = await checkProviderLaunchAvailable(launch);
1574
+ return availability.available;
1594
1575
  }
1595
1576
  catch {
1596
1577
  return false;
@@ -1600,61 +1581,17 @@ export class PiRpcAgentClient {
1600
1581
  try {
1601
1582
  const launch = await this.resolvePiLaunch();
1602
1583
  const availability = await checkProviderLaunchAvailable(launch);
1603
- const available = availability.available;
1604
1584
  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
1585
  return {
1645
1586
  diagnostic: formatProviderDiagnostic("Pi", [
1646
1587
  ...(await buildCommandResolutionDiagnosticRows(launch, {
1647
1588
  knownBinaryNames: [launch.command],
1648
1589
  })),
1649
1590
  ...(await buildBinaryDiagnosticRows(launch, availability)),
1650
- { label: "Configured providers", value: configuredProvidersValue },
1651
1591
  {
1652
1592
  label: "Auth config (~/.pi/agent/auth.json)",
1653
1593
  value: existsSync(authConfigPath) ? "found" : "not found",
1654
1594
  },
1655
- { label: "Models", value: modelsValue },
1656
- { label: "Paseo MCP tools", value: mcpToolsValue },
1657
- { label: "Status", value: status },
1658
1595
  ]),
1659
1596
  };
1660
1597
  }
@@ -2,15 +2,18 @@ import { type ChildProcessWithoutNullStreams } from "node:child_process";
2
2
  import type { Logger } from "pino";
3
3
  import type { ProviderRuntimeSettings } from "../../provider-launch-config.js";
4
4
  import { type PiRuntime, type PiRuntimeLaunch, type PiRuntimeSession, type PiStartSessionInput } from "./runtime.js";
5
+ import type { PiCommandsRpcType } from "./rpc-types.js";
5
6
  export interface PiCliRuntimeOptions {
6
7
  logger: Logger;
7
8
  runtimeSettings?: ProviderRuntimeSettings;
8
9
  command?: [string, ...string[]];
10
+ commandsRpcType?: PiCommandsRpcType;
9
11
  spawnProcess?: (launch: PiRuntimeLaunch) => ChildProcessWithoutNullStreams;
10
12
  }
11
13
  export declare class PiCliRuntime implements PiRuntime {
12
14
  private readonly options;
13
15
  private readonly command;
16
+ private readonly commandsRpcType;
14
17
  private readonly spawnProcess;
15
18
  constructor(options: PiCliRuntimeOptions);
16
19
  startSession(input: PiStartSessionInput): Promise<PiRuntimeSession>;
@@ -5,6 +5,7 @@ const DEFAULT_PI_COMMAND = [
5
5
  process.env.PI_COMMAND ?? process.env.PI_ACP_PI_COMMAND ?? "pi",
6
6
  ];
7
7
  const DEFAULT_TIMEOUT_MS = 30000;
8
+ const DEFAULT_COMMANDS_RPC_TYPE = "get_commands";
8
9
  const STDERR_BUFFER_LIMIT = 8192;
9
10
  const GRACEFUL_SHUTDOWN_TIMEOUT_MS = 2000;
10
11
  const FORCE_SHUTDOWN_TIMEOUT_MS = 1000;
@@ -17,6 +18,7 @@ export class PiCliRuntime {
17
18
  constructor(options) {
18
19
  this.options = options;
19
20
  this.command = options.command ?? DEFAULT_PI_COMMAND;
21
+ this.commandsRpcType = options.commandsRpcType ?? DEFAULT_COMMANDS_RPC_TYPE;
20
22
  this.spawnProcess =
21
23
  options.spawnProcess ??
22
24
  ((launch) => {
@@ -36,13 +38,14 @@ export class PiCliRuntime {
36
38
  runtimeSettings: this.options.runtimeSettings,
37
39
  session: input,
38
40
  });
39
- return new PiCliRuntimeSession(launch, this.spawnProcess(launch), this.options.logger);
41
+ return new PiCliRuntimeSession(launch, this.spawnProcess(launch), this.options.logger, this.commandsRpcType);
40
42
  }
41
43
  }
42
44
  class PiCliRuntimeSession {
43
- constructor(_launch, child, logger) {
45
+ constructor(_launch, child, logger, commandsRpcType) {
44
46
  this.child = child;
45
47
  this.logger = logger;
48
+ this.commandsRpcType = commandsRpcType;
46
49
  this.pending = new Map();
47
50
  this.subscribers = new Set();
48
51
  this.stderrBuffer = "";
@@ -95,8 +98,8 @@ class PiCliRuntimeSession {
95
98
  const data = (await this.request({ type: "get_messages" }));
96
99
  return data.messages ?? [];
97
100
  }
98
- async getAvailableModels() {
99
- const data = (await this.request({ type: "get_available_models" }));
101
+ async getAvailableModels(timeoutMs) {
102
+ const data = (await this.request({ type: "get_available_models" }, timeoutMs));
100
103
  return data.models ?? [];
101
104
  }
102
105
  async setModel(provider, modelId) {
@@ -109,7 +112,7 @@ class PiCliRuntimeSession {
109
112
  return (await this.request({ type: "get_session_stats" }));
110
113
  }
111
114
  async getCommands() {
112
- const data = (await this.request({ type: "get_commands" }));
115
+ const data = (await this.request({ type: this.commandsRpcType }));
113
116
  return data.commands ?? [];
114
117
  }
115
118
  respondToExtensionUiRequest(id, response) {
@@ -94,6 +94,7 @@ export interface PiRpcSlashCommand {
94
94
  source: "extension" | "prompt" | "skill";
95
95
  sourceInfo?: Record<string, unknown>;
96
96
  }
97
+ export type PiCommandsRpcType = "get_commands" | "get_available_commands";
97
98
  export type PiRpcCommand = {
98
99
  id?: string;
99
100
  type: "prompt";
@@ -133,7 +134,7 @@ export type PiRpcCommand = {
133
134
  type: "get_session_stats";
134
135
  } | {
135
136
  id?: string;
136
- type: "get_commands";
137
+ type: PiCommandsRpcType;
137
138
  };
138
139
  export interface PiRpcResponse {
139
140
  id?: string;
@@ -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) {