fix(team): observe opencode deliveries by prompt id
This commit is contained in:
parent
565362a911
commit
f055193b16
8 changed files with 109 additions and 3 deletions
|
|
@ -368,7 +368,11 @@ type OpenCodeRuntimeMessageAdapter = TeamLaunchRuntimeAdapter & {
|
||||||
input: OpenCodeTeamRuntimeMessageInput
|
input: OpenCodeTeamRuntimeMessageInput
|
||||||
): Promise<OpenCodeTeamRuntimeMessageResult>;
|
): Promise<OpenCodeTeamRuntimeMessageResult>;
|
||||||
observeMessageDelivery?(
|
observeMessageDelivery?(
|
||||||
input: OpenCodeTeamRuntimeMessageInput & { prePromptCursor?: string | null }
|
input: OpenCodeTeamRuntimeMessageInput & {
|
||||||
|
prePromptCursor?: string | null;
|
||||||
|
sessionId?: string;
|
||||||
|
runtimePromptMessageId?: string;
|
||||||
|
}
|
||||||
): Promise<OpenCodeTeamRuntimeMessageResult>;
|
): Promise<OpenCodeTeamRuntimeMessageResult>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -8358,6 +8362,8 @@ export class TeamProvisioningService {
|
||||||
workSyncReviewRequestEventIds: input.workSyncReviewRequestEventIds,
|
workSyncReviewRequestEventIds: input.workSyncReviewRequestEventIds,
|
||||||
taskRefs: input.taskRefs,
|
taskRefs: input.taskRefs,
|
||||||
prePromptCursor: ledgerRecord.prePromptCursor,
|
prePromptCursor: ledgerRecord.prePromptCursor,
|
||||||
|
sessionId: ledgerRecord.runtimeSessionId ?? undefined,
|
||||||
|
runtimePromptMessageId: ledgerRecord.runtimePromptMessageId ?? undefined,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const reason = `opencode_direct_user_delivery_inline_observe_failed: ${getErrorMessage(
|
const reason = `opencode_direct_user_delivery_inline_observe_failed: ${getErrorMessage(
|
||||||
|
|
@ -9808,6 +9814,8 @@ export class TeamProvisioningService {
|
||||||
workSyncReviewRequestEventIds: input.workSyncReviewRequestEventIds,
|
workSyncReviewRequestEventIds: input.workSyncReviewRequestEventIds,
|
||||||
taskRefs: input.taskRefs,
|
taskRefs: input.taskRefs,
|
||||||
prePromptCursor: ledgerRecord.prePromptCursor,
|
prePromptCursor: ledgerRecord.prePromptCursor,
|
||||||
|
sessionId: ledgerRecord.runtimeSessionId ?? undefined,
|
||||||
|
runtimePromptMessageId: ledgerRecord.runtimePromptMessageId ?? undefined,
|
||||||
});
|
});
|
||||||
await this.rememberOpenCodeRuntimePidFromBridge({
|
await this.rememberOpenCodeRuntimePidFromBridge({
|
||||||
teamName,
|
teamName,
|
||||||
|
|
@ -9983,6 +9991,7 @@ export class TeamProvisioningService {
|
||||||
attempted: true,
|
attempted: true,
|
||||||
responseObservation,
|
responseObservation,
|
||||||
sessionId: result.sessionId,
|
sessionId: result.sessionId,
|
||||||
|
runtimePromptMessageId: result.runtimePromptMessageId,
|
||||||
prePromptCursor: result.prePromptCursor,
|
prePromptCursor: result.prePromptCursor,
|
||||||
diagnostics: result.diagnostics,
|
diagnostics: result.diagnostics,
|
||||||
reason: promptAccepted ? responseObservation?.reason : result.diagnostics[0],
|
reason: promptAccepted ? responseObservation?.reason : result.diagnostics[0],
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import type {
|
||||||
export const OPEN_CODE_BRIDGE_SCHEMA_VERSION = 1 as const;
|
export const OPEN_CODE_BRIDGE_SCHEMA_VERSION = 1 as const;
|
||||||
export const OPEN_CODE_TASK_LEDGER_EVIDENCE_CONTRACT_VERSION = 1 as const;
|
export const OPEN_CODE_TASK_LEDGER_EVIDENCE_CONTRACT_VERSION = 1 as const;
|
||||||
export const OPEN_CODE_APP_MANAGED_BOOTSTRAP_CONTRACT_VERSION = 1 as const;
|
export const OPEN_CODE_APP_MANAGED_BOOTSTRAP_CONTRACT_VERSION = 1 as const;
|
||||||
|
export const OPEN_CODE_DELIVERY_ACCEPTANCE_CONTRACT_VERSION = 1 as const;
|
||||||
|
|
||||||
export type OpenCodeBridgeCommandName =
|
export type OpenCodeBridgeCommandName =
|
||||||
| 'opencode.handshake'
|
| 'opencode.handshake'
|
||||||
|
|
@ -172,6 +173,7 @@ export interface OpenCodeSendMessageCommandBody {
|
||||||
messageId?: string;
|
messageId?: string;
|
||||||
deliveryAttemptId?: string;
|
deliveryAttemptId?: string;
|
||||||
payloadHash?: string;
|
payloadHash?: string;
|
||||||
|
settlementMode?: 'observed' | 'acceptance';
|
||||||
fileParts?: {
|
fileParts?: {
|
||||||
type: 'file';
|
type: 'file';
|
||||||
mime: 'image/png' | 'image/jpeg' | 'image/webp';
|
mime: 'image/png' | 'image/jpeg' | 'image/webp';
|
||||||
|
|
@ -233,6 +235,7 @@ export interface OpenCodeSendMessageCommandData {
|
||||||
memberName: string;
|
memberName: string;
|
||||||
runtimePid?: number;
|
runtimePid?: number;
|
||||||
prePromptCursor?: string | null;
|
prePromptCursor?: string | null;
|
||||||
|
runtimePromptMessageId?: string;
|
||||||
responseObservation?: OpenCodeDeliveryResponseObservation;
|
responseObservation?: OpenCodeDeliveryResponseObservation;
|
||||||
diagnostics: OpenCodeTeamBridgeDiagnostic[];
|
diagnostics: OpenCodeTeamBridgeDiagnostic[];
|
||||||
}
|
}
|
||||||
|
|
@ -284,6 +287,8 @@ export interface OpenCodeObserveMessageDeliveryCommandBody {
|
||||||
projectPath: string;
|
projectPath: string;
|
||||||
memberName: string;
|
memberName: string;
|
||||||
messageId: string;
|
messageId: string;
|
||||||
|
sessionId?: string;
|
||||||
|
runtimePromptMessageId?: string;
|
||||||
prePromptCursor?: string | null;
|
prePromptCursor?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -292,6 +297,7 @@ export interface OpenCodeObserveMessageDeliveryCommandData {
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
memberName: string;
|
memberName: string;
|
||||||
runtimePid?: number;
|
runtimePid?: number;
|
||||||
|
runtimePromptMessageId?: string;
|
||||||
responseObservation: OpenCodeDeliveryResponseObservation;
|
responseObservation: OpenCodeDeliveryResponseObservation;
|
||||||
diagnostics: OpenCodeTeamBridgeDiagnostic[];
|
diagnostics: OpenCodeTeamBridgeDiagnostic[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ const DEFAULT_BACKFILL_TIMEOUT_MS = 45_000;
|
||||||
const DEFAULT_COMMAND_STATUS_TIMEOUT_MS = 5_000;
|
const DEFAULT_COMMAND_STATUS_TIMEOUT_MS = 5_000;
|
||||||
|
|
||||||
function buildSendPayloadHash(input: OpenCodeSendMessageCommandBody): string {
|
function buildSendPayloadHash(input: OpenCodeSendMessageCommandBody): string {
|
||||||
const { payloadHash: _payloadHash, ...hashable } = input;
|
const { payloadHash: _payloadHash, settlementMode: _settlementMode, ...hashable } = input;
|
||||||
return stableHash(hashable);
|
return stableHash(hashable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,6 +334,7 @@ export class OpenCodeReadinessBridge implements OpenCodeTeamRuntimeBridgePort {
|
||||||
memberName: input.body.memberName,
|
memberName: input.body.memberName,
|
||||||
sessionId: status.sessionId,
|
sessionId: status.sessionId,
|
||||||
runtimePid: status.runtimePid,
|
runtimePid: status.runtimePid,
|
||||||
|
runtimePromptMessageId: status.runtimePromptMessageId,
|
||||||
prePromptCursor: status.prePromptCursor,
|
prePromptCursor: status.prePromptCursor,
|
||||||
diagnostics,
|
diagnostics,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ export interface OpenCodePromptDeliveryLedgerRecord {
|
||||||
laneId: string;
|
laneId: string;
|
||||||
runId: string | null;
|
runId: string | null;
|
||||||
runtimeSessionId: string | null;
|
runtimeSessionId: string | null;
|
||||||
|
runtimePromptMessageId?: string | null;
|
||||||
inboxMessageId: string;
|
inboxMessageId: string;
|
||||||
inboxTimestamp: string;
|
inboxTimestamp: string;
|
||||||
source: 'watcher' | 'ui-send' | 'manual' | 'watchdog' | 'member-work-sync-review-pickup';
|
source: 'watcher' | 'ui-send' | 'manual' | 'watchdog' | 'member-work-sync-review-pickup';
|
||||||
|
|
@ -136,6 +137,7 @@ export interface ApplyOpenCodePromptDeliveryResultInput {
|
||||||
attempted?: boolean;
|
attempted?: boolean;
|
||||||
responseObservation?: OpenCodeDeliveryResponseObservation;
|
responseObservation?: OpenCodeDeliveryResponseObservation;
|
||||||
sessionId?: string | null;
|
sessionId?: string | null;
|
||||||
|
runtimePromptMessageId?: string | null;
|
||||||
runtimePid?: number;
|
runtimePid?: number;
|
||||||
prePromptCursor?: string | null;
|
prePromptCursor?: string | null;
|
||||||
diagnostics?: string[];
|
diagnostics?: string[];
|
||||||
|
|
@ -210,6 +212,7 @@ export class OpenCodePromptDeliveryLedgerStore {
|
||||||
laneId: input.laneId,
|
laneId: input.laneId,
|
||||||
runId: input.runId ?? null,
|
runId: input.runId ?? null,
|
||||||
runtimeSessionId: null,
|
runtimeSessionId: null,
|
||||||
|
runtimePromptMessageId: null,
|
||||||
inboxMessageId: input.inboxMessageId,
|
inboxMessageId: input.inboxMessageId,
|
||||||
inboxTimestamp: input.inboxTimestamp,
|
inboxTimestamp: input.inboxTimestamp,
|
||||||
source: input.source,
|
source: input.source,
|
||||||
|
|
@ -315,6 +318,8 @@ export class OpenCodePromptDeliveryLedgerStore {
|
||||||
attempts:
|
attempts:
|
||||||
input.accepted || input.attempted === true ? record.attempts + 1 : record.attempts,
|
input.accepted || input.attempted === true ? record.attempts + 1 : record.attempts,
|
||||||
runtimeSessionId: input.sessionId ?? record.runtimeSessionId,
|
runtimeSessionId: input.sessionId ?? record.runtimeSessionId,
|
||||||
|
runtimePromptMessageId:
|
||||||
|
input.runtimePromptMessageId ?? record.runtimePromptMessageId ?? null,
|
||||||
acceptanceUnknown: input.accepted ? false : record.acceptanceUnknown,
|
acceptanceUnknown: input.accepted ? false : record.acceptanceUnknown,
|
||||||
lastAttemptAt: input.now,
|
lastAttemptAt: input.now,
|
||||||
lastObservedAt: observation ? input.now : record.lastObservedAt,
|
lastObservedAt: observation ? input.now : record.lastObservedAt,
|
||||||
|
|
@ -714,6 +719,7 @@ function isOpenCodePromptDeliveryLedgerRecord(
|
||||||
typeof record.laneId === 'string' &&
|
typeof record.laneId === 'string' &&
|
||||||
isOptionalNullableString(record.runId) &&
|
isOptionalNullableString(record.runId) &&
|
||||||
isOptionalNullableString(record.runtimeSessionId) &&
|
isOptionalNullableString(record.runtimeSessionId) &&
|
||||||
|
isOptionalNullableString(record.runtimePromptMessageId) &&
|
||||||
typeof record.inboxMessageId === 'string' &&
|
typeof record.inboxMessageId === 'string' &&
|
||||||
typeof record.inboxTimestamp === 'string' &&
|
typeof record.inboxTimestamp === 'string' &&
|
||||||
isOpenCodePromptDeliverySource(record.source) &&
|
isOpenCodePromptDeliverySource(record.source) &&
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ export interface OpenCodeTeamRuntimeMessageResult {
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
runtimePid?: number;
|
runtimePid?: number;
|
||||||
prePromptCursor?: string | null;
|
prePromptCursor?: string | null;
|
||||||
|
runtimePromptMessageId?: string;
|
||||||
responseObservation?: OpenCodeSendMessageCommandData['responseObservation'];
|
responseObservation?: OpenCodeSendMessageCommandData['responseObservation'];
|
||||||
diagnostics: string[];
|
diagnostics: string[];
|
||||||
}
|
}
|
||||||
|
|
@ -333,6 +334,7 @@ export class OpenCodeTeamRuntimeAdapter implements TeamLaunchRuntimeAdapter {
|
||||||
text: buildOpenCodeRuntimeMessageText(input),
|
text: buildOpenCodeRuntimeMessageText(input),
|
||||||
messageId: input.messageId,
|
messageId: input.messageId,
|
||||||
...(input.deliveryAttemptId ? { deliveryAttemptId: input.deliveryAttemptId } : {}),
|
...(input.deliveryAttemptId ? { deliveryAttemptId: input.deliveryAttemptId } : {}),
|
||||||
|
settlementMode: 'acceptance',
|
||||||
fileParts: input.fileParts,
|
fileParts: input.fileParts,
|
||||||
actionMode: input.actionMode,
|
actionMode: input.actionMode,
|
||||||
messageKind: input.messageKind,
|
messageKind: input.messageKind,
|
||||||
|
|
@ -347,13 +349,18 @@ export class OpenCodeTeamRuntimeAdapter implements TeamLaunchRuntimeAdapter {
|
||||||
sessionId: data.sessionId,
|
sessionId: data.sessionId,
|
||||||
runtimePid: data.runtimePid,
|
runtimePid: data.runtimePid,
|
||||||
prePromptCursor: data.prePromptCursor,
|
prePromptCursor: data.prePromptCursor,
|
||||||
|
runtimePromptMessageId: data.runtimePromptMessageId,
|
||||||
responseObservation: data.responseObservation,
|
responseObservation: data.responseObservation,
|
||||||
diagnostics: data.diagnostics.map((diagnostic) => diagnostic.message),
|
diagnostics: data.diagnostics.map((diagnostic) => diagnostic.message),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async observeMessageDelivery(
|
async observeMessageDelivery(
|
||||||
input: OpenCodeTeamRuntimeMessageInput & { prePromptCursor?: string | null }
|
input: OpenCodeTeamRuntimeMessageInput & {
|
||||||
|
prePromptCursor?: string | null;
|
||||||
|
sessionId?: string;
|
||||||
|
runtimePromptMessageId?: string;
|
||||||
|
}
|
||||||
): Promise<OpenCodeTeamRuntimeMessageResult> {
|
): Promise<OpenCodeTeamRuntimeMessageResult> {
|
||||||
if (!this.bridge.observeOpenCodeTeamMessageDelivery) {
|
if (!this.bridge.observeOpenCodeTeamMessageDelivery) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -380,6 +387,8 @@ export class OpenCodeTeamRuntimeAdapter implements TeamLaunchRuntimeAdapter {
|
||||||
projectPath: input.cwd,
|
projectPath: input.cwd,
|
||||||
memberName: input.memberName,
|
memberName: input.memberName,
|
||||||
messageId: input.messageId,
|
messageId: input.messageId,
|
||||||
|
sessionId: input.sessionId,
|
||||||
|
runtimePromptMessageId: input.runtimePromptMessageId,
|
||||||
prePromptCursor: input.prePromptCursor ?? null,
|
prePromptCursor: input.prePromptCursor ?? null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -389,6 +398,7 @@ export class OpenCodeTeamRuntimeAdapter implements TeamLaunchRuntimeAdapter {
|
||||||
memberName: input.memberName,
|
memberName: input.memberName,
|
||||||
sessionId: data.sessionId,
|
sessionId: data.sessionId,
|
||||||
runtimePid: data.runtimePid,
|
runtimePid: data.runtimePid,
|
||||||
|
runtimePromptMessageId: data.runtimePromptMessageId,
|
||||||
responseObservation: data.responseObservation,
|
responseObservation: data.responseObservation,
|
||||||
diagnostics: data.diagnostics.map((diagnostic) => diagnostic.message),
|
diagnostics: data.diagnostics.map((diagnostic) => diagnostic.message),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,8 @@ describe('OpenCodePromptDeliveryLedger', () => {
|
||||||
id: unanswered.id,
|
id: unanswered.id,
|
||||||
accepted: true,
|
accepted: true,
|
||||||
attempted: true,
|
attempted: true,
|
||||||
|
sessionId: 'oc-session-1',
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
responseObservation: {
|
responseObservation: {
|
||||||
state: 'empty_assistant_turn',
|
state: 'empty_assistant_turn',
|
||||||
deliveredUserMessageId: 'oc-user-1',
|
deliveredUserMessageId: 'oc-user-1',
|
||||||
|
|
@ -332,6 +334,8 @@ describe('OpenCodePromptDeliveryLedger', () => {
|
||||||
expect(emptyResult.status).toBe('unanswered');
|
expect(emptyResult.status).toBe('unanswered');
|
||||||
expect(emptyResult.responseState).toBe('empty_assistant_turn');
|
expect(emptyResult.responseState).toBe('empty_assistant_turn');
|
||||||
expect(emptyResult.attempts).toBe(1);
|
expect(emptyResult.attempts).toBe(1);
|
||||||
|
expect(emptyResult.runtimeSessionId).toBe('oc-session-1');
|
||||||
|
expect(emptyResult.runtimePromptMessageId).toBe('msg_prompt_1');
|
||||||
|
|
||||||
const noAssistant = await store.ensurePending({
|
const noAssistant = await store.ensurePending({
|
||||||
teamName: 'team-a',
|
teamName: 'team-a',
|
||||||
|
|
|
||||||
|
|
@ -484,6 +484,7 @@ describe('OpenCodeTeamRuntimeAdapter', () => {
|
||||||
sessionId: 'oc-session-bob',
|
sessionId: 'oc-session-bob',
|
||||||
memberName: 'bob',
|
memberName: 'bob',
|
||||||
runtimePid: 456,
|
runtimePid: 456,
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
diagnostics: [],
|
diagnostics: [],
|
||||||
}));
|
}));
|
||||||
const adapter = new OpenCodeTeamRuntimeAdapter(
|
const adapter = new OpenCodeTeamRuntimeAdapter(
|
||||||
|
|
@ -511,6 +512,7 @@ describe('OpenCodeTeamRuntimeAdapter', () => {
|
||||||
memberName: 'bob',
|
memberName: 'bob',
|
||||||
sessionId: 'oc-session-bob',
|
sessionId: 'oc-session-bob',
|
||||||
runtimePid: 456,
|
runtimePid: 456,
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
diagnostics: [],
|
diagnostics: [],
|
||||||
});
|
});
|
||||||
expect(sendOpenCodeTeamMessage).toHaveBeenCalledWith({
|
expect(sendOpenCodeTeamMessage).toHaveBeenCalledWith({
|
||||||
|
|
@ -522,6 +524,7 @@ describe('OpenCodeTeamRuntimeAdapter', () => {
|
||||||
memberName: 'bob',
|
memberName: 'bob',
|
||||||
text: expect.stringContaining('agent-teams_message_send'),
|
text: expect.stringContaining('agent-teams_message_send'),
|
||||||
messageId: 'msg-1',
|
messageId: 'msg-1',
|
||||||
|
settlementMode: 'acceptance',
|
||||||
actionMode: 'delegate',
|
actionMode: 'delegate',
|
||||||
taskRefs: [{ taskId: 'task-1', displayId: 'abcd1234', teamName: 'team-a' }],
|
taskRefs: [{ taskId: 'task-1', displayId: 'abcd1234', teamName: 'team-a' }],
|
||||||
agent: 'teammate',
|
agent: 'teammate',
|
||||||
|
|
@ -542,6 +545,65 @@ describe('OpenCodeTeamRuntimeAdapter', () => {
|
||||||
expect(sentText).toContain('never use #00000000');
|
expect(sentText).toContain('never use #00000000');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('observes direct teammate messages by exact accepted runtime prompt id', async () => {
|
||||||
|
const observeOpenCodeTeamMessageDelivery = vi.fn<
|
||||||
|
NonNullable<OpenCodeTeamRuntimeBridgePort['observeOpenCodeTeamMessageDelivery']>
|
||||||
|
>(async () => ({
|
||||||
|
observed: true,
|
||||||
|
sessionId: 'oc-session-bob',
|
||||||
|
memberName: 'bob',
|
||||||
|
runtimePid: 456,
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
|
responseObservation: {
|
||||||
|
state: 'responded_plain_text',
|
||||||
|
deliveredUserMessageId: 'msg_prompt_1',
|
||||||
|
assistantMessageId: 'oc-assistant-1',
|
||||||
|
toolCallNames: [],
|
||||||
|
visibleMessageToolCallId: null,
|
||||||
|
visibleReplyMessageId: null,
|
||||||
|
visibleReplyCorrelation: null,
|
||||||
|
latestAssistantPreview: 'done',
|
||||||
|
reason: null,
|
||||||
|
},
|
||||||
|
diagnostics: [],
|
||||||
|
}));
|
||||||
|
const adapter = new OpenCodeTeamRuntimeAdapter(
|
||||||
|
bridgePort(readiness({ state: 'ready', launchAllowed: true }), {
|
||||||
|
observeOpenCodeTeamMessageDelivery,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
adapter.observeMessageDelivery({
|
||||||
|
runId: 'run-1',
|
||||||
|
teamName: 'team-a',
|
||||||
|
laneId: 'secondary:opencode:bob',
|
||||||
|
memberName: 'bob',
|
||||||
|
cwd: '/repo',
|
||||||
|
text: 'hello bob',
|
||||||
|
messageId: 'msg-1',
|
||||||
|
sessionId: 'oc-session-bob',
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
|
prePromptCursor: 'cursor-before',
|
||||||
|
})
|
||||||
|
).resolves.toMatchObject({
|
||||||
|
ok: true,
|
||||||
|
sessionId: 'oc-session-bob',
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
|
responseObservation: {
|
||||||
|
deliveredUserMessageId: 'msg_prompt_1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(observeOpenCodeTeamMessageDelivery).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
sessionId: 'oc-session-bob',
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
|
prePromptCursor: 'cursor-before',
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('sends member work sync nudges with report-oriented response instructions', async () => {
|
it('sends member work sync nudges with report-oriented response instructions', async () => {
|
||||||
const sendOpenCodeTeamMessage = vi.fn<
|
const sendOpenCodeTeamMessage = vi.fn<
|
||||||
NonNullable<OpenCodeTeamRuntimeBridgePort['sendOpenCodeTeamMessage']>
|
NonNullable<OpenCodeTeamRuntimeBridgePort['sendOpenCodeTeamMessage']>
|
||||||
|
|
|
||||||
|
|
@ -6161,6 +6161,7 @@ describe('TeamProvisioningService', () => {
|
||||||
providerId: 'opencode',
|
providerId: 'opencode',
|
||||||
memberName: String(input.memberName),
|
memberName: String(input.memberName),
|
||||||
sessionId: 'oc-session-bob',
|
sessionId: 'oc-session-bob',
|
||||||
|
runtimePromptMessageId: `msg_prompt_${sendMessageToMember.mock.calls.length}`,
|
||||||
prePromptCursor: `cursor-${sendMessageToMember.mock.calls.length}`,
|
prePromptCursor: `cursor-${sendMessageToMember.mock.calls.length}`,
|
||||||
responseObservation: {
|
responseObservation: {
|
||||||
state: 'pending',
|
state: 'pending',
|
||||||
|
|
@ -6293,6 +6294,13 @@ describe('TeamProvisioningService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(observeMessageDelivery).toHaveBeenCalledTimes(1);
|
expect(observeMessageDelivery).toHaveBeenCalledTimes(1);
|
||||||
|
expect(observeMessageDelivery).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
sessionId: 'oc-session-bob',
|
||||||
|
runtimePromptMessageId: 'msg_prompt_1',
|
||||||
|
prePromptCursor: 'cursor-1',
|
||||||
|
})
|
||||||
|
);
|
||||||
expect(sendMessageToMember).toHaveBeenCalledTimes(2);
|
expect(sendMessageToMember).toHaveBeenCalledTimes(2);
|
||||||
expect(sendMessageToMember.mock.calls[1]?.[0]).toMatchObject({
|
expect(sendMessageToMember.mock.calls[1]?.[0]).toMatchObject({
|
||||||
runId: 'opencode-run-bob',
|
runId: 'opencode-run-bob',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue