@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
@@ -2580,8 +2580,8 @@ export class AgentManager {
2580
2580
  const client = this.clients.get(normalized.provider);
2581
2581
  if (client) {
2582
2582
  try {
2583
- const models = await client.listModels({ cwd: normalized.cwd, force: false });
2584
- const defaultModel = models.find((model) => model.isDefault) ?? models[0];
2583
+ const catalog = await client.fetchCatalog({ cwd: normalized.cwd, force: false });
2584
+ const defaultModel = catalog.models.find((model) => model.isDefault) ?? catalog.models[0];
2585
2585
  if (defaultModel) {
2586
2586
  normalized.model = defaultModel.id;
2587
2587
  }
@@ -578,21 +578,26 @@ export interface AgentSession {
578
578
  }): Promise<void>;
579
579
  } | null;
580
580
  }
581
- export interface ListModelsOptions {
581
+ export interface FetchCatalogOptions {
582
582
  cwd: string;
583
583
  force: boolean;
584
584
  }
585
- export interface ListModesOptions {
586
- cwd: string;
587
- force: boolean;
585
+ export interface ProviderCatalog {
586
+ models: AgentModelDefinition[];
587
+ modes: AgentMode[];
588
588
  }
589
589
  export interface AgentClient {
590
590
  readonly provider: AgentProvider;
591
591
  readonly capabilities: AgentCapabilityFlags;
592
592
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext, options?: AgentCreateSessionOptions): Promise<AgentSession>;
593
593
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
594
- listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
595
- listModes?(options: ListModesOptions): Promise<AgentMode[]>;
594
+ /**
595
+ * Discover models and modes together. Implementations may use one upstream
596
+ * process, separate upstream calls, static modes, or private helpers; callers
597
+ * outside the provider do not get separate runtime model/mode probes.
598
+ * The registry is responsible for merging configured model overrides.
599
+ */
600
+ fetchCatalog(options: FetchCatalogOptions): Promise<ProviderCatalog>;
596
601
  resolveCreateConfig?(input: ResolveAgentCreateConfigInput): ResolveAgentCreateConfigResult;
597
602
  isCreateConfigUnattended?(input: AgentCreateConfigUnattendedInput): boolean;
598
603
  listCommands?(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
@@ -1,5 +1,5 @@
1
1
  import type { Logger } from "pino";
2
- import type { AgentClient, AgentCreateConfigUnattendedInput, AgentMode, AgentModelDefinition, AgentProvider, AgentSession, ListModelsOptions, ListModesOptions, ResolveAgentCreateConfigInput, ResolveAgentCreateConfigResult } from "./agent-sdk-types.js";
2
+ import type { AgentClient, AgentCreateConfigUnattendedInput, AgentProvider, AgentSession, FetchCatalogOptions, ProviderCatalog, ResolveAgentCreateConfigInput, ResolveAgentCreateConfigResult } from "./agent-sdk-types.js";
3
3
  import type { WorkspaceGitService } from "../workspace-git-service.js";
4
4
  import type { ManagedProcessRegistry } from "../managed-processes/managed-processes.js";
5
5
  import type { AgentProviderRuntimeSettingsMap, ProviderOverride } from "./provider-launch-config.js";
@@ -17,8 +17,11 @@ export interface ProviderDefinition extends AgentProviderDefinition {
17
17
  createClient: (logger: Logger) => AgentClient;
18
18
  resolveCreateConfig: (input: ResolveAgentCreateConfigInput) => ResolveAgentCreateConfigResult;
19
19
  isCreateConfigUnattended: (input: AgentCreateConfigUnattendedInput) => boolean;
20
- fetchModels: (options: ListModelsOptions) => Promise<AgentModelDefinition[]>;
21
- fetchModes: (options: ListModesOptions) => Promise<AgentMode[]>;
20
+ /**
21
+ * Single catalog discovery call used by ProviderSnapshotManager. Should spawn
22
+ * at most one provider runtime process and return both models and modes.
23
+ */
24
+ fetchCatalog: (options: FetchCatalogOptions, client?: AgentClient) => Promise<ProviderCatalog>;
22
25
  }
23
26
  export interface BuildProviderRegistryOptions {
24
27
  runtimeSettings?: AgentProviderRuntimeSettingsMap;
@@ -232,10 +232,15 @@ function wrapClientProvider(provider, inner, profileModels, additionalModels, pr
232
232
  provider: inner.provider,
233
233
  }
234
234
  : undefined, launchContext)),
235
- listModels: async (options) => mergeModels(provider, profileModels, additionalModels, await inner.listModels(options), {
236
- profileModelsAreAdditive,
237
- }),
238
- listModes: inner.listModes?.bind(inner),
235
+ fetchCatalog: async (options) => {
236
+ const catalog = await inner.fetchCatalog(options);
237
+ return {
238
+ models: mergeModels(provider, profileModels, additionalModels, catalog.models, {
239
+ profileModelsAreAdditive,
240
+ }),
241
+ modes: catalog.modes,
242
+ };
243
+ },
239
244
  resolveCreateConfig: inner.resolveCreateConfig?.bind(inner),
240
245
  isCreateConfigUnattended: inner.isCreateConfigUnattended?.bind(inner),
241
246
  listImportableSessions: listImportableSessions
@@ -275,6 +280,22 @@ function wrapClientProvider(provider, inner, profileModels, additionalModels, pr
275
280
  }
276
281
  function createRegistryEntry(logger, provider, resolved) {
277
282
  const modelClient = resolved.createBaseClient(logger);
283
+ const hasReplacementModels = resolved.profileModels.length > 0 && !resolved.profileModelsAreAdditive;
284
+ const replacementModels = hasReplacementModels
285
+ ? resolved.profileModels.map((model) => mapModel(provider, model))
286
+ : [];
287
+ const decorateModes = (modes) => modes.map((mode) => {
288
+ if (mode.icon && mode.colorTier)
289
+ return mode;
290
+ const definitionMode = resolved.definition.modes.find((d) => d.id === mode.id);
291
+ if (!definitionMode)
292
+ return mode;
293
+ return Object.assign({}, mode, {
294
+ icon: mode.icon ?? definitionMode.icon,
295
+ colorTier: mode.colorTier ?? definitionMode.colorTier,
296
+ });
297
+ });
298
+ const hasStaticModes = resolved.definition.modes.length > 0;
278
299
  return {
279
300
  ...resolved.definition,
280
301
  enabled: resolved.enabled,
@@ -282,24 +303,29 @@ function createRegistryEntry(logger, provider, resolved) {
282
303
  createClient: (providerLogger) => createResolvedProviderClient(providerLogger, provider, resolved),
283
304
  resolveCreateConfig: modelClient.resolveCreateConfig ?? resolveDefaultAgentCreateConfig,
284
305
  isCreateConfigUnattended: modelClient.isCreateConfigUnattended ?? isDefaultAgentCreateConfigUnattended,
285
- fetchModels: async (options) => mergeModels(provider, resolved.profileModels, resolved.additionalModels, await modelClient.listModels(options), {
286
- profileModelsAreAdditive: resolved.profileModelsAreAdditive,
287
- }),
288
- fetchModes: async (options) => {
289
- const modes = modelClient.listModes
290
- ? await modelClient.listModes(options)
291
- : resolved.definition.modes;
292
- return modes.map((mode) => {
293
- if (mode.icon && mode.colorTier)
294
- return mode;
295
- const definitionMode = resolved.definition.modes.find((d) => d.id === mode.id);
296
- if (!definitionMode)
297
- return mode;
298
- return Object.assign({}, mode, {
299
- icon: mode.icon ?? definitionMode.icon,
300
- colorTier: mode.colorTier ?? definitionMode.colorTier,
301
- });
302
- });
306
+ fetchCatalog: async (options, client) => {
307
+ const catalogClient = client ?? modelClient;
308
+ if (hasReplacementModels) {
309
+ // Replacement models skip runtime model discovery, but additionalModels
310
+ // must still be merged on top. If modes are dynamic, probe for modes via
311
+ // the single catalog API; otherwise use static/empty modes with no runtime.
312
+ const models = mergeModelAdditions(provider, replacementModels, resolved.additionalModels);
313
+ if (hasStaticModes) {
314
+ return {
315
+ models,
316
+ modes: decorateModes(resolved.definition.modes),
317
+ };
318
+ }
319
+ const catalog = await catalogClient.fetchCatalog(options);
320
+ return { models, modes: decorateModes(catalog.modes) };
321
+ }
322
+ const catalog = await catalogClient.fetchCatalog(options);
323
+ return {
324
+ models: mergeModels(provider, resolved.profileModels, resolved.additionalModels, catalog.models, {
325
+ profileModelsAreAdditive: resolved.profileModelsAreAdditive,
326
+ }),
327
+ modes: decorateModes(catalog.modes),
328
+ };
303
329
  },
304
330
  };
305
331
  }
@@ -5,6 +5,7 @@ import { expandTilde } from "../../utils/path.js";
5
5
  import { withTimeout } from "../../utils/promise-timeout.js";
6
6
  import { buildProviderRegistry, shutdownAgentClients, } from "./provider-registry.js";
7
7
  import { applyMutableProviderConfigToOverrides } from "../daemon-config-store.js";
8
+ import { formatProviderDiagnostic } from "./providers/diagnostic-utils.js";
8
9
  const DEFAULT_REFRESH_TIMEOUT_MS = 30000;
9
10
  const REFRESH_TIMEOUT_ENV_VAR = "PASEO_PROVIDER_REFRESH_TIMEOUT_MS";
10
11
  // Provider refresh probes can be slow on cold starts (e.g. Copilot's first
@@ -179,13 +180,19 @@ export class ProviderSnapshotManager {
179
180
  });
180
181
  }
181
182
  async getProviderDiagnostic(provider) {
182
- const client = this.providerClients[provider];
183
- if (!client) {
184
- throw new Error(`Provider ${provider} is not configured`);
185
- }
186
- const diagnostic = client.getDiagnostic
183
+ const definition = this.requireProvider(provider);
184
+ const client = this.ensureClient(provider, definition);
185
+ // Force-refresh the snapshot so Models/Status come from the single catalog authority.
186
+ await this.refreshSnapshotForCwd({ cwd: homedir(), providers: [provider] });
187
+ const entry = await this.getProvider({ cwd: homedir(), provider, wait: true });
188
+ const modelCount = entry.status === "ready" ? String(entry.models?.length ?? 0) : "—";
189
+ const status = formatProviderStatus(entry);
190
+ const baseDiagnostic = client.getDiagnostic
187
191
  ? (await client.getDiagnostic()).diagnostic
188
- : "No diagnostic available for this provider.";
192
+ : formatProviderDiagnostic(definition.label ?? provider, [
193
+ { label: "Diagnostic", value: "No diagnostic available" },
194
+ ]);
195
+ const diagnostic = `${baseDiagnostic}\n Models: ${modelCount}\n Status: ${status}`;
189
196
  return { provider, diagnostic };
190
197
  }
191
198
  applyMutableProviderConfig(mutableProviders) {
@@ -238,8 +245,7 @@ export class ProviderSnapshotManager {
238
245
  createClient: () => client,
239
246
  resolveCreateConfig: client.resolveCreateConfig?.bind(client) ?? definition.resolveCreateConfig,
240
247
  isCreateConfigUnattended: client.isCreateConfigUnattended?.bind(client) ?? definition.isCreateConfigUnattended,
241
- fetchModels: client.listModels.bind(client),
242
- fetchModes: client.listModes?.bind(client) ?? definition.fetchModes,
248
+ fetchCatalog: client.fetchCatalog.bind(client),
243
249
  };
244
250
  }
245
251
  return registry;
@@ -448,16 +454,13 @@ export class ProviderSnapshotManager {
448
454
  setEntry({ ...base, status: "unavailable", enabled: true });
449
455
  return;
450
456
  }
451
- const [models, modes] = await withTimeout(Promise.all([
452
- definition.fetchModels({ cwd, force }),
453
- definition.fetchModes({ cwd, force }),
454
- ]), this.refreshTimeoutMs, `Timed out refreshing ${definition.label} after ${this.refreshTimeoutMs}ms`);
457
+ const catalog = await withTimeout(definition.fetchCatalog({ cwd, force }, client), this.refreshTimeoutMs, `Timed out refreshing ${definition.label} after ${this.refreshTimeoutMs}ms`);
455
458
  setEntry({
456
459
  ...base,
457
460
  status: "ready",
458
461
  enabled: true,
459
- models,
460
- modes,
462
+ models: catalog.models,
463
+ modes: catalog.modes,
461
464
  fetchedAt: new Date().toISOString(),
462
465
  });
463
466
  }
@@ -580,4 +583,13 @@ function toErrorMessage(error) {
580
583
  }
581
584
  return "Unknown error";
582
585
  }
586
+ function formatProviderStatus(entry) {
587
+ if (entry.status === "ready")
588
+ return "Ready";
589
+ if (entry.status === "error")
590
+ return `Error: ${entry.error ?? "Unknown error"}`;
591
+ if (entry.status === "unavailable")
592
+ return "Unavailable";
593
+ return "Loading";
594
+ }
583
595
  //# sourceMappingURL=provider-snapshot-manager.js.map
@@ -3,7 +3,7 @@ import type { ProcessTerminator } from "../../../utils/tree-kill.js";
3
3
  import type { ReadableStream as NodeReadableStream, WritableStream as NodeWritableStream } from "node:stream/web";
4
4
  import { ClientSideConnection, type Client as ACPClient, type CreateTerminalRequest, type InitializeResponse, type KillTerminalRequest, type LoadSessionResponse, type NewSessionResponse, type ReadTextFileRequest, type RequestPermissionRequest, type RequestPermissionResponse, type ResumeSessionResponse, type SessionConfigOption, type SessionMode, type SessionModelState, type SessionNotification, type TerminalOutputRequest, type TerminalOutputResponse, type ToolCallContent, type ToolCallLocation, type ToolCallStatus, type ToolKind, type Usage, type WaitForTerminalExitRequest, type WriteTextFileRequest, type Stream as ACPStream } from "@agentclientprotocol/sdk";
5
5
  import type { Logger } from "pino";
6
- 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 AgentUsage, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModesOptions, type ListModelsOptions } from "../agent-sdk-types.js";
6
+ 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 AgentUsage, type FetchCatalogOptions, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ProviderCatalog } from "../agent-sdk-types.js";
7
7
  import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
8
8
  export declare function summarizeACPRequestError(error: unknown): {
9
9
  message: string;
@@ -155,8 +155,7 @@ export declare class ACPAgentClient implements AgentClient {
155
155
  constructor(options: ACPAgentClientOptions);
156
156
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext): Promise<AgentSession>;
157
157
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
158
- listModels(options: ListModelsOptions): Promise<AgentModelDefinition[]>;
159
- listModes(options: ListModesOptions): Promise<AgentMode[]>;
158
+ fetchCatalog(options: FetchCatalogOptions): Promise<ProviderCatalog>;
160
159
  listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
161
160
  importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
162
161
  isAvailable(): Promise<boolean>;
@@ -194,6 +193,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
194
193
  private readonly pendingPermissions;
195
194
  private readonly messageAssemblies;
196
195
  private readonly submittedUserMessageIds;
196
+ private activeSubmittedUserMessage;
197
197
  private readonly toolCalls;
198
198
  private readonly terminalEntries;
199
199
  private readonly persistedHistory;
@@ -282,6 +282,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
282
282
  private translateSessionUpdate;
283
283
  private handleToolCallUpdate;
284
284
  private createMessageTimelineItem;
285
+ private messageAssemblyKey;
285
286
  private handleCurrentModeUpdate;
286
287
  private handleConfigOptionUpdate;
287
288
  private handleSessionInfoUpdate;
@@ -292,6 +293,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
292
293
  private emitSubmittedUserMessage;
293
294
  private runtimeInfo;
294
295
  private finishTurn;
296
+ private isSubmittedUserMessageEcho;
295
297
  private emitBootstrapThreadEvent;
296
298
  private synthesizeCanceledToolCalls;
297
299
  private collectDiagnostic;
@@ -344,7 +344,7 @@ export class ACPAgentClient {
344
344
  await session.initializeResumedSession();
345
345
  return session;
346
346
  }
347
- async listModels(options) {
347
+ async fetchCatalog(options) {
348
348
  const { cwd } = options;
349
349
  const probe = await this.spawnProcess(PROBE_ENV);
350
350
  try {
@@ -354,23 +354,11 @@ export class ACPAgentClient {
354
354
  }));
355
355
  const transformed = this.transformSessionResponse(response);
356
356
  const models = deriveModelDefinitionsFromACP(this.provider, transformed.models, transformed.configOptions);
357
- return this.modelTransformer ? this.modelTransformer(models) : models;
358
- }
359
- finally {
360
- await this.closeProbe(probe);
361
- }
362
- }
363
- async listModes(options) {
364
- const { cwd } = options;
365
- const probe = await this.spawnProcess(PROBE_ENV);
366
- try {
367
- const response = await this.runACPRequest(() => probe.connection.newSession({
368
- cwd,
369
- mcpServers: [],
370
- }));
371
- const transformed = this.transformSessionResponse(response);
372
357
  const modeInfo = deriveModesFromACP(this.defaultModes, transformed.modes, transformed.configOptions);
373
- return modeInfo.modes;
358
+ return {
359
+ models: this.modelTransformer ? this.modelTransformer(models) : models,
360
+ modes: modeInfo.modes,
361
+ };
374
362
  }
375
363
  finally {
376
364
  await this.closeProbe(probe);
@@ -561,6 +549,7 @@ export class ACPAgentSession {
561
549
  this.pendingPermissions = new Map();
562
550
  this.messageAssemblies = new Map();
563
551
  this.submittedUserMessageIds = new Set();
552
+ this.activeSubmittedUserMessage = null;
564
553
  this.toolCalls = new Map();
565
554
  this.terminalEntries = new Map();
566
555
  this.persistedHistory = [];
@@ -690,6 +679,7 @@ export class ACPAgentSession {
690
679
  const turnId = randomUUID();
691
680
  const messageId = options?.messageId ?? randomUUID();
692
681
  this.activeForegroundTurnId = turnId;
682
+ this.activeSubmittedUserMessage = null;
693
683
  this.emitBootstrapThreadEvent();
694
684
  this.pushEvent({ type: "turn_started", provider: this.provider, turnId });
695
685
  this.emitSubmittedUserMessage(prompt, messageId, turnId);
@@ -1413,7 +1403,10 @@ export class ACPAgentSession {
1413
1403
  if (!item) {
1414
1404
  return [];
1415
1405
  }
1416
- if (update.messageId && this.submittedUserMessageIds.has(update.messageId)) {
1406
+ if (item.type !== "user_message") {
1407
+ return [this.wrapTimeline(item)];
1408
+ }
1409
+ if (this.isSubmittedUserMessageEcho(item)) {
1417
1410
  return [];
1418
1411
  }
1419
1412
  return [this.wrapTimeline(item)];
@@ -1476,7 +1469,7 @@ export class ACPAgentSession {
1476
1469
  if (!chunkText) {
1477
1470
  return null;
1478
1471
  }
1479
- const key = `${type}:${update.messageId ?? "default"}`;
1472
+ const key = this.messageAssemblyKey(type, update.messageId);
1480
1473
  const state = this.messageAssemblies.get(key) ?? { text: "" };
1481
1474
  state.text += chunkText;
1482
1475
  this.messageAssemblies.set(key, state);
@@ -1488,6 +1481,10 @@ export class ACPAgentSession {
1488
1481
  }
1489
1482
  return { type: "reasoning", text: chunkText };
1490
1483
  }
1484
+ messageAssemblyKey(type, messageId) {
1485
+ const fallbackId = type === "user_message" ? (this.activeForegroundTurnId ?? "default") : "default";
1486
+ return `${type}:${messageId ?? fallbackId}`;
1487
+ }
1491
1488
  handleCurrentModeUpdate(update) {
1492
1489
  this.currentMode = this.transformModeId(update.currentModeId);
1493
1490
  }
@@ -1589,6 +1586,7 @@ export class ACPAgentSession {
1589
1586
  return;
1590
1587
  }
1591
1588
  this.submittedUserMessageIds.add(messageId);
1589
+ this.activeSubmittedUserMessage = { messageId, text, turnId };
1592
1590
  this.pushEvent({
1593
1591
  type: "timeline",
1594
1592
  provider: this.provider,
@@ -1611,8 +1609,23 @@ export class ACPAgentSession {
1611
1609
  }
1612
1610
  finishTurn(event) {
1613
1611
  this.activeForegroundTurnId = null;
1612
+ if (this.activeSubmittedUserMessage?.turnId === event.turnId) {
1613
+ this.activeSubmittedUserMessage = null;
1614
+ }
1614
1615
  this.pushEvent(event);
1615
1616
  }
1617
+ isSubmittedUserMessageEcho(item) {
1618
+ const active = this.activeSubmittedUserMessage;
1619
+ if (!active || active.turnId !== this.activeForegroundTurnId) {
1620
+ return false;
1621
+ }
1622
+ if (item.messageId) {
1623
+ if (this.submittedUserMessageIds.has(item.messageId)) {
1624
+ return true;
1625
+ }
1626
+ }
1627
+ return active.text.startsWith(item.text);
1628
+ }
1616
1629
  emitBootstrapThreadEvent() {
1617
1630
  if (!this.bootstrapThreadEventPending || !this.sessionId) {
1618
1631
  return;
@@ -1,7 +1,7 @@
1
1
  import { type AgentDefinition, type McpServerConfig as ClaudeSdkMcpServerConfig, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
2
2
  import type { Logger } from "pino";
3
3
  import { type ClaudeQueryFactory } from "./query.js";
4
- import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMetadata, type AgentModelDefinition, type AgentPersistenceHandle, type AgentSession, type AgentSessionConfig, type AgentTimelineItem, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModelsOptions, type McpServerConfig } from "../../agent-sdk-types.js";
4
+ import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMetadata, type AgentPersistenceHandle, type AgentSession, type AgentSessionConfig, type AgentTimelineItem, type FetchCatalogOptions, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type McpServerConfig, type ProviderCatalog } from "../../agent-sdk-types.js";
5
5
  import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
6
6
  export declare function normalizeClaudeAskUserQuestionRequestInput(toolName: string, input: AgentMetadata): AgentMetadata;
7
7
  export declare function normalizeClaudeAskUserQuestionUpdatedInput(updatedInput: AgentMetadata | undefined, fallbackInput: AgentMetadata | undefined): AgentMetadata;
@@ -39,7 +39,7 @@ export declare class ClaudeAgentClient implements AgentClient {
39
39
  constructor(options: ClaudeAgentClientOptions);
40
40
  createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext, options?: AgentCreateSessionOptions): Promise<AgentSession>;
41
41
  resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
42
- listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
42
+ fetchCatalog(_options: FetchCatalogOptions): Promise<ProviderCatalog>;
43
43
  listFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
44
44
  listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
45
45
  importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../../agent-sdk-types.js").ImportedProviderSession>;
@@ -9,7 +9,7 @@ import { getClaudeModelsWithSettings, normalizeClaudeRuntimeModelId } from "./mo
9
9
  import { parsePartialJsonObject } from "./partial-json.js";
10
10
  import { ClaudeSidechainTracker } from "./sidechain-tracker.js";
11
11
  import { buildClaudeFeatures, claudeModelSupportsFastMode } from "./feature-definitions.js";
12
- import { buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, toDiagnosticErrorMessage, } from "../diagnostic-utils.js";
12
+ import { buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, formatProviderDiagnostic, formatProviderDiagnosticError, } from "../diagnostic-utils.js";
13
13
  import { appendOrReplaceGrowingAssistantMessage, runProviderTurn } from "../provider-runner.js";
14
14
  import { renderPromptAttachmentAsText } from "../../prompt-attachments.js";
15
15
  import { claudeQuery } from "./query.js";
@@ -1032,9 +1032,10 @@ export class ClaudeAgentClient {
1032
1032
  resolveBinary: this.resolveBinary,
1033
1033
  });
1034
1034
  }
1035
- async listModels(_options) {
1035
+ async fetchCatalog(_options) {
1036
1036
  // Claude exposes a global catalog here; cwd/force are intentionally irrelevant.
1037
- return await getClaudeModelsWithSettings(this.logger, this.configDir);
1037
+ const models = await getClaudeModelsWithSettings(this.logger, this.configDir);
1038
+ return { models, modes: DEFAULT_MODES };
1038
1039
  }
1039
1040
  async listFeatures(config) {
1040
1041
  const claudeConfig = this.assertConfig(config);
@@ -1079,28 +1080,9 @@ export class ClaudeAgentClient {
1079
1080
  defaultBinary: "claude",
1080
1081
  });
1081
1082
  const availability = await checkProviderLaunchAvailable(launch);
1082
- const available = availability.available;
1083
- const auth = available
1083
+ const auth = availability.available
1084
1084
  ? await resolveClaudeAuth(launch, availability, this.runtimeSettings)
1085
1085
  : null;
1086
- let modelsValue = "Not checked";
1087
- let status = formatDiagnosticStatus(available);
1088
- if (available) {
1089
- try {
1090
- const models = await this.listModels({
1091
- cwd: os.homedir(),
1092
- force: false,
1093
- });
1094
- modelsValue = String(models.length);
1095
- }
1096
- catch (error) {
1097
- modelsValue = `Error - ${toDiagnosticErrorMessage(error)}`;
1098
- status = formatDiagnosticStatus(available, {
1099
- source: "model fetch",
1100
- cause: error,
1101
- });
1102
- }
1103
- }
1104
1086
  return {
1105
1087
  diagnostic: formatProviderDiagnostic("Claude Code", [
1106
1088
  ...(await buildCommandResolutionDiagnosticRows(launch, {
@@ -1108,8 +1090,6 @@ export class ClaudeAgentClient {
1108
1090
  })),
1109
1091
  ...(await buildBinaryDiagnosticRows(launch, availability)),
1110
1092
  ...(auth ? [{ label: "Auth", value: auth }] : []),
1111
- { label: "Models", value: modelsValue },
1112
- { label: "Status", value: status },
1113
1093
  ]),
1114
1094
  };
1115
1095
  }
@@ -1,4 +1,4 @@
1
- import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPersistenceHandle, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentProviderNotice, type AgentPromptContentBlock, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentTimelineItem, type ToolCallTimelineItem, type AgentUsage, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ListModelsOptions } from "../agent-sdk-types.js";
1
+ import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentPersistenceHandle, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentProviderNotice, type AgentPromptContentBlock, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentTimelineItem, type ToolCallTimelineItem, type AgentUsage, type FetchCatalogOptions, type ImportableProviderSession, type ImportProviderSessionContext, type ImportProviderSessionInput, type ListImportableSessionsOptions, type ProviderCatalog } from "../agent-sdk-types.js";
2
2
  import type { Logger } from "pino";
3
3
  import type { ChildProcessWithoutNullStreams } from "node:child_process";
4
4
  import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
@@ -295,7 +295,8 @@ export declare class CodexAppServerAgentClient implements AgentClient {
295
295
  }, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
296
296
  listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
297
297
  importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
298
- listModels(_options: ListModelsOptions): Promise<AgentModelDefinition[]>;
298
+ fetchCatalog(_options: FetchCatalogOptions): Promise<ProviderCatalog>;
299
+ private fetchModelsFromAppServer;
299
300
  archiveNativeSession(handle: AgentPersistenceHandle): Promise<void>;
300
301
  unarchiveNativeSession(handle: AgentPersistenceHandle): Promise<void>;
301
302
  isAvailable(): Promise<boolean>;
@@ -1,6 +1,5 @@
1
1
  import { getAgentStreamEventTurnId, } from "../agent-sdk-types.js";
2
2
  import { importSessionFromPersistence } from "../provider-session-import.js";
3
- import { homedir } from "node:os";
4
3
  import { randomUUID } from "node:crypto";
5
4
  import * as fsSync from "node:fs";
6
5
  import fs from "node:fs/promises";
@@ -21,7 +20,7 @@ import { CodexAppServerClient, parseCodexThreadForkResponse, parseCodexThreadRol
21
20
  import { revertCodexConversation } from "./codex/rewind.js";
22
21
  import { renderProviderImageOutputAsAssistantMarkdown, } from "./provider-image-output.js";
23
22
  import { normalizeProviderReplayTimestamp } from "../provider-history-timestamps.js";
24
- import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
23
+ import { formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, resolveBinaryVersion, } from "./diagnostic-utils.js";
25
24
  import { runProviderTurn } from "./provider-runner.js";
26
25
  import { SETTING_APPLIES_NEXT_TURN_NOTICE } from "../provider-notices.js";
27
26
  function assertChildWithPipes(child) {
@@ -4376,7 +4375,11 @@ export class CodexAppServerAgentClient {
4376
4375
  resumeSession: this.resumeSession.bind(this),
4377
4376
  });
4378
4377
  }
4379
- async listModels(_options) {
4378
+ async fetchCatalog(_options) {
4379
+ const models = await this.fetchModelsFromAppServer();
4380
+ return { models, modes: CODEX_MODES };
4381
+ }
4382
+ async fetchModelsFromAppServer() {
4380
4383
  // Codex model/list is global to the app server in this flow; cwd/force are intentionally ignored.
4381
4384
  const child = await this.spawnAppServer();
4382
4385
  const client = new CodexAppServerClient(child, this.logger);
@@ -4454,34 +4457,12 @@ export class CodexAppServerAgentClient {
4454
4457
  try {
4455
4458
  const launch = await resolveCodexLaunch(this.runtimeSettings);
4456
4459
  const availability = await checkCodexLaunchAvailable(launch);
4457
- const available = availability.available;
4458
4460
  const entries = [
4459
4461
  ...(await buildCommandResolutionDiagnosticRows(launch, {
4460
4462
  knownBinaryNames: ["codex"],
4461
4463
  })),
4462
4464
  ...(await buildBinaryDiagnosticRows(launch, availability)),
4463
4465
  ];
4464
- let status = formatDiagnosticStatus(available);
4465
- if (!available) {
4466
- entries.push({ label: "Models", value: "Not checked" });
4467
- }
4468
- else {
4469
- try {
4470
- const models = await this.listModels({ cwd: homedir(), force: false });
4471
- entries.push({ label: "Models", value: String(models.length) });
4472
- }
4473
- catch (error) {
4474
- entries.push({
4475
- label: "Models",
4476
- value: `Error - ${toDiagnosticErrorMessage(error)}`,
4477
- });
4478
- status = formatDiagnosticStatus(available, {
4479
- source: "model fetch",
4480
- cause: error,
4481
- });
4482
- }
4483
- }
4484
- entries.push({ label: "Status", value: status });
4485
4466
  return {
4486
4467
  diagnostic: formatProviderDiagnostic("Codex", entries),
4487
4468
  };
@@ -1,7 +1,6 @@
1
- import { homedir } from "node:os";
2
1
  import { checkProviderLaunchAvailable, resolveProviderLaunch, } from "../provider-launch-config.js";
3
2
  import { ACPAgentClient, } from "./acp-agent.js";
4
- import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
3
+ import { formatProviderDiagnostic, formatProviderDiagnosticError, buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, } from "./diagnostic-utils.js";
5
4
  const COPILOT_CAPABILITIES = {
6
5
  supportsStreaming: true,
7
6
  supportsSessionPersistence: true,
@@ -64,41 +63,12 @@ export class CopilotACPAgentClient extends ACPAgentClient {
64
63
  defaultBinary: "copilot",
65
64
  });
66
65
  const availability = await checkProviderLaunchAvailable(launch);
67
- const available = availability.available;
68
- let modelsValue = "Not checked";
69
- let status = formatDiagnosticStatus(available);
70
- if (available) {
71
- try {
72
- const models = await this.listModels({ cwd: homedir(), force: false });
73
- modelsValue = String(models.length);
74
- }
75
- catch (error) {
76
- modelsValue = `Error - ${toDiagnosticErrorMessage(error)}`;
77
- status = formatDiagnosticStatus(available, {
78
- source: "model fetch",
79
- cause: error,
80
- });
81
- }
82
- if (!modelsValue.startsWith("Error -")) {
83
- try {
84
- await this.listModes({ cwd: homedir(), force: false });
85
- }
86
- catch (error) {
87
- status = formatDiagnosticStatus(available, {
88
- source: "mode fetch",
89
- cause: error,
90
- });
91
- }
92
- }
93
- }
94
66
  return {
95
67
  diagnostic: formatProviderDiagnostic("Copilot", [
96
68
  ...(await buildCommandResolutionDiagnosticRows(launch, {
97
69
  knownBinaryNames: ["copilot"],
98
70
  })),
99
71
  ...(await buildBinaryDiagnosticRows(launch, availability)),
100
- { label: "Models", value: modelsValue },
101
- { label: "Status", value: status },
102
72
  ]),
103
73
  };
104
74
  }
@@ -28,7 +28,6 @@ export declare class GenericACPAgentClient extends ACPAgentClient {
28
28
  diagnostic: string;
29
29
  }>;
30
30
  private resolveConfiguredLaunch;
31
- private runDiagnosticACPProbe;
32
31
  }
33
32
  export interface CommandInvocation {
34
33
  command: string;