@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.
- package/dist/server/server/agent/agent-manager.js +2 -2
- package/dist/server/server/agent/agent-sdk-types.d.ts +11 -6
- package/dist/server/server/agent/provider-registry.d.ts +6 -3
- package/dist/server/server/agent/provider-registry.js +49 -22
- package/dist/server/server/agent/provider-snapshot-manager.js +26 -14
- package/dist/server/server/agent/providers/acp-agent.d.ts +23 -3
- package/dist/server/server/agent/providers/acp-agent.js +139 -9
- package/dist/server/server/agent/providers/claude/agent.d.ts +2 -2
- package/dist/server/server/agent/providers/claude/agent.js +41 -77
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +3 -2
- package/dist/server/server/agent/providers/codex-app-server-agent.js +6 -25
- package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +2 -1
- package/dist/server/server/agent/providers/copilot-acp-agent.js +11 -31
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +0 -1
- package/dist/server/server/agent/providers/generic-acp-agent.js +2 -108
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +2 -3
- package/dist/server/server/agent/providers/mock-load-test-agent.js +5 -5
- package/dist/server/server/agent/providers/mock-slow-provider.d.ts +2 -3
- package/dist/server/server/agent/providers/mock-slow-provider.js +2 -5
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts +14 -11
- package/dist/server/server/agent/providers/opencode/server-manager.js +149 -91
- package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +6 -5
- package/dist/server/server/agent/providers/opencode/test-server-manager.js +13 -3
- package/dist/server/server/agent/providers/opencode/test-utils/{test-opencode-runtime.d.ts → test-opencode-harness.d.ts} +11 -11
- package/dist/server/server/agent/providers/opencode/test-utils/{test-opencode-runtime.js → test-opencode-harness.js} +23 -10
- package/dist/server/server/agent/providers/opencode-agent.d.ts +13 -6
- package/dist/server/server/agent/providers/opencode-agent.js +74 -137
- package/dist/server/server/agent/providers/pi/agent.d.ts +4 -4
- package/dist/server/server/agent/providers/pi/agent.js +13 -76
- package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +3 -0
- package/dist/server/server/agent/providers/pi/cli-runtime.js +8 -5
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +2 -1
- package/dist/server/server/agent/providers/pi/runtime.d.ts +1 -1
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +1 -1
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +1 -1
- package/dist/server/server/session/agent-config/agent-config-session.d.ts +50 -0
- package/dist/server/server/session/agent-config/agent-config-session.js +98 -0
- package/dist/server/server/session/chat/chat-schedule-loop-session.d.ts +120 -0
- package/dist/server/server/session/chat/chat-schedule-loop-session.js +489 -0
- package/dist/server/server/session/checkout/checkout-session.d.ts +142 -0
- package/dist/server/server/session/checkout/checkout-session.js +925 -0
- package/dist/server/server/session/daemon/daemon-session.d.ts +50 -0
- package/dist/server/server/session/daemon/daemon-session.js +98 -0
- package/dist/server/server/session/files/workspace-files-session.d.ts +43 -0
- package/dist/server/server/session/files/workspace-files-session.js +218 -0
- package/dist/server/server/session/project-config/project-config-session.d.ts +34 -0
- package/dist/server/server/session/project-config/project-config-session.js +125 -0
- package/dist/server/server/session/provider/provider-catalog-session.d.ts +74 -0
- package/dist/server/server/session/provider/provider-catalog-session.js +339 -0
- package/dist/server/server/session/voice/voice-session.d.ts +166 -0
- package/dist/server/server/session/voice/voice-session.js +893 -0
- package/dist/server/server/{voice → session/voice}/voice-turn-controller.d.ts +2 -2
- package/dist/server/server/{voice → session/voice}/voice-turn-controller.js +2 -2
- package/dist/server/server/session.d.ts +13 -208
- package/dist/server/server/session.js +2132 -5105
- package/dist/server/utils/checkout-git.d.ts +6 -0
- package/package.json +5 -5
- package/dist/server/server/agent/providers/opencode/runtime.d.ts +0 -28
- package/dist/server/server/agent/providers/opencode/runtime.js +0 -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
|
|
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
|
|
581
|
+
export interface FetchCatalogOptions {
|
|
582
582
|
cwd: string;
|
|
583
583
|
force: boolean;
|
|
584
584
|
}
|
|
585
|
-
export interface
|
|
586
|
-
|
|
587
|
-
|
|
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
|
-
|
|
595
|
-
|
|
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,
|
|
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
|
-
|
|
21
|
-
|
|
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;
|
|
@@ -51,6 +51,7 @@ const PROVIDER_CLIENT_FACTORIES = {
|
|
|
51
51
|
providerParams: options?.providerParams ?? {
|
|
52
52
|
sessionDir: "~/.omp/agent/sessions",
|
|
53
53
|
},
|
|
54
|
+
commandsRpcType: "get_available_commands",
|
|
54
55
|
}),
|
|
55
56
|
mock: (logger) => new MockLoadTestAgentClient(logger),
|
|
56
57
|
"mock-slow": () => new MockSlowProviderClient(),
|
|
@@ -232,10 +233,15 @@ function wrapClientProvider(provider, inner, profileModels, additionalModels, pr
|
|
|
232
233
|
provider: inner.provider,
|
|
233
234
|
}
|
|
234
235
|
: undefined, launchContext)),
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
fetchCatalog: async (options) => {
|
|
237
|
+
const catalog = await inner.fetchCatalog(options);
|
|
238
|
+
return {
|
|
239
|
+
models: mergeModels(provider, profileModels, additionalModels, catalog.models, {
|
|
240
|
+
profileModelsAreAdditive,
|
|
241
|
+
}),
|
|
242
|
+
modes: catalog.modes,
|
|
243
|
+
};
|
|
244
|
+
},
|
|
239
245
|
resolveCreateConfig: inner.resolveCreateConfig?.bind(inner),
|
|
240
246
|
isCreateConfigUnattended: inner.isCreateConfigUnattended?.bind(inner),
|
|
241
247
|
listImportableSessions: listImportableSessions
|
|
@@ -275,6 +281,22 @@ function wrapClientProvider(provider, inner, profileModels, additionalModels, pr
|
|
|
275
281
|
}
|
|
276
282
|
function createRegistryEntry(logger, provider, resolved) {
|
|
277
283
|
const modelClient = resolved.createBaseClient(logger);
|
|
284
|
+
const hasReplacementModels = resolved.profileModels.length > 0 && !resolved.profileModelsAreAdditive;
|
|
285
|
+
const replacementModels = hasReplacementModels
|
|
286
|
+
? resolved.profileModels.map((model) => mapModel(provider, model))
|
|
287
|
+
: [];
|
|
288
|
+
const decorateModes = (modes) => modes.map((mode) => {
|
|
289
|
+
if (mode.icon && mode.colorTier)
|
|
290
|
+
return mode;
|
|
291
|
+
const definitionMode = resolved.definition.modes.find((d) => d.id === mode.id);
|
|
292
|
+
if (!definitionMode)
|
|
293
|
+
return mode;
|
|
294
|
+
return Object.assign({}, mode, {
|
|
295
|
+
icon: mode.icon ?? definitionMode.icon,
|
|
296
|
+
colorTier: mode.colorTier ?? definitionMode.colorTier,
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
const hasStaticModes = resolved.definition.modes.length > 0;
|
|
278
300
|
return {
|
|
279
301
|
...resolved.definition,
|
|
280
302
|
enabled: resolved.enabled,
|
|
@@ -282,24 +304,29 @@ function createRegistryEntry(logger, provider, resolved) {
|
|
|
282
304
|
createClient: (providerLogger) => createResolvedProviderClient(providerLogger, provider, resolved),
|
|
283
305
|
resolveCreateConfig: modelClient.resolveCreateConfig ?? resolveDefaultAgentCreateConfig,
|
|
284
306
|
isCreateConfigUnattended: modelClient.isCreateConfigUnattended ?? isDefaultAgentCreateConfigUnattended,
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
307
|
+
fetchCatalog: async (options, client) => {
|
|
308
|
+
const catalogClient = client ?? modelClient;
|
|
309
|
+
if (hasReplacementModels) {
|
|
310
|
+
// Replacement models skip runtime model discovery, but additionalModels
|
|
311
|
+
// must still be merged on top. If modes are dynamic, probe for modes via
|
|
312
|
+
// the single catalog API; otherwise use static/empty modes with no runtime.
|
|
313
|
+
const models = mergeModelAdditions(provider, replacementModels, resolved.additionalModels);
|
|
314
|
+
if (hasStaticModes) {
|
|
315
|
+
return {
|
|
316
|
+
models,
|
|
317
|
+
modes: decorateModes(resolved.definition.modes),
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
const catalog = await catalogClient.fetchCatalog(options);
|
|
321
|
+
return { models, modes: decorateModes(catalog.modes) };
|
|
322
|
+
}
|
|
323
|
+
const catalog = await catalogClient.fetchCatalog(options);
|
|
324
|
+
return {
|
|
325
|
+
models: mergeModels(provider, resolved.profileModels, resolved.additionalModels, catalog.models, {
|
|
326
|
+
profileModelsAreAdditive: resolved.profileModelsAreAdditive,
|
|
327
|
+
}),
|
|
328
|
+
modes: decorateModes(catalog.modes),
|
|
329
|
+
};
|
|
303
330
|
},
|
|
304
331
|
};
|
|
305
332
|
}
|
|
@@ -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
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
const
|
|
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
|
-
:
|
|
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
|
-
|
|
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
|
|
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
|
|
6
|
+
import { type AgentCapabilityFlags, type AgentClient, 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 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;
|
|
@@ -24,6 +24,7 @@ interface ACPAgentClientOptions {
|
|
|
24
24
|
modelTransformer?: (models: AgentModelDefinition[]) => AgentModelDefinition[];
|
|
25
25
|
sessionResponseTransformer?: (response: SessionStateResponse) => SessionStateResponse;
|
|
26
26
|
configOptionsTransformer?: (configOptions: SessionConfigOption[]) => SessionConfigOption[];
|
|
27
|
+
configFeatureOptions?: ACPConfigFeatureOption[];
|
|
27
28
|
modeIdTransformer?: (modeId: string) => string | null;
|
|
28
29
|
toolSnapshotTransformer?: (snapshot: ACPToolSnapshot) => ACPToolSnapshot;
|
|
29
30
|
providerModeWriter?: (context: ACPProviderModeWriterContext) => Promise<ACPProviderModeWriteResult>;
|
|
@@ -43,6 +44,7 @@ interface ACPAgentSessionOptions {
|
|
|
43
44
|
modelTransformer?: (models: AgentModelDefinition[]) => AgentModelDefinition[];
|
|
44
45
|
sessionResponseTransformer?: (response: SessionStateResponse) => SessionStateResponse;
|
|
45
46
|
configOptionsTransformer?: (configOptions: SessionConfigOption[]) => SessionConfigOption[];
|
|
47
|
+
configFeatureOptions?: ACPConfigFeatureOption[];
|
|
46
48
|
modeIdTransformer?: (modeId: string) => string | null;
|
|
47
49
|
toolSnapshotTransformer?: (snapshot: ACPToolSnapshot) => ACPToolSnapshot;
|
|
48
50
|
providerModeWriter?: (context: ACPProviderModeWriterContext) => Promise<ACPProviderModeWriteResult>;
|
|
@@ -76,6 +78,16 @@ interface TerminalExit {
|
|
|
76
78
|
exitCode?: number | null;
|
|
77
79
|
signal?: string | null;
|
|
78
80
|
}
|
|
81
|
+
export interface ACPConfigFeatureOption {
|
|
82
|
+
id: string;
|
|
83
|
+
configId: string;
|
|
84
|
+
category: string;
|
|
85
|
+
label: string;
|
|
86
|
+
description?: string;
|
|
87
|
+
tooltip?: string;
|
|
88
|
+
icon?: string;
|
|
89
|
+
emptyOptionLabel?: string;
|
|
90
|
+
}
|
|
79
91
|
type SelectConfigOption = Extract<SessionConfigOption, {
|
|
80
92
|
type: "select";
|
|
81
93
|
}>;
|
|
@@ -134,6 +146,7 @@ export declare function deriveModesFromACP(fallbackModes: AgentMode[], modeState
|
|
|
134
146
|
currentModeId: string | null;
|
|
135
147
|
};
|
|
136
148
|
export declare function deriveModelDefinitionsFromACP(provider: string, models: SessionModelState | null | undefined, configOptions?: SessionConfigOption[] | null): AgentModelDefinition[];
|
|
149
|
+
export declare function deriveFeaturesFromACP(configOptions: SessionConfigOption[] | null | undefined, featureOptions: ACPConfigFeatureOption[]): AgentFeature[];
|
|
137
150
|
export declare class ACPAgentClient implements AgentClient {
|
|
138
151
|
readonly provider: string;
|
|
139
152
|
readonly capabilities: AgentCapabilityFlags;
|
|
@@ -144,6 +157,7 @@ export declare class ACPAgentClient implements AgentClient {
|
|
|
144
157
|
private readonly modelTransformer?;
|
|
145
158
|
private readonly sessionResponseTransformer?;
|
|
146
159
|
private readonly configOptionsTransformer?;
|
|
160
|
+
private readonly configFeatureOptions;
|
|
147
161
|
private readonly modeIdTransformer?;
|
|
148
162
|
private readonly toolSnapshotTransformer?;
|
|
149
163
|
private readonly providerModeWriter?;
|
|
@@ -155,8 +169,8 @@ export declare class ACPAgentClient implements AgentClient {
|
|
|
155
169
|
constructor(options: ACPAgentClientOptions);
|
|
156
170
|
createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
157
171
|
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
158
|
-
|
|
159
|
-
|
|
172
|
+
fetchCatalog(options: FetchCatalogOptions): Promise<ProviderCatalog>;
|
|
173
|
+
listFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
|
|
160
174
|
listImportableSessions(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
|
|
161
175
|
importSession(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<import("../agent-sdk-types.js").ImportedProviderSession>;
|
|
162
176
|
isAvailable(): Promise<boolean>;
|
|
@@ -183,6 +197,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
|
|
|
183
197
|
protected readonly modelTransformer?: (models: AgentModelDefinition[]) => AgentModelDefinition[];
|
|
184
198
|
private readonly sessionResponseTransformer?;
|
|
185
199
|
private readonly configOptionsTransformer?;
|
|
200
|
+
private readonly configFeatureOptions;
|
|
186
201
|
private readonly modeIdTransformer?;
|
|
187
202
|
private readonly toolSnapshotTransformer?;
|
|
188
203
|
private readonly providerModeWriter?;
|
|
@@ -194,6 +209,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
|
|
|
194
209
|
private readonly pendingPermissions;
|
|
195
210
|
private readonly messageAssemblies;
|
|
196
211
|
private readonly submittedUserMessageIds;
|
|
212
|
+
private activeSubmittedUserMessage;
|
|
197
213
|
private readonly toolCalls;
|
|
198
214
|
private readonly terminalEntries;
|
|
199
215
|
private readonly persistedHistory;
|
|
@@ -236,6 +252,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
|
|
|
236
252
|
getRuntimeInfo(): Promise<AgentRuntimeInfo>;
|
|
237
253
|
getAvailableModes(): Promise<AgentMode[]>;
|
|
238
254
|
getCurrentMode(): Promise<string | null>;
|
|
255
|
+
get features(): AgentFeature[];
|
|
239
256
|
private ensureCommandsReadyDeferred;
|
|
240
257
|
private settleCommandsReady;
|
|
241
258
|
private waitForCommandsReady;
|
|
@@ -246,6 +263,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
|
|
|
246
263
|
setModel(modelId: string | null): Promise<void>;
|
|
247
264
|
private setModelWithSelection;
|
|
248
265
|
setThinkingOption(thinkingOptionId: string | null): Promise<void>;
|
|
266
|
+
setFeature(featureId: string, value: unknown): Promise<void>;
|
|
249
267
|
private applyConfigOptionResponse;
|
|
250
268
|
getPendingPermissions(): AgentPermissionRequest[];
|
|
251
269
|
respondToPermission(requestId: string, response: AgentPermissionResponse): Promise<void>;
|
|
@@ -282,6 +300,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
|
|
|
282
300
|
private translateSessionUpdate;
|
|
283
301
|
private handleToolCallUpdate;
|
|
284
302
|
private createMessageTimelineItem;
|
|
303
|
+
private messageAssemblyKey;
|
|
285
304
|
private handleCurrentModeUpdate;
|
|
286
305
|
private handleConfigOptionUpdate;
|
|
287
306
|
private handleSessionInfoUpdate;
|
|
@@ -292,6 +311,7 @@ export declare class ACPAgentSession implements AgentSession, ACPClient {
|
|
|
292
311
|
private emitSubmittedUserMessage;
|
|
293
312
|
private runtimeInfo;
|
|
294
313
|
private finishTurn;
|
|
314
|
+
private isSubmittedUserMessageEcho;
|
|
295
315
|
private emitBootstrapThreadEvent;
|
|
296
316
|
private synthesizeCanceledToolCalls;
|
|
297
317
|
private collectDiagnostic;
|
|
@@ -257,6 +257,26 @@ export function deriveModelDefinitionsFromACP(provider, models, configOptions) {
|
|
|
257
257
|
metadata: option.metadata,
|
|
258
258
|
}));
|
|
259
259
|
}
|
|
260
|
+
export function deriveFeaturesFromACP(configOptions, featureOptions) {
|
|
261
|
+
return featureOptions.flatMap((featureOption) => {
|
|
262
|
+
const option = findSelectConfigFeatureOption(configOptions, featureOption);
|
|
263
|
+
if (!option) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
return [
|
|
267
|
+
{
|
|
268
|
+
type: "select",
|
|
269
|
+
id: featureOption.id,
|
|
270
|
+
label: featureOption.label,
|
|
271
|
+
description: featureOption.description,
|
|
272
|
+
tooltip: featureOption.tooltip,
|
|
273
|
+
icon: featureOption.icon,
|
|
274
|
+
value: option.currentValue ?? null,
|
|
275
|
+
options: deriveConfigFeatureSelectOptions(option, featureOption),
|
|
276
|
+
},
|
|
277
|
+
];
|
|
278
|
+
});
|
|
279
|
+
}
|
|
260
280
|
export class ACPAgentClient {
|
|
261
281
|
constructor(options) {
|
|
262
282
|
this.provider = options.provider;
|
|
@@ -272,6 +292,7 @@ export class ACPAgentClient {
|
|
|
272
292
|
this.modelTransformer = options.modelTransformer;
|
|
273
293
|
this.sessionResponseTransformer = options.sessionResponseTransformer;
|
|
274
294
|
this.configOptionsTransformer = options.configOptionsTransformer;
|
|
295
|
+
this.configFeatureOptions = options.configFeatureOptions ?? [];
|
|
275
296
|
this.modeIdTransformer = options.modeIdTransformer;
|
|
276
297
|
this.toolSnapshotTransformer = options.toolSnapshotTransformer;
|
|
277
298
|
this.providerModeWriter = options.providerModeWriter;
|
|
@@ -291,6 +312,7 @@ export class ACPAgentClient {
|
|
|
291
312
|
modelTransformer: this.modelTransformer,
|
|
292
313
|
sessionResponseTransformer: this.sessionResponseTransformer,
|
|
293
314
|
configOptionsTransformer: this.configOptionsTransformer,
|
|
315
|
+
configFeatureOptions: this.configFeatureOptions,
|
|
294
316
|
modeIdTransformer: this.modeIdTransformer,
|
|
295
317
|
toolSnapshotTransformer: this.toolSnapshotTransformer,
|
|
296
318
|
providerModeWriter: this.providerModeWriter,
|
|
@@ -329,6 +351,7 @@ export class ACPAgentClient {
|
|
|
329
351
|
modelTransformer: this.modelTransformer,
|
|
330
352
|
sessionResponseTransformer: this.sessionResponseTransformer,
|
|
331
353
|
configOptionsTransformer: this.configOptionsTransformer,
|
|
354
|
+
configFeatureOptions: this.configFeatureOptions,
|
|
332
355
|
modeIdTransformer: this.modeIdTransformer,
|
|
333
356
|
toolSnapshotTransformer: this.toolSnapshotTransformer,
|
|
334
357
|
providerModeWriter: this.providerModeWriter,
|
|
@@ -344,7 +367,7 @@ export class ACPAgentClient {
|
|
|
344
367
|
await session.initializeResumedSession();
|
|
345
368
|
return session;
|
|
346
369
|
}
|
|
347
|
-
async
|
|
370
|
+
async fetchCatalog(options) {
|
|
348
371
|
const { cwd } = options;
|
|
349
372
|
const probe = await this.spawnProcess(PROBE_ENV);
|
|
350
373
|
try {
|
|
@@ -354,23 +377,29 @@ export class ACPAgentClient {
|
|
|
354
377
|
}));
|
|
355
378
|
const transformed = this.transformSessionResponse(response);
|
|
356
379
|
const models = deriveModelDefinitionsFromACP(this.provider, transformed.models, transformed.configOptions);
|
|
357
|
-
|
|
380
|
+
const modeInfo = deriveModesFromACP(this.defaultModes, transformed.modes, transformed.configOptions);
|
|
381
|
+
return {
|
|
382
|
+
models: this.modelTransformer ? this.modelTransformer(models) : models,
|
|
383
|
+
modes: modeInfo.modes,
|
|
384
|
+
};
|
|
358
385
|
}
|
|
359
386
|
finally {
|
|
360
387
|
await this.closeProbe(probe);
|
|
361
388
|
}
|
|
362
389
|
}
|
|
363
|
-
async
|
|
364
|
-
|
|
390
|
+
async listFeatures(config) {
|
|
391
|
+
if (this.configFeatureOptions.length === 0) {
|
|
392
|
+
return [];
|
|
393
|
+
}
|
|
394
|
+
this.assertProvider(config);
|
|
365
395
|
const probe = await this.spawnProcess(PROBE_ENV);
|
|
366
396
|
try {
|
|
367
397
|
const response = await this.runACPRequest(() => probe.connection.newSession({
|
|
368
|
-
cwd,
|
|
398
|
+
cwd: config.cwd,
|
|
369
399
|
mcpServers: [],
|
|
370
400
|
}));
|
|
371
401
|
const transformed = this.transformSessionResponse(response);
|
|
372
|
-
|
|
373
|
-
return modeInfo.modes;
|
|
402
|
+
return deriveFeaturesFromACP(transformed.configOptions, this.configFeatureOptions);
|
|
374
403
|
}
|
|
375
404
|
finally {
|
|
376
405
|
await this.closeProbe(probe);
|
|
@@ -561,6 +590,7 @@ export class ACPAgentSession {
|
|
|
561
590
|
this.pendingPermissions = new Map();
|
|
562
591
|
this.messageAssemblies = new Map();
|
|
563
592
|
this.submittedUserMessageIds = new Set();
|
|
593
|
+
this.activeSubmittedUserMessage = null;
|
|
564
594
|
this.toolCalls = new Map();
|
|
565
595
|
this.terminalEntries = new Map();
|
|
566
596
|
this.persistedHistory = [];
|
|
@@ -593,6 +623,7 @@ export class ACPAgentSession {
|
|
|
593
623
|
this.modelTransformer = options.modelTransformer;
|
|
594
624
|
this.sessionResponseTransformer = options.sessionResponseTransformer;
|
|
595
625
|
this.configOptionsTransformer = options.configOptionsTransformer;
|
|
626
|
+
this.configFeatureOptions = options.configFeatureOptions ?? [];
|
|
596
627
|
this.modeIdTransformer = options.modeIdTransformer;
|
|
597
628
|
this.toolSnapshotTransformer = options.toolSnapshotTransformer;
|
|
598
629
|
this.providerModeWriter = options.providerModeWriter;
|
|
@@ -690,6 +721,7 @@ export class ACPAgentSession {
|
|
|
690
721
|
const turnId = randomUUID();
|
|
691
722
|
const messageId = options?.messageId ?? randomUUID();
|
|
692
723
|
this.activeForegroundTurnId = turnId;
|
|
724
|
+
this.activeSubmittedUserMessage = null;
|
|
693
725
|
this.emitBootstrapThreadEvent();
|
|
694
726
|
this.pushEvent({ type: "turn_started", provider: this.provider, turnId });
|
|
695
727
|
this.emitSubmittedUserMessage(prompt, messageId, turnId);
|
|
@@ -749,6 +781,9 @@ export class ACPAgentSession {
|
|
|
749
781
|
async getCurrentMode() {
|
|
750
782
|
return this.currentMode;
|
|
751
783
|
}
|
|
784
|
+
get features() {
|
|
785
|
+
return deriveFeaturesFromACP(this.configOptions, this.configFeatureOptions);
|
|
786
|
+
}
|
|
752
787
|
ensureCommandsReadyDeferred() {
|
|
753
788
|
if (this.commandsReadyDeferred || this.commandsReadySettled || this.cachedCommands.length > 0) {
|
|
754
789
|
return;
|
|
@@ -1025,6 +1060,37 @@ export class ACPAgentSession {
|
|
|
1025
1060
|
thinkingOptionId: this.thinkingOptionId,
|
|
1026
1061
|
});
|
|
1027
1062
|
}
|
|
1063
|
+
async setFeature(featureId, value) {
|
|
1064
|
+
if (!this.connection || !this.sessionId) {
|
|
1065
|
+
throw new Error("ACP session not initialized");
|
|
1066
|
+
}
|
|
1067
|
+
const featureOption = this.configFeatureOptions.find((option) => option.id === featureId);
|
|
1068
|
+
if (!featureOption) {
|
|
1069
|
+
throw new Error(`Unknown ${this.provider} feature: ${featureId}`);
|
|
1070
|
+
}
|
|
1071
|
+
const option = findSelectConfigFeatureOption(this.configOptions, featureOption);
|
|
1072
|
+
if (!option) {
|
|
1073
|
+
throw new Error(`${this.provider} does not expose ACP feature '${featureId}'`);
|
|
1074
|
+
}
|
|
1075
|
+
const requestedValue = normalizeConfigFeatureValue(value);
|
|
1076
|
+
const choice = findSelectConfigChoice({ option, value: requestedValue });
|
|
1077
|
+
if (!choice) {
|
|
1078
|
+
throw new Error(`${this.provider} feature '${featureId}' does not include option '${requestedValue}'`);
|
|
1079
|
+
}
|
|
1080
|
+
const response = await this.connection.setSessionConfigOption({
|
|
1081
|
+
sessionId: this.sessionId,
|
|
1082
|
+
configId: option.id,
|
|
1083
|
+
value: requestedValue,
|
|
1084
|
+
});
|
|
1085
|
+
const currentValue = this.applyConfigOptionResponse({
|
|
1086
|
+
response,
|
|
1087
|
+
configId: option.id,
|
|
1088
|
+
category: featureOption.category,
|
|
1089
|
+
requestedValue,
|
|
1090
|
+
label: featureOption.label,
|
|
1091
|
+
});
|
|
1092
|
+
this.config.featureValues = { ...this.config.featureValues, [featureId]: currentValue };
|
|
1093
|
+
}
|
|
1028
1094
|
applyConfigOptionResponse({ response, configId, category, requestedValue, label, }) {
|
|
1029
1095
|
this.configOptions = this.transformConfigOptions(response.configOptions);
|
|
1030
1096
|
const responseOption = findSelectConfigOption({
|
|
@@ -1396,6 +1462,13 @@ export class ACPAgentSession {
|
|
|
1396
1462
|
if (this.config.thinkingOptionId && this.config.thinkingOptionId !== this.thinkingOptionId) {
|
|
1397
1463
|
await this.setThinkingOption(this.config.thinkingOptionId);
|
|
1398
1464
|
}
|
|
1465
|
+
const configuredFeatureValues = this.config.featureValues ?? {};
|
|
1466
|
+
for (const featureOption of this.configFeatureOptions) {
|
|
1467
|
+
if (!Object.prototype.hasOwnProperty.call(configuredFeatureValues, featureOption.id)) {
|
|
1468
|
+
continue;
|
|
1469
|
+
}
|
|
1470
|
+
await this.setFeature(featureOption.id, configuredFeatureValues[featureOption.id]);
|
|
1471
|
+
}
|
|
1399
1472
|
}
|
|
1400
1473
|
warnInvalidSelection(value, message) {
|
|
1401
1474
|
this.logger.warn({ value }, message);
|
|
@@ -1413,7 +1486,10 @@ export class ACPAgentSession {
|
|
|
1413
1486
|
if (!item) {
|
|
1414
1487
|
return [];
|
|
1415
1488
|
}
|
|
1416
|
-
if (
|
|
1489
|
+
if (item.type !== "user_message") {
|
|
1490
|
+
return [this.wrapTimeline(item)];
|
|
1491
|
+
}
|
|
1492
|
+
if (this.isSubmittedUserMessageEcho(item)) {
|
|
1417
1493
|
return [];
|
|
1418
1494
|
}
|
|
1419
1495
|
return [this.wrapTimeline(item)];
|
|
@@ -1476,7 +1552,7 @@ export class ACPAgentSession {
|
|
|
1476
1552
|
if (!chunkText) {
|
|
1477
1553
|
return null;
|
|
1478
1554
|
}
|
|
1479
|
-
const key =
|
|
1555
|
+
const key = this.messageAssemblyKey(type, update.messageId);
|
|
1480
1556
|
const state = this.messageAssemblies.get(key) ?? { text: "" };
|
|
1481
1557
|
state.text += chunkText;
|
|
1482
1558
|
this.messageAssemblies.set(key, state);
|
|
@@ -1488,6 +1564,10 @@ export class ACPAgentSession {
|
|
|
1488
1564
|
}
|
|
1489
1565
|
return { type: "reasoning", text: chunkText };
|
|
1490
1566
|
}
|
|
1567
|
+
messageAssemblyKey(type, messageId) {
|
|
1568
|
+
const fallbackId = type === "user_message" ? (this.activeForegroundTurnId ?? "default") : "default";
|
|
1569
|
+
return `${type}:${messageId ?? fallbackId}`;
|
|
1570
|
+
}
|
|
1491
1571
|
handleCurrentModeUpdate(update) {
|
|
1492
1572
|
this.currentMode = this.transformModeId(update.currentModeId);
|
|
1493
1573
|
}
|
|
@@ -1589,6 +1669,7 @@ export class ACPAgentSession {
|
|
|
1589
1669
|
return;
|
|
1590
1670
|
}
|
|
1591
1671
|
this.submittedUserMessageIds.add(messageId);
|
|
1672
|
+
this.activeSubmittedUserMessage = { messageId, text, turnId };
|
|
1592
1673
|
this.pushEvent({
|
|
1593
1674
|
type: "timeline",
|
|
1594
1675
|
provider: this.provider,
|
|
@@ -1611,8 +1692,23 @@ export class ACPAgentSession {
|
|
|
1611
1692
|
}
|
|
1612
1693
|
finishTurn(event) {
|
|
1613
1694
|
this.activeForegroundTurnId = null;
|
|
1695
|
+
if (this.activeSubmittedUserMessage?.turnId === event.turnId) {
|
|
1696
|
+
this.activeSubmittedUserMessage = null;
|
|
1697
|
+
}
|
|
1614
1698
|
this.pushEvent(event);
|
|
1615
1699
|
}
|
|
1700
|
+
isSubmittedUserMessageEcho(item) {
|
|
1701
|
+
const active = this.activeSubmittedUserMessage;
|
|
1702
|
+
if (!active || active.turnId !== this.activeForegroundTurnId) {
|
|
1703
|
+
return false;
|
|
1704
|
+
}
|
|
1705
|
+
if (item.messageId) {
|
|
1706
|
+
if (this.submittedUserMessageIds.has(item.messageId)) {
|
|
1707
|
+
return true;
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return active.text.startsWith(item.text);
|
|
1711
|
+
}
|
|
1616
1712
|
emitBootstrapThreadEvent() {
|
|
1617
1713
|
if (!this.bootstrapThreadEventPending || !this.sessionId) {
|
|
1618
1714
|
return;
|
|
@@ -1658,6 +1754,12 @@ function findSelectConfigOption({ configOptions, category, id, }) {
|
|
|
1658
1754
|
const option = configOptions?.find((entry) => entry.type === "select" && entry.category === category && (!id || entry.id === id));
|
|
1659
1755
|
return option ?? null;
|
|
1660
1756
|
}
|
|
1757
|
+
function findSelectConfigFeatureOption(configOptions, featureOption) {
|
|
1758
|
+
const option = configOptions?.find((entry) => entry.type === "select" &&
|
|
1759
|
+
entry.id === featureOption.configId &&
|
|
1760
|
+
entry.category === featureOption.category);
|
|
1761
|
+
return option ?? null;
|
|
1762
|
+
}
|
|
1661
1763
|
function findSelectConfigChoice({ option, value, }) {
|
|
1662
1764
|
if (!option) {
|
|
1663
1765
|
return null;
|
|
@@ -1677,6 +1779,34 @@ function flattenSelectOptions(options) {
|
|
|
1677
1779
|
}
|
|
1678
1780
|
return flattened;
|
|
1679
1781
|
}
|
|
1782
|
+
function deriveConfigFeatureSelectOptions(option, featureOption) {
|
|
1783
|
+
return flattenSelectOptions(option.options).map((choice) => ({
|
|
1784
|
+
id: choice.value,
|
|
1785
|
+
label: normalizeConfigFeatureOptionLabel(choice, featureOption),
|
|
1786
|
+
description: choice.description ?? undefined,
|
|
1787
|
+
isDefault: choice.value === option.currentValue,
|
|
1788
|
+
metadata: choice.group ? { group: choice.group } : undefined,
|
|
1789
|
+
}));
|
|
1790
|
+
}
|
|
1791
|
+
function normalizeConfigFeatureOptionLabel(choice, featureOption) {
|
|
1792
|
+
const name = choice.name.trim();
|
|
1793
|
+
if (name) {
|
|
1794
|
+
return name;
|
|
1795
|
+
}
|
|
1796
|
+
if (choice.value === "" && featureOption.emptyOptionLabel) {
|
|
1797
|
+
return featureOption.emptyOptionLabel;
|
|
1798
|
+
}
|
|
1799
|
+
return choice.value;
|
|
1800
|
+
}
|
|
1801
|
+
function normalizeConfigFeatureValue(value) {
|
|
1802
|
+
if (typeof value === "string") {
|
|
1803
|
+
return value;
|
|
1804
|
+
}
|
|
1805
|
+
if (value === null) {
|
|
1806
|
+
return "";
|
|
1807
|
+
}
|
|
1808
|
+
throw new Error(`ACP feature value must be a string`);
|
|
1809
|
+
}
|
|
1680
1810
|
function deriveSelectorOptions(configOptions, category) {
|
|
1681
1811
|
const option = findSelectConfigOption({ configOptions, category });
|
|
1682
1812
|
if (!option) {
|