fix(orchestration): name the provider's words when a worker's preamble is rejected (#35791)

When a structured worker's dispatch preamble is definitively rejected, the
dispatch_preamble_undelivered error now appends the provider's failure detail
("Details: ...") unless the rejection sentence already quotes it. The quoted
text is bounded and normalized by the same quotedProviderDetail helper the
rejection writer uses.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
This commit is contained in:
Venius24
2026-10-29 03:35:49 -07:00
committed by GitHub
co-authored by Neil
parent bccdb0254f
commit e08616e95d
3 changed files with 60 additions and 9 deletions
@@ -7,6 +7,8 @@ import type { AgentJournalSubmission } from '../../../../shared/agent-session-jo
import type { AgentMessageSource } from '../../../../shared/agent-session/agent-session-message-source'
import { getAppEnvironment } from '../../../../shared/app-environment'
import { DISPATCH_REJECTED_WRITE_FAILED } from '../../../../shared/structured-agent-session-dispatch-rejection'
import { agentSessionFailureFact } from '../../../../shared/agent-session-failure'
import { codexDispatchRejection } from '../../../codex/codex-structured-turn-end-settlement'
const hostRef: { current: unknown } = { current: null }
const createSpy = vi.fn()
@@ -231,7 +233,7 @@ describe('structured worker session', () => {
describe('structured worker dispatch preamble', () => {
type PreambleHost = Parameters<typeof sendStructuredWorkerPreamble>[0]['host']
type Settled = Pick<AgentJournalSubmission, 'dispatchState' | 'reason'>
type Settled = Pick<AgentJournalSubmission, 'dispatchState' | 'reason' | 'rejection'>
function submissionOf(settled: Settled): AgentJournalSubmission {
return {
@@ -377,6 +379,43 @@ describe('structured worker dispatch preamble', () => {
expect(isUnknownWorkerStartOutcome(error, 'dispatch_input')).toBe(false)
})
it('names a provider log detail the rejection sentence leaves out', async () => {
const error = await send(
hostWithSubmission({
dispatchState: 'rejected',
...codexDispatchRejection(
agentSessionFailureFact('providerRejected', {
detail: { text: 'thread/start: unsupported service tier', audience: 'log' },
neverReachedAgent: true
})
)
})
).catch((thrown: unknown) => thrown)
expect(error).toMatchObject({
code: 'dispatch_preamble_undelivered',
message:
"The dispatch preamble was not delivered (providerRejected): Codex didn't accept this message. Details: thread/start: unsupported service tier."
})
})
it('does not repeat provider words the rejection sentence already quotes', async () => {
const error = await send(
hostWithSubmission({
dispatchState: 'rejected',
...codexDispatchRejection(
agentSessionFailureFact('providerRejected', {
detail: { text: 'Unsupported service tier.', audience: 'person' },
neverReachedAgent: true
})
)
})
).catch((thrown: unknown) => thrown)
expect(error).toMatchObject({
message:
"The dispatch preamble was not delivered (providerRejected): Codex didn't accept this message: Unsupported service tier."
})
})
it('ends the message with one period whether the reason is a sentence or a marker', async () => {
const sentence = await send(
hostWithSubmission({
@@ -4,6 +4,11 @@
import { randomUUID } from 'node:crypto'
import { isDefinitiveAgentSessionCreateRefusal } from '../../../../shared/agent-session-definitive-refusal'
import type { AgentMessageSource } from '../../../../shared/agent-session/agent-session-message-source'
import {
agentSessionFailureDetailText,
readAgentSessionFailureFact
} from '../../../../shared/agent-session-failure'
import { quotedProviderDetail } from '../../../../shared/agent-session-failure-quoted-detail'
import type {
AgentJournalMessageItem,
AgentJournalSubmission
@@ -240,12 +245,17 @@ export function preambleDispatchState(
return submission.dispatchState
}
if (submission?.dispatchState === 'rejected') {
// Name the failure detail unless the reason already quotes it.
const detail = agentSessionFailureDetailText(readAgentSessionFailureFact(submission.rejection))
const quoted = detail ? quotedProviderDetail(detail) : ''
const detailClause =
quoted && !submission.reason?.includes(quoted) ? ` Details: ${quoted}.` : ''
// Definitive rejection gets a typed non-delivery code so the coordinator can retry without a duplicate turn.
throw new OrchestrationError(
'dispatch_preamble_undelivered',
`The dispatch preamble was not delivered${
submission.rejection ? ` (${submission.rejection.kind})` : ''
}: ${reasonClause(submission.reason)}.`
}: ${reasonClause(submission.reason)}.${detailClause}`
)
}
// Only accepted proves delivery; adapter/transport unknown requires an outcome_unknown receipt that tells the coordinator to inspect.
@@ -8,6 +8,14 @@ import type {
/** Person-facing provider text is quoted, but bounded so the sentence stays one. */
const MAX_QUOTED_DETAIL_CHARS = 512
/** Provider text as a failure sentence quotes it. */
export function quotedProviderDetail(text: string): string {
return text
.slice(0, MAX_QUOTED_DETAIL_CHARS)
.trim()
.replace(/[.\s]+$/, '')
}
/** The quoted lead when the provider wrote the detail for a person; the plain lead otherwise. */
export function quotingPersonDetail(
say: AgentSessionFailureSay,
@@ -16,12 +24,6 @@ export function quotingPersonDetail(
detail: ProviderDiagnostic | undefined,
values: AgentSessionFailureCopyValues = {}
): string {
const quoted =
detail?.audience === 'person'
? detail.text
.slice(0, MAX_QUOTED_DETAIL_CHARS)
.trim()
.replace(/[.\s]+$/, '')
: ''
const quoted = detail?.audience === 'person' ? quotedProviderDetail(detail.text) : ''
return quoted ? say(quotedLead, { ...values, detail: quoted }) : say(lead, values)
}