From 54e9f80a5797f90f39a70701276dcea73b58fddc Mon Sep 17 00:00:00 2001 From: nrslib <38722970+nrslib@users.noreply.github.com> Date: Fri, 13 Feb 2026 23:11:32 +0900 Subject: [PATCH] =?UTF-8?q?opencode=E3=81=8C=E3=83=91=E3=83=A9=E3=83=AC?= =?UTF-8?q?=E3=83=AB=E5=AE=9F=E8=A1=8C=E6=99=82=E3=81=AB=E3=82=BB=E3=83=83?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3ID=E3=82=92=E5=BC=95=E3=81=8D?= =?UTF-8?q?=E7=B6=99=E3=81=92=E3=81=AA=E3=81=84=E3=81=93=E3=81=A8=E3=81=8C?= =?UTF-8?q?=E3=81=82=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/agents/types.ts | 10 ----- src/infra/opencode/client.ts | 80 +++++++++++++++++++----------------- src/infra/opencode/types.ts | 6 +-- src/infra/providers/types.ts | 8 ---- 4 files changed, 44 insertions(+), 60 deletions(-) diff --git a/src/agents/types.ts b/src/agents/types.ts index a7cbd06..d2b6e32 100644 --- a/src/agents/types.ts +++ b/src/agents/types.ts @@ -14,26 +14,17 @@ export interface RunAgentOptions { sessionId?: string; model?: string; provider?: 'claude' | 'codex' | 'opencode' | 'mock'; - /** Resolved path to persona prompt file */ personaPath?: string; - /** Allowed tools for this agent run */ allowedTools?: string[]; - /** MCP servers for this agent run */ mcpServers?: Record; - /** Maximum number of agentic turns */ maxTurns?: number; - /** Permission mode for tool execution (from piece step) */ permissionMode?: PermissionMode; - /** Provider-specific movement options */ providerOptions?: MovementProviderOptions; onStream?: StreamCallback; onPermissionRequest?: PermissionHandler; onAskUserQuestion?: AskUserQuestionHandler; - /** Bypass all permission checks (sacrifice-my-pc mode) */ bypassPermissions?: boolean; - /** Language for template resolution */ language?: Language; - /** Piece meta information for system prompt template */ pieceMeta?: { pieceName: string; pieceDescription?: string; @@ -41,6 +32,5 @@ export interface RunAgentOptions { movementsList: ReadonlyArray<{ name: string; description?: string }>; currentPosition: string; }; - /** JSON Schema for structured output */ outputSchema?: Record; } diff --git a/src/infra/opencode/client.ts b/src/infra/opencode/client.ts index 1f33038..07f3970 100644 --- a/src/infra/opencode/client.ts +++ b/src/infra/opencode/client.ts @@ -273,6 +273,8 @@ export class OpenCodeClient { let diagRef: StreamDiagnostics | undefined; let serverClose: (() => void) | undefined; let opencodeApiClient: Awaited>['client'] | undefined; + let sessionId: string | undefined = options.sessionId; + const interactionTimeoutMs = options.interactionTimeoutMs ?? OPENCODE_INTERACTION_TIMEOUT_MS; const resetIdleTimeout = (): void => { if (idleTimeoutId !== undefined) { @@ -330,14 +332,14 @@ export class OpenCodeClient { opencodeApiClient = client; serverClose = server.close; - const sessionResult = options.sessionId - ? { data: { id: options.sessionId } } + const sessionResult = sessionId + ? { data: { id: sessionId } } : await client.session.create({ directory: options.cwd, permission: buildOpenCodePermissionRuleset(options.permissionMode, options.networkAccess), }); - const sessionId = sessionResult.data?.id; + sessionId = sessionResult.data?.id; if (!sessionId) { throw new Error('Failed to create OpenCode session'); } @@ -420,18 +422,24 @@ export class OpenCodeClient { sessionID: string; }; if (permProps.sessionID === sessionId) { - const reply = options.permissionMode - ? mapToOpenCodePermissionReply(options.permissionMode) - : 'once'; - await withTimeout( - (signal) => client.permission.reply({ - requestID: permProps.id, - directory: options.cwd, - reply, - }, { signal }), - OPENCODE_INTERACTION_TIMEOUT_MS, - 'OpenCode permission reply timed out', - ); + try { + const reply = options.permissionMode + ? mapToOpenCodePermissionReply(options.permissionMode) + : 'once'; + await withTimeout( + (signal) => client.permission.reply({ + requestID: permProps.id, + directory: options.cwd, + reply, + }, { signal }), + interactionTimeoutMs, + 'OpenCode permission reply timed out', + ); + } catch (e) { + success = false; + failureMessage = getErrorMessage(e); + break; + } } continue; } @@ -440,14 +448,20 @@ export class OpenCodeClient { const questionProps = sseEvent.properties as OpenCodeQuestionAskedProperties; if (questionProps.sessionID === sessionId) { if (!options.onAskUserQuestion) { - await withTimeout( - (signal) => client.question.reject({ - requestID: questionProps.id, - directory: options.cwd, - }, { signal }), - OPENCODE_INTERACTION_TIMEOUT_MS, - 'OpenCode question reject timed out', - ); + try { + await withTimeout( + (signal) => client.question.reject({ + requestID: questionProps.id, + directory: options.cwd, + }, { signal }), + interactionTimeoutMs, + 'OpenCode question reject timed out', + ); + } catch (e) { + success = false; + failureMessage = getErrorMessage(e); + break; + } continue; } @@ -459,20 +473,12 @@ export class OpenCodeClient { directory: options.cwd, answers: toQuestionAnswers(questionProps, answers), }, { signal }), - OPENCODE_INTERACTION_TIMEOUT_MS, + interactionTimeoutMs, 'OpenCode question reply timed out', ); - } catch { - await withTimeout( - (signal) => client.question.reject({ - requestID: questionProps.id, - directory: options.cwd, - }, { signal }), - OPENCODE_INTERACTION_TIMEOUT_MS, - 'OpenCode question reject timed out', - ); + } catch (e) { success = false; - failureMessage = 'OpenCode question handling failed'; + failureMessage = getErrorMessage(e); break; } } @@ -631,8 +637,8 @@ export class OpenCodeClient { continue; } - if (options.sessionId) { - emitResult(options.onStream, false, errorMessage, options.sessionId); + if (sessionId) { + emitResult(options.onStream, false, errorMessage, sessionId); } return { @@ -640,7 +646,7 @@ export class OpenCodeClient { status: 'error', content: errorMessage, timestamp: new Date(), - sessionId: options.sessionId, + sessionId, }; } finally { if (idleTimeoutId !== undefined) { diff --git a/src/infra/opencode/types.ts b/src/infra/opencode/types.ts index e407d6b..a0c2c42 100644 --- a/src/infra/opencode/types.ts +++ b/src/infra/opencode/types.ts @@ -187,15 +187,11 @@ export interface OpenCodeCallOptions { model: string; systemPrompt?: string; allowedTools?: string[]; - /** Permission mode for automatic permission handling */ permissionMode?: PermissionMode; - /** Override network access (webfetch/websearch) */ networkAccess?: boolean; - /** Enable streaming mode with callback (best-effort) */ onStream?: StreamCallback; onAskUserQuestion?: AskUserQuestionHandler; - /** OpenCode API key */ opencodeApiKey?: string; - /** JSON Schema for structured output */ outputSchema?: Record; + interactionTimeoutMs?: number; } diff --git a/src/infra/providers/types.ts b/src/infra/providers/types.ts index 9560cf2..b5c9263 100644 --- a/src/infra/providers/types.ts +++ b/src/infra/providers/types.ts @@ -24,25 +24,17 @@ export interface ProviderCallOptions { sessionId?: string; model?: string; allowedTools?: string[]; - /** MCP servers configuration */ mcpServers?: Record; - /** Maximum number of agentic turns */ maxTurns?: number; - /** Permission mode for tool execution (from piece step) */ permissionMode?: PermissionMode; - /** Provider-specific movement options */ providerOptions?: MovementProviderOptions; onStream?: StreamCallback; onPermissionRequest?: PermissionHandler; onAskUserQuestion?: AskUserQuestionHandler; bypassPermissions?: boolean; - /** Anthropic API key for Claude provider */ anthropicApiKey?: string; - /** OpenAI API key for Codex provider */ openaiApiKey?: string; - /** OpenCode API key for OpenCode provider */ opencodeApiKey?: string; - /** JSON Schema for structured output */ outputSchema?: Record; }