@getpaseo/server 0.10.0 → 0.10.2
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 +1 -0
- package/dist/server/server/agent/provider-registry.js +8 -0
- package/dist/server/server/agent/providers/claude/model-manifest.d.ts +9 -1
- package/dist/server/server/agent/providers/claude/model-manifest.js +10 -1
- package/dist/server/server/agent/providers/codex/rewind.d.ts +1 -0
- package/dist/server/server/agent/providers/codex/rewind.js +13 -14
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +3 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +14 -13
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +16 -6
- package/dist/server/server/agent/providers/opencode/v2/api.d.ts +1 -1
- package/dist/server/server/agent/providers/opencode/v2/permissions.js +3 -2
- package/dist/server/server/agent/providers/opencode/v2/session.d.ts +2 -1
- package/dist/server/server/agent/providers/opencode/v2/session.js +43 -20
- package/dist/server/server/agent/providers/opencode/v2/turns.d.ts +20 -5
- package/dist/server/server/agent/providers/opencode/v2/turns.js +168 -72
- package/dist/server/server/agent/providers/opencode/v2/usage.d.ts +21 -0
- package/dist/server/server/agent/providers/opencode/v2/usage.js +48 -0
- package/dist/server/server/agent/providers/opencode-agent.js +24 -0
- package/dist/server/server/agent/tools/paseo-tools.js +6 -4
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js → desktop-attachment-bridge-9b9ae7a48611e7619ae3dcfc5573a81d.js} +1 -1
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js.br → desktop-attachment-bridge-9b9ae7a48611e7619ae3dcfc5573a81d.js.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-9da07adb97f5e0eb726f7762afee43f5.js.gz → desktop-attachment-bridge-9b9ae7a48611e7619ae3dcfc5573a81d.js.gz} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-d5d3402a752965d3037191484127123b.js → desktop-attachment-store-850db74e505f3e0b8091b8a319bf6d95.js} +1 -1
- package/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-d5d3402a752965d3037191484127123b.js.br → desktop-attachment-store-850db74e505f3e0b8091b8a319bf6d95.js.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-850db74e505f3e0b8091b8a319bf6d95.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-136fa41d4adb7ec5c6392839cc354136.js → index-48b52108bb348a6334547c3c03400d50.js} +463 -462
- package/dist/server/web-ui/_expo/static/js/web/index-48b52108bb348a6334547c3c03400d50.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{index-136fa41d4adb7ec5c6392839cc354136.js.gz → index-48b52108bb348a6334547c3c03400d50.js.gz} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js → indexeddb-attachment-store-8233162f2e9e360c5680127250516411.js} +1 -1
- package/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js.br → indexeddb-attachment-store-8233162f2e9e360c5680127250516411.js.br} +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-8233162f2e9e360c5680127250516411.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js → native-file-attachment-store-eb2d324071f66d94742cf09a46103e22.js} +3 -3
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-eb2d324071f66d94742cf09a46103e22.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-eb2d324071f66d94742cf09a46103e22.js.gz +0 -0
- package/dist/server/web-ui/index.html +1 -1
- package/dist/server/web-ui/index.html.br +0 -0
- package/dist/server/web-ui/index.html.gz +0 -0
- package/package.json +6 -6
- package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-d5d3402a752965d3037191484127123b.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/index-136fa41d4adb7ec5c6392839cc354136.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-3afc19e43c8152bd3c6d71b3ea8776dc.js.gz +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js.br +0 -0
- package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-187a9d5c32188f357dbbf037a0f89073.js.gz +0 -0
|
@@ -1204,6 +1204,7 @@ export class AgentManager {
|
|
|
1204
1204
|
if (agent.runtimeInfo) {
|
|
1205
1205
|
agent.runtimeInfo = { ...agent.runtimeInfo, model: normalizedModelId };
|
|
1206
1206
|
}
|
|
1207
|
+
this.refreshSessionPersistence(agent);
|
|
1207
1208
|
this.touchUpdatedAt(agent);
|
|
1208
1209
|
this.emitState(agent);
|
|
1209
1210
|
}
|
|
@@ -262,6 +262,8 @@ function wrapClientProvider(provider, inner, profileModels, additionalModels, pr
|
|
|
262
262
|
const listImportableSessions = inner.listImportableSessions?.bind(inner);
|
|
263
263
|
const importSession = inner.importSession?.bind(inner);
|
|
264
264
|
const listFeatures = inner.listFeatures?.bind(inner);
|
|
265
|
+
const archiveNativeSession = inner.archiveNativeSession?.bind(inner);
|
|
266
|
+
const unarchiveNativeSession = inner.unarchiveNativeSession?.bind(inner);
|
|
265
267
|
return {
|
|
266
268
|
provider,
|
|
267
269
|
capabilities: inner.capabilities,
|
|
@@ -332,6 +334,12 @@ function wrapClientProvider(provider, inner, profileModels, additionalModels, pr
|
|
|
332
334
|
};
|
|
333
335
|
}
|
|
334
336
|
: undefined,
|
|
337
|
+
archiveNativeSession: archiveNativeSession
|
|
338
|
+
? async (handle) => await archiveNativeSession({ ...handle, provider: inner.provider })
|
|
339
|
+
: undefined,
|
|
340
|
+
unarchiveNativeSession: unarchiveNativeSession
|
|
341
|
+
? async (handle) => await unarchiveNativeSession({ ...handle, provider: inner.provider })
|
|
342
|
+
: undefined,
|
|
335
343
|
getCatalogCacheKey: inner.getCatalogCacheKey?.bind(inner),
|
|
336
344
|
isAvailable: (signal, options) => inner.isAvailable(signal, options),
|
|
337
345
|
getDiagnostic: inner.getDiagnostic?.bind(inner),
|
|
@@ -53,10 +53,18 @@ export declare const CLAUDE_MODEL_MANIFEST: readonly [{
|
|
|
53
53
|
readonly effortLevels: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
54
54
|
readonly supportsThinkingDisabled: true;
|
|
55
55
|
readonly supportsFastMode: true;
|
|
56
|
+
}, {
|
|
57
|
+
readonly id: "claude-sonnet-5-5";
|
|
58
|
+
readonly label: "Sonnet 5.5";
|
|
59
|
+
readonly description: "Sonnet 5.5 · Best for everyday tasks";
|
|
60
|
+
readonly minimumClaudeCodeVersion: "2.1.284";
|
|
61
|
+
readonly defaultThinkingOptionId: "medium";
|
|
62
|
+
readonly contextWindowMaxTokens: 1000000;
|
|
63
|
+
readonly effortLevels: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
56
64
|
}, {
|
|
57
65
|
readonly id: "claude-sonnet-5";
|
|
58
66
|
readonly label: "Sonnet 5";
|
|
59
|
-
readonly description: "Sonnet 5 ·
|
|
67
|
+
readonly description: "Sonnet 5 · Previous release";
|
|
60
68
|
readonly contextWindowMaxTokens: 200000;
|
|
61
69
|
readonly effortLevels: readonly ["low", "medium", "high", "xhigh", "max"];
|
|
62
70
|
readonly supportsThinkingDisabled: true;
|
|
@@ -71,10 +71,19 @@ export const CLAUDE_MODEL_MANIFEST = [
|
|
|
71
71
|
supportsThinkingDisabled: true,
|
|
72
72
|
supportsFastMode: true,
|
|
73
73
|
},
|
|
74
|
+
{
|
|
75
|
+
id: "claude-sonnet-5-5",
|
|
76
|
+
label: "Sonnet 5.5",
|
|
77
|
+
description: "Sonnet 5.5 · Best for everyday tasks",
|
|
78
|
+
minimumClaudeCodeVersion: "2.1.284",
|
|
79
|
+
defaultThinkingOptionId: "medium",
|
|
80
|
+
contextWindowMaxTokens: 1000000,
|
|
81
|
+
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
|
|
82
|
+
},
|
|
74
83
|
{
|
|
75
84
|
id: "claude-sonnet-5",
|
|
76
85
|
label: "Sonnet 5",
|
|
77
|
-
description: "Sonnet 5 ·
|
|
86
|
+
description: "Sonnet 5 · Previous release",
|
|
78
87
|
contextWindowMaxTokens: 200000,
|
|
79
88
|
effortLevels: CLAUDE_EFFORT_LEVELS.xhigh,
|
|
80
89
|
supportsThinkingDisabled: true,
|
|
@@ -18,6 +18,7 @@ export declare function revertCodexConversation(input: {
|
|
|
18
18
|
cwd?: string | null;
|
|
19
19
|
model?: string | null;
|
|
20
20
|
serviceTier?: string | null;
|
|
21
|
+
config?: Record<string, unknown> | null;
|
|
21
22
|
userMessageTurns: CodexUserMessageTurnIndex;
|
|
22
23
|
setThreadId: (threadId: string) => void | Promise<void>;
|
|
23
24
|
}): Promise<void>;
|
|
@@ -38,33 +38,32 @@ export async function revertCodexConversation(input) {
|
|
|
38
38
|
if (numTurns < 0) {
|
|
39
39
|
throw new Error(`Codex user message ${input.messageId} is outside the current thread`);
|
|
40
40
|
}
|
|
41
|
+
// Codex does not carry the parent thread's config into a fork; without it the
|
|
42
|
+
// forked thread falls back to the default model provider.
|
|
43
|
+
const forkParams = {
|
|
44
|
+
threadId: input.threadId,
|
|
45
|
+
cwd: input.cwd ?? null,
|
|
46
|
+
model: input.model ?? null,
|
|
47
|
+
serviceTier: input.serviceTier ?? null,
|
|
48
|
+
...(input.config ? { config: input.config } : {}),
|
|
49
|
+
excludeTurns: false,
|
|
50
|
+
persistExtendedHistory: true,
|
|
51
|
+
};
|
|
41
52
|
const historyMode = await readCodexThreadHistoryMode(input.client, input.threadId);
|
|
42
53
|
if (historyMode === "paginated") {
|
|
43
54
|
if (!targetTurn.turnId) {
|
|
44
55
|
throw new Error(`Codex could not find the turn containing user message ${input.messageId}`);
|
|
45
56
|
}
|
|
46
57
|
const forked = await forkCodexThread(input.client, {
|
|
47
|
-
|
|
58
|
+
...forkParams,
|
|
48
59
|
beforeTurnId: targetTurn.turnId,
|
|
49
|
-
cwd: input.cwd ?? null,
|
|
50
|
-
model: input.model ?? null,
|
|
51
|
-
serviceTier: input.serviceTier ?? null,
|
|
52
|
-
excludeTurns: false,
|
|
53
|
-
persistExtendedHistory: true,
|
|
54
60
|
});
|
|
55
61
|
await input.setThreadId(forked.thread.id);
|
|
56
62
|
return;
|
|
57
63
|
}
|
|
58
64
|
// Fork is non-destructive: the old thread file stays on disk and remains
|
|
59
65
|
// recoverable with `codex resume <old-uuid>` if the rewind target was wrong.
|
|
60
|
-
const forked = await forkCodexThread(input.client,
|
|
61
|
-
threadId: input.threadId,
|
|
62
|
-
cwd: input.cwd ?? null,
|
|
63
|
-
model: input.model ?? null,
|
|
64
|
-
serviceTier: input.serviceTier ?? null,
|
|
65
|
-
excludeTurns: false,
|
|
66
|
-
persistExtendedHistory: true,
|
|
67
|
-
});
|
|
66
|
+
const forked = await forkCodexThread(input.client, forkParams);
|
|
68
67
|
const forkedThreadId = forked.thread.id;
|
|
69
68
|
// Codex rollback is chat-only by design. File edits from rewound turns stay
|
|
70
69
|
// on disk; a future file primitive would be a separate capability.
|
|
@@ -21,6 +21,7 @@ interface CodexAppServerAgentDeps {
|
|
|
21
21
|
extends: string;
|
|
22
22
|
};
|
|
23
23
|
customCodexConfig?: CodexCustomProviderConfig | null;
|
|
24
|
+
codexHome?: string;
|
|
24
25
|
_createCodexClient?: (child: ChildProcessWithoutNullStreams, logger: Logger, getTraceContext: () => CodexAppServerTraceContext) => CodexAppServerClientLike;
|
|
25
26
|
resolveSlashCommandInvocation?: (prompt: AgentPromptInput) => Promise<{
|
|
26
27
|
commandName: string;
|
|
@@ -31,7 +32,7 @@ export declare function normalizeCodexOutputSchema(schema: unknown): Record<stri
|
|
|
31
32
|
export declare function codexMicrosoftStoreBinaryCandidates(packageRoot: string, entries: Dirent[]): string[];
|
|
32
33
|
export declare function findCodexMicrosoftStoreBinary(): Promise<string | null>;
|
|
33
34
|
export declare function findDefaultCodexBinary(): Promise<string | null>;
|
|
34
|
-
export declare function listCodexSkills(cwd: string, workspaceGitService?: Pick<WorkspaceGitService, "resolveRepoRoot">): Promise<AgentSlashCommand[]>;
|
|
35
|
+
export declare function listCodexSkills(cwd: string, codexHome: string, workspaceGitService?: Pick<WorkspaceGitService, "resolveRepoRoot">): Promise<AgentSlashCommand[]>;
|
|
35
36
|
export declare function toAgentUsage(tokenUsage: unknown): AgentUsage | undefined;
|
|
36
37
|
export declare function planStepsToMarkdown(steps: Array<{
|
|
37
38
|
step: string;
|
|
@@ -126,6 +127,7 @@ export declare class CodexAppServerAgentSession implements AgentSession {
|
|
|
126
127
|
private readonly logger;
|
|
127
128
|
private readonly config;
|
|
128
129
|
private readonly asyncQuestions;
|
|
130
|
+
private readonly codexHome;
|
|
129
131
|
private currentMode;
|
|
130
132
|
private hasWorkflowModeOverride;
|
|
131
133
|
private readonly providerOptions;
|
|
@@ -321,8 +321,8 @@ async function checkCodexLaunchAvailable(launch) {
|
|
|
321
321
|
resolvePath: findDefaultCodexBinary,
|
|
322
322
|
});
|
|
323
323
|
}
|
|
324
|
-
function resolveCodexHomeDir() {
|
|
325
|
-
return
|
|
324
|
+
function resolveCodexHomeDir(env) {
|
|
325
|
+
return env.CODEX_HOME ?? path.join(os.homedir(), ".codex");
|
|
326
326
|
}
|
|
327
327
|
function decodeEscapedChar(next) {
|
|
328
328
|
if (next === "n")
|
|
@@ -423,8 +423,7 @@ function parseFrontMatter(markdown) {
|
|
|
423
423
|
}
|
|
424
424
|
return { frontMatter, body };
|
|
425
425
|
}
|
|
426
|
-
async function listCodexCustomPrompts() {
|
|
427
|
-
const codexHome = resolveCodexHomeDir();
|
|
426
|
+
async function listCodexCustomPrompts(codexHome) {
|
|
428
427
|
const promptsDir = path.join(codexHome, "prompts");
|
|
429
428
|
let entries;
|
|
430
429
|
try {
|
|
@@ -457,7 +456,7 @@ async function listCodexCustomPrompts() {
|
|
|
457
456
|
const commands = parsedCommands.filter((cmd) => cmd !== null);
|
|
458
457
|
return commands.sort((a, b) => a.name.localeCompare(b.name));
|
|
459
458
|
}
|
|
460
|
-
export async function listCodexSkills(cwd, workspaceGitService) {
|
|
459
|
+
export async function listCodexSkills(cwd, codexHome, workspaceGitService) {
|
|
461
460
|
const candidates = [];
|
|
462
461
|
candidates.push(path.join(cwd, ".codex", "skills"));
|
|
463
462
|
const repoRoot = workspaceGitService
|
|
@@ -467,7 +466,7 @@ export async function listCodexSkills(cwd, workspaceGitService) {
|
|
|
467
466
|
candidates.push(path.join(path.dirname(cwd), ".codex", "skills"));
|
|
468
467
|
candidates.push(path.join(repoRoot, ".codex", "skills"));
|
|
469
468
|
}
|
|
470
|
-
candidates.push(path.join(
|
|
469
|
+
candidates.push(path.join(codexHome, "skills"));
|
|
471
470
|
const candidateReads = await Promise.all(candidates.map(async (dir) => {
|
|
472
471
|
let entries;
|
|
473
472
|
try {
|
|
@@ -2532,6 +2531,7 @@ export class CodexAppServerAgentSession {
|
|
|
2532
2531
|
this.providerOptions = CodexProviderOptionsSchema.parse(config.providerOptions ?? {});
|
|
2533
2532
|
this.config = config;
|
|
2534
2533
|
this.asyncQuestions = new CodexAsyncQuestions(resumeHandle?.metadata?.asyncQuestions);
|
|
2534
|
+
this.codexHome = deps.codexHome ?? resolveCodexHomeDir(process.env);
|
|
2535
2535
|
this.config.thinkingOptionId = normalizeCodexThinkingOptionId(this.config.thinkingOptionId);
|
|
2536
2536
|
if (this.config.featureValues?.fast_mode && codexModelSupportsFastMode(this.config.model)) {
|
|
2537
2537
|
this.serviceTier = "fast";
|
|
@@ -3023,8 +3023,7 @@ export class CodexAppServerAgentSession {
|
|
|
3023
3023
|
async buildCommandPromptInput(commandName, args) {
|
|
3024
3024
|
if (commandName.startsWith("prompts:")) {
|
|
3025
3025
|
const promptName = commandName.slice("prompts:".length);
|
|
3026
|
-
const
|
|
3027
|
-
const promptPath = path.join(codexHome, "prompts", `${promptName}.md`);
|
|
3026
|
+
const promptPath = path.join(this.codexHome, "prompts", `${promptName}.md`);
|
|
3028
3027
|
const raw = await fs.readFile(promptPath, "utf8");
|
|
3029
3028
|
const parsed = parseFrontMatter(raw);
|
|
3030
3029
|
return expandCodexCustomPrompt(parsed.body, args);
|
|
@@ -3688,6 +3687,7 @@ export class CodexAppServerAgentSession {
|
|
|
3688
3687
|
cwd: this.config.cwd ?? null,
|
|
3689
3688
|
model: this.config.model ?? null,
|
|
3690
3689
|
serviceTier: this.serviceTier,
|
|
3690
|
+
config: this.buildCodexInnerConfig(),
|
|
3691
3691
|
userMessageTurns: this.codexUserMessageTurns(),
|
|
3692
3692
|
setThreadId: async (threadId) => {
|
|
3693
3693
|
this.currentThreadId = threadId;
|
|
@@ -3783,7 +3783,7 @@ export class CodexAppServerAgentSession {
|
|
|
3783
3783
|
this.client = null;
|
|
3784
3784
|
}
|
|
3785
3785
|
async listCommands() {
|
|
3786
|
-
const prompts = await listCodexCustomPrompts();
|
|
3786
|
+
const prompts = await listCodexCustomPrompts(this.codexHome);
|
|
3787
3787
|
if (this.connectionState === "disconnected") {
|
|
3788
3788
|
await this.connect();
|
|
3789
3789
|
}
|
|
@@ -3797,7 +3797,7 @@ export class CodexAppServerAgentSession {
|
|
|
3797
3797
|
kind: "skill",
|
|
3798
3798
|
}));
|
|
3799
3799
|
const fallbackSkills = this.cachedSkills === null
|
|
3800
|
-
? await listCodexSkills(this.config.cwd, this.deps.workspaceGitService)
|
|
3800
|
+
? await listCodexSkills(this.config.cwd, this.codexHome, this.deps.workspaceGitService)
|
|
3801
3801
|
: [];
|
|
3802
3802
|
const builtin = [
|
|
3803
3803
|
{
|
|
@@ -5602,9 +5602,10 @@ export class CodexAppServerAgentClient {
|
|
|
5602
5602
|
this.goalsEnabledPromise = null;
|
|
5603
5603
|
this.autoReviewEnabledPromise = null;
|
|
5604
5604
|
}
|
|
5605
|
-
sessionDeps() {
|
|
5605
|
+
sessionDeps(launchEnv) {
|
|
5606
5606
|
return {
|
|
5607
5607
|
...this.deps,
|
|
5608
|
+
codexHome: resolveCodexHomeDir(buildCodexAppServerEnv(this.runtimeSettings, launchEnv)),
|
|
5608
5609
|
customCodexConfig: this.customProviderConfig(),
|
|
5609
5610
|
};
|
|
5610
5611
|
}
|
|
@@ -5690,7 +5691,7 @@ export class CodexAppServerAgentClient {
|
|
|
5690
5691
|
const sessionConfig = { ...config, provider: CODEX_PROVIDER };
|
|
5691
5692
|
const goalsEnabled = await this.resolveGoalsEnabled();
|
|
5692
5693
|
const autoReviewEnabled = await this.resolveAutoReviewEnabled();
|
|
5693
|
-
const session = new CodexAppServerAgentSession(sessionConfig, null, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(), options?.persistSession === false, goalsEnabled, autoReviewEnabled, launchContext?.agentId);
|
|
5694
|
+
const session = new CodexAppServerAgentSession(sessionConfig, null, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(launchContext?.env), options?.persistSession === false, goalsEnabled, autoReviewEnabled, launchContext?.agentId);
|
|
5694
5695
|
await session.connect();
|
|
5695
5696
|
return session;
|
|
5696
5697
|
}
|
|
@@ -5704,7 +5705,7 @@ export class CodexAppServerAgentClient {
|
|
|
5704
5705
|
};
|
|
5705
5706
|
const goalsEnabled = await this.resolveGoalsEnabled();
|
|
5706
5707
|
const autoReviewEnabled = await this.resolveAutoReviewEnabled();
|
|
5707
|
-
const session = new CodexAppServerAgentSession(merged, handle, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(), false, goalsEnabled, autoReviewEnabled, launchContext?.agentId, options?.purpose ?? "interactive");
|
|
5708
|
+
const session = new CodexAppServerAgentSession(merged, handle, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled, agentId: launchContext?.agentId }), this.sessionDeps(launchContext?.env), false, goalsEnabled, autoReviewEnabled, launchContext?.agentId, options?.purpose ?? "interactive");
|
|
5708
5709
|
await session.connect();
|
|
5709
5710
|
return session;
|
|
5710
5711
|
}
|
|
@@ -164,6 +164,14 @@ function deriveOpencodeTaskDetail(input, output, error, metadata) {
|
|
|
164
164
|
actions: [],
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
|
+
function toOpencodeEditInput(value) {
|
|
168
|
+
return {
|
|
169
|
+
filePath: value.filePath,
|
|
170
|
+
oldString: nonEmptyString(value.oldString),
|
|
171
|
+
newString: nonEmptyString(value.newString),
|
|
172
|
+
unifiedDiff: undefined,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
167
175
|
const OpencodeEditInputSchema = z.union([
|
|
168
176
|
z
|
|
169
177
|
.object({
|
|
@@ -172,12 +180,12 @@ const OpencodeEditInputSchema = z.union([
|
|
|
172
180
|
newString: z.string().optional(),
|
|
173
181
|
})
|
|
174
182
|
.passthrough()
|
|
175
|
-
.transform(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
183
|
+
.transform(toOpencodeEditInput),
|
|
184
|
+
// OpenCode v2's edit tool names the file `path`.
|
|
185
|
+
z
|
|
186
|
+
.object({ path: z.string(), oldString: z.string(), newString: z.string() })
|
|
187
|
+
.passthrough()
|
|
188
|
+
.transform((value) => toOpencodeEditInput({ ...value, filePath: value.path })),
|
|
181
189
|
ToolEditInputSchema,
|
|
182
190
|
]);
|
|
183
191
|
const OpencodeEditOutputSchema = z.union([z.string().transform(() => null), ToolEditOutputSchema]);
|
|
@@ -199,6 +207,8 @@ const OpencodeKnownToolDetailSchema = z.union([
|
|
|
199
207
|
toolDetailBranchByToolName("edit", OpencodeEditInputSchema, OpencodeEditOutputSchema, toEditToolDetail),
|
|
200
208
|
toolDetailBranchByToolName("apply_patch", OpencodeEditInputSchema, OpencodeEditOutputSchema, toEditToolDetail),
|
|
201
209
|
toolDetailBranchByToolName("apply_patch", OpencodeApplyPatchTextInputSchema, z.unknown(), (input) => toEditToolDetail(input, null)),
|
|
210
|
+
// OpenCode v2 reports apply_patch as `patch`.
|
|
211
|
+
toolDetailBranchByToolName("patch", OpencodeApplyPatchTextInputSchema, z.unknown(), (input) => toEditToolDetail(input, null)),
|
|
202
212
|
toolDetailBranchByToolName("apply_diff", OpencodeEditInputSchema, OpencodeEditOutputSchema, toEditToolDetail),
|
|
203
213
|
toolDetailBranchByToolName("search", ToolSearchInputSchema, z.unknown(), (input) => toSearchToolDetail({ input, toolName: "search" })),
|
|
204
214
|
toolDetailBranchByToolName("grep", ToolSearchInputSchema, OpencodeGrepOutputSchema, (input, output) => toSearchToolDetail({ input, output, toolName: "grep" })),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OpenCodeClient } from "@opencode/client";
|
|
2
2
|
export interface V2Api {
|
|
3
3
|
server: OpenCodeClient["server"];
|
|
4
|
-
session: Pick<OpenCodeClient["session"], "create" | "get" | "list" | "active" | "remove" | "switchAgent" | "switchModel" | "environment" | "instructions" | "prompt" | "command" | "compact" | "
|
|
4
|
+
session: Pick<OpenCodeClient["session"], "create" | "get" | "list" | "active" | "remove" | "switchAgent" | "switchModel" | "environment" | "instructions" | "prompt" | "command" | "compact" | "interrupt" | "revert" | "log"> & {
|
|
5
5
|
form: Pick<OpenCodeClient["session"]["form"], "list" | "reply" | "cancel">;
|
|
6
6
|
};
|
|
7
7
|
plugin: Pick<OpenCodeClient["plugin"], "list">;
|
|
@@ -94,10 +94,11 @@ export class SessionPermissions {
|
|
|
94
94
|
title: form.title,
|
|
95
95
|
input: {
|
|
96
96
|
questions: form.fields.map((field) => ({
|
|
97
|
-
header: field.key,
|
|
98
|
-
question: field.title ?? field.key,
|
|
97
|
+
header: field.title ?? field.key,
|
|
98
|
+
question: field.description ?? field.title ?? field.key,
|
|
99
99
|
options: "options" in field ? field.options : undefined,
|
|
100
100
|
multiple: field.type === "multiselect",
|
|
101
|
+
allowOther: "custom" in field && field.custom === true,
|
|
101
102
|
})),
|
|
102
103
|
},
|
|
103
104
|
};
|
|
@@ -20,6 +20,7 @@ export declare class OpenCodeV2Session implements AgentSession {
|
|
|
20
20
|
private readonly permissions;
|
|
21
21
|
private readonly turns;
|
|
22
22
|
private readonly children;
|
|
23
|
+
private readonly usage;
|
|
23
24
|
private stream;
|
|
24
25
|
private streamAbort;
|
|
25
26
|
private exited;
|
|
@@ -63,7 +64,7 @@ export declare class OpenCodeV2Session implements AgentSession {
|
|
|
63
64
|
describePersistence(): AgentPersistenceHandle;
|
|
64
65
|
run(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<import("../../../agent-sdk-types.js").AgentRunResult>;
|
|
65
66
|
startTurn(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<{
|
|
66
|
-
turnId:
|
|
67
|
+
turnId: string;
|
|
67
68
|
}>;
|
|
68
69
|
steerActiveTurn(prompt: AgentPromptInput, options: SteerActiveTurnOptions): Promise<SteerResult>;
|
|
69
70
|
interrupt(): Promise<void>;
|
|
@@ -13,6 +13,7 @@ import { features } from "./configuration.js";
|
|
|
13
13
|
import { commands } from "./commands.js";
|
|
14
14
|
import { messages } from "./history.js";
|
|
15
15
|
import { SessionPermissions } from "./permissions.js";
|
|
16
|
+
import { SessionUsage } from "./usage.js";
|
|
16
17
|
export class OpenCodeV2Session {
|
|
17
18
|
constructor(connection, info, config, logger, persist, requiresPaseoPlugin, unbind, bindChild, acquire, moved) {
|
|
18
19
|
this.connection = connection;
|
|
@@ -57,11 +58,19 @@ export class OpenCodeV2Session {
|
|
|
57
58
|
await this.reconcile();
|
|
58
59
|
return { info: this.info, history: this.history };
|
|
59
60
|
},
|
|
61
|
+
reportReconciliationError: (error) => this.logger.warn({ error: toDiagnosticErrorMessage(error) }, "OpenCode turn reconciliation failed; retrying"),
|
|
60
62
|
clearPermissions: async () => {
|
|
61
63
|
for (const request of this.permissions.list())
|
|
62
64
|
await this.permissions.respondToPermission(request.id, { behavior: "deny" });
|
|
63
65
|
},
|
|
64
66
|
});
|
|
67
|
+
this.usage = new SessionUsage({
|
|
68
|
+
client: () => this.client,
|
|
69
|
+
cwd: config.cwd,
|
|
70
|
+
info: () => this.info,
|
|
71
|
+
emit: (event) => this.emit(event),
|
|
72
|
+
reportError: (error) => this.logger.warn({ error: toDiagnosticErrorMessage(error) }, "OpenCode context usage update failed"),
|
|
73
|
+
});
|
|
65
74
|
}
|
|
66
75
|
get id() {
|
|
67
76
|
return this.info.id;
|
|
@@ -239,24 +248,42 @@ export class OpenCodeV2Session {
|
|
|
239
248
|
}
|
|
240
249
|
async setModel(model) {
|
|
241
250
|
await this.reconnectIfExited();
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
: (await this.client.model.default({ location: { directory: this.config.cwd } })).data;
|
|
251
|
+
const location = { directory: this.config.cwd };
|
|
252
|
+
const selected = model ? modelRef(model) : (await this.client.model.default({ location })).data;
|
|
245
253
|
if (!selected)
|
|
246
254
|
throw new Error("OpenCode has no default model");
|
|
247
|
-
await this.client.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
+
const catalog = await this.client.model.list({ location });
|
|
256
|
+
const target = catalog.data.find((entry) => entry.enabled && entry.providerID === selected.providerID && entry.id === selected.id);
|
|
257
|
+
if (!target)
|
|
258
|
+
throw new Error(`OpenCode model unavailable: ${selected.providerID}/${selected.id}`);
|
|
259
|
+
const retainedVariant = this.config.thinkingOptionId;
|
|
260
|
+
const variant = retainedVariant !== "default" && target.variants.some((entry) => entry.id === retainedVariant)
|
|
261
|
+
? retainedVariant
|
|
262
|
+
: undefined;
|
|
263
|
+
const nextModel = {
|
|
264
|
+
id: selected.id,
|
|
265
|
+
providerID: selected.providerID,
|
|
266
|
+
...(variant ? { variant } : {}),
|
|
267
|
+
};
|
|
268
|
+
await this.client.session.switchModel({ sessionID: this.id, model: nextModel });
|
|
269
|
+
this.info.model = nextModel;
|
|
255
270
|
this.config.model = model ?? undefined;
|
|
271
|
+
this.config.thinkingOptionId = variant;
|
|
272
|
+
this.emit({
|
|
273
|
+
type: "thinking_option_changed",
|
|
274
|
+
provider: "opencode",
|
|
275
|
+
thinkingOptionId: variant ?? null,
|
|
276
|
+
});
|
|
256
277
|
this.emit({
|
|
257
278
|
type: "model_changed",
|
|
258
279
|
provider: "opencode",
|
|
259
|
-
runtimeInfo:
|
|
280
|
+
runtimeInfo: {
|
|
281
|
+
provider: "opencode",
|
|
282
|
+
sessionId: this.id,
|
|
283
|
+
model: `${selected.providerID}/${selected.id}`,
|
|
284
|
+
modeId: this.info.agent ?? null,
|
|
285
|
+
thinkingOptionId: variant ?? null,
|
|
286
|
+
},
|
|
260
287
|
});
|
|
261
288
|
}
|
|
262
289
|
async setThinkingOption(variant) {
|
|
@@ -359,9 +386,7 @@ export class OpenCodeV2Session {
|
|
|
359
386
|
await this.client.session.environment({ sessionID: this.id, variables: this.launchEnv });
|
|
360
387
|
await this.reconcile();
|
|
361
388
|
await this.children.reconcile(this.id);
|
|
362
|
-
|
|
363
|
-
if (active[this.id])
|
|
364
|
-
this.turns.observeActiveTurn();
|
|
389
|
+
await this.turns.reconcile();
|
|
365
390
|
}
|
|
366
391
|
scheduleReconcile() {
|
|
367
392
|
if (this.refreshTimer || this.closed)
|
|
@@ -404,12 +429,9 @@ export class OpenCodeV2Session {
|
|
|
404
429
|
return;
|
|
405
430
|
}
|
|
406
431
|
this.permissions.observe(event);
|
|
407
|
-
|
|
408
|
-
|
|
432
|
+
this.usage.observe(event);
|
|
433
|
+
this.turns.observe(event);
|
|
409
434
|
this.scheduleReconcile();
|
|
410
|
-
if (event.type !== "session.execution.started" || this.turns.id)
|
|
411
|
-
return;
|
|
412
|
-
this.turns.observeActiveTurn();
|
|
413
435
|
}
|
|
414
436
|
async consume(ready, fail) {
|
|
415
437
|
const signal = AbortSignal.any([this.abort.signal, this.streamAbort.signal]);
|
|
@@ -448,6 +470,7 @@ export class OpenCodeV2Session {
|
|
|
448
470
|
return;
|
|
449
471
|
this.closed = true;
|
|
450
472
|
this.abort.abort();
|
|
473
|
+
this.turns.close();
|
|
451
474
|
this.streamAbort.abort();
|
|
452
475
|
if (this.refreshTimer)
|
|
453
476
|
clearTimeout(this.refreshTimer);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionInfo, SessionMessageInfo } from "@opencode/client";
|
|
1
|
+
import type { OpenCodeEvent, SessionInfo, SessionMessageInfo } from "@opencode/client";
|
|
2
2
|
import type { AgentPromptInput, AgentRunOptions, AgentStreamEvent, SteerActiveTurnOptions, SteerResult } from "../../../agent-sdk-types.js";
|
|
3
3
|
import type { V2Api } from "./api.js";
|
|
4
4
|
interface TurnSnapshot {
|
|
@@ -13,28 +13,43 @@ interface TurnOptions {
|
|
|
13
13
|
emit(event: AgentStreamEvent): void;
|
|
14
14
|
reconcile(): Promise<TurnSnapshot>;
|
|
15
15
|
clearPermissions(): Promise<void>;
|
|
16
|
+
reportReconciliationError(error: unknown): void;
|
|
16
17
|
}
|
|
17
18
|
export declare class SessionTurns {
|
|
18
19
|
private readonly options;
|
|
19
20
|
private turn;
|
|
20
21
|
private stopping;
|
|
21
22
|
private stopFailed;
|
|
22
|
-
|
|
23
|
+
private revision;
|
|
24
|
+
private execution;
|
|
25
|
+
private sequence;
|
|
26
|
+
private refresh;
|
|
27
|
+
private dirty;
|
|
28
|
+
private retryTimer;
|
|
23
29
|
constructor(options: TurnOptions);
|
|
24
30
|
get id(): string | undefined;
|
|
25
31
|
get hasStructuredOutput(): boolean;
|
|
26
32
|
fail(error: Error): void;
|
|
33
|
+
private release;
|
|
34
|
+
close(): void;
|
|
35
|
+
private createTurn;
|
|
27
36
|
startTurn(prompt: AgentPromptInput, options?: AgentRunOptions): Promise<{
|
|
28
|
-
turnId:
|
|
37
|
+
turnId: string;
|
|
29
38
|
}>;
|
|
30
39
|
private submit;
|
|
40
|
+
observe(event: OpenCodeEvent): void;
|
|
41
|
+
private requestReconciliation;
|
|
42
|
+
private scheduleRecovery;
|
|
43
|
+
reconcile(): Promise<void>;
|
|
44
|
+
private drainReconciliation;
|
|
45
|
+
private reconcileTurn;
|
|
31
46
|
private dispatch;
|
|
32
47
|
private finish;
|
|
33
|
-
private
|
|
48
|
+
private readExecution;
|
|
34
49
|
private promptInput;
|
|
35
50
|
steerActiveTurn(prompt: AgentPromptInput, options: SteerActiveTurnOptions): Promise<SteerResult>;
|
|
36
51
|
interrupt(): Promise<void>;
|
|
37
|
-
observeActiveTurn
|
|
52
|
+
private observeActiveTurn;
|
|
38
53
|
}
|
|
39
54
|
export {};
|
|
40
55
|
//# sourceMappingURL=turns.d.ts.map
|