/** * OpenCode stream event handling. * * Converts OpenCode SDK SSE events into the unified StreamCallback format * used throughout the takt codebase. */ import type { StreamCallback } from '../../shared/types/provider.js'; import { type BoundedSensitiveValues, type SensitiveTextStreamRedactor } from '../../shared/utils/sensitiveText.js'; /** Subset of OpenCode Part types relevant for stream handling */ export interface OpenCodeTextPart { id: string; sessionID: string; type: 'text'; text: string; } export interface OpenCodeReasoningPart { id: string; sessionID: string; type: 'reasoning'; text: string; } export interface OpenCodeToolPart { id: string; sessionID: string; type: 'tool'; callID: string; tool: string; state: OpenCodeToolState; } export type OpenCodeToolState = { status: 'pending'; input: Record; } | { status: 'running'; input: Record; title?: string; } | { status: 'completed'; input: Record; output: string; title: string; metadata?: Record; } | { status: 'error'; input: Record; error: string; }; export type OpenCodePart = OpenCodeTextPart | OpenCodeReasoningPart | OpenCodeToolPart | { id: string; type: string; sessionID?: string; }; export type OpenCodeStreamTrackingLimitReason = 'event_count' | 'tracked_id_count' | 'text_bytes' | 'reasoning_bytes' | 'sensitive_sources'; /** OpenCode SSE event types relevant for stream handling */ export interface OpenCodeMessagePartUpdatedEvent { type: 'message.part.updated'; properties: { part: OpenCodePart; delta?: string; }; } export interface OpenCodeSessionIdleEvent { type: 'session.idle'; properties: { sessionID: string; }; } export interface OpenCodeSessionStatusEvent { type: 'session.status'; properties: { sessionID: string; status: { type: 'idle' | 'busy' | 'retry'; attempt?: number; message?: string; next?: number; }; }; } export interface OpenCodeSessionErrorEvent { type: 'session.error'; properties: { sessionID?: string; error?: { name: string; data: { message: string; }; }; }; } export interface OpenCodeMessageUpdatedEvent { type: 'message.updated'; properties: { info: { sessionID: string; role: 'assistant' | 'user'; time?: { created?: number; completed?: number; }; error?: unknown; }; }; } export interface OpenCodeMessageCompletedEvent { type: 'message.completed'; properties: { info: { sessionID: string; role: 'assistant' | 'user'; error?: unknown; }; }; } export interface OpenCodeMessageFailedEvent { type: 'message.failed'; properties: { info: { sessionID: string; role: 'assistant' | 'user'; error?: unknown; }; }; } export interface OpenCodePermissionAskedEvent { type: 'permission.asked'; properties: { id: string; sessionID: string; permission: string; patterns: string[]; metadata: Record; always: string[]; }; } export interface OpenCodeQuestionAskedEvent { type: 'question.asked'; properties: { id: string; sessionID: string; questions: Array<{ question: string; header: string; options: Array<{ label: string; description: string; }>; multiple?: boolean; }>; }; } export type OpenCodeStreamEvent = OpenCodeMessagePartUpdatedEvent | OpenCodeMessageUpdatedEvent | OpenCodeMessageCompletedEvent | OpenCodeMessageFailedEvent | OpenCodeSessionStatusEvent | OpenCodeSessionIdleEvent | OpenCodeSessionErrorEvent | OpenCodePermissionAskedEvent | OpenCodeQuestionAskedEvent | { type: string; properties: Record; }; /** Volume/memory limits applied to a single attempt's stream tracking. */ export interface OpenCodeStreamLimits { /** 可視テキスト累計バイト上限。 */ textByteLimit: number; /** reasoning 累計バイト上限。 */ reasoningByteLimit: number; /** 追跡する part/tool ID 数の上限(メモリ有界化)。 */ idLimit: number; } /** Tracking state for stream offsets during a single OpenCode session */ export interface StreamTrackingState { textOffsets: Map; thinkingOffsets: Map; textRedactors: Map; thinkingRedactors: Map; partTypes: Map; startedTools: Set; sensitiveSources: BoundedSensitiveValues; eventCount: number; textBytes: number; reasoningBytes: number; trackedIds: Set; limits: OpenCodeStreamLimits; trackingLimitReason?: OpenCodeStreamTrackingLimitReason; exhausted: boolean; } export declare const OPENCODE_STREAM_EVENT_LIMIT = 500000; export declare const OPENCODE_STREAM_ID_LIMIT = 8192; export declare const OPENCODE_STREAM_TEXT_BYTE_LIMIT: number; export declare const OPENCODE_STREAM_REASONING_BYTE_LIMIT: number; export declare const OPENCODE_STREAM_TRACKING_LIMIT_MESSAGE = "OpenCode stream tracking limit exceeded"; /** * 呼び出し時に評価する。優先順位は既存 provider_options 機構と同じで * env > config(env は実験・テスト用の一時上書き、運用調整は config/persona)。 * 容量上限は profile では切れない(有界資源層)。 */ export declare function resolveOpenCodeStreamLimits(guards?: { textByteLimit?: number; reasoningByteLimit?: number; }): OpenCodeStreamLimits; export declare function createStreamTrackingState(limits?: OpenCodeStreamLimits, sensitiveSources?: BoundedSensitiveValues): StreamTrackingState; export declare function trackOpenCodeTextBytes(state: StreamTrackingState, text: string): boolean; export declare function trackOpenCodeReasoningBytes(state: StreamTrackingState, text: string): boolean; export declare function describeOpenCodeStreamTrackingLimitFailure(reason: OpenCodeStreamTrackingLimitReason | undefined): string; export declare function trackOpenCodeStreamEvent(state: StreamTrackingState, event: OpenCodeStreamEvent): boolean; export declare function emitInit(onStream: StreamCallback | undefined, model: string, sessionId: string): void; export declare function emitText(onStream: StreamCallback | undefined, text: string): void; export declare function emitThinking(onStream: StreamCallback | undefined, thinking: string): void; export declare function flushSensitiveTextStreams(onStream: StreamCallback | undefined, state: StreamTrackingState): void; export declare function emitToolUse(onStream: StreamCallback | undefined, tool: string, input: Record, id: string): void; export declare function emitToolResult(onStream: StreamCallback | undefined, content: string, isError: boolean, sensitiveSources: unknown, id: string, tool?: string, input?: Record): void; export declare function emitPermissionAsked(onStream: StreamCallback | undefined, data: { requestId: string; sessionId: string; permission: string; patterns: string[]; always: string[]; reply: string; }): void; export declare function emitPermissionSummary(onStream: StreamCallback | undefined, data: { sessionId: string; permissionMode?: string; allowedTools?: readonly string[]; networkAccess?: boolean; resolvedPermissions: Array<{ permission: string; pattern: string; action: string; }>; }): void; export declare function emitResult(onStream: StreamCallback | undefined, success: boolean, result: string, sessionId: string, sensitiveSources: unknown): void; /** Process a message.part.updated event and emit appropriate stream events */ export declare function handlePartUpdated(part: OpenCodePart, delta: string | undefined, onStream: StreamCallback | undefined, state: StreamTrackingState): boolean; //# sourceMappingURL=OpenCodeStreamHandler.d.ts.map