Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 48 additions & 6 deletions build/cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38516,21 +38516,20 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.buildCodexExecutionPolicy = buildCodexExecutionPolicy;
const agent_execution_plan_1 = __nccwpck_require__(12253);
const provider_execution_policy_1 = __nccwpck_require__(50480);
const strict_output_schema_policy_1 = __nccwpck_require__(56743);
const codex_output_schema_policy_1 = __nccwpck_require__(71503);
function buildCodexExecutionPolicy(input) {
const { configuration } = input;
if (configuration.provider !== 'codex')
throw new Error('Codex policy requires Codex configuration.');
if (input.outputSchema)
(0, strict_output_schema_policy_1.assertStrictOutputSchema)(input.outputSchema);
const nativeSchema = input.outputSchema ? (0, codex_output_schema_policy_1.projectCodexOutputSchema)(input.outputSchema) : undefined;
const workspaceMode = (0, agent_execution_plan_1.workspaceModeForCapability)(input.capability);
const outputSchemaPath = input.outputSchema
? (0, provider_execution_policy_1.managedArtifactPath)(input.runtimeDirectory, 'response.schema.json')
: undefined;
const moduleCache = (0, provider_execution_policy_1.managedArtifactPath)(input.runtimeDirectory, 'shell/local/powershell-module-analysis.cache');
const artifacts = outputSchemaPath ? [{
path: outputSchemaPath,
contents: JSON.stringify(input.outputSchema),
contents: JSON.stringify(nativeSchema),
purpose: 'output-schema',
}] : [];
const argv = [
Expand Down Expand Up @@ -38584,6 +38583,38 @@ function tomlString(value) {
}


/***/ }),

/***/ 71503:
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {

"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.projectCodexOutputSchema = projectCodexOutputSchema;
const strict_output_schema_policy_1 = __nccwpck_require__(56743);
/** Keep string-size acceptance local; Codex's native decoder receives the compatible closed shape. */
function projectCodexOutputSchema(schema) {
(0, strict_output_schema_policy_1.assertStrictOutputSchema)(schema);
return projectNode(schema);
}
function projectNode(schema) {
const projected = { ...schema };
const types = typeof schema.type === 'string' ? [schema.type] : schema.type;
if (types.includes('string')) {
delete projected.minLength;
delete projected.maxLength;
}
if (types.includes('object')) {
projected.properties = Object.fromEntries(Object.entries(schema.properties)
.map(([name, nested]) => [name, projectNode(nested)]));
}
if (types.includes('array'))
projected.items = projectNode(schema.items);
return projected;
}


/***/ }),

/***/ 93955:
Expand Down Expand Up @@ -58775,14 +58806,15 @@ const agent_response_length_failure_1 = __nccwpck_require__(28528);
/** Size and typed format failures share one regeneration; the writer still validates every candidate. */
async function draftSddMarkdown(agent, configuration, plan, prompt, validate) {
const maximum = plan.action === 'update' ? pre_branch_sdd_1.SDD_MAX_UPDATE_CHARACTERS : pre_branch_sdd_1.SDD_MAX_DRAFT_CHARACTERS;
const target = Math.min(10000, Math.floor(maximum / 3));
const schema = {
type: 'object',
properties: { markdown: { type: 'string', minLength: pre_branch_sdd_1.SDD_MIN_DRAFT_CHARACTERS, maxLength: maximum } },
required: ['markdown'], additionalProperties: false,
};
let problem = 'size';
let formatReason = 'required-heading';
const contractPrompt = `${prompt}\n\nDraft contract: keep the complete draft within ${maximum} characters; aim for ${Math.floor(maximum * 2 / 3)} characters. Preserve the same owner, decisions and requirements. Include these literal canonical heading prefixes as Markdown headings, with the shown capitalization:\n${pre_branch_sdd_1.SDD_REQUIRED_HEADINGS.join('\n')}\nUse the canonical numeric test-budget table in section 14: Area | Minimum distinct cases | Behaviors/risks covered. Every allocation and the Total must be a positive integer, and the Total must equal the sum of the allocations. A justified positive integer sentence of distinct tests or cases is also accepted. Return only the required JSON.`;
const contractPrompt = `${prompt}\n\nDraft contract: keep the complete draft within ${maximum} characters; aim for ${target} characters. Preserve the same owner, decisions and requirements. Include these literal canonical heading prefixes as Markdown headings, with the shown capitalization:\n${pre_branch_sdd_1.SDD_REQUIRED_HEADINGS.join('\n')}\nUse the canonical numeric test-budget table in section 14: Area | Minimum distinct cases | Behaviors/risks covered. Every allocation and the Total must be a positive integer, and the Total must equal the sum of the allocations. A justified positive integer sentence of distinct tests or cases is also accepted. Return only the required JSON.`;
for (let attempt = 0; attempt < 2; attempt++) {
let value;
try {
Expand Down Expand Up @@ -77502,6 +77534,7 @@ function createAgentProcessLifecycle(child, plan, signal, resolve, reject, onToo
const stdoutChunks = [];
let stderrBytes = 0;
const stderrChunks = [];
let stderrTail = Buffer.alloc(0);
let outputBytes = 0;
let settled = false;
let terminationError;
Expand Down Expand Up @@ -77567,6 +77600,9 @@ function createAgentProcessLifecycle(child, plan, signal, resolve, reject, onToo
stderrChunks.push(retained);
stderrBytes += retained.byteLength;
}
const retainedTail = chunk.subarray(-MAX_STDERR_BYTES);
const previousTail = stderrTail.subarray(Math.max(0, stderrTail.length + retainedTail.length - MAX_STDERR_BYTES));
stderrTail = Buffer.concat([previousTail, retainedTail]);
};
const onStdinError = () => beginTermination(new agent_cli_contracts_1.AgentCliError('Unable to send the prompt to the agent CLI.', 'process'));
const onError = () => finishReject(new agent_cli_contracts_1.AgentCliError('Unable to start agent CLI.', 'process'));
Expand All @@ -77577,8 +77613,11 @@ function createAgentProcessLifecycle(child, plan, signal, resolve, reject, onToo
}
if (code !== 0) {
const diagnostic = stderrBytes > 0 ? ' Diagnostic output was suppressed for safety.' : '';
const terminalDiagnostic = (0, agent_cli_exit_diagnostic_1.classifyAgentCliExitDiagnostic)(stderrTail.toString('utf8'));
const exitDiagnostic = stderrBytes > 0
? (0, agent_cli_exit_diagnostic_1.classifyAgentCliExitDiagnostic)(Buffer.concat(stderrChunks).toString('utf8'))
? terminalDiagnostic === 'unclassified'
? (0, agent_cli_exit_diagnostic_1.classifyAgentCliExitDiagnostic)(Buffer.concat(stderrChunks).toString('utf8'))
: terminalDiagnostic
: undefined;
finishReject(new agent_cli_contracts_1.AgentCliError(`Agent CLI exited with code ${code}.${diagnostic}`, 'process', code === 75, code ?? undefined, exitDiagnostic));
return;
Expand Down Expand Up @@ -77768,6 +77807,9 @@ function classifyAgentCliToolDiagnostic(stderr) {
}
/** Provider stderr is untrusted and may contain credentials. Return a fixed code only. */
function classifyAgentCliExitDiagnostic(stderr) {
if (/^ERROR: Incomplete response returned, reason: max_output_tokens\r?$/mu.test(stderr)) {
return 'reported-output-token-limit';
}
const toolDiagnostic = classifyAgentCliToolDiagnostic(stderr);
if (toolDiagnostic)
return toolDiagnostic;
Expand Down
54 changes: 48 additions & 6 deletions build/github_action/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39628,21 +39628,20 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.buildCodexExecutionPolicy = buildCodexExecutionPolicy;
const agent_execution_plan_1 = __nccwpck_require__(12253);
const provider_execution_policy_1 = __nccwpck_require__(50480);
const strict_output_schema_policy_1 = __nccwpck_require__(56743);
const codex_output_schema_policy_1 = __nccwpck_require__(71503);
function buildCodexExecutionPolicy(input) {
const { configuration } = input;
if (configuration.provider !== 'codex')
throw new Error('Codex policy requires Codex configuration.');
if (input.outputSchema)
(0, strict_output_schema_policy_1.assertStrictOutputSchema)(input.outputSchema);
const nativeSchema = input.outputSchema ? (0, codex_output_schema_policy_1.projectCodexOutputSchema)(input.outputSchema) : undefined;
const workspaceMode = (0, agent_execution_plan_1.workspaceModeForCapability)(input.capability);
const outputSchemaPath = input.outputSchema
? (0, provider_execution_policy_1.managedArtifactPath)(input.runtimeDirectory, 'response.schema.json')
: undefined;
const moduleCache = (0, provider_execution_policy_1.managedArtifactPath)(input.runtimeDirectory, 'shell/local/powershell-module-analysis.cache');
const artifacts = outputSchemaPath ? [{
path: outputSchemaPath,
contents: JSON.stringify(input.outputSchema),
contents: JSON.stringify(nativeSchema),
purpose: 'output-schema',
}] : [];
const argv = [
Expand Down Expand Up @@ -39696,6 +39695,38 @@ function tomlString(value) {
}


/***/ }),

/***/ 71503:
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {

"use strict";

Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.projectCodexOutputSchema = projectCodexOutputSchema;
const strict_output_schema_policy_1 = __nccwpck_require__(56743);
/** Keep string-size acceptance local; Codex's native decoder receives the compatible closed shape. */
function projectCodexOutputSchema(schema) {
(0, strict_output_schema_policy_1.assertStrictOutputSchema)(schema);
return projectNode(schema);
}
function projectNode(schema) {
const projected = { ...schema };
const types = typeof schema.type === 'string' ? [schema.type] : schema.type;
if (types.includes('string')) {
delete projected.minLength;
delete projected.maxLength;
}
if (types.includes('object')) {
projected.properties = Object.fromEntries(Object.entries(schema.properties)
.map(([name, nested]) => [name, projectNode(nested)]));
}
if (types.includes('array'))
projected.items = projectNode(schema.items);
return projected;
}


/***/ }),

/***/ 93955:
Expand Down Expand Up @@ -57354,14 +57385,15 @@ const agent_response_length_failure_1 = __nccwpck_require__(28528);
/** Size and typed format failures share one regeneration; the writer still validates every candidate. */
async function draftSddMarkdown(agent, configuration, plan, prompt, validate) {
const maximum = plan.action === 'update' ? pre_branch_sdd_1.SDD_MAX_UPDATE_CHARACTERS : pre_branch_sdd_1.SDD_MAX_DRAFT_CHARACTERS;
const target = Math.min(10000, Math.floor(maximum / 3));
const schema = {
type: 'object',
properties: { markdown: { type: 'string', minLength: pre_branch_sdd_1.SDD_MIN_DRAFT_CHARACTERS, maxLength: maximum } },
required: ['markdown'], additionalProperties: false,
};
let problem = 'size';
let formatReason = 'required-heading';
const contractPrompt = `${prompt}\n\nDraft contract: keep the complete draft within ${maximum} characters; aim for ${Math.floor(maximum * 2 / 3)} characters. Preserve the same owner, decisions and requirements. Include these literal canonical heading prefixes as Markdown headings, with the shown capitalization:\n${pre_branch_sdd_1.SDD_REQUIRED_HEADINGS.join('\n')}\nUse the canonical numeric test-budget table in section 14: Area | Minimum distinct cases | Behaviors/risks covered. Every allocation and the Total must be a positive integer, and the Total must equal the sum of the allocations. A justified positive integer sentence of distinct tests or cases is also accepted. Return only the required JSON.`;
const contractPrompt = `${prompt}\n\nDraft contract: keep the complete draft within ${maximum} characters; aim for ${target} characters. Preserve the same owner, decisions and requirements. Include these literal canonical heading prefixes as Markdown headings, with the shown capitalization:\n${pre_branch_sdd_1.SDD_REQUIRED_HEADINGS.join('\n')}\nUse the canonical numeric test-budget table in section 14: Area | Minimum distinct cases | Behaviors/risks covered. Every allocation and the Total must be a positive integer, and the Total must equal the sum of the allocations. A justified positive integer sentence of distinct tests or cases is also accepted. Return only the required JSON.`;
for (let attempt = 0; attempt < 2; attempt++) {
let value;
try {
Expand Down Expand Up @@ -69610,6 +69642,7 @@ function createAgentProcessLifecycle(child, plan, signal, resolve, reject, onToo
const stdoutChunks = [];
let stderrBytes = 0;
const stderrChunks = [];
let stderrTail = Buffer.alloc(0);
let outputBytes = 0;
let settled = false;
let terminationError;
Expand Down Expand Up @@ -69675,6 +69708,9 @@ function createAgentProcessLifecycle(child, plan, signal, resolve, reject, onToo
stderrChunks.push(retained);
stderrBytes += retained.byteLength;
}
const retainedTail = chunk.subarray(-MAX_STDERR_BYTES);
const previousTail = stderrTail.subarray(Math.max(0, stderrTail.length + retainedTail.length - MAX_STDERR_BYTES));
stderrTail = Buffer.concat([previousTail, retainedTail]);
};
const onStdinError = () => beginTermination(new agent_cli_contracts_1.AgentCliError('Unable to send the prompt to the agent CLI.', 'process'));
const onError = () => finishReject(new agent_cli_contracts_1.AgentCliError('Unable to start agent CLI.', 'process'));
Expand All @@ -69685,8 +69721,11 @@ function createAgentProcessLifecycle(child, plan, signal, resolve, reject, onToo
}
if (code !== 0) {
const diagnostic = stderrBytes > 0 ? ' Diagnostic output was suppressed for safety.' : '';
const terminalDiagnostic = (0, agent_cli_exit_diagnostic_1.classifyAgentCliExitDiagnostic)(stderrTail.toString('utf8'));
const exitDiagnostic = stderrBytes > 0
? (0, agent_cli_exit_diagnostic_1.classifyAgentCliExitDiagnostic)(Buffer.concat(stderrChunks).toString('utf8'))
? terminalDiagnostic === 'unclassified'
? (0, agent_cli_exit_diagnostic_1.classifyAgentCliExitDiagnostic)(Buffer.concat(stderrChunks).toString('utf8'))
: terminalDiagnostic
: undefined;
finishReject(new agent_cli_contracts_1.AgentCliError(`Agent CLI exited with code ${code}.${diagnostic}`, 'process', code === 75, code ?? undefined, exitDiagnostic));
return;
Expand Down Expand Up @@ -69876,6 +69915,9 @@ function classifyAgentCliToolDiagnostic(stderr) {
}
/** Provider stderr is untrusted and may contain credentials. Return a fixed code only. */
function classifyAgentCliExitDiagnostic(stderr) {
if (/^ERROR: Incomplete response returned, reason: max_output_tokens\r?$/mu.test(stderr)) {
return 'reported-output-token-limit';
}
const toolDiagnostic = classifyAgentCliToolDiagnostic(stderr);
if (toolDiagnostic)
return toolDiagnostic;
Expand Down
12 changes: 12 additions & 0 deletions docs/agents/execution-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ list is fixed by Copilot and cannot be expanded through repository inputs.

The hard maxima are 15 minutes, 512 KiB of prompt bytes, and 4 MiB of combined process output. Structured tasks declare a JSON Schema. Before Codex starts, Copilot requires a closed object schema in which every property is required, optional values are nullable, nested objects reject additional properties, and arrays define their items. Copilot then validates the returned response locally as well. An incompatible contract, invalid or oversized output, and prose-wrapped JSON are rejected; removed response shapes have no legacy conversion path.

For Codex, the native schema preserves that closed JSON shape while string
length bounds are enforced locally from the complete original schema. This
provider compatibility projection also covers nested and nullable strings;
it does not change numeric/array bounds, required fields or local acceptance.

Every product-facing read-only task also receives the canonical effective
`targetLocale` and must return the exact same tag in required `outputLocale`
metadata. This covers Think and help answers, recommendations, progress,
Expand All @@ -59,6 +64,13 @@ The reviewed runtime baseline is Codex `codex-cli 0.156.1`, OpenCode `1.18.3`, a

When a run rejects process output, its log includes a fixed local cause: `output-limit`, `empty-output`, `malformed-json-event`, `invalid-json-event`, `missing-text-events`, or `unclassified`. These codes distinguish the existing rejection paths without exposing the response or prompt. Inspect the code before retrying or changing a provider integration; a historical log that only says `run/output` cannot establish the cause.

A failed CLI process can report `reported-output-token-limit` when the provider
cuts off generation before completing its response. This differs from Copilot's
combined output-byte limit or request timeout. Failure classification checks a
bounded last 8 KiB of stderr before the existing first 8 KiB, so a long prompt
cannot hide a terminal diagnostic. Only a fixed hint is logged; neither window
is published. The hint does not authorize an automatic retry or a settings change.

## Codex service-runner support

**Codex no soportado en runners Windows ejecutados como servicio.** Codex jobs
Expand Down
8 changes: 8 additions & 0 deletions docs/agents/failure-policy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ process completion from the reported sandbox tool failure. This hint does not
change the process result, authorize a retry or certify capability success.
Model prose and unknown or truncated provider text are not diagnostic evidence.

Nonzero exits also inspect a separate last-8-KiB stderr window before falling
back to the first window. The exact CLI terminal output-token-limit line maps
to `reported-output-token-limit`; response content, raw stderr and prompts stay
private. That failure still stops the capability. For SDD drafting, use the
[compact generation and recovery guidance](/issues/pre-branch-sdds#draft-validation-recovery)
before rerunning the same issue; changing tokens or permissions does not address
a provider output-token limit.

## Cost rule

A real provider request MUST be authorized before execution when it can incur usage charges or consume plan quotas. Binary/version/help checks are not evidence of successful model authentication.
Expand Down
15 changes: 15 additions & 0 deletions docs/issues/pre-branch-sdds.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ Automatic updates retain the owning SDD from its original Git commit, including

### Draft validation recovery

Drafting aims for a complete compact document: about 6,000 characters for an
update appendix or 10,000 for a new/companion SDD. These targets leave room for
the provider to complete its structured response; they do not remove resolved
requirements or change the acceptance limits below. Codex receives a compatible
closed JSON shape; Copilot enforces the complete original string-length schema
locally before any document reaches the writer.

Copilot limits proposed update appendices to 18,000 characters and complete new
or companion specifications to 70,000. If a generated draft exceeds its limit,
it tries one concise regeneration for the same owner and answers. Missing
Expand All @@ -71,6 +78,14 @@ All validation and freshness checks still apply. If the second draft still fails
no draft is published; existing answers and SDDs are retained. Retry with a proportional
change or an approved companion specification.

If the Action log reports `reported-output-token-limit`, the provider stopped
before completing its response. No draft or branch is published for that failed
generation, and the answered plan is retained. Update Copilot to use the compact
targets and native-schema compatibility, then rerun the same issue workflow. If it still fails, review concise
coverage of the resolved scope before another run. This is a different limit
from a request timeout or a GitHub permission failure; the Action does not
silently change models, credentials, native JSON shape or hard document limits.

### Additional clarification rounds

The question card shows its current round. Reply to each new round in a new
Expand Down
Loading
Loading