fix(opencode): queue specific relay behind active relay

This commit is contained in:
777genius 2026-05-14 02:14:09 +03:00
parent bc571f5fc7
commit e016515024
2 changed files with 115 additions and 82 deletions

View file

@ -21748,10 +21748,9 @@ export class TeamProvisioningService {
const relayKey = this.getOpenCodeMemberRelayKey(teamName, memberName);
const existing = this.openCodeMemberInboxRelayInFlight.get(relayKey);
if (existing) {
const existingResult = await existing;
const onlyMessageId = options.onlyMessageId?.trim();
if (!onlyMessageId) {
return existingResult;
return existing;
}
const inboxMessages = await this.inboxReader
.getMessagesFor(teamName, memberName)
@ -21764,7 +21763,6 @@ export class TeamProvisioningService {
delivered: 1,
failed: 0,
lastDelivery: { delivered: true },
diagnostics: existingResult.diagnostics,
};
}
if (!targetMessage) {
@ -21782,6 +21780,29 @@ export class TeamProvisioningService {
diagnostics: [diagnostic],
};
}
const diagnostic = `opencode_inbox_relay_queued_behind_active_relay: ${relayKey}/${onlyMessageId}`;
this.scheduleOpenCodeMemberInboxDeliveryWake({
teamName,
memberName,
messageId: onlyMessageId,
delayMs: 500,
});
return {
relayed: 0,
attempted: 1,
delivered: 0,
failed: 0,
lastDelivery: {
delivered: true,
accepted: false,
responsePending: true,
queuedBehindMessageId: onlyMessageId,
reason: 'opencode_inbox_relay_queued_behind_active_relay',
diagnostics: [diagnostic],
},
diagnostics: [diagnostic],
};
}
const work = (async (): Promise<OpenCodeMemberInboxRelayResult> => {

View file

@ -2706,9 +2706,11 @@ Messages:
}
});
it('does not let an older in-flight OpenCode relay mask a specific UI-send message', async () => {
it('queues a specific OpenCode relay behind an active member relay without duplicate prompts', async () => {
vi.useFakeTimers();
const service = new TeamProvisioningService();
const teamName = 'my-team';
try {
hoisted.files.set(
`/mock/teams/${teamName}/config.json`,
JSON.stringify({
@ -2764,10 +2766,23 @@ Messages:
},
]);
const uiRelay = service.relayOpenCodeMemberInboxMessages(teamName, 'jack', {
await expect(
service.relayOpenCodeMemberInboxMessages(teamName, 'jack', {
onlyMessageId: 'opencode-inflight-new',
source: 'ui-send',
deliveryMetadata: { replyRecipient: 'user' },
})
).resolves.toMatchObject({
attempted: 1,
delivered: 0,
failed: 0,
lastDelivery: {
delivered: true,
accepted: false,
responsePending: true,
queuedBehindMessageId: 'opencode-inflight-new',
reason: 'opencode_inbox_relay_queued_behind_active_relay',
},
});
releaseOldDelivery.resolve(undefined);
@ -2775,21 +2790,18 @@ Messages:
attempted: 1,
delivered: 1,
});
await expect(uiRelay).resolves.toMatchObject({
attempted: 1,
delivered: 1,
failed: 0,
});
expect(deliverSpy).toHaveBeenCalledTimes(1);
expect(deliverSpy).toHaveBeenCalledWith(
teamName,
expect.objectContaining({ messageId: 'opencode-inflight-old' })
);
expect(deliverSpy).toHaveBeenCalledWith(
teamName,
expect.objectContaining({ messageId: 'opencode-inflight-new' })
const rows = JSON.parse(
hoisted.files.get(`/mock/teams/${teamName}/inboxes/jack.json`) ?? '[]'
);
const rows = JSON.parse(hoisted.files.get(`/mock/teams/${teamName}/inboxes/jack.json`) ?? '[]');
expect(rows.map((row: { read?: boolean }) => row.read)).toEqual([true, true]);
expect(rows.map((row: { read?: boolean }) => row.read)).toEqual([true, false]);
} finally {
vi.useRealTimers();
}
});
it('treats an already-read specific OpenCode inbox row as delivered for UI-send relay', async () => {