fix(team): harden opencode delivery prompt evidence

This commit is contained in:
777genius 2026-05-14 04:25:48 +03:00
parent f055193b16
commit 55e1c8f3c4
16 changed files with 820 additions and 33 deletions

View file

@ -142,6 +142,7 @@ export class TeamInboxReader {
row.messageKind === 'slash_command' ||
row.messageKind === 'slash_command_result' ||
row.messageKind === 'task_comment_notification' ||
row.messageKind === 'task_stall_remediation' ||
row.messageKind === 'member_work_sync_nudge' ||
row.messageKind === 'agent_error'
? row.messageKind

View file

@ -8363,7 +8363,10 @@ export class TeamProvisioningService {
taskRefs: input.taskRefs,
prePromptCursor: ledgerRecord.prePromptCursor,
sessionId: ledgerRecord.runtimeSessionId ?? undefined,
runtimePromptMessageId: ledgerRecord.runtimePromptMessageId ?? undefined,
runtimePromptMessageId:
ledgerRecord.lastRuntimePromptMessageId ??
ledgerRecord.runtimePromptMessageId ??
undefined,
});
} catch (error) {
const reason = `opencode_direct_user_delivery_inline_observe_failed: ${getErrorMessage(
@ -8416,6 +8419,8 @@ export class TeamProvisioningService {
latestAssistantPreview: null,
reason: observed.diagnostics[0] ?? null,
},
sessionId: observed.sessionId,
runtimePromptMessageId: observed.runtimePromptMessageId,
diagnostics: [
`opencode_direct_user_delivery_inline_observe_attempt_${inlineObserveAttempt}`,
...(hadMessageSendToolError ? ['opencode_message_send_tool_error_inline_observe'] : []),
@ -9815,7 +9820,10 @@ export class TeamProvisioningService {
taskRefs: input.taskRefs,
prePromptCursor: ledgerRecord.prePromptCursor,
sessionId: ledgerRecord.runtimeSessionId ?? undefined,
runtimePromptMessageId: ledgerRecord.runtimePromptMessageId ?? undefined,
runtimePromptMessageId:
ledgerRecord.lastRuntimePromptMessageId ??
ledgerRecord.runtimePromptMessageId ??
undefined,
});
await this.rememberOpenCodeRuntimePidFromBridge({
teamName,
@ -9842,6 +9850,8 @@ export class TeamProvisioningService {
latestAssistantPreview: null,
reason: observed.diagnostics[0] ?? null,
},
sessionId: observed.sessionId,
runtimePromptMessageId: observed.runtimePromptMessageId,
diagnostics: observed.diagnostics,
observedAt: nowIso(),
});
@ -9982,8 +9992,17 @@ export class TeamProvisioningService {
const responseObservation = this.normalizeOpenCodeDeliveryResponseObservation(
result.responseObservation
);
const promptAccepted =
result.ok || this.isOpenCodePromptAcceptedByObservation(responseObservation);
const promptAcceptedByRuntimeIdentity = Boolean(
result.ok && result.runtimePromptMessageId?.trim()
);
const promptAcceptedByObservation =
this.isOpenCodePromptAcceptedByObservation(responseObservation);
const promptAccepted = promptAcceptedByRuntimeIdentity || promptAcceptedByObservation;
const promptAcceptanceMissingRuntimePromptId =
result.ok && !promptAcceptedByRuntimeIdentity && !promptAcceptedByObservation;
const deliveryDiagnostics = promptAcceptanceMissingRuntimePromptId
? [...result.diagnostics, 'opencode_prompt_acceptance_missing_runtime_prompt_id']
: result.diagnostics;
if (ledgerRecord && ledger) {
ledgerRecord = await ledger.applyDeliveryResult({
id: ledgerRecord.id,
@ -9992,9 +10011,10 @@ export class TeamProvisioningService {
responseObservation,
sessionId: result.sessionId,
runtimePromptMessageId: result.runtimePromptMessageId,
deliveryAttemptId,
prePromptCursor: result.prePromptCursor,
diagnostics: result.diagnostics,
reason: promptAccepted ? responseObservation?.reason : result.diagnostics[0],
diagnostics: deliveryDiagnostics,
reason: promptAccepted ? responseObservation?.reason : deliveryDiagnostics[0],
now: nowIso(),
});
this.emitOpenCodePromptDeliveryTaskLogChange(
@ -10049,7 +10069,7 @@ export class TeamProvisioningService {
ledgerRecord,
{
accepted: promptAccepted,
reason: ledgerRecord.lastReason ?? result.diagnostics[0] ?? null,
reason: ledgerRecord.lastReason ?? deliveryDiagnostics[0] ?? null,
}
);
}
@ -10112,16 +10132,21 @@ export class TeamProvisioningService {
}
}
if (ledgerRecord && !promptAccepted) {
const reason = this.isOpenCodePromptAcceptanceUnknownFailure(result.diagnostics)
? 'opencode_prompt_acceptance_unknown_after_bridge_timeout'
: (result.diagnostics[0] ?? 'opencode_message_delivery_failed');
if (reason === 'opencode_prompt_acceptance_unknown_after_bridge_timeout') {
const reason = promptAcceptanceMissingRuntimePromptId
? 'opencode_prompt_acceptance_unknown_missing_runtime_prompt_id'
: this.isOpenCodePromptAcceptanceUnknownFailure(deliveryDiagnostics)
? 'opencode_prompt_acceptance_unknown_after_bridge_timeout'
: (deliveryDiagnostics[0] ?? 'opencode_message_delivery_failed');
if (
reason === 'opencode_prompt_acceptance_unknown_after_bridge_timeout' ||
reason === 'opencode_prompt_acceptance_unknown_missing_runtime_prompt_id'
) {
const delayMs = OPENCODE_PROMPT_DELIVERY_OBSERVE_DELAY_MS;
ledgerRecord = await ledger!.markAcceptanceUnknown({
id: ledgerRecord.id,
reason,
nextAttemptAt: new Date(Date.now() + delayMs).toISOString(),
diagnostics: result.diagnostics,
diagnostics: deliveryDiagnostics,
markedAt: nowIso(),
});
this.scheduleOpenCodePromptDeliveryWatchdog({

View file

@ -438,6 +438,7 @@ export interface OpenCodeBridgePeerIdentity {
supportedCommands: OpenCodeBridgeCommandName[];
opencodeTaskLedgerEvidenceContractVersion?: number;
opencodeAppManagedBootstrapContractVersion?: number;
opencodeDeliveryAcceptanceContractVersion?: number;
};
runtime: {
providerId: 'opencode';
@ -618,6 +619,7 @@ export function validateOpenCodeBridgeHandshake(input: {
expectedCapabilitySnapshotId: string | null;
expectedManifestHighWatermark: number | null;
expectedRunId: string | null;
requiresDeliveryAcceptanceContract?: boolean;
}): { ok: true } | { ok: false; reason: string } {
const shape = validateOpenCodeBridgeHandshakeShape(input.handshake);
if (!shape.ok) {
@ -676,6 +678,19 @@ export function validateOpenCodeBridgeHandshake(input: {
}
}
if (
input.requiredCommand === 'opencode.sendMessage' &&
input.requiresDeliveryAcceptanceContract === true &&
input.handshake.server.bridgeProtocol.opencodeDeliveryAcceptanceContractVersion !==
OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION
) {
return {
ok: false,
reason:
'OpenCode delivery acceptance mode is required, but the orchestrator does not advertise contract version 1. Falling back to observed delivery mode is required.',
};
}
if (
input.expectedCapabilitySnapshotId &&
input.handshake.server.runtime.capabilitySnapshotId !== input.expectedCapabilitySnapshotId
@ -948,7 +963,10 @@ function isPeerIdentity(value: unknown): value is OpenCodeBridgePeerIdentity {
(bridgeProtocol.opencodeTaskLedgerEvidenceContractVersion as number) < 1)) ||
(bridgeProtocol.opencodeAppManagedBootstrapContractVersion !== undefined &&
(!Number.isInteger(bridgeProtocol.opencodeAppManagedBootstrapContractVersion) ||
(bridgeProtocol.opencodeAppManagedBootstrapContractVersion as number) < 1))
(bridgeProtocol.opencodeAppManagedBootstrapContractVersion as number) < 1)) ||
(bridgeProtocol.opencodeDeliveryAcceptanceContractVersion !== undefined &&
(!Number.isInteger(bridgeProtocol.opencodeDeliveryAcceptanceContractVersion) ||
(bridgeProtocol.opencodeDeliveryAcceptanceContractVersion as number) < 1))
) {
return false;
}

View file

@ -1,5 +1,6 @@
import {
OPEN_CODE_APP_MANAGED_BOOTSTRAP_CONTRACT_VERSION,
OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION,
OPEN_CODE_TASK_LEDGER_EVIDENCE_CONTRACT_VERSION,
} from './OpenCodeBridgeCommandContract';
@ -103,6 +104,7 @@ export function createOpenCodeBridgeClientIdentity(input: {
],
opencodeTaskLedgerEvidenceContractVersion: OPEN_CODE_TASK_LEDGER_EVIDENCE_CONTRACT_VERSION,
opencodeAppManagedBootstrapContractVersion: OPEN_CODE_APP_MANAGED_BOOTSTRAP_CONTRACT_VERSION,
opencodeDeliveryAcceptanceContractVersion: OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION,
},
runtime: {
providerId: 'opencode',

View file

@ -232,29 +232,56 @@ export class OpenCodeReadinessBridge implements OpenCodeTeamRuntimeBridgePort {
...input,
payloadHash: input.payloadHash ?? buildSendPayloadHash(input),
};
const result = await this.bridge.execute<
OpenCodeSendMessageCommandBody,
OpenCodeSendMessageCommandData
>('opencode.sendMessage', body, {
cwd: body.projectPath,
timeoutMs: this.options.sendTimeoutMs ?? DEFAULT_SEND_TIMEOUT_MS,
requestId: commandRequestId,
});
let activeRequestId = commandRequestId;
let activeBody = body;
let usedObservedFallback = false;
const executeSend = (nextBody: OpenCodeSendMessageCommandBody, requestId: string) =>
this.bridge.execute<OpenCodeSendMessageCommandBody, OpenCodeSendMessageCommandData>(
'opencode.sendMessage',
nextBody,
{
cwd: nextBody.projectPath,
timeoutMs: this.options.sendTimeoutMs ?? DEFAULT_SEND_TIMEOUT_MS,
requestId,
}
);
let result: OpenCodeBridgeResult<OpenCodeSendMessageCommandData>;
try {
result = await executeSend(activeBody, activeRequestId);
} catch (error) {
if (
body.settlementMode !== 'acceptance' ||
!isOpenCodeAcceptanceContractMissingError(error)
) {
throw error;
}
activeRequestId = `${commandRequestId}-observed`;
activeBody = {
...body,
settlementMode: 'observed',
};
usedObservedFallback = true;
result = await executeSend(activeBody, activeRequestId);
}
if (result.ok) {
return result.data;
return usedObservedFallback
? withOpenCodeObservedFallbackDiagnostic(result.data)
: result.data;
}
if (result.error.kind === 'timeout') {
const recovered = await this.recoverTimedOutSendMessage({
originalRequestId: commandRequestId,
body,
originalRequestId: activeRequestId,
body: activeBody,
});
if (recovered) {
return recovered;
return usedObservedFallback ? withOpenCodeObservedFallbackDiagnostic(recovered) : recovered;
}
}
return {
accepted: false,
memberName: body.memberName,
memberName: activeBody.memberName,
diagnostics: [
{
code: result.error.kind,
@ -543,6 +570,28 @@ function formatDiagnosticEvent(event: OpenCodeBridgeDiagnosticEvent): string {
return `${event.type}: ${event.message}`;
}
function isOpenCodeAcceptanceContractMissingError(error: unknown): boolean {
const message = error instanceof Error ? error.message : String(error);
return message.includes('OpenCode delivery acceptance mode is required');
}
function withOpenCodeObservedFallbackDiagnostic(
data: OpenCodeSendMessageCommandData
): OpenCodeSendMessageCommandData {
return {
...data,
diagnostics: [
{
code: 'opencode_accept_fast_capability_missing',
severity: 'warning',
message:
'OpenCode delivery acceptance capability was not advertised by the orchestrator; used observed delivery mode.',
},
...data.diagnostics,
],
};
}
function thrownBridgeFailure<TData>(
command: OpenCodeBridgeCommandName,
runId: string,

View file

@ -118,6 +118,10 @@ export class OpenCodeStateChangingBridgeCommandService {
expectedCapabilitySnapshotId: input.capabilitySnapshotId,
expectedManifestHighWatermark: manifest.highWatermark,
expectedRunId: input.runId,
requiresDeliveryAcceptanceContract: requiresOpenCodeDeliveryAcceptanceContract(
input.command,
input.body
),
});
if (!handshakeValidation.ok) {
@ -299,6 +303,16 @@ function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function requiresOpenCodeDeliveryAcceptanceContract(
command: OpenCodeBridgeCommandName,
body: unknown
): boolean {
if (command !== 'opencode.sendMessage' || !isRecord(body)) {
return false;
}
return body.settlementMode === 'acceptance';
}
function stringifyError(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}

View file

@ -30,6 +30,9 @@ export interface OpenCodePromptDeliveryLedgerRecord {
runId: string | null;
runtimeSessionId: string | null;
runtimePromptMessageId?: string | null;
runtimePromptMessageIds?: string[];
lastRuntimePromptMessageId?: string | null;
lastDeliveryAttemptIdWithAcceptedPrompt?: string | null;
inboxMessageId: string;
inboxTimestamp: string;
source: 'watcher' | 'ui-send' | 'manual' | 'watchdog' | 'member-work-sync-review-pickup';
@ -138,6 +141,7 @@ export interface ApplyOpenCodePromptDeliveryResultInput {
responseObservation?: OpenCodeDeliveryResponseObservation;
sessionId?: string | null;
runtimePromptMessageId?: string | null;
deliveryAttemptId?: string | null;
runtimePid?: number;
prePromptCursor?: string | null;
diagnostics?: string[];
@ -213,6 +217,9 @@ export class OpenCodePromptDeliveryLedgerStore {
runId: input.runId ?? null,
runtimeSessionId: null,
runtimePromptMessageId: null,
runtimePromptMessageIds: [],
lastRuntimePromptMessageId: null,
lastDeliveryAttemptIdWithAcceptedPrompt: null,
inboxMessageId: input.inboxMessageId,
inboxTimestamp: input.inboxTimestamp,
source: input.source,
@ -305,6 +312,37 @@ export class OpenCodePromptDeliveryLedgerStore {
observation?.state ?? (input.accepted ? record.responseState : 'not_observed');
const responded = isOpenCodePromptResponseStateResponded(responseState);
const unanswered = isOpenCodePromptDeliveryUnansweredResponseState(responseState);
const acceptedRuntimePromptMessageId =
input.accepted && input.runtimePromptMessageId?.trim()
? input.runtimePromptMessageId.trim()
: null;
const previousRuntimePromptMessageIds = getOpenCodeRuntimePromptMessageIds(record);
const runtimePromptMessageIds =
acceptedRuntimePromptMessageId &&
!previousRuntimePromptMessageIds.includes(acceptedRuntimePromptMessageId)
? [...previousRuntimePromptMessageIds, acceptedRuntimePromptMessageId]
: previousRuntimePromptMessageIds;
const acceptedDeliveryAttemptId = input.deliveryAttemptId?.trim() || null;
const acceptedAttemptAlreadyRecorded = Boolean(
input.accepted &&
acceptedDeliveryAttemptId &&
record.lastDeliveryAttemptIdWithAcceptedPrompt === acceptedDeliveryAttemptId
);
const acceptedPromptAlreadyRecorded = Boolean(
input.accepted &&
acceptedRuntimePromptMessageId &&
previousRuntimePromptMessageIds.includes(acceptedRuntimePromptMessageId)
);
const shouldIncrementAttempts =
(input.accepted || input.attempted === true) &&
!acceptedAttemptAlreadyRecorded &&
!acceptedPromptAlreadyRecorded;
const lastRuntimePromptMessageId =
acceptedRuntimePromptMessageId ??
record.lastRuntimePromptMessageId ??
record.runtimePromptMessageId ??
runtimePromptMessageIds[runtimePromptMessageIds.length - 1] ??
null;
return {
...record,
status: input.accepted
@ -315,11 +353,15 @@ export class OpenCodePromptDeliveryLedgerStore {
: 'accepted'
: 'failed_retryable',
responseState,
attempts:
input.accepted || input.attempted === true ? record.attempts + 1 : record.attempts,
attempts: shouldIncrementAttempts ? record.attempts + 1 : record.attempts,
runtimeSessionId: input.sessionId ?? record.runtimeSessionId,
runtimePromptMessageId:
input.runtimePromptMessageId ?? record.runtimePromptMessageId ?? null,
runtimePromptMessageId: lastRuntimePromptMessageId,
runtimePromptMessageIds,
lastRuntimePromptMessageId,
lastDeliveryAttemptIdWithAcceptedPrompt:
input.accepted && acceptedDeliveryAttemptId
? acceptedDeliveryAttemptId
: (record.lastDeliveryAttemptIdWithAcceptedPrompt ?? null),
acceptanceUnknown: input.accepted ? false : record.acceptanceUnknown,
lastAttemptAt: input.now,
lastObservedAt: observation ? input.now : record.lastObservedAt,
@ -348,6 +390,8 @@ export class OpenCodePromptDeliveryLedgerStore {
async applyObservation(input: {
id: string;
responseObservation: OpenCodeDeliveryResponseObservation;
sessionId?: string | null;
runtimePromptMessageId?: string | null;
diagnostics?: string[];
observedAt: string;
}): Promise<OpenCodePromptDeliveryLedgerRecord> {
@ -356,17 +400,48 @@ export class OpenCodePromptDeliveryLedgerStore {
const unanswered = isOpenCodePromptDeliveryUnansweredResponseState(
input.responseObservation.state
);
const previousRuntimePromptMessageIds = getOpenCodeRuntimePromptMessageIds(record);
const deliveredRuntimePromptMessageId =
input.responseObservation.deliveredUserMessageId?.trim() || null;
const requestedRuntimePromptMessageId = input.runtimePromptMessageId?.trim() || null;
const requestedRuntimePromptMessageIdIsKnown = Boolean(
requestedRuntimePromptMessageId &&
previousRuntimePromptMessageIds.includes(requestedRuntimePromptMessageId)
);
const observedRuntimePromptMessageId =
deliveredRuntimePromptMessageId ||
(requestedRuntimePromptMessageIdIsKnown ? requestedRuntimePromptMessageId : null);
const runtimePromptMessageIds =
observedRuntimePromptMessageId &&
!previousRuntimePromptMessageIds.includes(observedRuntimePromptMessageId)
? [...previousRuntimePromptMessageIds, observedRuntimePromptMessageId]
: previousRuntimePromptMessageIds;
const promptAcceptedByObservation = Boolean(deliveredRuntimePromptMessageId);
const lastRuntimePromptMessageId =
observedRuntimePromptMessageId ??
record.lastRuntimePromptMessageId ??
record.runtimePromptMessageId ??
runtimePromptMessageIds[runtimePromptMessageIds.length - 1] ??
null;
return {
...record,
status: responded
? 'responded'
: unanswered
? 'unanswered'
: record.status === 'pending'
: record.status === 'pending' || promptAcceptedByObservation
? 'accepted'
: record.status,
responseState: input.responseObservation.state,
runtimeSessionId: input.sessionId ?? record.runtimeSessionId,
runtimePromptMessageId: lastRuntimePromptMessageId,
runtimePromptMessageIds,
lastRuntimePromptMessageId,
acceptanceUnknown: promptAcceptedByObservation ? false : record.acceptanceUnknown,
lastObservedAt: input.observedAt,
acceptedAt: promptAcceptedByObservation
? (record.acceptedAt ?? input.observedAt)
: record.acceptedAt,
respondedAt: responded ? (record.respondedAt ?? input.observedAt) : record.respondedAt,
deliveredUserMessageId:
input.responseObservation.deliveredUserMessageId ?? record.deliveredUserMessageId,
@ -660,6 +735,41 @@ export function hashOpenCodePromptDeliveryPayload(input: {
})}`;
}
export function getOpenCodeRuntimePromptMessageIds(
record: Pick<
OpenCodePromptDeliveryLedgerRecord,
'runtimePromptMessageId' | 'runtimePromptMessageIds' | 'lastRuntimePromptMessageId'
>
): string[] {
const ids: string[] = [];
for (const value of [
...(Array.isArray(record.runtimePromptMessageIds) ? record.runtimePromptMessageIds : []),
record.runtimePromptMessageId,
record.lastRuntimePromptMessageId,
]) {
const id = typeof value === 'string' ? value.trim() : '';
if (id && !ids.includes(id)) {
ids.push(id);
}
}
return ids;
}
export function getLatestOpenCodeRuntimePromptMessageId(
record: Pick<
OpenCodePromptDeliveryLedgerRecord,
'runtimePromptMessageId' | 'runtimePromptMessageIds' | 'lastRuntimePromptMessageId'
>
): string | null {
const explicit =
record.lastRuntimePromptMessageId?.trim() || record.runtimePromptMessageId?.trim();
if (explicit) {
return explicit;
}
const ids = getOpenCodeRuntimePromptMessageIds(record);
return ids[ids.length - 1] ?? null;
}
export function isOpenCodePromptResponseStateResponded(
state: OpenCodeDeliveryResponseState
): boolean {
@ -720,6 +830,9 @@ function isOpenCodePromptDeliveryLedgerRecord(
isOptionalNullableString(record.runId) &&
isOptionalNullableString(record.runtimeSessionId) &&
isOptionalNullableString(record.runtimePromptMessageId) &&
isOptionalStringArray(record.runtimePromptMessageIds) &&
isOptionalNullableString(record.lastRuntimePromptMessageId) &&
isOptionalNullableString(record.lastDeliveryAttemptIdWithAcceptedPrompt) &&
typeof record.inboxMessageId === 'string' &&
typeof record.inboxTimestamp === 'string' &&
isOpenCodePromptDeliverySource(record.source) &&
@ -812,6 +925,7 @@ function isOptionalNullableInboxMessageKind(
value === 'slash_command' ||
value === 'slash_command_result' ||
value === 'task_comment_notification' ||
value === 'task_stall_remediation' ||
value === 'member_work_sync_nudge' ||
value === 'agent_error'
);
@ -825,6 +939,10 @@ function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === 'string');
}
function isOptionalStringArray(value: unknown): value is string[] | undefined {
return value === undefined || isStringArray(value);
}
function isNonNegativeInteger(value: unknown): value is number {
return Number.isInteger(value) && (value as number) >= 0;
}

View file

@ -3,6 +3,7 @@ import * as path from 'node:path';
import {
createOpenCodePromptDeliveryLedgerStore,
getLatestOpenCodeRuntimePromptMessageId,
type OpenCodePromptDeliveryLedgerRecord,
} from '../../opencode/delivery/OpenCodePromptDeliveryLedger';
import {
@ -158,7 +159,10 @@ function toAttributionRecord(
])
: undefined;
const until = addMsToIso(terminalUntil ?? fallbackUntil, TERMINAL_EVIDENCE_GRACE_MS);
const startMessageUuid = record.deliveredUserMessageId?.trim() || undefined;
const startMessageUuid =
record.deliveredUserMessageId?.trim() ||
getLatestOpenCodeRuntimePromptMessageId(record) ||
undefined;
return {
taskId: task.id,
@ -241,7 +245,9 @@ export class TaskLogOpenCodeSessionEvidenceSource implements OpenCodeTaskLogSess
record.memberName.trim().toLowerCase(),
record.laneId.trim(),
sessionId,
record.deliveredUserMessageId ?? record.inboxMessageId,
record.deliveredUserMessageId ??
getLatestOpenCodeRuntimePromptMessageId(record) ??
record.inboxMessageId,
].join('::');
if (seen.has(key)) {
continue;

View file

@ -7,6 +7,7 @@ import {
createOpenCodeBridgeIdempotencyKey,
isOpenCodeBridgeCommandName,
OPEN_CODE_APP_MANAGED_BOOTSTRAP_CONTRACT_VERSION,
OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION,
OPEN_CODE_TASK_LEDGER_EVIDENCE_CONTRACT_VERSION,
parseSingleBridgeJsonResult,
stableHash,
@ -240,6 +241,66 @@ describe('OpenCodeBridgeCommandContract', () => {
});
});
it('requires the delivery acceptance contract only for acceptance-mode sendMessage', () => {
const client = peerIdentity('claude_team');
const server = peerIdentity('agent_teams_orchestrator');
client.bridgeProtocol.supportedCommands.push('opencode.sendMessage');
server.bridgeProtocol.supportedCommands.push('opencode.sendMessage');
let handshake = withAcceptedCommands(buildHandshake({ client, server }), [
'opencode.launchTeam',
'opencode.stopTeam',
'opencode.sendMessage',
]);
expect(
validateOpenCodeBridgeHandshake({
handshake,
expectedClient: client,
requiredCommand: 'opencode.sendMessage',
expectedCapabilitySnapshotId: null,
expectedManifestHighWatermark: 10,
expectedRunId: 'run-1',
requiresDeliveryAcceptanceContract: false,
})
).toEqual({ ok: true });
expect(
validateOpenCodeBridgeHandshake({
handshake,
expectedClient: client,
requiredCommand: 'opencode.sendMessage',
expectedCapabilitySnapshotId: null,
expectedManifestHighWatermark: 10,
expectedRunId: 'run-1',
requiresDeliveryAcceptanceContract: true,
})
).toEqual({
ok: false,
reason:
'OpenCode delivery acceptance mode is required, but the orchestrator does not advertise contract version 1. Falling back to observed delivery mode is required.',
});
server.bridgeProtocol.opencodeDeliveryAcceptanceContractVersion =
OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION;
handshake = withAcceptedCommands(buildHandshake({ client, server }), [
'opencode.launchTeam',
'opencode.stopTeam',
'opencode.sendMessage',
]);
expect(
validateOpenCodeBridgeHandshake({
handshake,
expectedClient: client,
requiredCommand: 'opencode.sendMessage',
expectedCapabilitySnapshotId: null,
expectedManifestHighWatermark: 10,
expectedRunId: 'run-1',
requiresDeliveryAcceptanceContract: true,
})
).toEqual({ ok: true });
});
it('creates deterministic idempotency keys for equivalent JSON bodies', () => {
const first = createOpenCodeBridgeIdempotencyKey({
command: 'opencode.launchTeam',
@ -352,3 +413,18 @@ function buildHandshake(input: {
identityHash: createOpenCodeBridgeHandshakeIdentityHash(withoutHash),
};
}
function withAcceptedCommands(
handshake: OpenCodeBridgeHandshake,
acceptedCommands: OpenCodeBridgeHandshake['acceptedCommands']
): OpenCodeBridgeHandshake {
const { identityHash: _identityHash, ...rest } = handshake;
const withoutHash: Omit<OpenCodeBridgeHandshake, 'identityHash'> = {
...rest,
acceptedCommands,
};
return {
...withoutHash,
identityHash: createOpenCodeBridgeHandshakeIdentityHash(withoutHash),
};
}

View file

@ -400,6 +400,169 @@ describe('OpenCodePromptDeliveryLedger', () => {
expect(observed.observedAssistantPreview).toBe('Понял');
});
it('tracks accepted runtime prompt ids without double-counting recovered command status', async () => {
const store = createStore();
const record = await store.ensurePending({
teamName: 'team-a',
memberName: 'jack',
laneId: 'secondary:opencode:jack',
inboxMessageId: 'msg-accepted',
inboxTimestamp: '2026-04-25T09:59:00.000Z',
source: 'watcher',
replyRecipient: 'user',
payloadHash: 'sha256:accepted',
now: '2026-04-25T10:00:00.000Z',
});
const firstAccepted = await store.applyDeliveryResult({
id: record.id,
accepted: true,
attempted: true,
sessionId: 'oc-session-1',
runtimePromptMessageId: 'msg_prompt_1',
deliveryAttemptId: 'attempt-1',
now: '2026-04-25T10:00:05.000Z',
});
expect(firstAccepted).toMatchObject({
status: 'accepted',
attempts: 1,
runtimePromptMessageId: 'msg_prompt_1',
lastRuntimePromptMessageId: 'msg_prompt_1',
lastDeliveryAttemptIdWithAcceptedPrompt: 'attempt-1',
});
expect(firstAccepted.runtimePromptMessageIds).toEqual(['msg_prompt_1']);
const recoveredSamePrompt = await store.applyDeliveryResult({
id: record.id,
accepted: true,
attempted: true,
sessionId: 'oc-session-1',
runtimePromptMessageId: 'msg_prompt_1',
deliveryAttemptId: 'attempt-1',
now: '2026-04-25T10:00:06.000Z',
});
expect(recoveredSamePrompt.attempts).toBe(1);
expect(recoveredSamePrompt.runtimePromptMessageIds).toEqual(['msg_prompt_1']);
const retryAccepted = await store.applyDeliveryResult({
id: record.id,
accepted: true,
attempted: true,
sessionId: 'oc-session-2',
runtimePromptMessageId: 'msg_prompt_2',
deliveryAttemptId: 'attempt-2',
now: '2026-04-25T10:01:00.000Z',
});
expect(retryAccepted.attempts).toBe(2);
expect(retryAccepted.runtimePromptMessageIds).toEqual(['msg_prompt_1', 'msg_prompt_2']);
expect(retryAccepted.lastRuntimePromptMessageId).toBe('msg_prompt_2');
});
it('keeps schema-1 legacy prompt-id fields compatible and normalizes when touched', async () => {
const store = createStore();
const legacy = await store.ensurePending({
teamName: 'team-a',
memberName: 'jack',
laneId: 'secondary:opencode:jack',
inboxMessageId: 'msg-legacy-runtime-prompt',
inboxTimestamp: '2026-04-25T09:59:00.000Z',
source: 'watcher',
replyRecipient: 'user',
payloadHash: 'sha256:legacy-runtime-prompt',
now: '2026-04-25T10:00:00.000Z',
});
const envelope = JSON.parse(await fs.readFile(ledgerPath(), 'utf8')) as {
data: Record<string, unknown>[];
};
delete envelope.data[0].runtimePromptMessageIds;
delete envelope.data[0].lastRuntimePromptMessageId;
delete envelope.data[0].lastDeliveryAttemptIdWithAcceptedPrompt;
await fs.writeFile(ledgerPath(), `${JSON.stringify(envelope, null, 2)}\n`, 'utf8');
await expect(store.list()).resolves.toHaveLength(1);
const touched = await store.applyDeliveryResult({
id: legacy.id,
accepted: true,
attempted: true,
runtimePromptMessageId: 'msg_prompt_legacy_touch',
deliveryAttemptId: 'attempt-legacy-touch',
now: '2026-04-25T10:00:05.000Z',
});
expect(touched.runtimePromptMessageIds).toEqual(['msg_prompt_legacy_touch']);
expect(touched.lastRuntimePromptMessageId).toBe('msg_prompt_legacy_touch');
expect(touched.lastDeliveryAttemptIdWithAcceptedPrompt).toBe('attempt-legacy-touch');
});
it('accepts task stall remediation message kind across ledger validation', async () => {
const store = createStore();
const record = await store.ensurePending({
teamName: 'team-a',
memberName: 'jack',
laneId: 'secondary:opencode:jack',
inboxMessageId: 'task-stall:team-a:jack:task-a',
inboxTimestamp: '2026-04-25T09:59:00.000Z',
source: 'watchdog',
messageKind: 'task_stall_remediation',
replyRecipient: 'team-lead',
actionMode: 'do',
payloadHash: 'sha256:task-stall',
now: '2026-04-25T10:00:00.000Z',
});
expect(record.messageKind).toBe('task_stall_remediation');
await expect(store.list()).resolves.toMatchObject([
{ messageKind: 'task_stall_remediation' },
]);
});
it('upgrades acceptance-unknown records when exact observation finds the prompt', async () => {
const store = createStore();
const record = await store.ensurePending({
teamName: 'team-a',
memberName: 'jack',
laneId: 'secondary:opencode:jack',
inboxMessageId: 'msg-observed-later',
inboxTimestamp: '2026-04-25T09:59:00.000Z',
source: 'watcher',
replyRecipient: 'user',
payloadHash: 'sha256:observed-later',
now: '2026-04-25T10:00:00.000Z',
});
const unknown = await store.markAcceptanceUnknown({
id: record.id,
reason: 'opencode_prompt_acceptance_unknown_after_bridge_timeout',
nextAttemptAt: '2026-04-25T10:01:00.000Z',
markedAt: '2026-04-25T10:00:45.000Z',
});
expect(unknown.acceptanceUnknown).toBe(true);
const observed = await store.applyObservation({
id: record.id,
sessionId: 'oc-session-recovered',
runtimePromptMessageId: 'msg_prompt_recovered',
responseObservation: {
state: 'pending',
deliveredUserMessageId: 'msg_prompt_recovered',
assistantMessageId: null,
toolCallNames: [],
visibleMessageToolCallId: null,
visibleReplyMessageId: null,
visibleReplyCorrelation: null,
latestAssistantPreview: null,
reason: 'assistant_response_pending',
},
observedAt: '2026-04-25T10:00:50.000Z',
});
expect(observed.status).toBe('accepted');
expect(observed.acceptanceUnknown).toBe(false);
expect(observed.acceptedAt).toBe('2026-04-25T10:00:50.000Z');
expect(observed.runtimeSessionId).toBe('oc-session-recovered');
expect(observed.runtimePromptMessageIds).toEqual(['msg_prompt_recovered']);
});
it('keeps plain-text responses active until their visible inbox reply is materialized', async () => {
const store = createStore();
const record = await store.ensurePending({

View file

@ -308,6 +308,63 @@ describe('OpenCodeReadinessBridge', () => {
);
});
it('falls back to observed sendMessage when acceptance capability is missing', async () => {
const execute = vi
.fn()
.mockRejectedValueOnce(
new Error(
'OpenCode delivery acceptance mode is required, but the orchestrator does not advertise contract version 1.'
)
)
.mockResolvedValueOnce(
bridgeCommandSuccess({
command: 'opencode.sendMessage',
requestId: 'send-req-observed',
data: {
accepted: true,
memberName: 'bob',
sessionId: 'session-bob',
diagnostics: [],
},
})
);
const executor = {
execute: execute as unknown as OpenCodeReadinessBridgeCommandExecutor['execute'] &
ReturnType<typeof vi.fn>,
};
const bridge = new OpenCodeReadinessBridge(executor);
await expect(
bridge.sendOpenCodeTeamMessage({
teamId: 'team-a',
teamName: 'team-a',
laneId: 'secondary:opencode:bob',
projectPath: '/repo',
memberName: 'bob',
text: 'hello',
messageId: 'message-1',
deliveryAttemptId: 'ledger-1:1:payload',
settlementMode: 'acceptance',
})
).resolves.toMatchObject({
accepted: true,
sessionId: 'session-bob',
diagnostics: [
expect.objectContaining({
code: 'opencode_accept_fast_capability_missing',
severity: 'warning',
}),
],
});
expect(execute).toHaveBeenCalledTimes(2);
expect(execute.mock.calls[0]?.[1]).toMatchObject({ settlementMode: 'acceptance' });
expect(execute.mock.calls[1]?.[1]).toMatchObject({ settlementMode: 'observed' });
expect(execute.mock.calls[1]?.[2]).toMatchObject({
requestId: expect.stringMatching(/-observed$/),
});
});
it('recovers accepted OpenCode sendMessage after bridge timeout through commandStatus by default', async () => {
const executor = fakeSequenceExecutor([
bridgeFailure('timeout', 'OpenCode bridge command timed out', []),

View file

@ -6,6 +6,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import {
OPEN_CODE_APP_MANAGED_BOOTSTRAP_CONTRACT_VERSION,
OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION,
createOpenCodeBridgeHandshakeIdentityHash,
type OpenCodeBridgeCommandName,
type OpenCodeBridgeHandshake,
@ -85,6 +86,45 @@ describe('OpenCodeStateChangingBridgeCommandService', () => {
await expect(leaseStore.getActive('team-a')).resolves.toBeNull();
});
it('requires delivery acceptance contract only for acceptance-mode sendMessage', async () => {
clientIdentity.bridgeProtocol.supportedCommands.push('opencode.sendMessage');
const server = peerIdentity('agent_teams_orchestrator');
server.bridgeProtocol.supportedCommands.push('opencode.sendMessage');
handshakePort.nextHandshake = buildHandshakeWithAcceptedCommands(
{ client: clientIdentity, server },
['opencode.launchTeam', 'opencode.stopTeam', 'opencode.sendMessage']
);
const service = createService();
await expect(service.execute(buildSendInput('acceptance'))).rejects.toThrow(
'OpenCode delivery acceptance mode is required'
);
expect(bridge.calls).toHaveLength(0);
await expect(ledger.list()).resolves.toEqual([]);
await expect(leaseStore.getActive('team-a')).resolves.toBeNull();
server.bridgeProtocol.opencodeDeliveryAcceptanceContractVersion =
OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION;
handshakePort.nextHandshake = buildHandshakeWithAcceptedCommands(
{ client: clientIdentity, server },
['opencode.launchTeam', 'opencode.stopTeam', 'opencode.sendMessage']
);
bridge.resultFactory = ({ body, command, options }) =>
bridgeSuccess({
requestId: options.requestId,
command,
data: {
runId: 'run-1',
idempotencyKey: body.preconditions.idempotencyKey,
runtimeStoreManifestHighWatermark: 10,
},
});
await expect(service.execute(buildSendInput('acceptance'))).resolves.toMatchObject({
ok: true,
});
expect(bridge.calls).toHaveLength(1);
});
it('adds preconditions, commits ledger, and releases lease on success', async () => {
bridge.resultFactory = ({ body, options }) =>
bridgeSuccess({
@ -227,6 +267,32 @@ function buildLaunchInput(): Parameters<OpenCodeStateChangingBridgeCommandServic
};
}
function buildSendInput(
settlementMode: 'observed' | 'acceptance'
): Parameters<OpenCodeStateChangingBridgeCommandService['execute']>[0] {
return {
command: 'opencode.sendMessage',
teamName: 'team-a',
laneId: 'secondary:opencode:bob',
runId: 'run-1',
capabilitySnapshotId: null,
behaviorFingerprint: null,
body: {
runId: 'run-1',
laneId: 'secondary:opencode:bob',
teamId: 'team-a',
teamName: 'team-a',
projectPath: '/tmp/project',
memberName: 'bob',
text: 'hello',
messageId: 'msg-1',
settlementMode,
},
cwd: '/tmp/project',
timeoutMs: 10_000,
};
}
function bridgeSuccess(
overrides: Partial<OpenCodeBridgeSuccess<unknown>> = {}
): OpenCodeBridgeSuccess<unknown> {
@ -313,6 +379,29 @@ function buildHandshake(input: {
};
}
function buildHandshakeWithAcceptedCommands(
input: {
client: OpenCodeBridgePeerIdentity;
server: OpenCodeBridgePeerIdentity;
},
acceptedCommands: OpenCodeBridgeHandshake['acceptedCommands']
): OpenCodeBridgeHandshake {
const withoutHash: Omit<OpenCodeBridgeHandshake, 'identityHash'> = {
schemaVersion: 1,
requestId: 'handshake-1',
client: input.client,
server: input.server,
agreedProtocolVersion: 1,
acceptedCommands,
serverTime: '2026-04-21T12:00:00.000Z',
};
return {
...withoutHash,
identityHash: createOpenCodeBridgeHandshakeIdentityHash(withoutHash),
};
}
class FakeBridgeExecutor implements OpenCodeBridgeCommandExecutor {
calls: Array<{
command: OpenCodeBridgeCommandName;

View file

@ -291,6 +291,7 @@ describe('OpenCodeTaskLogStreamSource real OpenCode fixture e2e', () => {
expect(bridge.getOpenCodeTranscript).toHaveBeenCalledWith('/tmp/agent_teams_orchestrator', {
teamId: 'relay-works-10',
memberName: 'jack',
sessionId: 'ses_23edf9243ffeSNYPWObDloBJyQ',
limit: 500,
});
});
@ -361,6 +362,7 @@ describe('OpenCodeTaskLogStreamSource real OpenCode fixture e2e', () => {
{
teamId: 'relay-works-10',
memberName: 'jack',
sessionId: 'stale-session-id',
limit: 500,
}
);

View file

@ -37,6 +37,9 @@ function createLedgerRecord(
laneId: 'lane-a',
runId: 'run-a',
runtimeSessionId: 'session-a',
runtimePromptMessageIds: [],
lastRuntimePromptMessageId: null,
lastDeliveryAttemptIdWithAcceptedPrompt: null,
inboxMessageId: 'inbox-a',
inboxTimestamp: '2026-04-21T10:00:00.000Z',
source: 'watcher',
@ -203,4 +206,33 @@ describe('TaskLogOpenCodeSessionEvidenceSource', () => {
await expect(source.readTaskRecords('team-a', createTask())).resolves.toEqual([]);
});
it('uses accepted runtime prompt id as task-log start anchor before observation catches up', async () => {
const teamsBasePath = await createTempTeamsBasePath();
await writeLedger({
teamsBasePath,
teamName: 'team-a',
laneId: 'lane-a',
records: [
createLedgerRecord({
id: 'record-accepted-only',
runtimeSessionId: 'session-accepted-only',
runtimePromptMessageId: 'msg_prompt_current',
runtimePromptMessageIds: ['msg_prompt_previous', 'msg_prompt_current'],
lastRuntimePromptMessageId: 'msg_prompt_current',
deliveredUserMessageId: null,
}),
],
});
const source = new TaskLogOpenCodeSessionEvidenceSource({ teamsBasePath });
const records = await source.readTaskRecords('team-a', createTask());
expect(records).toEqual([
expect.objectContaining({
sessionId: 'session-accepted-only',
startMessageUuid: 'msg_prompt_current',
}),
]);
});
});

View file

@ -206,6 +206,31 @@ describe('TeamInboxReader', () => {
});
});
it('preserves task-stall remediation semantic kind', async () => {
hoisted.files.set(
'/mock/teams/my-team/inboxes/alice.json',
JSON.stringify([
{
from: 'system',
to: 'alice',
text: 'Please continue the stalled task or report a blocker.',
timestamp: '2026-01-01T02:45:00.000Z',
read: false,
messageId: 'task-stall:my-team:alice:task-a',
source: 'system_notification',
messageKind: 'task_stall_remediation',
},
])
);
const messages = await reader.getMessagesFor('my-team', 'alice');
expect(messages).toHaveLength(1);
expect(messages[0]).toMatchObject({
messageId: 'task-stall:my-team:alice:task-a',
messageKind: 'task_stall_remediation',
});
});
it('preserves agent error semantic kind from the team lead inbox', async () => {
hoisted.files.set(
'/mock/teams/my-team/inboxes/team-lead.json',

View file

@ -5426,6 +5426,7 @@ describe('TeamProvisioningService', () => {
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
runtimePromptMessageId: 'msg_prompt_direct_lane',
runtimePid: 456,
diagnostics: [],
}));
@ -5507,6 +5508,7 @@ describe('TeamProvisioningService', () => {
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
runtimePromptMessageId: 'msg_prompt_verified_pid',
runtimePid: 456,
diagnostics: [],
}));
@ -5632,6 +5634,7 @@ describe('TeamProvisioningService', () => {
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
runtimePromptMessageId: 'msg_prompt_unverified_pid',
runtimePid: 456,
diagnostics: [],
}));
@ -5734,6 +5737,7 @@ describe('TeamProvisioningService', () => {
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
runtimePromptMessageId: 'msg_prompt_snapshot_config',
diagnostics: [],
}));
svc.setRuntimeAdapterRegistry(
@ -5824,6 +5828,7 @@ describe('TeamProvisioningService', () => {
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
runtimePromptMessageId: 'msg_prompt_worktree_cwd',
diagnostics: [],
}));
svc.setRuntimeAdapterRegistry(
@ -7071,6 +7076,109 @@ describe('TeamProvisioningService', () => {
expect(ledgerEnvelope.data[0].nextAttemptAt).toBeTruthy();
});
it('keeps accepted OpenCode responses without exact prompt identity acceptance-unknown', async () => {
const svc = new TeamProvisioningService();
const sendMessageToMember = vi.fn(async (input: Record<string, unknown>) => ({
ok: true,
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
prePromptCursor: 'cursor-before',
diagnostics: [],
}));
const registry = new TeamRuntimeAdapterRegistry([
{
providerId: 'opencode',
prepare: vi.fn(),
launch: vi.fn(),
reconcile: vi.fn(),
stop: vi.fn(),
sendMessageToMember,
observeMessageDelivery: vi.fn(),
} as any,
]);
svc.setRuntimeAdapterRegistry(registry);
(svc as any).getTrackedRunId = vi.fn(() => 'run-1');
(svc as any).provisioningRunByTeam.set('team-a', 'run-1');
(svc as any).setSecondaryRuntimeRun({
teamName: 'team-a',
runId: 'opencode-run-bob',
providerId: 'opencode',
laneId: 'secondary:opencode:bob',
memberName: 'bob',
cwd: '/repo',
});
await writeDefaultBobOpenCodeBootstrapEvidence();
(svc as any).configReader = {
getConfig: vi.fn(async () => ({
projectPath: '/repo',
members: [
{ name: 'team-lead', providerId: 'codex', model: 'gpt-5.4' },
{ name: 'bob', providerId: 'opencode', model: 'minimax-m2.5-free' },
],
})),
};
(svc as any).teamMetaStore = {
getMeta: vi.fn(async () => ({
launchIdentity: { providerId: 'codex' },
providerId: 'codex',
})),
};
(svc as any).membersMetaStore = {
getMembers: vi.fn(async () => [
{
name: 'bob',
providerId: 'opencode',
model: 'opencode/minimax-m2.5-free',
},
]),
};
await expect(
svc.deliverOpenCodeMemberMessage('team-a', {
memberName: 'bob',
text: 'Please handle this.',
messageId: 'msg-accepted-missing-prompt-id',
replyRecipient: 'user',
actionMode: 'ask',
source: 'watcher',
inboxTimestamp: '2026-04-25T10:00:00.000Z',
})
).resolves.toMatchObject({
delivered: true,
accepted: false,
responsePending: true,
acceptanceUnknown: true,
reason: 'opencode_prompt_acceptance_unknown_missing_runtime_prompt_id',
});
const ledgerPath = getOpenCodeLaneScopedRuntimeFilePath({
teamsBasePath: tempTeamsBase,
teamName: 'team-a',
laneId: 'secondary:opencode:bob',
fileName: 'opencode-prompt-delivery-ledger.json',
});
const ledgerEnvelope = JSON.parse(await fsPromises.readFile(ledgerPath, 'utf8')) as {
data: Array<{
acceptanceUnknown: boolean;
status: string;
runtimePromptMessageId: string | null;
lastReason: string | null;
diagnostics: string[];
}>;
};
expect(ledgerEnvelope.data[0]).toMatchObject({
acceptanceUnknown: true,
status: 'failed_retryable',
runtimePromptMessageId: null,
lastReason: 'opencode_prompt_acceptance_unknown_missing_runtime_prompt_id',
});
expect(ledgerEnvelope.data[0].diagnostics).toContain(
'opencode_prompt_acceptance_missing_runtime_prompt_id'
);
});
it('marks OpenCode payload hash mismatch terminal without sending a duplicate prompt', async () => {
const svc = new TeamProvisioningService();
const sendMessageToMember = vi.fn(async (input: Record<string, unknown>) => ({
@ -8923,6 +9031,7 @@ describe('TeamProvisioningService', () => {
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
runtimePromptMessageId: 'msg_prompt_after_restart',
diagnostics: [],
}));
const registry = new TeamRuntimeAdapterRegistry([
@ -9015,6 +9124,7 @@ describe('TeamProvisioningService', () => {
providerId: 'opencode',
memberName: String(input.memberName),
sessionId: 'oc-session-bob',
runtimePromptMessageId: 'msg_prompt_live_lane',
diagnostics: [],
}));
svc.setRuntimeAdapterRegistry(