@getpaseo/server 0.1.91-beta.1 → 0.1.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/supervisor.js +21 -0
- package/dist/server/server/agent/agent-manager.d.ts +1 -1
- package/dist/server/server/agent/agent-manager.js +23 -48
- package/dist/server/server/agent/agent-sdk-types.d.ts +15 -0
- package/dist/server/server/agent/prompt-attachments.js +8 -0
- package/dist/server/server/agent/provider-registry.d.ts +0 -1
- package/dist/server/server/agent/provider-registry.js +22 -4
- package/dist/server/server/agent/provider-snapshot-manager.js +19 -1
- package/dist/server/server/agent/providers/claude/agent.d.ts +5 -2
- package/dist/server/server/agent/providers/claude/agent.js +6 -2
- package/dist/server/server/agent/providers/claude/models.d.ts +1 -1
- package/dist/server/server/agent/providers/claude/models.js +6 -6
- package/dist/server/server/agent/providers/codex-app-server-agent.js +9 -5
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +1 -0
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +4 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts +16 -2
- package/dist/server/server/agent/providers/opencode-agent.js +75 -4
- package/dist/server/server/agent/providers/pi/agent.d.ts +23 -1
- package/dist/server/server/agent/providers/pi/agent.js +219 -13
- package/dist/server/server/agent/providers/pi/cli-runtime.js +9 -0
- package/dist/server/server/agent/providers/pi/rpc-types.d.ts +9 -0
- package/dist/server/server/agent/providers/pi/runtime.d.ts +2 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +12 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.js +304 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.d.ts +8 -0
- package/dist/server/server/agent/providers/pi/test-utils/fake-pi.js +22 -0
- package/dist/server/server/agent/runtime-mcp-config.d.ts +8 -0
- package/dist/server/server/agent/runtime-mcp-config.js +50 -0
- package/dist/server/server/auth.js +16 -1
- package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +2 -2
- package/dist/server/server/daemon-worker.js +84 -1
- package/dist/server/server/file-upload/index.d.ts +27 -0
- package/dist/server/server/file-upload/index.js +158 -0
- package/dist/server/server/loop-service.d.ts +12 -12
- package/dist/server/server/persisted-config.d.ts +11 -0
- package/dist/server/server/persisted-config.js +2 -1
- package/dist/server/server/persistence-hooks.js +6 -4
- package/dist/server/server/session.d.ts +5 -2
- package/dist/server/server/session.js +20 -2
- package/dist/server/server/speech/providers/local/runtime.js +1 -0
- package/dist/server/server/speech/providers/local/worker-client.d.ts +14 -1
- package/dist/server/server/speech/providers/local/worker-client.js +169 -7
- package/dist/server/server/websocket-server.d.ts +2 -0
- package/dist/server/server/websocket-server.js +20 -7
- package/dist/server/server/workspace-registry.d.ts +4 -4
- package/dist/server/utils/directory-suggestions.js +10 -5
- package/dist/server/utils/worktree.d.ts +4 -0
- package/dist/server/utils/worktree.js +19 -2
- package/dist/src/server/persisted-config.js +2 -1
- package/package.json +5 -5
|
@@ -127,6 +127,26 @@ export function runSupervisor(options) {
|
|
|
127
127
|
execArgv: workerExecArgv,
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
|
+
const currentChild = child;
|
|
131
|
+
const heartbeat = setInterval(() => {
|
|
132
|
+
const message = { type: "paseo:supervisor-heartbeat" };
|
|
133
|
+
if (currentChild.connected) {
|
|
134
|
+
currentChild.send?.(message, (error) => {
|
|
135
|
+
if (error) {
|
|
136
|
+
writeLifecycleLog("Worker heartbeat IPC send failed", {
|
|
137
|
+
error: error instanceof Error ? error.message : String(error),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
writeLifecycleLog("Worker heartbeat skipped because IPC channel is disconnected");
|
|
144
|
+
}
|
|
145
|
+
}, 1000);
|
|
146
|
+
heartbeat.unref();
|
|
147
|
+
child.on("disconnect", () => {
|
|
148
|
+
writeLifecycleLog("Worker IPC channel disconnected");
|
|
149
|
+
});
|
|
130
150
|
child.stdout?.on("data", (chunk) => {
|
|
131
151
|
process.stdout.write(chunk);
|
|
132
152
|
writeDurableChunk(chunk);
|
|
@@ -157,6 +177,7 @@ export function runSupervisor(options) {
|
|
|
157
177
|
requestRestart("Restart requested by worker");
|
|
158
178
|
});
|
|
159
179
|
child.on("close", (code, signal) => {
|
|
180
|
+
clearInterval(heartbeat);
|
|
160
181
|
const exitDescriptor = describeExit(code, signal);
|
|
161
182
|
writeLifecycleLog("Worker exited", { code, signal, exit: exitDescriptor });
|
|
162
183
|
if (shuttingDown) {
|
|
@@ -163,7 +163,6 @@ export interface AgentMetricsSnapshot {
|
|
|
163
163
|
export declare class AgentManager {
|
|
164
164
|
private readonly clients;
|
|
165
165
|
private readonly providerEnabled;
|
|
166
|
-
private readonly providerDerivedFromId;
|
|
167
166
|
private readonly agents;
|
|
168
167
|
private readonly timelineStore;
|
|
169
168
|
private readonly agentsAwaitingInitialSnapshotPersist;
|
|
@@ -337,6 +336,7 @@ export declare class AgentManager {
|
|
|
337
336
|
private dispatchStream;
|
|
338
337
|
private dispatch;
|
|
339
338
|
private normalizeConfig;
|
|
339
|
+
private prepareSessionConfig;
|
|
340
340
|
private applyDaemonAppendSystemPrompt;
|
|
341
341
|
private buildLaunchContext;
|
|
342
342
|
private requireAvailableClient;
|
|
@@ -10,9 +10,9 @@ import { InMemoryAgentTimelineStore, } from "./agent-timeline-store.js";
|
|
|
10
10
|
import { AGENT_STREAM_COALESCE_DEFAULT_WINDOW_MS, AgentStreamCoalescer, } from "./agent-stream-coalescer.js";
|
|
11
11
|
import { ForegroundRunState } from "./foreground-run-state.js";
|
|
12
12
|
import { getAgentProviderDefinition } from "@getpaseo/protocol/provider-manifest";
|
|
13
|
-
import { IMPORTABLE_PROVIDERS } from "./provider-registry.js";
|
|
14
13
|
import { invokeRewindCapability } from "./rewind/rewind.js";
|
|
15
14
|
import { isSystemInjectedEnvelope } from "./agent-prompt.js";
|
|
15
|
+
import { stripInternalPaseoMcpServer, withRuntimePaseoMcpServer } from "./runtime-mcp-config.js";
|
|
16
16
|
const RELOAD_SESSION_CLOSE_TIMEOUT_MS = 3000;
|
|
17
17
|
const INTERRUPT_SESSION_TIMEOUT_MS = 2000;
|
|
18
18
|
const STORED_AGENT_CAPABILITIES = {
|
|
@@ -54,7 +54,7 @@ function buildStoredAgentConfig(record) {
|
|
|
54
54
|
}
|
|
55
55
|
if (record.config.mcpServers != null)
|
|
56
56
|
config.mcpServers = record.config.mcpServers;
|
|
57
|
-
return config;
|
|
57
|
+
return stripInternalPaseoMcpServer(config);
|
|
58
58
|
}
|
|
59
59
|
export { AGENT_LIFECYCLE_STATUSES };
|
|
60
60
|
function resolveInitialAttention(input) {
|
|
@@ -126,7 +126,6 @@ export class AgentManager {
|
|
|
126
126
|
constructor(options) {
|
|
127
127
|
this.clients = new Map();
|
|
128
128
|
this.providerEnabled = new Map();
|
|
129
|
-
this.providerDerivedFromId = new Map();
|
|
130
129
|
this.agents = new Map();
|
|
131
130
|
this.timelineStore = new InMemoryAgentTimelineStore();
|
|
132
131
|
this.agentsAwaitingInitialSnapshotPersist = new Set();
|
|
@@ -166,7 +165,6 @@ export class AgentManager {
|
|
|
166
165
|
for (const [provider, definition] of Object.entries(input.providerDefinitions)) {
|
|
167
166
|
if (definition) {
|
|
168
167
|
this.providerEnabled.set(provider, definition.enabled);
|
|
169
|
-
this.providerDerivedFromId.set(provider, definition.derivedFromProviderId ?? null);
|
|
170
168
|
}
|
|
171
169
|
}
|
|
172
170
|
for (const [provider, client] of Object.entries(input.clients)) {
|
|
@@ -303,15 +301,9 @@ export class AgentManager {
|
|
|
303
301
|
.slice(0, limit);
|
|
304
302
|
}
|
|
305
303
|
isProviderImportable(provider, providerFilter) {
|
|
306
|
-
if (!IMPORTABLE_PROVIDERS.includes(provider)) {
|
|
307
|
-
return false;
|
|
308
|
-
}
|
|
309
304
|
if (this.providerEnabled.get(provider) === false) {
|
|
310
305
|
return false;
|
|
311
306
|
}
|
|
312
|
-
if (this.providerDerivedFromId.get(provider) != null) {
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
307
|
if (providerFilter && !providerFilter.has(provider)) {
|
|
316
308
|
return false;
|
|
317
309
|
}
|
|
@@ -427,27 +419,15 @@ export class AgentManager {
|
|
|
427
419
|
}
|
|
428
420
|
async createAgent(config, agentId, options) {
|
|
429
421
|
const resolvedAgentId = validateAgentId(agentId ?? this.idFactory(), "createAgent");
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
: {
|
|
433
|
-
...config,
|
|
434
|
-
mcpServers: {
|
|
435
|
-
paseo: {
|
|
436
|
-
type: "http",
|
|
437
|
-
url: `${this.mcpBaseUrl}?callerAgentId=${resolvedAgentId}`,
|
|
438
|
-
},
|
|
439
|
-
...config.mcpServers,
|
|
440
|
-
},
|
|
441
|
-
};
|
|
442
|
-
this.requireEnabledProvider(injectedConfig.provider);
|
|
443
|
-
const normalizedConfig = this.applyDaemonAppendSystemPrompt(await this.normalizeConfig(injectedConfig));
|
|
422
|
+
const { storedConfig, launchConfig } = await this.prepareSessionConfig(config, resolvedAgentId);
|
|
423
|
+
this.requireEnabledProvider(storedConfig.provider);
|
|
444
424
|
const launchContext = this.buildLaunchContext(resolvedAgentId, options?.env);
|
|
445
425
|
const client = await this.requireAvailableClient({
|
|
446
|
-
provider:
|
|
426
|
+
provider: storedConfig.provider,
|
|
447
427
|
});
|
|
448
428
|
const createOptions = this.buildCreateSessionOptions(options);
|
|
449
|
-
const session = await client.createSession(
|
|
450
|
-
return this.registerSession(session,
|
|
429
|
+
const session = await client.createSession(launchConfig, launchContext, createOptions);
|
|
430
|
+
return this.registerSession(session, storedConfig, resolvedAgentId, {
|
|
451
431
|
labels: options?.labels,
|
|
452
432
|
workspaceId: options?.workspaceId,
|
|
453
433
|
initialTitle: options?.initialTitle,
|
|
@@ -468,29 +448,15 @@ export class AgentManager {
|
|
|
468
448
|
...overrides,
|
|
469
449
|
provider: handle.provider,
|
|
470
450
|
};
|
|
471
|
-
const
|
|
472
|
-
const resumeOverrides = { ...overrides };
|
|
473
|
-
let hasResumeOverrides = overrides !== undefined;
|
|
474
|
-
if (normalizedConfig.model !== mergedConfig.model) {
|
|
475
|
-
resumeOverrides.model = normalizedConfig.model;
|
|
476
|
-
hasResumeOverrides = true;
|
|
477
|
-
}
|
|
478
|
-
if (normalizedConfig.modeId !== mergedConfig.modeId) {
|
|
479
|
-
resumeOverrides.modeId = normalizedConfig.modeId;
|
|
480
|
-
hasResumeOverrides = true;
|
|
481
|
-
}
|
|
482
|
-
if (metadata.daemonAppendSystemPrompt !== normalizedConfig.daemonAppendSystemPrompt) {
|
|
483
|
-
resumeOverrides.daemonAppendSystemPrompt = normalizedConfig.daemonAppendSystemPrompt;
|
|
484
|
-
hasResumeOverrides = true;
|
|
485
|
-
}
|
|
451
|
+
const { storedConfig, launchConfig } = await this.prepareSessionConfig(mergedConfig, resolvedAgentId);
|
|
486
452
|
const launchContext = this.buildLaunchContext(resolvedAgentId);
|
|
487
453
|
const client = this.requireClient(handle.provider);
|
|
488
454
|
const available = await client.isAvailable();
|
|
489
455
|
if (!available) {
|
|
490
456
|
throw new Error(`Provider '${handle.provider}' is not available. Please ensure the CLI is installed.`);
|
|
491
457
|
}
|
|
492
|
-
const session = await client.resumeSession(handle,
|
|
493
|
-
return this.registerSession(session,
|
|
458
|
+
const session = await client.resumeSession(handle, launchConfig, launchContext);
|
|
459
|
+
return this.registerSession(session, storedConfig, resolvedAgentId, options);
|
|
494
460
|
}
|
|
495
461
|
// Hot-reload an active agent session with config overrides. By default the
|
|
496
462
|
// in-memory timeline is preserved (used for voice-mode toggles and similar
|
|
@@ -517,11 +483,11 @@ export class AgentManager {
|
|
|
517
483
|
...overrides,
|
|
518
484
|
provider,
|
|
519
485
|
};
|
|
520
|
-
const
|
|
486
|
+
const { storedConfig, launchConfig } = await this.prepareSessionConfig(refreshConfig, agentId);
|
|
521
487
|
const launchContext = this.buildLaunchContext(agentId);
|
|
522
488
|
const session = handle
|
|
523
|
-
? await client.resumeSession(handle,
|
|
524
|
-
: await client.createSession(
|
|
489
|
+
? await client.resumeSession(handle, launchConfig, launchContext)
|
|
490
|
+
: await client.createSession(launchConfig, launchContext);
|
|
525
491
|
this.agentStreamCoalescer.flushAndDiscard(agentId);
|
|
526
492
|
// Remove the existing agent entry before swapping sessions
|
|
527
493
|
this.agents.delete(agentId);
|
|
@@ -539,7 +505,7 @@ export class AgentManager {
|
|
|
539
505
|
this.timelineStore.delete(agentId);
|
|
540
506
|
}
|
|
541
507
|
// Preserve existing labels and timeline during reload.
|
|
542
|
-
return this.registerSession(session,
|
|
508
|
+
return this.registerSession(session, storedConfig, agentId, {
|
|
543
509
|
labels: existing.labels,
|
|
544
510
|
createdAt: existing.createdAt,
|
|
545
511
|
updatedAt: existing.updatedAt,
|
|
@@ -2503,6 +2469,15 @@ export class AgentManager {
|
|
|
2503
2469
|
}
|
|
2504
2470
|
return normalized;
|
|
2505
2471
|
}
|
|
2472
|
+
async prepareSessionConfig(config, agentId) {
|
|
2473
|
+
const storedConfig = await this.normalizeConfig(stripInternalPaseoMcpServer(config));
|
|
2474
|
+
const launchConfig = this.applyDaemonAppendSystemPrompt(withRuntimePaseoMcpServer({
|
|
2475
|
+
config: storedConfig,
|
|
2476
|
+
agentId,
|
|
2477
|
+
mcpBaseUrl: this.mcpBaseUrl,
|
|
2478
|
+
}));
|
|
2479
|
+
return { storedConfig, launchConfig };
|
|
2480
|
+
}
|
|
2506
2481
|
applyDaemonAppendSystemPrompt(config) {
|
|
2507
2482
|
const daemonAppendSystemPrompt = this.appendSystemPrompt.trim();
|
|
2508
2483
|
const next = { ...config };
|
|
@@ -12,6 +12,11 @@ export interface McpStdioServerConfig {
|
|
|
12
12
|
command: string;
|
|
13
13
|
args?: string[];
|
|
14
14
|
env?: Record<string, string>;
|
|
15
|
+
/**
|
|
16
|
+
* When true, all tools from this server are always included in the prompt
|
|
17
|
+
* and never deferred behind tool search. Honored by the Claude provider.
|
|
18
|
+
*/
|
|
19
|
+
alwaysLoad?: boolean;
|
|
15
20
|
}
|
|
16
21
|
/**
|
|
17
22
|
* HTTP-based MCP server.
|
|
@@ -20,6 +25,11 @@ export interface McpHttpServerConfig {
|
|
|
20
25
|
type: "http";
|
|
21
26
|
url: string;
|
|
22
27
|
headers?: Record<string, string>;
|
|
28
|
+
/**
|
|
29
|
+
* When true, all tools from this server are always included in the prompt
|
|
30
|
+
* and never deferred behind tool search. Honored by the Claude provider.
|
|
31
|
+
*/
|
|
32
|
+
alwaysLoad?: boolean;
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* SSE-based MCP server (Server-Sent Events over HTTP).
|
|
@@ -28,6 +38,11 @@ export interface McpSseServerConfig {
|
|
|
28
38
|
type: "sse";
|
|
29
39
|
url: string;
|
|
30
40
|
headers?: Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* When true, all tools from this server are always included in the prompt
|
|
43
|
+
* and never deferred behind tool search. Honored by the Claude provider.
|
|
44
|
+
*/
|
|
45
|
+
alwaysLoad?: boolean;
|
|
31
46
|
}
|
|
32
47
|
/**
|
|
33
48
|
* Canonical MCP server configuration.
|
|
@@ -45,6 +45,14 @@ export function renderPromptAttachmentAsText(attachment) {
|
|
|
45
45
|
});
|
|
46
46
|
return lines.join("\n");
|
|
47
47
|
}
|
|
48
|
+
case "uploaded_file": {
|
|
49
|
+
return [
|
|
50
|
+
`Uploaded file: ${attachment.fileName}`,
|
|
51
|
+
`Path: ${attachment.path}`,
|
|
52
|
+
`MIME: ${attachment.mimeType}`,
|
|
53
|
+
`Size: ${attachment.size} bytes`,
|
|
54
|
+
].join("\n");
|
|
55
|
+
}
|
|
48
56
|
default:
|
|
49
57
|
throw new Error("unreachable");
|
|
50
58
|
}
|
|
@@ -19,7 +19,6 @@ export interface ProviderDefinition extends AgentProviderDefinition {
|
|
|
19
19
|
fetchModels: (options: ListModelsOptions) => Promise<AgentModelDefinition[]>;
|
|
20
20
|
fetchModes: (options: ListModesOptions) => Promise<AgentMode[]>;
|
|
21
21
|
}
|
|
22
|
-
export { IMPORTABLE_PROVIDERS } from "@getpaseo/protocol/importable-providers";
|
|
23
22
|
export interface BuildProviderRegistryOptions {
|
|
24
23
|
runtimeSettings?: AgentProviderRuntimeSettingsMap;
|
|
25
24
|
providerOverrides?: Record<string, ProviderOverride>;
|
|
@@ -14,7 +14,6 @@ function isNonEmptyStringArray(value) {
|
|
|
14
14
|
return value.length > 0;
|
|
15
15
|
}
|
|
16
16
|
export { AGENT_PROVIDER_DEFINITIONS, getAgentProviderDefinition };
|
|
17
|
-
export { IMPORTABLE_PROVIDERS } from "@getpaseo/protocol/importable-providers";
|
|
18
17
|
const PROVIDER_CLIENT_FACTORIES = {
|
|
19
18
|
claude: (logger, runtimeSettings) => new ClaudeAgentClient({
|
|
20
19
|
logger,
|
|
@@ -34,9 +33,22 @@ const PROVIDER_CLIENT_FACTORIES = {
|
|
|
34
33
|
env: runtimeSettings?.env,
|
|
35
34
|
}),
|
|
36
35
|
opencode: (logger, runtimeSettings) => new OpenCodeAgentClient(logger, runtimeSettings),
|
|
37
|
-
pi: (logger, runtimeSettings) => new PiRpcAgentClient({
|
|
36
|
+
pi: (logger, runtimeSettings, options) => new PiRpcAgentClient({
|
|
38
37
|
logger,
|
|
39
38
|
runtimeSettings,
|
|
39
|
+
providerParams: options?.providerParams,
|
|
40
|
+
}),
|
|
41
|
+
omp: (logger, runtimeSettings, options) => new PiRpcAgentClient({
|
|
42
|
+
logger,
|
|
43
|
+
runtimeSettings: mergeRuntimeSettings({
|
|
44
|
+
command: {
|
|
45
|
+
mode: "replace",
|
|
46
|
+
argv: ["omp"],
|
|
47
|
+
},
|
|
48
|
+
}, runtimeSettings),
|
|
49
|
+
providerParams: options?.providerParams ?? {
|
|
50
|
+
sessionDir: "~/.omp/agent/sessions",
|
|
51
|
+
},
|
|
40
52
|
}),
|
|
41
53
|
mock: (logger) => new MockLoadTestAgentClient(logger),
|
|
42
54
|
"mock-slow": () => new MockSlowProviderClient(),
|
|
@@ -292,11 +304,13 @@ function buildResolvedBuiltinProviders(providerOverrides, runtimeSettings, optio
|
|
|
292
304
|
runtimeSettings: mergedRuntimeSettings,
|
|
293
305
|
profileModels: override?.models ?? [],
|
|
294
306
|
additionalModels: override?.additionalModels ?? [],
|
|
295
|
-
profileModelsAreAdditive:
|
|
296
|
-
enabled: override?.enabled
|
|
307
|
+
profileModelsAreAdditive: false,
|
|
308
|
+
enabled: override?.enabled ?? definition.enabledByDefault ?? true,
|
|
297
309
|
derivedFromProviderId: null,
|
|
310
|
+
providerParams: override?.params,
|
|
298
311
|
createBaseClient: (logger) => factory(logger, mergedRuntimeSettings, {
|
|
299
312
|
workspaceGitService: options.workspaceGitService,
|
|
313
|
+
providerParams: override?.params,
|
|
300
314
|
}),
|
|
301
315
|
});
|
|
302
316
|
}
|
|
@@ -330,6 +344,7 @@ function addDerivedProviders(resolvedProviders, providerOverrides) {
|
|
|
330
344
|
profileModelsAreAdditive: false,
|
|
331
345
|
enabled: override.enabled !== false,
|
|
332
346
|
derivedFromProviderId: null,
|
|
347
|
+
providerParams: override.params,
|
|
333
348
|
createBaseClient: (logger) => providerId === "cursor"
|
|
334
349
|
? new CursorACPAgentClient({
|
|
335
350
|
logger,
|
|
@@ -356,6 +371,7 @@ function addDerivedProviders(resolvedProviders, providerOverrides) {
|
|
|
356
371
|
const mergedRuntimeSettings = mergeRuntimeSettings(baseProvider.runtimeSettings, toRuntimeSettings(override));
|
|
357
372
|
const baseDefinition = baseProvider.definition;
|
|
358
373
|
const baseFactory = getProviderClientFactory(baseProviderId);
|
|
374
|
+
const providerParams = override.params ?? baseProvider.providerParams;
|
|
359
375
|
resolvedProviders.set(providerId, {
|
|
360
376
|
definition: createDerivedDefinition(providerId, baseDefinition, override),
|
|
361
377
|
runtimeSettings: mergedRuntimeSettings,
|
|
@@ -364,7 +380,9 @@ function addDerivedProviders(resolvedProviders, providerOverrides) {
|
|
|
364
380
|
profileModelsAreAdditive: false,
|
|
365
381
|
enabled: override.enabled !== false,
|
|
366
382
|
derivedFromProviderId: baseProviderId,
|
|
383
|
+
providerParams,
|
|
367
384
|
createBaseClient: (logger) => baseFactory(logger, mergedRuntimeSettings, {
|
|
385
|
+
providerParams,
|
|
368
386
|
customProvider: {
|
|
369
387
|
id: providerId,
|
|
370
388
|
label: override.label ?? providerId,
|
|
@@ -6,6 +6,24 @@ 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
8
|
const DEFAULT_REFRESH_TIMEOUT_MS = 30000;
|
|
9
|
+
const REFRESH_TIMEOUT_ENV_VAR = "PASEO_PROVIDER_REFRESH_TIMEOUT_MS";
|
|
10
|
+
// Provider refresh probes can be slow on cold starts (e.g. Copilot's first
|
|
11
|
+
// `copilot --acp` invocation, OpenCode workspace probes with many MCP servers).
|
|
12
|
+
// Allow operators to bump the ceiling via env var without rebuilding.
|
|
13
|
+
function resolveRefreshTimeoutMs(option) {
|
|
14
|
+
if (typeof option === "number" && Number.isFinite(option) && option > 0) {
|
|
15
|
+
return option;
|
|
16
|
+
}
|
|
17
|
+
const fromEnv = process.env[REFRESH_TIMEOUT_ENV_VAR];
|
|
18
|
+
if (fromEnv) {
|
|
19
|
+
// Number() handles scientific notation (e.g. "6e4") which parseInt would silently truncate.
|
|
20
|
+
const parsed = Number(fromEnv);
|
|
21
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return DEFAULT_REFRESH_TIMEOUT_MS;
|
|
26
|
+
}
|
|
9
27
|
export class ProviderSnapshotManager {
|
|
10
28
|
constructor(options) {
|
|
11
29
|
this.snapshots = new Map();
|
|
@@ -19,7 +37,7 @@ export class ProviderSnapshotManager {
|
|
|
19
37
|
this.runtimeSettings = options.runtimeSettings;
|
|
20
38
|
this.providerOverrides = options.providerOverrides;
|
|
21
39
|
this.baseProviderOverrides = options.providerOverrides;
|
|
22
|
-
this.refreshTimeoutMs = options.refreshTimeoutMs
|
|
40
|
+
this.refreshTimeoutMs = resolveRefreshTimeoutMs(options.refreshTimeoutMs);
|
|
23
41
|
this.providerRegistry = this.buildRegistry();
|
|
24
42
|
this.providerClients = { ...this.extraClients };
|
|
25
43
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type AgentDefinition, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
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 ListModelsOptions, type ListPersistedAgentsOptions, type PersistedAgentDescriptor } from "../../agent-sdk-types.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 ListModelsOptions, type ListPersistedAgentsOptions, type McpServerConfig, type PersistedAgentDescriptor } from "../../agent-sdk-types.js";
|
|
5
5
|
import { type ProviderRuntimeSettings } from "../../provider-launch-config.js";
|
|
6
6
|
export declare function normalizeClaudeAskUserQuestionUpdatedInput(updatedInput: AgentMetadata | undefined, fallbackInput: AgentMetadata | undefined): AgentMetadata;
|
|
7
7
|
interface EventIdentifiers {
|
|
@@ -21,8 +21,10 @@ interface ClaudeAgentClientOptions {
|
|
|
21
21
|
runtimeSettings?: ProviderRuntimeSettings;
|
|
22
22
|
queryFactory?: ClaudeQueryFactory;
|
|
23
23
|
resolveBinary?: () => Promise<string>;
|
|
24
|
+
configDir?: string;
|
|
24
25
|
}
|
|
25
26
|
export declare function extractUserMessageText(content: unknown): string | null;
|
|
27
|
+
export declare function toClaudeSdkMcpConfig(config: McpServerConfig): ClaudeSdkMcpServerConfig;
|
|
26
28
|
export declare function readEventIdentifiers(message: SDKMessage): EventIdentifiers;
|
|
27
29
|
export declare class ClaudeAgentClient implements AgentClient {
|
|
28
30
|
readonly provider: "claude";
|
|
@@ -32,6 +34,7 @@ export declare class ClaudeAgentClient implements AgentClient {
|
|
|
32
34
|
private readonly runtimeSettings?;
|
|
33
35
|
private readonly queryFactory?;
|
|
34
36
|
private readonly resolveBinary;
|
|
37
|
+
private readonly configDir?;
|
|
35
38
|
constructor(options: ClaudeAgentClientOptions);
|
|
36
39
|
createSession(config: AgentSessionConfig, launchContext?: AgentLaunchContext, options?: AgentCreateSessionOptions): Promise<AgentSession>;
|
|
37
40
|
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>, launchContext?: AgentLaunchContext): Promise<AgentSession>;
|
|
@@ -539,7 +539,7 @@ function coerceSessionMetadata(metadata) {
|
|
|
539
539
|
}
|
|
540
540
|
return result;
|
|
541
541
|
}
|
|
542
|
-
function toClaudeSdkMcpConfig(config) {
|
|
542
|
+
export function toClaudeSdkMcpConfig(config) {
|
|
543
543
|
switch (config.type) {
|
|
544
544
|
case "stdio":
|
|
545
545
|
return {
|
|
@@ -547,18 +547,21 @@ function toClaudeSdkMcpConfig(config) {
|
|
|
547
547
|
command: config.command,
|
|
548
548
|
args: config.args,
|
|
549
549
|
env: config.env,
|
|
550
|
+
alwaysLoad: config.alwaysLoad,
|
|
550
551
|
};
|
|
551
552
|
case "http":
|
|
552
553
|
return {
|
|
553
554
|
type: "http",
|
|
554
555
|
url: config.url,
|
|
555
556
|
headers: config.headers,
|
|
557
|
+
alwaysLoad: config.alwaysLoad,
|
|
556
558
|
};
|
|
557
559
|
case "sse":
|
|
558
560
|
return {
|
|
559
561
|
type: "sse",
|
|
560
562
|
url: config.url,
|
|
561
563
|
headers: config.headers,
|
|
564
|
+
alwaysLoad: config.alwaysLoad,
|
|
562
565
|
};
|
|
563
566
|
}
|
|
564
567
|
throw new Error("Unhandled MCP server config type");
|
|
@@ -922,6 +925,7 @@ export class ClaudeAgentClient {
|
|
|
922
925
|
this.runtimeSettings = options.runtimeSettings;
|
|
923
926
|
this.queryFactory = options.queryFactory;
|
|
924
927
|
this.resolveBinary = options.resolveBinary ?? (() => resolveClaudeBinary(this.runtimeSettings));
|
|
928
|
+
this.configDir = options.configDir;
|
|
925
929
|
}
|
|
926
930
|
async createSession(config, launchContext, options) {
|
|
927
931
|
const claudeConfig = this.assertConfig(config);
|
|
@@ -961,7 +965,7 @@ export class ClaudeAgentClient {
|
|
|
961
965
|
}
|
|
962
966
|
async listModels(_options) {
|
|
963
967
|
// Claude exposes a global catalog here; cwd/force are intentionally irrelevant.
|
|
964
|
-
return await getClaudeModelsWithSettings(this.logger);
|
|
968
|
+
return await getClaudeModelsWithSettings(this.logger, this.configDir);
|
|
965
969
|
}
|
|
966
970
|
async listFeatures(config) {
|
|
967
971
|
const claudeConfig = this.assertConfig(config);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Logger } from "pino";
|
|
2
2
|
import type { AgentModelDefinition } from "../../agent-sdk-types.js";
|
|
3
3
|
export declare function getClaudeModels(): AgentModelDefinition[];
|
|
4
|
-
export declare function getClaudeModelsWithSettings(logger: Logger): Promise<AgentModelDefinition[]>;
|
|
4
|
+
export declare function getClaudeModelsWithSettings(logger: Logger, configDir?: string): Promise<AgentModelDefinition[]>;
|
|
5
5
|
/**
|
|
6
6
|
* Normalize a runtime model string (from SDK init message) to a known model ID.
|
|
7
7
|
* Handles the `[1m]` suffix that the SDK appends for 1M context sessions.
|
|
@@ -89,9 +89,9 @@ const CLAUDE_SETTINGS_MODEL_ENV_KEYS = [
|
|
|
89
89
|
export function getClaudeModels() {
|
|
90
90
|
return CLAUDE_MODELS.map((model) => ({ ...model }));
|
|
91
91
|
}
|
|
92
|
-
export async function getClaudeModelsWithSettings(logger) {
|
|
92
|
+
export async function getClaudeModelsWithSettings(logger, configDir) {
|
|
93
93
|
const hardcodedModels = getClaudeModels();
|
|
94
|
-
const settingsModels = await readClaudeSettingsModels(logger);
|
|
94
|
+
const settingsModels = await readClaudeSettingsModels(logger, configDir);
|
|
95
95
|
if (settingsModels.length === 0) {
|
|
96
96
|
return hardcodedModels;
|
|
97
97
|
}
|
|
@@ -106,8 +106,8 @@ export async function getClaudeModelsWithSettings(logger) {
|
|
|
106
106
|
}
|
|
107
107
|
return models;
|
|
108
108
|
}
|
|
109
|
-
async function readClaudeSettingsModels(logger) {
|
|
110
|
-
const settingsPath = path.join(resolveClaudeConfigDir(), "settings.json");
|
|
109
|
+
async function readClaudeSettingsModels(logger, configDir) {
|
|
110
|
+
const settingsPath = path.join(resolveClaudeConfigDir(configDir), "settings.json");
|
|
111
111
|
let parsed;
|
|
112
112
|
try {
|
|
113
113
|
const rawSettings = await fs.readFile(settingsPath, "utf8");
|
|
@@ -136,8 +136,8 @@ async function readClaudeSettingsModels(logger) {
|
|
|
136
136
|
}
|
|
137
137
|
return models;
|
|
138
138
|
}
|
|
139
|
-
function resolveClaudeConfigDir() {
|
|
140
|
-
return process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
|
|
139
|
+
function resolveClaudeConfigDir(configDir) {
|
|
140
|
+
return configDir ?? process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
|
|
141
141
|
}
|
|
142
142
|
function addSettingsModel(models, value, settingsKey) {
|
|
143
143
|
if (typeof value !== "string") {
|
|
@@ -34,6 +34,14 @@ const TURN_START_TIMEOUT_MS = 90 * 1000;
|
|
|
34
34
|
const INTERRUPT_TIMEOUT_MS = 2000;
|
|
35
35
|
const CODEX_PROVIDER = "codex";
|
|
36
36
|
const CODEX_IMAGE_ATTACHMENT_DIR = "paseo-attachments";
|
|
37
|
+
// Codex treats most app-server client names as the model-request originator.
|
|
38
|
+
// This reserved Codex name is non-originating, so requests keep Codex's default
|
|
39
|
+
// CLI identity instead of showing up as Paseo in provider usage logs.
|
|
40
|
+
const CODEX_NON_ORIGINATING_APP_SERVER_CLIENT_INFO = {
|
|
41
|
+
name: "codex_app_server_daemon",
|
|
42
|
+
title: "Codex App Server Daemon",
|
|
43
|
+
version: "0.0.0",
|
|
44
|
+
};
|
|
37
45
|
const ASSISTANT_MESSAGE_BOUNDARY_MARKDOWN = "\n\n---\n\n";
|
|
38
46
|
const CODEX_TOOL_THREAD_ITEM_TYPES = new Set([
|
|
39
47
|
"commandExecution",
|
|
@@ -2093,11 +2101,7 @@ export function buildCodexAppServerEnv(runtimeSettings, launchEnv) {
|
|
|
2093
2101
|
}
|
|
2094
2102
|
function buildCodexAppServerInitializeParams() {
|
|
2095
2103
|
return {
|
|
2096
|
-
clientInfo:
|
|
2097
|
-
name: "paseo",
|
|
2098
|
-
title: "Paseo",
|
|
2099
|
-
version: "0.0.0",
|
|
2100
|
-
},
|
|
2104
|
+
clientInfo: CODEX_NON_ORIGINATING_APP_SERVER_CLIENT_INFO,
|
|
2101
2105
|
capabilities: {
|
|
2102
2106
|
experimentalApi: true,
|
|
2103
2107
|
},
|
|
@@ -76,6 +76,7 @@ export declare class TestOpenCodeClient {
|
|
|
76
76
|
sessionMessagesResponse: OpenCodeResponse;
|
|
77
77
|
sessionPromptAsyncEvents: unknown[];
|
|
78
78
|
sessionPromptAsyncResponse: OpenCodeResponse;
|
|
79
|
+
sessionSummarizeEvents: unknown[];
|
|
79
80
|
sessionSummarizeResponse: OpenCodeResponse;
|
|
80
81
|
sessionUpdateResponse: OpenCodeResponse;
|
|
81
82
|
private readonly queuedEventStream;
|
|
@@ -70,6 +70,7 @@ export class TestOpenCodeClient {
|
|
|
70
70
|
this.sessionMessagesResponse = { data: [] };
|
|
71
71
|
this.sessionPromptAsyncEvents = [idleEvent()];
|
|
72
72
|
this.sessionPromptAsyncResponse = {};
|
|
73
|
+
this.sessionSummarizeEvents = [idleEvent()];
|
|
73
74
|
this.sessionSummarizeResponse = { data: {} };
|
|
74
75
|
this.sessionUpdateResponse = {};
|
|
75
76
|
this.queuedEventStream = createQueuedEventStream();
|
|
@@ -182,6 +183,9 @@ export class TestOpenCodeClient {
|
|
|
182
183
|
},
|
|
183
184
|
summarize: async (parameters) => {
|
|
184
185
|
this.calls.sessionSummarize.push(parameters);
|
|
186
|
+
for (const event of this.sessionSummarizeEvents) {
|
|
187
|
+
this.emitEvent(event);
|
|
188
|
+
}
|
|
185
189
|
return this.sessionSummarizeResponse;
|
|
186
190
|
},
|
|
187
191
|
update: async (parameters) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type AssistantMessage as OpenCodeAssistantMessage, type Event as OpenCodeEvent, type FilePartInput as OpenCodeFilePartInput, type OpencodeClient, type TextPartInput as OpenCodeTextPartInput } from "@opencode-ai/sdk/v2/client";
|
|
1
|
+
import { type AssistantMessage as OpenCodeAssistantMessage, type Event as OpenCodeEvent, type FilePartInput as OpenCodeFilePartInput, type Message as OpenCodeMessage, type OpencodeClient, type Part as OpenCodePart, type TextPartInput as OpenCodeTextPartInput } from "@opencode-ai/sdk/v2/client";
|
|
2
2
|
import type { Logger } from "pino";
|
|
3
|
-
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentUsage, type ResolveAgentCreateConfigInput, type ResolveAgentCreateConfigResult, type ListModelsOptions, type ListModesOptions, type ListPersistedAgentsOptions, type PersistedAgentDescriptor, type ToolCallTimelineItem } from "../agent-sdk-types.js";
|
|
3
|
+
import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOptions, type AgentFeature, type AgentLaunchContext, type AgentMode, type AgentModelDefinition, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPersistenceHandle, type AgentPromptInput, type AgentRunOptions, type AgentRunResult, type AgentRuntimeInfo, type AgentSession, type AgentSessionConfig, type AgentSlashCommand, type AgentStreamEvent, type AgentTimelineItem, type AgentUsage, type ResolveAgentCreateConfigInput, type ResolveAgentCreateConfigResult, type ListModelsOptions, type ListModesOptions, type ListPersistedAgentsOptions, type PersistedAgentDescriptor, type ToolCallTimelineItem } from "../agent-sdk-types.js";
|
|
4
4
|
import { isDefaultAgentCreateConfigUnattended } from "../create-agent-mode.js";
|
|
5
5
|
import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
|
|
6
6
|
import { type OpenCodeRuntime } from "./opencode/runtime.js";
|
|
@@ -10,6 +10,10 @@ type OpenCodeAgentConfig = AgentSessionConfig & {
|
|
|
10
10
|
provider: "opencode";
|
|
11
11
|
};
|
|
12
12
|
type OpenCodeMessageRole = "user" | "assistant";
|
|
13
|
+
interface OpenCodeSessionMessage {
|
|
14
|
+
info: OpenCodeMessage;
|
|
15
|
+
parts: OpenCodePart[];
|
|
16
|
+
}
|
|
13
17
|
declare function reconcileOpenCodeSessionClose(params: {
|
|
14
18
|
client: Pick<OpencodeClient, "session">;
|
|
15
19
|
sessionId: string;
|
|
@@ -79,8 +83,10 @@ declare function mergeOpenCodeStepFinishUsage(usage: AgentUsage, part: {
|
|
|
79
83
|
}): void;
|
|
80
84
|
declare function hasNormalizedOpenCodeUsage(usage: AgentUsage): boolean;
|
|
81
85
|
declare function buildOpenCodePromptParts(prompt: AgentPromptInput): Array<OpenCodeTextPartInput | OpenCodeFilePartInput>;
|
|
86
|
+
declare function buildOpenCodeSessionTimeline(messages: ReadonlyArray<OpenCodeSessionMessage>): AgentTimelineItem[];
|
|
82
87
|
export declare const __openCodeInternals: {
|
|
83
88
|
buildOpenCodePromptParts: typeof buildOpenCodePromptParts;
|
|
89
|
+
buildOpenCodeSessionTimeline: typeof buildOpenCodeSessionTimeline;
|
|
84
90
|
buildOpenCodeModelContextWindowLookup: typeof buildOpenCodeModelContextWindowLookup;
|
|
85
91
|
buildOpenCodeModelDefinition: typeof buildOpenCodeModelDefinition;
|
|
86
92
|
buildOpenCodeModelLookupKey: typeof buildOpenCodeModelLookupKey;
|
|
@@ -133,6 +139,11 @@ export interface OpenCodeEventTranslationState {
|
|
|
133
139
|
sessionTotalCostUsd?: number;
|
|
134
140
|
streamedPartKeys: Set<string>;
|
|
135
141
|
emittedStructuredMessageIds: Set<string>;
|
|
142
|
+
compactionSummaryMessageIds: Set<string>;
|
|
143
|
+
emittedCompactionPartIds: Set<string>;
|
|
144
|
+
suppressAssistantMessagesUntilIdle?: {
|
|
145
|
+
active: boolean;
|
|
146
|
+
};
|
|
136
147
|
/** Tracks the type of each part by ID, learned from message.part.updated events. */
|
|
137
148
|
partTypes: Map<string, string>;
|
|
138
149
|
subAgentsByCallId?: Map<string, OpenCodeSubAgentActivityState>;
|
|
@@ -186,6 +197,9 @@ declare class OpenCodeAgentSession implements AgentSession {
|
|
|
186
197
|
private streamedPartKeys;
|
|
187
198
|
/** Tracks assistant messages already emitted from structured payloads. */
|
|
188
199
|
private emittedStructuredMessageIds;
|
|
200
|
+
private compactionSummaryMessageIds;
|
|
201
|
+
private emittedCompactionPartIds;
|
|
202
|
+
private suppressAssistantMessagesUntilIdle;
|
|
189
203
|
/** Tracks the type of each part by ID, learned from message.part.updated events. */
|
|
190
204
|
private partTypes;
|
|
191
205
|
private availableModesCache;
|