#13694: feat(cron): structured output via responseSchema for isolated agentTurn jobs
app: macos
app: web-ui
gateway
stale
size: XL
Cluster:
Cron Job Enhancements
## Summary
Adds optional `responseSchema` support for cron jobs with `kind: agentTurn`. When a schema is provided, the system:
1. **Injects schema instructions** into the agent prompt (model-agnostic — works with any provider)
2. **Extracts JSON** from the agent's text response (supports raw JSON, markdown fences, mixed text)
3. **Validates with AJV** (`coerceTypes: false`, `allErrors: true`, `ajv-formats`)
4. **Stores structured output** in the cron run result as `structuredOutput`
5. **Supports `formattedReport`** — if the validated output contains a `formattedReport` string field, it bypasses the announce→summarize pipeline and posts directly to the delivery channel
## Motivation
Isolated cron jobs often produce reports (briefings, research digests, status checks) that need consistent structure for downstream processing. Without schema enforcement, weaker/cheaper models may produce inconsistent output that breaks parsing.
This feature enables:
- **Model-agnostic structured output** without relying on provider-specific `response_format` APIs
- **Reliable JSON contracts** between cron jobs and delivery/processing pipelines
- **Direct delivery** of pre-formatted reports (skip the announce→summarize round trip)
- **Cost optimization** — run structured jobs on cheaper models (e.g., Sonnet) with confidence
## Usage
```json
{
"payload": {
"kind": "agentTurn",
"message": "Generate a daily briefing...",
"responseSchema": {
"type": "object",
"required": ["summary", "items", "formattedReport"],
"properties": {
"summary": { "type": "string" },
"items": { "type": "array", "items": { "type": "string" } },
"formattedReport": { "type": "string" }
}
}
}
}
```
## Implementation
### New files
- `src/cron/isolated-agent/helpers.ts` — `extractJsonFromText()` and `validateJsonSchema()`
- `src/cron/isolated-agent/helpers.test.ts` — 11 unit tests
- `src/cron/isolated-agent.response-schema.test.ts` — 4 integration tests
### Modified files
- `src/cron/types.ts` — Added `responseSchema` to `CronPayload` and `CronPayloadPatch`
- `src/gateway/protocol/schema/cron.ts` — TypeBox schema for protocol validation
- `src/cron/service/jobs.ts` — Merge support for responseSchema in job patches
- `src/cron/isolated-agent/run.ts` — Prompt injection, post-run validation, formattedReport delivery override
### Dependencies
- Added `ajv-formats@3.0.1` (format validation for JSON Schema)
## Design Decisions
- **Prompt injection over native API**: Works with any model provider, not just those supporting `response_format`
- **`coerceTypes: false`**: Strict validation — `[1]` won't silently become `["1"]` for string arrays
- **`formattedReport` triggers direct delivery**: When present, bypasses the announce flow (which routes through the main session for summarization) and posts directly to the delivery channel. This avoids burning main-session tokens on cron output.
- **Graceful degradation**: If JSON extraction or validation fails, the run still completes — structured output is best-effort, not blocking
## Tests
15 tests passing:
- 11 unit tests for JSON extraction (fenced, raw, mixed text, nested, arrays, invalid)
- 4 integration tests for schema validation, prompt building, and error handling
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
Adds optional `responseSchema` support for isolated `agentTurn` cron jobs, enabling model-agnostic structured output via prompt injection, JSON extraction, and AJV validation. When provided, the schema is injected into the agent prompt, the response is parsed and validated against the schema, and the structured output is stored in the cron run result.
Key changes:
- New helper functions `extractJsonFromText()` and `validateJsonSchema()` with comprehensive unit tests (11 tests)
- Schema validation using AJV with `coerceTypes: false` for strict type checking and `ajv-formats` for format validation
- `formattedReport` field support: when present in validated output, bypasses announce→summarize pipeline and delivers directly to the channel
- Integration tests verify prompt injection, validation errors, and successful structured output extraction (4 tests)
- Protocol schema updates to support `responseSchema` in `CronPayload` and `CronPayloadPatch`
- Added `ajv-formats@3.0.1` dependency for JSON Schema format validation
The implementation follows the codebase's existing patterns for AJV usage, includes graceful error handling that returns detailed validation errors, and maintains backwards compatibility with existing cron jobs.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The implementation is well-structured with comprehensive test coverage (15 tests total), follows existing codebase patterns for AJV usage, includes proper error handling, maintains backwards compatibility, and adds a useful feature without breaking changes. The code is clean, well-documented, and the design decisions are sound.
- No files require special attention
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#18743: Cron Tool Hardening: Normalize Gateway Params and Enforce Valid Sch...
by cccat6 · 2026-02-17
78.2%
#15115: fix: pre-load skill docs in cron sessions to prevent hallucinated syn…
by joaolcorreia · 2026-02-13
78.1%
#2071: fix: accept JSON string for cron.add job parameter (#1940)
by andrescardonas7 · 2026-01-26
77.6%
#14391: feat(cron): add raw delivery mode for verbatim output
by therealZpoint-bot · 2026-02-12
76.0%
#23562: feat: add sessionFreshness config for isolated cron jobs (#23539)
by MunemHashmi · 2026-02-22
75.8%
#6522: fix(cron): deliver original message when agent response is heartbea...
by sidmohan0 · 2026-02-01
75.6%
#23329: feat: Add Markdown support for cron job payload
by HeXavi8 · 2026-02-22
75.3%
#11216: Fix nightly failures: cron webchat delivery result + media cleanup ...
by DeanoC · 2026-02-07
74.9%
#5624: add support_human_readable_time_format in cron
by simran122 · 2026-01-31
74.6%
#13065: fix(cron): Fix "every" schedule not re-arming after gateway restart
by trevorgordon981 · 2026-02-10
74.4%