fix: integrate audit findings round 1 - tools, worker, scheduler, main agent

- Unify ToolResultEnvelope (output vs content) for built-in tools
- Fix shell.run AsyncGenerator consumption in ToolRegistry.call/streaming
- Scheduler: consume WorkerResult.status instead of marking all running tasks completed
- WorkerProcess/WorkerManager: surface exit events and generate failed/cancelled result
- MainAgent: integrate ContextAssembler, Chinese destructive regex, ArchitectureDesigner impact gate
- run.ts: pendingConfirmation flow, dispatch extracted, .air files filtered from /results
- CapabilityRegistry wired into RuntimeApp and ServiceRegistry; DoctorService uses it
- release.ts: findRepoRoot/findBun, run air e2e + depcruise + runtime regression
- New gates: release-critical-gates, CLI run command regression
- 14/14 e2e gates pass; 3/3 release dry-run pass

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
AirCoding
2026-06-05 18:39:10 +08:00
parent a2d7aa0339
commit ddefcbb2b1
24 changed files with 1992 additions and 186 deletions

View File

@@ -248,13 +248,79 @@ export class Scheduler {
}
}
// Workers complete → mark running tasks as completed
if (this.worker_manager && !this.worker_manager.has_running()) {
// Mark ALL running tasks as completed (not just runnable)
const all_tasks = Array.from(this.graph['tasks']?.values() || [])
for (const t of all_tasks) {
if ((t as any).status === 'running') {
this.graph.update_status((t as any).id, 'completed')
// Workers complete → consume explicit WorkerResult status
if (this.worker_manager) {
const running_tasks = this.graph.get_tasks_by_status('running')
for (const task of running_tasks) {
const handle = this.worker_manager.get_handle_for_task(task.id)
const result = this.worker_manager.get_result_for_task(task.id)
if (!handle || !result) continue
const attempt_id = `${task.id}_1`
if (result.status === 'completed') {
await eventIngestor.ingest({
id: `evt_${task.id}_completed`,
type: 'task.completed',
version: 1,
session_id: this.context.session_id,
project_id: this.context.project_id,
timestamp: new Date().toISOString(),
source: { kind: 'scheduler' },
route: ['scheduler', 'monitoring'],
payload: {
task_id: task.id,
agent_id: handle.worker_id,
attempt_id,
worker_result_json: result,
summary: result.summary,
changed_files: result.changed_files,
evidence_refs: result.evidence_refs,
}
})
this.graph.update_status(task.id, 'completed')
this.agent_monitor.remove(handle.worker_id)
} else if (result.status === 'blocked') {
await eventIngestor.ingest({
id: `evt_${task.id}_blocked`,
type: 'task.blocked',
version: 1,
session_id: this.context.session_id,
project_id: this.context.project_id,
timestamp: new Date().toISOString(),
source: { kind: 'scheduler' },
route: ['scheduler', 'monitoring'],
payload: { task_id: task.id, agent_id: handle.worker_id, reason: result.summary, blocker_kind: 'worker_blocked', evidence_refs: result.evidence_refs, suggested_next_step: 'Review worker blocker and retry with corrected plan' }
})
this.graph.update_status(task.id, 'blocked')
this.agent_monitor.remove(handle.worker_id)
} else if (result.status === 'cancelled') {
await eventIngestor.ingest({
id: `evt_${task.id}_cancelled_result`,
type: 'task.cancelled',
version: 1,
session_id: this.context.session_id,
project_id: this.context.project_id,
timestamp: new Date().toISOString(),
source: { kind: 'scheduler' },
route: ['scheduler', 'monitoring'],
payload: { task_id: task.id, reason: result.summary, cancelled_by: handle.worker_id }
})
this.graph.update_status(task.id, 'cancelled')
this.agent_monitor.remove(handle.worker_id)
} else {
await eventIngestor.ingest({
id: `evt_${task.id}_failed_result`,
type: 'task.failed',
version: 1,
session_id: this.context.session_id,
project_id: this.context.project_id,
timestamp: new Date().toISOString(),
source: { kind: 'scheduler' },
route: ['scheduler', 'monitoring'],
payload: { task_id: task.id, agent_id: handle.worker_id, attempt_id, error: { message: result.summary }, evidence_refs: result.evidence_refs, metadata: { worker_status: result.status } }
})
this.graph.update_status(task.id, 'failed')
this.agent_monitor.remove(handle.worker_id)
}
}
}