[codex] Add escalation routing for out-of-bound actions#641
Conversation
There was a problem hiding this comment.
Pull request overview
Adds per-agent escalation routing so out-of-bound tool actions (relative to configured autonomy) are paused and promoted into explicit approval requests, with notifications routed to a configured channel/recipient and new audit coverage for escalation decisions.
Changes:
- Introduces per-agent
escalationTargetconfig (normalization, registry + CLI JSON updates, SQLite persistence via schema v25). - Threads escalation targets through gateway → runners → container approval evaluation → pending approvals + notifications.
- Adds
escalation.decisionstructured audit events and enriches approval prompts with proposed action + classifier reasoning.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/hybridai-skills-command.test.ts | Isolates runtime HOME/DATA_DIR for tests to avoid leaking local machine config. |
| tests/config-reload.integration.test.ts | Adds runtime-config normalization test for per-agent escalation targets. |
| tests/audit-events.test.ts | Verifies escalation.decision audit event payload + metadata threading. |
| tests/approval-policy.test.ts | Covers autonomy out-of-bound escalation behavior + prompt enrichment. |
| tests/agent-registry.test.ts | Ensures escalation targets normalize + persist through registry/SQLite migration v25. |
| src/types/execution.ts | Adds EscalationTarget type and threads it into ToolExecution + PendingApproval. |
| src/types/container.ts | Extends ContainerInput with escalationTarget. |
| src/memory/db.ts | Bumps schema to v25 and persists agents.escalation_target JSON. |
| src/infra/host-runner.ts | Passes escalation target into container input; parses it from approval progress. |
| src/infra/container-runner.ts | Passes escalation target into container input; parses it from approval progress. |
| src/gateway/text-channel-commands.ts | Stores pending approvals under escalation recipient user id when present. |
| src/gateway/gateway.ts | Adds routing helpers; suppresses in-channel approval UI when routed; supports proactive channel override. |
| src/gateway/gateway-types.ts | Extends proactive message callback payload with optional channelId. |
| src/gateway/gateway-chat-service.ts | Routes escalation approvals via proactive callback; passes resolved agent escalation target into execution. |
| src/gateway/fullauto-runtime.ts | Updates proactive message payload type to include optional channelId. |
| src/gateway/chat-approval.ts | Threads escalationTarget through extracted gateway approval events. |
| src/config/runtime-config.ts | Normalizes/clones per-agent escalation target in runtime config. |
| src/audit/audit-events.ts | Emits new escalation.decision audit event for non-none routes. |
| src/agents/agent-types.ts | Adds escalation target type + normalize/clone/equals helpers. |
| src/agents/agent-runtime-config.ts | Includes escalation target equality in agent config diffing. |
| src/agents/agent-registry.ts | Normalizes/defaults/fingerprints/escalation target and syncs it to DB. |
| src/agents/agent-config-command.ts | Adds CLI JSON config support/validation for escalationTarget. |
| src/agent/executor-types.ts | Threads escalation target through executor request. |
| container/src/types.ts | Adds EscalationTarget and threads it through container types. |
| container/src/index.ts | Passes escalation target into approval evaluation and tool execution metadata. |
| container/src/approval-policy.ts | Implements out-of-bound-by-autonomy escalation + prompt enrichment + target threading. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@claude Do a thorough review of this PR in terms of: KISS, YAGNI, DRY, Fail Fast, Secure by Default and performance/speed |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
@claude Do a thorough review of this PR in terms of: KISS, YAGNI, DRY, Fail Fast, Secure by Default and performance/speed |
|
Claude finished @furukama's task in 2m 24s —— View job PR Review: KISS, YAGNI, DRY, Fail Fast, Secure by Default, PerformanceTasks:
Overall the feature is well-scoped and the threading is thorough. The issues below range from a silent behavior change to genuine duplication and one security concern worth discussing. DRY — Significant violations1. 2. 3. Normalization logic implemented 5+ times across the codebase:
All of them trim two strings and return falsy if either is empty. The only variation is the return type ( 4. Approval-routing block triplicated in KISS — Moderate issues5. Triple normalization per approval in 6. 7. Dead fallback in 8. Dead fallback in 9. Fail Fast — One silent behavior change10. if (stakes === 'high' && baseTier !== 'red') { baseTier = 'red'; }
else if (stakes === 'medium' && baseTier === 'green') { baseTier = 'yellow'; }The new logic: if (stakes !== 'low') { outOfBoundByAutonomy = true; baseTier = 'red'; }For 11. userId: pendingApproval.escalationTarget?.recipient || userIdThis relies on the upstream runner having already validated and trimmed Secure by Default — One concern12. No authorization check before routing approvals to an arbitrary
For an internal-teams deployment this is likely fine, but for multi-tenant or untrusted-admin setups this is a confused-deputy / data-leak vector worth documenting explicitly. At minimum, consider logging the source agent ID alongside the target channel so the audit trail makes it traceable. Performance/Speed — Minor13. Triple 14. return `Escalation for ${target.recipient} on ${target.channel}.\n\n${approval.prompt}`;What's done well
Summary: The feature works and is well-tested, but there are 3 DRY violations worth fixing before merge (identical runners function, duplicate type, 5× normalization logic), one silent policy change that needs callout, and one security consideration for multi-tenant deployments. The YAGNI/KISS issues (dead fallbacks, unnecessary clone helper) are low-risk cleanup. |
Summary
Closes #587
Adding escalation routing for actions that exceed an agent's configured autonomy level.
escalationTargetconfiguration with channel and recipient, including runtime normalization, agent registry support, JSON config command handling, and SQLite persistence via schema v25.escalation.decisionaudit events for escalation routes.Validation
npm run linttsc --noEmit --noUnusedLocals --noUnusedParameters -p container/tsconfig.jsonvitest run tests/approval-policy.test.ts tests/audit-events.test.ts tests/agent-registry.test.ts tests/hybridai-skills-command.test.tsvitest run --configLoader runner --config vitest.integration.config.ts tests/config-reload.integration.test.tsgit diff --checkNotes
A full
npm run test:unitwas attempted. The new DB fixture issue it exposed was fixed. The remaining reproduced failure wastests/plugin-manager.singleton.test.tstiming out while loading this machine's configured external plugins from the real runtime home, which appears unrelated to this change.