agent-ecosystem/src/main/services/team/opencode/delivery/OpenCodeRuntimeDeliveryDiagnostics.ts
777genius 6e4f8ff8c4 fix: stabilize opencode mcp transport refresh
Keep OpenCode app MCP transport evidence durable, refresh stale sessions without consuming normal delivery attempts, and keep recoverable runtime diagnostics out of member card errors.

Cover stable MCP restart/fallback, forced session refresh, resolved_behavior_changed recovery, and renderer diagnostics with regression and safe e2e tests.
2026-05-18 13:08:34 +03:00

116 lines
4.4 KiB
TypeScript

import {
classifyRuntimeDiagnostic,
selectRuntimeDiagnosticClassification,
} from '../../runtime/RuntimeDiagnosticClassifier';
import type { OpenCodePromptDeliveryLedgerRecord } from './OpenCodePromptDeliveryLedger';
export function normalizeOpenCodeRuntimeDeliveryDiagnostic(
message: string | null | undefined
): string | null {
return classifyRuntimeDiagnostic(message).normalizedMessage;
}
export function isGenericOpenCodeRuntimeDeliveryDiagnostic(message: string): boolean {
return classifyRuntimeDiagnostic(message).generic;
}
export function selectOpenCodeRuntimeDeliveryReason(
record: OpenCodePromptDeliveryLedgerRecord
): string | null {
const candidates = [...record.diagnostics.slice().reverse(), record.lastReason].filter(
(diagnostic) => !isInformationalOpenCodeRuntimeDeliveryDiagnostic(diagnostic)
);
const selected = selectRuntimeDiagnosticClassification(candidates);
if (selected && !selected.generic && selected.normalizedMessage) {
return boundOpenCodeRuntimeDeliveryReason(selected.normalizedMessage);
}
const fallback = getOpenCodeRuntimeDeliveryStateFallback(record);
if (fallback) {
return fallback;
}
return selected ? 'OpenCode runtime delivery did not complete.' : null;
}
function isInformationalOpenCodeRuntimeDeliveryDiagnostic(
message: string | null | undefined
): boolean {
const normalized = message?.trim().toLowerCase();
return (
normalized === 'opencode app mcp is connected for message delivery.' ||
normalized ===
'opencode prompt_async accepted; response observation will continue through durable app-side ledger reconciliation.' ||
normalized === 'opencode session status busy' ||
normalized === 'opencode_delivery_response_pending' ||
normalized === 'opencode_session_refresh_scheduled_after_resolved_behavior_changed' ||
Boolean(
normalized?.startsWith('resolved_behavior_changed:') ||
normalized?.includes('opencode_app_mcp_transport_changed:')
)
);
}
export function isActionRequiredOpenCodeRuntimeDeliveryReason(
message: string | null | undefined
): boolean {
return classifyRuntimeDiagnostic(message).actionRequired;
}
function getOpenCodeRuntimeDeliveryStateFallback(
record: OpenCodePromptDeliveryLedgerRecord
): string | null {
const state = record.responseState?.trim();
const reason = record.lastReason?.trim();
const normalizedReason = reason?.toLowerCase();
const diagnostics = record.diagnostics.map((diagnostic) => diagnostic.trim().toLowerCase());
if (state === 'empty_assistant_turn' || normalizedReason === 'empty_assistant_turn') {
return 'OpenCode returned an empty assistant turn.';
}
if (
normalizedReason === 'visible_reply_missing_task_refs' ||
diagnostics.includes('visible_reply_missing_task_refs') ||
diagnostics.includes('visible_reply_missing_task_refs_after_merge')
) {
return 'OpenCode created a reply without the required taskRefs metadata.';
}
if (diagnostics.includes('visible_reply_task_refs_merge_failed')) {
return 'OpenCode created a reply without the required taskRefs metadata, and the app could not attach it automatically.';
}
if (
normalizedReason === 'visible_reply_still_required' ||
normalizedReason === 'visible_reply_ack_only_still_requires_answer' ||
normalizedReason === 'plain_text_ack_only_still_requires_answer'
) {
return 'OpenCode responded, but did not create a visible message_send reply.';
}
if (
state === 'prompt_delivered_no_assistant_message' ||
normalizedReason === 'prompt_delivered_no_assistant_message'
) {
return 'OpenCode accepted the prompt, but no assistant turn was recorded.';
}
if (
state === 'session_stale' ||
normalizedReason?.startsWith('resolved_behavior_changed:') ||
normalizedReason?.startsWith('opencode_app_mcp_transport_changed:')
) {
return 'OpenCode session changed; refreshing the session before retry.';
}
if (
normalizedReason === 'visible_reply_destination_not_found_yet' ||
normalizedReason === 'visible_reply_missing_relayofmessageid'
) {
return 'OpenCode created a reply without the required relayOfMessageId correlation.';
}
if (normalizedReason === 'non_visible_tool_without_task_progress') {
return 'OpenCode used tools, but did not create a visible reply or task progress proof.';
}
return null;
}
function boundOpenCodeRuntimeDeliveryReason(reason: string): string {
return reason.length > 500 ? `${reason.slice(0, 497).trimEnd()}...` : reason;
}