@getpaseo/server 0.1.91-beta.2 → 0.1.92
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 +13 -5
- package/dist/server/server/agent/agent-manager.js +110 -74
- package/dist/server/server/agent/agent-projections.d.ts +4 -2
- package/dist/server/server/agent/agent-projections.js +8 -28
- package/dist/server/server/agent/agent-sdk-types.d.ts +30 -10
- package/dist/server/server/agent/import-sessions.d.ts +3 -2
- package/dist/server/server/agent/import-sessions.js +23 -55
- 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 +55 -16
- package/dist/server/server/agent/provider-session-import.d.ts +10 -0
- package/dist/server/server/agent/provider-session-import.js +49 -0
- package/dist/server/server/agent/providers/acp-agent.d.ts +12 -2
- package/dist/server/server/agent/providers/acp-agent.js +78 -36
- package/dist/server/server/agent/providers/claude/agent.d.ts +3 -2
- package/dist/server/server/agent/providers/claude/agent.js +28 -24
- 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 +29 -26
- package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +1 -0
- package/dist/server/server/agent/providers/cursor-acp-agent.js +1 -0
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +9 -0
- package/dist/server/server/agent/providers/generic-acp-agent.js +18 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +3 -2
- package/dist/server/server/agent/providers/mock-load-test-agent.js +11 -1
- package/dist/server/server/agent/providers/mock-slow-provider.d.ts +1 -2
- package/dist/server/server/agent/providers/mock-slow-provider.js +0 -3
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.d.ts +3 -0
- package/dist/server/server/agent/providers/opencode/test-utils/test-opencode-runtime.js +12 -0
- package/dist/server/server/agent/providers/opencode-agent.d.ts +18 -3
- package/dist/server/server/agent/providers/opencode-agent.js +135 -36
- package/dist/server/server/agent/providers/pi/agent.d.ts +25 -2
- package/dist/server/server/agent/providers/pi/agent.js +243 -14
- 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 +11 -0
- package/dist/server/server/agent/providers/pi/session-descriptor.js +284 -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/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 +8 -0
- package/dist/server/server/persisted-config.js +1 -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 -3
- 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/src/server/persisted-config.js +1 -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) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AGENT_LIFECYCLE_STATUSES, type AgentLifecycleStatus } from "@getpaseo/protocol/agent-lifecycle";
|
|
2
2
|
import type { Logger } from "pino";
|
|
3
3
|
import type { TerminalManager } from "../../terminal/terminal-manager.js";
|
|
4
|
-
import { type AgentCapabilityFlags, type AgentClient, type AgentFeature, type AgentSlashCommand, type AgentMode, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentPersistenceHandle, type AgentPromptInput, type AgentProvider, type AgentRunOptions, type AgentRunResult, type AgentSession, type AgentSessionConfig, type AgentStreamEvent, type AgentTimelineItem, type AgentUsage, type AgentRuntimeInfo, type
|
|
4
|
+
import { type AgentCapabilityFlags, type AgentClient, type AgentFeature, type AgentSlashCommand, type AgentMode, type AgentPermissionRequest, type AgentPermissionResponse, type AgentPermissionResult, type AgentPersistenceHandle, type AgentPromptInput, type AgentProvider, type AgentRunOptions, type AgentRunResult, type AgentSession, type AgentSessionConfig, type AgentStreamEvent, type AgentTimelineItem, type AgentUsage, type AgentRuntimeInfo, type ImportableProviderSession, type ListImportableSessionsOptions } from "./agent-sdk-types.js";
|
|
5
5
|
import type { StoredAgentRecord, AgentStorage } from "./agent-storage.js";
|
|
6
6
|
import type { AgentTimelineFetchOptions, AgentTimelineFetchResult, AgentTimelineRow, AgentTimelineStore } from "./agent-timeline-store-types.js";
|
|
7
7
|
import { type ForegroundTurnWaiter } from "./foreground-run-state.js";
|
|
@@ -28,13 +28,16 @@ interface HydrateTimelineOptions {
|
|
|
28
28
|
force?: boolean;
|
|
29
29
|
broadcast?: boolean;
|
|
30
30
|
}
|
|
31
|
-
export type ImportablePersistedAgentQueryOptions =
|
|
31
|
+
export type ImportablePersistedAgentQueryOptions = ListImportableSessionsOptions & {
|
|
32
32
|
/**
|
|
33
33
|
* When set, only providers in this set are scanned, in addition to the
|
|
34
34
|
* built-in importable allowlist + enabled + non-derived rules.
|
|
35
35
|
*/
|
|
36
36
|
providerFilter?: Set<string>;
|
|
37
37
|
};
|
|
38
|
+
export interface ManagedImportableProviderSession extends ImportableProviderSession {
|
|
39
|
+
provider: AgentProvider;
|
|
40
|
+
}
|
|
38
41
|
export type AgentAttentionCallback = (params: {
|
|
39
42
|
agentId: string;
|
|
40
43
|
provider: AgentProvider;
|
|
@@ -163,7 +166,6 @@ export interface AgentMetricsSnapshot {
|
|
|
163
166
|
export declare class AgentManager {
|
|
164
167
|
private readonly clients;
|
|
165
168
|
private readonly providerEnabled;
|
|
166
|
-
private readonly providerDerivedFromId;
|
|
167
169
|
private readonly agents;
|
|
168
170
|
private readonly timelineStore;
|
|
169
171
|
private readonly agentsAwaitingInitialSnapshotPersist;
|
|
@@ -199,9 +201,8 @@ export declare class AgentManager {
|
|
|
199
201
|
hasInFlightRun(agentId: string): boolean;
|
|
200
202
|
subscribe(callback: AgentSubscriber, options?: SubscribeOptions): () => void;
|
|
201
203
|
listAgents(): ManagedAgent[];
|
|
202
|
-
|
|
204
|
+
listImportableSessions(options?: ImportablePersistedAgentQueryOptions): Promise<ManagedImportableProviderSession[]>;
|
|
203
205
|
private isProviderImportable;
|
|
204
|
-
findPersistedAgent(provider: AgentProvider, sessionId: string, options?: Pick<ListPersistedAgentsOptions, "cwd">): Promise<PersistedAgentDescriptor | null>;
|
|
205
206
|
listProviderAvailability(): Promise<ProviderAvailability[]>;
|
|
206
207
|
listDraftCommands(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
|
|
207
208
|
listDraftFeatures(config: AgentSessionConfig): Promise<AgentFeature[]>;
|
|
@@ -224,6 +225,12 @@ export declare class AgentManager {
|
|
|
224
225
|
lastUserMessageAt?: Date | null;
|
|
225
226
|
labels?: Record<string, string>;
|
|
226
227
|
}): Promise<ManagedAgent>;
|
|
228
|
+
importProviderSession(input: {
|
|
229
|
+
provider: AgentProvider;
|
|
230
|
+
providerHandleId: string;
|
|
231
|
+
cwd: string;
|
|
232
|
+
labels?: Record<string, string>;
|
|
233
|
+
}): Promise<ManagedAgent>;
|
|
227
234
|
reloadAgentSession(agentId: string, overrides?: Partial<AgentSessionConfig>, options?: {
|
|
228
235
|
rehydrateFromDisk?: boolean;
|
|
229
236
|
}): Promise<ManagedAgent>;
|
|
@@ -337,6 +344,7 @@ export declare class AgentManager {
|
|
|
337
344
|
private dispatchStream;
|
|
338
345
|
private dispatch;
|
|
339
346
|
private normalizeConfig;
|
|
347
|
+
private prepareSessionConfig;
|
|
340
348
|
private applyDaemonAppendSystemPrompt;
|
|
341
349
|
private buildLaunchContext;
|
|
342
350
|
private requireAvailableClient;
|
|
@@ -10,9 +10,10 @@ 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
|
+
import { resolveCreateAgentTitles } from "./create-agent-title.js";
|
|
16
17
|
const RELOAD_SESSION_CLOSE_TIMEOUT_MS = 3000;
|
|
17
18
|
const INTERRUPT_SESSION_TIMEOUT_MS = 2000;
|
|
18
19
|
const STORED_AGENT_CAPABILITIES = {
|
|
@@ -54,7 +55,7 @@ function buildStoredAgentConfig(record) {
|
|
|
54
55
|
}
|
|
55
56
|
if (record.config.mcpServers != null)
|
|
56
57
|
config.mcpServers = record.config.mcpServers;
|
|
57
|
-
return config;
|
|
58
|
+
return stripInternalPaseoMcpServer(config);
|
|
58
59
|
}
|
|
59
60
|
export { AGENT_LIFECYCLE_STATUSES };
|
|
60
61
|
function resolveInitialAttention(input) {
|
|
@@ -122,11 +123,48 @@ function buildExplicitTimelineSeedForRegister(now, options) {
|
|
|
122
123
|
timestamp: (options?.updatedAt ?? options?.createdAt ?? now).toISOString(),
|
|
123
124
|
};
|
|
124
125
|
}
|
|
126
|
+
function buildImportedTimelineRows(entries) {
|
|
127
|
+
const rows = [];
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
if (entry.item.type === "user_message" && isSystemInjectedEnvelope(entry.item.text)) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
rows.push({
|
|
133
|
+
seq: rows.length + 1,
|
|
134
|
+
timestamp: entry.timestamp ?? new Date().toISOString(),
|
|
135
|
+
item: entry.item,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return rows;
|
|
139
|
+
}
|
|
140
|
+
function resolveImportedAgentTitle(config, timelineRows) {
|
|
141
|
+
const initialPrompt = getFirstUserMessageTextFromRows(timelineRows);
|
|
142
|
+
if (!initialPrompt) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
const { explicitTitle, provisionalTitle } = resolveCreateAgentTitles({
|
|
146
|
+
configTitle: config.title,
|
|
147
|
+
initialPrompt,
|
|
148
|
+
});
|
|
149
|
+
return explicitTitle ?? provisionalTitle ?? null;
|
|
150
|
+
}
|
|
151
|
+
function getFirstUserMessageTextFromRows(rows) {
|
|
152
|
+
for (const row of rows) {
|
|
153
|
+
const item = row.item;
|
|
154
|
+
if (item.type !== "user_message") {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
const text = item.text.trim();
|
|
158
|
+
if (text) {
|
|
159
|
+
return text;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
125
164
|
export class AgentManager {
|
|
126
165
|
constructor(options) {
|
|
127
166
|
this.clients = new Map();
|
|
128
167
|
this.providerEnabled = new Map();
|
|
129
|
-
this.providerDerivedFromId = new Map();
|
|
130
168
|
this.agents = new Map();
|
|
131
169
|
this.timelineStore = new InMemoryAgentTimelineStore();
|
|
132
170
|
this.agentsAwaitingInitialSnapshotPersist = new Set();
|
|
@@ -166,7 +204,6 @@ export class AgentManager {
|
|
|
166
204
|
for (const [provider, definition] of Object.entries(input.providerDefinitions)) {
|
|
167
205
|
if (definition) {
|
|
168
206
|
this.providerEnabled.set(provider, definition.enabled);
|
|
169
|
-
this.providerDerivedFromId.set(provider, definition.derivedFromProviderId ?? null);
|
|
170
207
|
}
|
|
171
208
|
}
|
|
172
209
|
for (const [provider, client] of Object.entries(input.clients)) {
|
|
@@ -281,52 +318,37 @@ export class AgentManager {
|
|
|
281
318
|
.filter((agent) => !agent.internal)
|
|
282
319
|
.map((agent) => Object.assign({}, agent));
|
|
283
320
|
}
|
|
284
|
-
async
|
|
285
|
-
const providerEntries = Array.from(this.clients.entries()).filter(([provider, client]) =>
|
|
321
|
+
async listImportableSessions(options) {
|
|
322
|
+
const providerEntries = Array.from(this.clients.entries()).filter(([provider, client]) => client.capabilities.supportsSessionListing &&
|
|
323
|
+
!!client.listImportableSessions &&
|
|
286
324
|
this.isProviderImportable(provider, options?.providerFilter));
|
|
287
|
-
const
|
|
325
|
+
const sessionLists = await Promise.all(providerEntries.map(async ([provider, client]) => {
|
|
288
326
|
try {
|
|
289
|
-
return await client.
|
|
327
|
+
return (await client.listImportableSessions({
|
|
290
328
|
limit: options?.limit,
|
|
291
329
|
cwd: options?.cwd,
|
|
292
|
-
});
|
|
330
|
+
})).map((session) => Object.assign(session, { provider }));
|
|
293
331
|
}
|
|
294
332
|
catch (error) {
|
|
295
|
-
this.logger.warn({ err: error, provider }, "Failed to list
|
|
333
|
+
this.logger.warn({ err: error, provider }, "Failed to list importable sessions for provider");
|
|
296
334
|
return [];
|
|
297
335
|
}
|
|
298
336
|
}));
|
|
299
|
-
const
|
|
337
|
+
const sessions = sessionLists.flat();
|
|
300
338
|
const limit = options?.limit ?? 20;
|
|
301
|
-
return
|
|
339
|
+
return sessions
|
|
302
340
|
.sort((a, b) => b.lastActivityAt.getTime() - a.lastActivityAt.getTime())
|
|
303
341
|
.slice(0, limit);
|
|
304
342
|
}
|
|
305
343
|
isProviderImportable(provider, providerFilter) {
|
|
306
|
-
if (!IMPORTABLE_PROVIDERS.includes(provider)) {
|
|
307
|
-
return false;
|
|
308
|
-
}
|
|
309
344
|
if (this.providerEnabled.get(provider) === false) {
|
|
310
345
|
return false;
|
|
311
346
|
}
|
|
312
|
-
if (this.providerDerivedFromId.get(provider) != null) {
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
347
|
if (providerFilter && !providerFilter.has(provider)) {
|
|
316
348
|
return false;
|
|
317
349
|
}
|
|
318
350
|
return true;
|
|
319
351
|
}
|
|
320
|
-
async findPersistedAgent(provider, sessionId, options) {
|
|
321
|
-
const client = this.requireClient(provider);
|
|
322
|
-
if (!client.listPersistedAgents) {
|
|
323
|
-
return null;
|
|
324
|
-
}
|
|
325
|
-
const descriptors = await client.listPersistedAgents({ limit: 200, cwd: options?.cwd });
|
|
326
|
-
return (descriptors.find((descriptor) => {
|
|
327
|
-
return (descriptor.sessionId === sessionId || descriptor.persistence.nativeHandle === sessionId);
|
|
328
|
-
}) ?? null);
|
|
329
|
-
}
|
|
330
352
|
async listProviderAvailability() {
|
|
331
353
|
const checks = Array.from(this.clients.keys()).map(async (provider) => {
|
|
332
354
|
const client = this.clients.get(provider);
|
|
@@ -427,27 +449,15 @@ export class AgentManager {
|
|
|
427
449
|
}
|
|
428
450
|
async createAgent(config, agentId, options) {
|
|
429
451
|
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));
|
|
452
|
+
const { storedConfig, launchConfig } = await this.prepareSessionConfig(config, resolvedAgentId);
|
|
453
|
+
this.requireEnabledProvider(storedConfig.provider);
|
|
444
454
|
const launchContext = this.buildLaunchContext(resolvedAgentId, options?.env);
|
|
445
455
|
const client = await this.requireAvailableClient({
|
|
446
|
-
provider:
|
|
456
|
+
provider: storedConfig.provider,
|
|
447
457
|
});
|
|
448
458
|
const createOptions = this.buildCreateSessionOptions(options);
|
|
449
|
-
const session = await client.createSession(
|
|
450
|
-
return this.registerSession(session,
|
|
459
|
+
const session = await client.createSession(launchConfig, launchContext, createOptions);
|
|
460
|
+
return this.registerSession(session, storedConfig, resolvedAgentId, {
|
|
451
461
|
labels: options?.labels,
|
|
452
462
|
workspaceId: options?.workspaceId,
|
|
453
463
|
initialTitle: options?.initialTitle,
|
|
@@ -468,29 +478,44 @@ export class AgentManager {
|
|
|
468
478
|
...overrides,
|
|
469
479
|
provider: handle.provider,
|
|
470
480
|
};
|
|
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
|
-
}
|
|
481
|
+
const { storedConfig, launchConfig } = await this.prepareSessionConfig(mergedConfig, resolvedAgentId);
|
|
486
482
|
const launchContext = this.buildLaunchContext(resolvedAgentId);
|
|
487
483
|
const client = this.requireClient(handle.provider);
|
|
488
484
|
const available = await client.isAvailable();
|
|
489
485
|
if (!available) {
|
|
490
486
|
throw new Error(`Provider '${handle.provider}' is not available. Please ensure the CLI is installed.`);
|
|
491
487
|
}
|
|
492
|
-
const session = await client.resumeSession(handle,
|
|
493
|
-
return this.registerSession(session,
|
|
488
|
+
const session = await client.resumeSession(handle, launchConfig, launchContext);
|
|
489
|
+
return this.registerSession(session, storedConfig, resolvedAgentId, options);
|
|
490
|
+
}
|
|
491
|
+
async importProviderSession(input) {
|
|
492
|
+
const resolvedAgentId = validateAgentId(this.idFactory(), "importProviderSession");
|
|
493
|
+
this.requireEnabledProvider(input.provider);
|
|
494
|
+
const client = await this.requireAvailableClient({ provider: input.provider });
|
|
495
|
+
if (!client.importSession) {
|
|
496
|
+
throw new Error(`Provider '${input.provider}' does not support importing sessions`);
|
|
497
|
+
}
|
|
498
|
+
const { storedConfig, launchConfig } = await this.prepareSessionConfig({
|
|
499
|
+
provider: input.provider,
|
|
500
|
+
cwd: input.cwd,
|
|
501
|
+
}, resolvedAgentId);
|
|
502
|
+
const launchContext = this.buildLaunchContext(resolvedAgentId);
|
|
503
|
+
const imported = await client.importSession({
|
|
504
|
+
providerHandleId: input.providerHandleId,
|
|
505
|
+
cwd: input.cwd,
|
|
506
|
+
}, { config: launchConfig, storedConfig, launchContext });
|
|
507
|
+
const importedConfig = await this.normalizeConfig(stripInternalPaseoMcpServer(imported.config));
|
|
508
|
+
const timelineRows = buildImportedTimelineRows(imported.timeline);
|
|
509
|
+
const initialTitle = resolveImportedAgentTitle(importedConfig, timelineRows);
|
|
510
|
+
return this.registerSession(imported.session, importedConfig, resolvedAgentId, {
|
|
511
|
+
labels: input.labels,
|
|
512
|
+
timelineRows,
|
|
513
|
+
timelineNextSeq: timelineRows.length + 1,
|
|
514
|
+
persistence: imported.persistence,
|
|
515
|
+
historyPrimed: true,
|
|
516
|
+
initialTitle,
|
|
517
|
+
publishWhenReady: true,
|
|
518
|
+
});
|
|
494
519
|
}
|
|
495
520
|
// Hot-reload an active agent session with config overrides. By default the
|
|
496
521
|
// in-memory timeline is preserved (used for voice-mode toggles and similar
|
|
@@ -517,11 +542,11 @@ export class AgentManager {
|
|
|
517
542
|
...overrides,
|
|
518
543
|
provider,
|
|
519
544
|
};
|
|
520
|
-
const
|
|
545
|
+
const { storedConfig, launchConfig } = await this.prepareSessionConfig(refreshConfig, agentId);
|
|
521
546
|
const launchContext = this.buildLaunchContext(agentId);
|
|
522
547
|
const session = handle
|
|
523
|
-
? await client.resumeSession(handle,
|
|
524
|
-
: await client.createSession(
|
|
548
|
+
? await client.resumeSession(handle, launchConfig, launchContext)
|
|
549
|
+
: await client.createSession(launchConfig, launchContext);
|
|
525
550
|
this.agentStreamCoalescer.flushAndDiscard(agentId);
|
|
526
551
|
// Remove the existing agent entry before swapping sessions
|
|
527
552
|
this.agents.delete(agentId);
|
|
@@ -539,7 +564,7 @@ export class AgentManager {
|
|
|
539
564
|
this.timelineStore.delete(agentId);
|
|
540
565
|
}
|
|
541
566
|
// Preserve existing labels and timeline during reload.
|
|
542
|
-
return this.registerSession(session,
|
|
567
|
+
return this.registerSession(session, storedConfig, agentId, {
|
|
543
568
|
labels: existing.labels,
|
|
544
569
|
createdAt: existing.createdAt,
|
|
545
570
|
updatedAt: existing.updatedAt,
|
|
@@ -1639,13 +1664,15 @@ export class AgentManager {
|
|
|
1639
1664
|
this.agents.set(resolvedAgentId, managed);
|
|
1640
1665
|
// Initialize previousStatus to track transitions
|
|
1641
1666
|
this.previousStatuses.set(resolvedAgentId, managed.lifecycle);
|
|
1642
|
-
await this.refreshRuntimeInfo(managed);
|
|
1667
|
+
await this.refreshRuntimeInfo(managed, { emit: !options?.publishWhenReady });
|
|
1643
1668
|
await this.persistSnapshot(managed, {
|
|
1644
1669
|
workspaceId: options?.workspaceId,
|
|
1645
1670
|
title: initialPersistedTitle,
|
|
1646
1671
|
});
|
|
1647
|
-
|
|
1648
|
-
|
|
1672
|
+
if (!options?.publishWhenReady) {
|
|
1673
|
+
this.emitState(managed, { persist: false });
|
|
1674
|
+
}
|
|
1675
|
+
await this.refreshSessionState(managed, { emit: !options?.publishWhenReady });
|
|
1649
1676
|
managed.lifecycle = "idle";
|
|
1650
1677
|
await this.persistSnapshot(managed, { workspaceId: options?.workspaceId });
|
|
1651
1678
|
this.emitState(managed, { persist: false });
|
|
@@ -1694,7 +1721,7 @@ export class AgentManager {
|
|
|
1694
1721
|
foregroundTurnWaiters: new Set(),
|
|
1695
1722
|
finalizedForegroundTurnIds: new Set(),
|
|
1696
1723
|
unsubscribeSession: null,
|
|
1697
|
-
persistence: attachPersistenceCwd(session.describePersistence(), config.cwd),
|
|
1724
|
+
persistence: attachPersistenceCwd(options?.persistence ?? session.describePersistence(), config.cwd),
|
|
1698
1725
|
historyPrimed: options?.historyPrimed ?? durableTimelineHasRows,
|
|
1699
1726
|
lastUserMessageAt: options?.lastUserMessageAt ?? null,
|
|
1700
1727
|
lastUsage: options?.lastUsage,
|
|
@@ -1846,7 +1873,7 @@ export class AgentManager {
|
|
|
1846
1873
|
}
|
|
1847
1874
|
return this.registry;
|
|
1848
1875
|
}
|
|
1849
|
-
async refreshSessionState(agent) {
|
|
1876
|
+
async refreshSessionState(agent, options) {
|
|
1850
1877
|
try {
|
|
1851
1878
|
const modes = await agent.session.getAvailableModes();
|
|
1852
1879
|
agent.availableModes = modes;
|
|
@@ -1868,9 +1895,9 @@ export class AgentManager {
|
|
|
1868
1895
|
agent.pendingPermissions.clear();
|
|
1869
1896
|
}
|
|
1870
1897
|
this.syncFeaturesFromSession(agent);
|
|
1871
|
-
await this.refreshRuntimeInfo(agent);
|
|
1898
|
+
await this.refreshRuntimeInfo(agent, options);
|
|
1872
1899
|
}
|
|
1873
|
-
async refreshRuntimeInfo(agent) {
|
|
1900
|
+
async refreshRuntimeInfo(agent, options) {
|
|
1874
1901
|
try {
|
|
1875
1902
|
const newInfo = await agent.session.getRuntimeInfo();
|
|
1876
1903
|
const changed = newInfo.model !== agent.runtimeInfo?.model ||
|
|
@@ -1882,7 +1909,7 @@ export class AgentManager {
|
|
|
1882
1909
|
agent.persistence = attachPersistenceCwd({ provider: agent.provider, sessionId: newInfo.sessionId }, agent.cwd);
|
|
1883
1910
|
}
|
|
1884
1911
|
// Emit state if runtimeInfo changed so clients get the updated model
|
|
1885
|
-
if (changed) {
|
|
1912
|
+
if (changed && options?.emit !== false) {
|
|
1886
1913
|
this.emitState(agent);
|
|
1887
1914
|
}
|
|
1888
1915
|
}
|
|
@@ -2503,6 +2530,15 @@ export class AgentManager {
|
|
|
2503
2530
|
}
|
|
2504
2531
|
return normalized;
|
|
2505
2532
|
}
|
|
2533
|
+
async prepareSessionConfig(config, agentId) {
|
|
2534
|
+
const storedConfig = await this.normalizeConfig(stripInternalPaseoMcpServer(config));
|
|
2535
|
+
const launchConfig = this.applyDaemonAppendSystemPrompt(withRuntimePaseoMcpServer({
|
|
2536
|
+
config: storedConfig,
|
|
2537
|
+
agentId,
|
|
2538
|
+
mcpBaseUrl: this.mcpBaseUrl,
|
|
2539
|
+
}));
|
|
2540
|
+
return { storedConfig, launchConfig };
|
|
2541
|
+
}
|
|
2506
2542
|
applyDaemonAppendSystemPrompt(config) {
|
|
2507
2543
|
const daemonAppendSystemPrompt = this.appendSystemPrompt.trim();
|
|
2508
2544
|
const next = { ...config };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentListItemPayload, AgentSnapshotPayload, RecentProviderSessionDescriptorPayload } from "../messages.js";
|
|
2
2
|
import type { StoredAgentRecord } from "./agent-storage.js";
|
|
3
|
-
import type { AgentProvider, AgentRuntimeInfo,
|
|
3
|
+
import type { AgentProvider, AgentRuntimeInfo, ImportableProviderSession } from "./agent-sdk-types.js";
|
|
4
4
|
import type { ManagedAgent } from "./agent-manager.js";
|
|
5
5
|
export type { ManagedAgent };
|
|
6
6
|
interface ProjectionOptions {
|
|
@@ -19,6 +19,8 @@ export declare function toStoredAgentRecord(agent: ManagedAgent, options?: Proje
|
|
|
19
19
|
export declare function toAgentPayload(agent: ManagedAgent, options?: ProjectionOptions): AgentSnapshotPayload;
|
|
20
20
|
export declare function buildStoredAgentPayload(record: StoredAgentRecord, validProviders: Iterable<AgentProvider>): AgentSnapshotPayload;
|
|
21
21
|
export declare function toAgentListItemPayload(agent: AgentSnapshotPayload): AgentListItemPayload;
|
|
22
|
-
export declare function toRecentProviderSessionDescriptorPayload(
|
|
22
|
+
export declare function toRecentProviderSessionDescriptorPayload(session: ImportableProviderSession & {
|
|
23
|
+
provider: string;
|
|
24
|
+
}, options: RecentProviderSessionProjectionOptions): RecentProviderSessionDescriptorPayload;
|
|
23
25
|
export declare function resolveStoredAgentPayloadUpdatedAt(record: StoredAgentRecord): string;
|
|
24
26
|
//# sourceMappingURL=agent-projections.d.ts.map
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isStoredAgentProviderAvailable, toAgentPersistenceHandle } from "../persistence-hooks.js";
|
|
2
|
-
const PROMPT_PREVIEW_MAX_LENGTH = 160;
|
|
3
2
|
function normalizeThinkingOptionId(value) {
|
|
4
3
|
if (typeof value !== "string")
|
|
5
4
|
return null;
|
|
@@ -193,17 +192,16 @@ export function toAgentListItemPayload(agent) {
|
|
|
193
192
|
...(agent.providerUnavailable ? { providerUnavailable: true } : {}),
|
|
194
193
|
};
|
|
195
194
|
}
|
|
196
|
-
export function toRecentProviderSessionDescriptorPayload(
|
|
197
|
-
const promptPreviews = collectPromptPreviews(descriptor.timeline);
|
|
195
|
+
export function toRecentProviderSessionDescriptorPayload(session, options) {
|
|
198
196
|
return {
|
|
199
|
-
providerId:
|
|
197
|
+
providerId: session.provider,
|
|
200
198
|
providerLabel: options.providerLabel,
|
|
201
|
-
providerHandleId:
|
|
202
|
-
cwd:
|
|
203
|
-
title:
|
|
204
|
-
firstPromptPreview:
|
|
205
|
-
lastPromptPreview:
|
|
206
|
-
lastActivityAt:
|
|
199
|
+
providerHandleId: session.providerHandleId,
|
|
200
|
+
cwd: session.cwd,
|
|
201
|
+
title: session.title,
|
|
202
|
+
firstPromptPreview: session.firstPromptPreview,
|
|
203
|
+
lastPromptPreview: session.lastPromptPreview,
|
|
204
|
+
lastActivityAt: session.lastActivityAt.toISOString(),
|
|
207
205
|
};
|
|
208
206
|
}
|
|
209
207
|
export function resolveStoredAgentPayloadUpdatedAt(record) {
|
|
@@ -220,24 +218,6 @@ export function resolveStoredAgentPayloadUpdatedAt(record) {
|
|
|
220
218
|
timestamps.sort((a, b) => b.parsed - a.parsed);
|
|
221
219
|
return timestamps[0].raw;
|
|
222
220
|
}
|
|
223
|
-
function collectPromptPreviews(timeline) {
|
|
224
|
-
return timeline.flatMap((item) => {
|
|
225
|
-
if (item.type !== "user_message") {
|
|
226
|
-
return [];
|
|
227
|
-
}
|
|
228
|
-
const preview = normalizePromptPreview(item.text);
|
|
229
|
-
return preview ? [preview] : [];
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
function normalizePromptPreview(text) {
|
|
233
|
-
const normalized = text.trim().replace(/\s+/g, " ");
|
|
234
|
-
if (!normalized) {
|
|
235
|
-
return null;
|
|
236
|
-
}
|
|
237
|
-
return normalized.length > PROMPT_PREVIEW_MAX_LENGTH
|
|
238
|
-
? normalized.slice(0, PROMPT_PREVIEW_MAX_LENGTH)
|
|
239
|
-
: normalized;
|
|
240
|
-
}
|
|
241
221
|
function buildSerializableConfig(config) {
|
|
242
222
|
const serializable = {};
|
|
243
223
|
if (config.modeId) {
|
|
@@ -135,6 +135,7 @@ export type AgentFeature = AgentFeatureToggle | AgentFeatureSelect;
|
|
|
135
135
|
export interface AgentCapabilityFlags {
|
|
136
136
|
supportsStreaming: boolean;
|
|
137
137
|
supportsSessionPersistence: boolean;
|
|
138
|
+
supportsSessionListing?: boolean;
|
|
138
139
|
supportsDynamicModes: boolean;
|
|
139
140
|
supportsMcpServers: boolean;
|
|
140
141
|
supportsReasoningStream: boolean;
|
|
@@ -430,6 +431,7 @@ export interface AgentRuntimeInfo {
|
|
|
430
431
|
modeId?: string | null;
|
|
431
432
|
extra?: AgentMetadata;
|
|
432
433
|
}
|
|
434
|
+
export type AgentSlashCommandKind = "command" | "skill";
|
|
433
435
|
/**
|
|
434
436
|
* Represents a slash command available in an agent session.
|
|
435
437
|
* Commands are executed by sending them as prompts with / prefix.
|
|
@@ -438,25 +440,42 @@ export interface AgentSlashCommand {
|
|
|
438
440
|
name: string;
|
|
439
441
|
description: string;
|
|
440
442
|
argumentHint: string;
|
|
443
|
+
kind?: AgentSlashCommandKind;
|
|
441
444
|
}
|
|
442
|
-
export interface
|
|
445
|
+
export interface ListImportableSessionsOptions {
|
|
443
446
|
limit?: number;
|
|
444
447
|
/**
|
|
445
|
-
* Optional cwd hint. Providers that can cheaply pre-filter
|
|
446
|
-
* sessions by working directory should do so before doing expensive
|
|
447
|
-
* work like fetching turn timelines. Providers that can't filter
|
|
448
|
-
* cheaply may ignore this hint.
|
|
448
|
+
* Optional cwd hint. Providers that can cheaply pre-filter importable
|
|
449
|
+
* sessions by working directory should do so before doing expensive work.
|
|
449
450
|
*/
|
|
450
451
|
cwd?: string;
|
|
451
452
|
}
|
|
452
|
-
export interface
|
|
453
|
-
|
|
454
|
-
sessionId: string;
|
|
453
|
+
export interface ImportableProviderSession {
|
|
454
|
+
providerHandleId: string;
|
|
455
455
|
cwd: string;
|
|
456
456
|
title: string | null;
|
|
457
|
+
firstPromptPreview: string | null;
|
|
458
|
+
lastPromptPreview: string | null;
|
|
457
459
|
lastActivityAt: Date;
|
|
460
|
+
}
|
|
461
|
+
export interface ImportProviderSessionInput {
|
|
462
|
+
providerHandleId: string;
|
|
463
|
+
cwd: string;
|
|
464
|
+
}
|
|
465
|
+
export interface ImportProviderSessionContext {
|
|
466
|
+
config: AgentSessionConfig;
|
|
467
|
+
storedConfig: AgentSessionConfig;
|
|
468
|
+
launchContext?: AgentLaunchContext;
|
|
469
|
+
}
|
|
470
|
+
export interface ImportedTimelineEntry {
|
|
471
|
+
item: AgentTimelineItem;
|
|
472
|
+
timestamp?: string;
|
|
473
|
+
}
|
|
474
|
+
export interface ImportedProviderSession {
|
|
475
|
+
session: AgentSession;
|
|
476
|
+
config: AgentSessionConfig;
|
|
458
477
|
persistence: AgentPersistenceHandle;
|
|
459
|
-
timeline:
|
|
478
|
+
timeline: ImportedTimelineEntry[];
|
|
460
479
|
}
|
|
461
480
|
export interface AgentSessionConfig {
|
|
462
481
|
provider: AgentProvider;
|
|
@@ -575,7 +594,8 @@ export interface AgentClient {
|
|
|
575
594
|
isCreateConfigUnattended?(input: AgentCreateConfigUnattendedInput): boolean;
|
|
576
595
|
listCommands?(config: AgentSessionConfig): Promise<AgentSlashCommand[]>;
|
|
577
596
|
listFeatures?(config: AgentSessionConfig): Promise<AgentFeature[]>;
|
|
578
|
-
|
|
597
|
+
listImportableSessions?(options?: ListImportableSessionsOptions): Promise<ImportableProviderSession[]>;
|
|
598
|
+
importSession?(input: ImportProviderSessionInput, context: ImportProviderSessionContext): Promise<ImportedProviderSession>;
|
|
579
599
|
/**
|
|
580
600
|
* Check if this provider is available (CLI binary is installed).
|
|
581
601
|
* Returns true if available, false otherwise.
|
|
@@ -3,13 +3,14 @@ import type { Logger } from "pino";
|
|
|
3
3
|
import type { ProviderSnapshotManager } from "./provider-snapshot-manager.js";
|
|
4
4
|
import type { AgentManager, ManagedAgent } from "./agent-manager.js";
|
|
5
5
|
import type { AgentStorage } from "./agent-storage.js";
|
|
6
|
+
import type { AgentProvider } from "./agent-sdk-types.js";
|
|
6
7
|
import { scheduleAgentMetadataGeneration } from "./agent-metadata-generator.js";
|
|
7
8
|
import type { StructuredGenerationDaemonConfig } from "./structured-generation-providers.js";
|
|
8
9
|
import type { FetchRecentProviderSessionsRequestMessage, ImportAgentRequestMessageSchema, RecentProviderSessionDescriptorPayload } from "@getpaseo/protocol/messages";
|
|
9
10
|
import type { WorkspaceGitService } from "../workspace-git-service.js";
|
|
10
11
|
type ImportAgentRequestMessage = z.infer<typeof ImportAgentRequestMessageSchema>;
|
|
11
12
|
export interface NormalizedImportAgentRequest {
|
|
12
|
-
provider:
|
|
13
|
+
provider: AgentProvider;
|
|
13
14
|
providerHandleId: string;
|
|
14
15
|
cwd?: string;
|
|
15
16
|
labels?: Record<string, string>;
|
|
@@ -21,7 +22,7 @@ export declare class ImportSessionsRequestError extends Error {
|
|
|
21
22
|
}
|
|
22
23
|
export interface ListImportableProviderSessionsInput {
|
|
23
24
|
request: FetchRecentProviderSessionsRequestMessage;
|
|
24
|
-
agentManager: Pick<AgentManager, "listAgents" | "
|
|
25
|
+
agentManager: Pick<AgentManager, "listAgents" | "listImportableSessions">;
|
|
25
26
|
agentStorage: Pick<AgentStorage, "list">;
|
|
26
27
|
providerSnapshotManager: Pick<ProviderSnapshotManager, "getProviderLabel">;
|
|
27
28
|
}
|