Phase 1 run-control semantics and run_state events

This commit is contained in:
William Valentin
2026-02-25 10:22:44 -08:00
parent ae21681958
commit e4ee6acce8
13 changed files with 485 additions and 120 deletions
+73 -50
View File
@@ -3635,7 +3635,7 @@
"multi_agent_routing": {
"priority": "P2",
"status": "completed",
"description": "Config-driven agent routing: AgentConfigRegistry for named agent configs (system_prompt, model_tier, tool_profile, sandbox), AgentRouter with senderchanneldefault resolution (glob patterns), per-agent tool registry cloning with sandboxed overrides, daemon wiring",
"description": "Config-driven agent routing: AgentConfigRegistry for named agent configs (system_prompt, model_tier, tool_profile, sandbox), AgentRouter with sender\u2192channel\u2192default resolution (glob patterns), per-agent tool registry cloning with sandboxed overrides, daemon wiring",
"files_created": [
"src/agents/registry.ts",
"src/agents/registry.test.ts",
@@ -3789,7 +3789,7 @@
"auto_login": {
"priority": "P5",
"status": "completed",
"description": "Lazy token resolution with onLoginRequired callback triggers OAuth device flow automatically on first API call when no token is available",
"description": "Lazy token resolution with onLoginRequired callback \u2014 triggers OAuth device flow automatically on first API call when no token is available",
"files_modified": [
"src/models/github.ts",
"src/daemon/index.ts",
@@ -3937,7 +3937,7 @@
"p8-agent-tools": {
"status": "completed",
"date": "2026-02-07",
"summary": "8 new agent-callable tools exposing existing internal APIs, plus gap analysis audit update (25% 65% match rate)",
"summary": "8 new agent-callable tools exposing existing internal APIs, plus gap analysis audit update (25% \u2192 65% match rate)",
"phases": {
"sessions_tools": {
"priority": "P8",
@@ -3994,7 +3994,7 @@
"file_patch_tool": {
"priority": "Tier3",
"status": "completed",
"description": "file.patch tool for multi-hunk structured patches apply multiple line-based edits (replacements, insertions, deletions) across one or more files in a single tool call. Hunks applied bottom-up to preserve line numbers.",
"description": "file.patch tool for multi-hunk structured patches \u2014 apply multiple line-based edits (replacements, insertions, deletions) across one or more files in a single tool call. Hunks applied bottom-up to preserve line numbers.",
"files_created": [
"src/tools/builtin/file-patch.ts",
"src/tools/builtin/file-patch.test.ts"
@@ -4008,7 +4008,7 @@
"gmail_pubsub_watcher": {
"priority": "Tier3",
"status": "completed",
"description": "Gmail Pub/Sub watcher ChannelAdapter monitors Gmail via Google Cloud Pub/Sub push notifications with polling fallback. OAuth2 auth, configurable watch labels, template rendering with email metadata placeholders. Wired into daemon lifecycle and gateway (POST /gmail/push endpoint).",
"description": "Gmail Pub/Sub watcher ChannelAdapter \u2014 monitors Gmail via Google Cloud Pub/Sub push notifications with polling fallback. OAuth2 auth, configurable watch labels, template rendering with email metadata placeholders. Wired into daemon lifecycle and gateway (POST /gmail/push endpoint).",
"files_created": [
"src/automation/gmail.ts",
"src/automation/gmail.test.ts"
@@ -4133,7 +4133,7 @@
"phases": {
"ollama_tool_calling": {
"status": "completed",
"description": "Pass tools to Ollama API in correct format, parse tool_calls from responses with generated IDs, set stopReason to 'tool_use'. Handle thinking field from reasoning models (deepseek-r1, glm-4.7-flash) use as content fallback and expose via thinkingContent. Streaming support for both tool calls and thinking.",
"description": "Pass tools to Ollama API in correct format, parse tool_calls from responses with generated IDs, set stopReason to 'tool_use'. Handle thinking field from reasoning models (deepseek-r1, glm-4.7-flash) \u2014 use as content fallback and expose via thinkingContent. Streaming support for both tool calls and thinking.",
"files_modified": [
"src/models/local/ollama.ts",
"src/models/local/ollama.test.ts"
@@ -4159,7 +4159,7 @@
"lane_queue": {
"priority": "Tier3",
"status": "completed",
"description": "Per-session FIFO queue in gateway serializes concurrent requests instead of rejecting. LaneQueue class with enqueue/cancel/queueLength methods.",
"description": "Per-session FIFO queue in gateway \u2014 serializes concurrent requests instead of rejecting. LaneQueue class with enqueue/cancel/queueLength methods.",
"files_created": [
"src/gateway/lane-queue.ts",
"src/gateway/lane-queue.test.ts"
@@ -4174,7 +4174,7 @@
"credential_redaction": {
"priority": "Tier3",
"status": "completed",
"description": "Expanded redactConfig() from 2 secret locations to 18+ secret fields telegram, discord, slack tokens; server.token; all model tier api_key/auth_token; web_search, audio, memory embedding api_keys; webhook secrets; gmail credentials; MCP server env vars.",
"description": "Expanded redactConfig() from 2 secret locations to 18+ secret fields \u2014 telegram, discord, slack tokens; server.token; all model tier api_key/auth_token; web_search, audio, memory embedding api_keys; webhook secrets; gmail credentials; MCP server env vars.",
"files_modified": [
"src/gateway/handlers/config.ts",
"src/gateway/handlers/handlers.test.ts"
@@ -4199,7 +4199,7 @@
"xai_grok_provider": {
"priority": "Tier3",
"status": "completed",
"description": "xAI as OpenAI-compatible model provider reuses OpenAIClient with baseURL https://api.x.ai/v1, XAI_API_KEY env var fallback, pricing for grok-3/grok-3-mini/grok-2/grok-2-mini/grok-3-fast.",
"description": "xAI as OpenAI-compatible model provider \u2014 reuses OpenAIClient with baseURL https://api.x.ai/v1, XAI_API_KEY env var fallback, pricing for grok-3/grok-3-mini/grok-2/grok-2-mini/grok-3-fast.",
"files_modified": [
"src/config/schema.ts",
"src/daemon/index.ts",
@@ -4209,7 +4209,7 @@
"voyage_ai_embeddings": {
"priority": "Tier3",
"status": "completed",
"description": "Voyage AI embedding provider for memory/vector search OpenAI SDK with baseURL https://api.voyageai.com/v1, defaults to 1024 dimensions, VOYAGE_API_KEY env var.",
"description": "Voyage AI embedding provider for memory/vector search \u2014 OpenAI SDK with baseURL https://api.voyageai.com/v1, defaults to 1024 dimensions, VOYAGE_API_KEY env var.",
"files_modified": [
"src/config/schema.ts",
"src/memory/embeddings.ts",
@@ -4227,7 +4227,7 @@
"gateway_lock": {
"priority": "Tier4",
"status": "completed",
"description": "Single-client gateway mode if lock=true and a client is connected, reject new connections with code 4003. UI detects locked state.",
"description": "Single-client gateway mode \u2014 if lock=true and a client is connected, reject new connections with code 4003. UI detects locked state.",
"files_modified": [
"src/config/schema.ts",
"src/gateway/server.ts",
@@ -6656,52 +6656,75 @@
"docs/plans/state.json"
],
"test_status": "runtime validation: docker compose recreate + curl 127.0.0.1:18801 + POST /v1/audio/transcriptions returned HTTP response"
},
"deeper-surfaces-phase1-run-control": {
"status": "completed",
"date": "2026-02-25",
"updated": "2026-02-25",
"summary": "Implemented Phase 1 run-control semantics and gateway UX signals: hardened interrupt queue behavior with latest-wins semantics, added run_state lifecycle events to the gateway protocol/UI, aligned channel-path interrupt cancellation with active-run tracking, and added focused tests.",
"files_modified": [
"src/gateway/lane-queue.ts",
"src/gateway/lane-queue.test.ts",
"src/gateway/handlers/agent.ts",
"src/gateway/handlers/agent.test.ts",
"src/gateway/protocol.ts",
"src/gateway/ui/pages/chat.js",
"src/gateway/ui/pages/chat.test.ts",
"src/daemon/routing.ts",
"src/daemon/routing.test.ts",
"docs/api/PROTOCOL.md",
"docs/architecture/AGENT_DIAGRAM.md",
"docs/architecture/GATEWAY_SESSIONS_AND_QUEUE.md",
"docs/plans/state.json"
],
"test_status": "pnpm test:run src/gateway/lane-queue.test.ts src/gateway/handlers/agent.test.ts src/gateway/ui/pages/chat.test.ts src/daemon/routing.test.ts passing"
}
},
"overall_progress": {
"total_test_count": 2009,
"total_test_count": 2013,
"all_tests_passing": true,
"p0_completion": "3/3 (100%)",
"p1_completion": "4/4 (100%)",
"p2_completion": "7/7 (100%)",
"p3_completion": "completed (group chat, gateway auth, Gemini, OpenRouter, Bedrock, browser control)",
"p4_completion": "1/1 (100%) multimodal media pipeline",
"p5_completion": "1/1 (100%) GitHub Copilot provider with auto-login",
"p6_completion": "4/4 (100%) enhanced media pipeline (image.analyze, outbound attachments, gateway attachments, audio transcription)",
"p7_completion": "6/6 (100%) web UI dashboard SPA (dashboard, chat, sessions, settings)",
"p8_completion": "8/8 (100%) agent tools (sessions.list/history/create/delete, agents.list, message.send, cron.list/trigger) + gap analysis audit",
"tier1_completion": "5/5 (100%) !!think prefix, /verbose command, typing indicators (Discord/WhatsApp), session pruning (TTL), tool groups",
"tier2_completion": "4/4 (100%) inbound webhooks, vector memory search, Dockerfile, heartbeat monitor",
"tier3_completion": "5/5 (100%) lane queue, credential redaction, web UI token dashboard, xAI (Grok) provider, Voyage AI embeddings",
"tier4_completion": "4/4 (100%) gateway lock, shell completion, Tailscale Serve/Funnel, DM pairing codes",
"p4_completion": "1/1 (100%) \u2014 multimodal media pipeline",
"p5_completion": "1/1 (100%) \u2014 GitHub Copilot provider with auto-login",
"p6_completion": "4/4 (100%) \u2014 enhanced media pipeline (image.analyze, outbound attachments, gateway attachments, audio transcription)",
"p7_completion": "6/6 (100%) \u2014 web UI dashboard SPA (dashboard, chat, sessions, settings)",
"p8_completion": "8/8 (100%) \u2014 agent tools (sessions.list/history/create/delete, agents.list, message.send, cron.list/trigger) + gap analysis audit",
"tier1_completion": "5/5 (100%) \u2014 !!think prefix, /verbose command, typing indicators (Discord/WhatsApp), session pruning (TTL), tool groups",
"tier2_completion": "4/4 (100%) \u2014 inbound webhooks, vector memory search, Dockerfile, heartbeat monitor",
"tier3_completion": "5/5 (100%) \u2014 lane queue, credential redaction, web UI token dashboard, xAI (Grok) provider, Voyage AI embeddings",
"tier4_completion": "4/4 (100%) \u2014 gateway lock, shell completion, Tailscale Serve/Funnel, DM pairing codes",
"feature_gap_scorecard": "128/128 match (100%), 0 partial (0%), 0 missing (0%)",
"operator_dx_milestone": "Phase 3 (Live Ops Dashboard): 2/2 plans complete milestone done",
"dashboard_observability": "completed service health graphs + core service log viewer added to web UI via observability RPCs and bounded backend sampling",
"operator_dx_milestone": "Phase 3 (Live Ops Dashboard): 2/2 plans complete \u2014 milestone done",
"dashboard_observability": "completed \u2014 service health graphs + core service log viewer added to web UI via observability RPCs and bounded backend sampling",
"gmail_auth_cli": "flynn gmail-auth command implemented with OAuth2 flow, doctor check, config routed to Telegram",
"gmail_filter_creation": "completed gmail.filter.create tool added with criteria/action validation; gmail-auth requests explicit gmail.settings.basic + gmail.readonly scopes for filter creation and inbox reads",
"toolloop_action_intent_recovery": "completed when a model claims it will execute a tool but emits no tool call, NativeAgent now issues one internal nudge and continues the same turn to execute tools or produce a concrete blocker",
"toolloop_execution_claim_recovery": "completed when a model claims a known tool already succeeded/failed without emitting a tool call, NativeAgent now nudges once and retries the same turn before returning text",
"daily_briefing_google_scope_remediation": "completed calendar.* and tasks.* now append explicit re-auth guidance (`flynn gcal-auth` / `flynn gtasks-auth`) for insufficient-scope errors, and operator runbook includes remediation steps",
"council_tool_timeout_override": "completed ToolExecutor supports per-tool timeout overrides and council.run now uses a 180s timeout to avoid false 30s council timeouts in the tool loop",
"minimal_tui_multiline_paste_mode": "completed minimal TUI now supports `/paste`/`/multiline` multiline compose mode ending with single '.' line, preventing newline truncation for pasted prompts",
"config_profile_consolidation": "completed config/paas.yaml is now generated from canonical config/default.yaml + config/profiles/paas.overlay.yaml with CI-checkable drift detection",
"google_auth_hardening": "completed shared Google OAuth runtime helper + auth store (auth.json), legacy token-file migration, refresh persistence, service-wide doctor checks, and unified `flynn google-auth` command",
"model_router_correctness": "completed fallback paths now avoid duplicate clients, apply retry policy consistently, and reject unsupported OpenAI OAuth tool requests early",
"native_audio_support": "completed smart routing for native audio (Gemini/OpenAI/GitHub) vs Whisper transcription fallback, plus 2026-02-23 arg hydration hardening, tool.args_rewritten audit metric, transient fetch retry/timeout hardening, localhost->127.0.0.1 fallback for transcription endpoint connectivity, and whisper docker-compose entrypoint arg fix for port 18801",
"remaining_phases_completion": "Phase 1: 3/3 (100%) context levels, command registry, memory structure. Phase 2: 3/3 (100%) component registry, confidence routing, history index. Phase 3: 2/2 (100%) adaptive memory/compaction, truthfulness/autonomy hardening",
"deeper_surfaces_behavior_stack_plan": "completed documented a decision-complete balanced-hybrid roadmap for OpenClaw-like end-user surface depth plus integrated behavior semantics with phased scope, acceptance gates, and rollout constraints",
"deeper_surfaces_phase0_ticket_pack": "completed produced an atomic implementation checklist for Phase 0 baseline observability work (audit events, router/gateway emitters, metrics counters, baseline summary tooling, docs sync)",
"deeper_surfaces_phase0_ticket_01": "completed audit schema/logger now capture run lifecycle and reaction decision baseline events (`run.state`, `run.cancel`, `reaction.match`, `reaction.skip`) with regression test coverage",
"deeper_surfaces_phase0_ticket_02": "completed gateway + daemon routing emit run lifecycle/cancel telemetry and reaction match/skip audit events with filter summaries and cancellation latency, plus focused tests",
"deeper_surfaces_phase0_ticket_03": "completed gateway metrics now track run-state outcomes, cancel latency samples, and reaction decision counters with routing/gateway emitters",
"deeper_surfaces_phase0_ticket_04": "completed added phase-0 baseline summary tooling for run outcomes, cancel latency, and reaction decisions with markdown/json CLI output",
"deeper_surfaces_phase0_ticket_05": "completed documented phase-0 telemetry fields/workflow, refreshed architecture/protocol docs, and generated baseline artifacts from a probe log with representative channel + gateway events",
"gmail_filter_creation": "completed \u2014 gmail.filter.create tool added with criteria/action validation; gmail-auth requests explicit gmail.settings.basic + gmail.readonly scopes for filter creation and inbox reads",
"toolloop_action_intent_recovery": "completed \u2014 when a model claims it will execute a tool but emits no tool call, NativeAgent now issues one internal nudge and continues the same turn to execute tools or produce a concrete blocker",
"toolloop_execution_claim_recovery": "completed \u2014 when a model claims a known tool already succeeded/failed without emitting a tool call, NativeAgent now nudges once and retries the same turn before returning text",
"daily_briefing_google_scope_remediation": "completed \u2014 calendar.* and tasks.* now append explicit re-auth guidance (`flynn gcal-auth` / `flynn gtasks-auth`) for insufficient-scope errors, and operator runbook includes remediation steps",
"council_tool_timeout_override": "completed \u2014 ToolExecutor supports per-tool timeout overrides and council.run now uses a 180s timeout to avoid false 30s council timeouts in the tool loop",
"minimal_tui_multiline_paste_mode": "completed \u2014 minimal TUI now supports `/paste`/`/multiline` multiline compose mode ending with single '.' line, preventing newline truncation for pasted prompts",
"config_profile_consolidation": "completed \u2014 config/paas.yaml is now generated from canonical config/default.yaml + config/profiles/paas.overlay.yaml with CI-checkable drift detection",
"google_auth_hardening": "completed \u2014 shared Google OAuth runtime helper + auth store (auth.json), legacy token-file migration, refresh persistence, service-wide doctor checks, and unified `flynn google-auth` command",
"model_router_correctness": "completed \u2014 fallback paths now avoid duplicate clients, apply retry policy consistently, and reject unsupported OpenAI OAuth tool requests early",
"native_audio_support": "completed \u2014 smart routing for native audio (Gemini/OpenAI/GitHub) vs Whisper transcription fallback, plus 2026-02-23 arg hydration hardening, tool.args_rewritten audit metric, transient fetch retry/timeout hardening, localhost->127.0.0.1 fallback for transcription endpoint connectivity, and whisper docker-compose entrypoint arg fix for port 18801",
"remaining_phases_completion": "Phase 1: 3/3 (100%) \u2014 context levels, command registry, memory structure. Phase 2: 3/3 (100%) \u2014 component registry, confidence routing, history index. Phase 3: 2/2 (100%) \u2014 adaptive memory/compaction, truthfulness/autonomy hardening",
"deeper_surfaces_behavior_stack_plan": "completed \u2014 documented a decision-complete balanced-hybrid roadmap for OpenClaw-like end-user surface depth plus integrated behavior semantics with phased scope, acceptance gates, and rollout constraints",
"deeper_surfaces_phase0_ticket_pack": "completed \u2014 produced an atomic implementation checklist for Phase 0 baseline observability work (audit events, router/gateway emitters, metrics counters, baseline summary tooling, docs sync)",
"deeper_surfaces_phase0_ticket_01": "completed \u2014 audit schema/logger now capture run lifecycle and reaction decision baseline events (`run.state`, `run.cancel`, `reaction.match`, `reaction.skip`) with regression test coverage",
"deeper_surfaces_phase0_ticket_02": "completed \u2014 gateway + daemon routing emit run lifecycle/cancel telemetry and reaction match/skip audit events with filter summaries and cancellation latency, plus focused tests",
"deeper_surfaces_phase0_ticket_03": "completed \u2014 gateway metrics now track run-state outcomes, cancel latency samples, and reaction decision counters with routing/gateway emitters",
"deeper_surfaces_phase0_ticket_04": "completed \u2014 added phase-0 baseline summary tooling for run outcomes, cancel latency, and reaction decisions with markdown/json CLI output",
"deeper_surfaces_phase0_ticket_05": "completed \u2014 documented phase-0 telemetry fields/workflow, refreshed architecture/protocol docs, and generated baseline artifacts from a probe log with representative channel + gateway events",
"next_up": "Replace probe baseline artifacts with live audit samples once gateway/channel sessions emit real run/reaction events",
"pi_embedded_canary_spike": "completed added optional pi_embedded backend adapter, canary-safe no-tools routing guard, backend success/fallback latency audit events, and docs/diagram updates while native remains default",
"pi_embedded_evaluation_phase": "completed final decision rollback (applied in runtime config): Window A failed latency/fallback gates (p50 +259ms, p95 +5695ms, fallback 25%, categories: pi_module_interface/empty_assistant_text); Window B remained sample-insufficient; controlled probes verified guard coverage (pi_no_tools_mode/capability_query/attachments_present each hit once)",
"pi_embedded_manual_mode": "completed added persisted runtime backend controls for manual Pi activation/deactivation (`/runtime` preferred, `/backend` alias; `status`, `activate pi`, `deactivate pi`, `use config`) while keeping config-driven default routing",
"openclaw_gateway_first_tui_runtime_unification": "completed shared `/runtime` backend-mode command service across channel router + gateway, plus TUI `/runtime` forwarding through a gateway bridge with daemon/gateway auto-start attach",
"gateway_startup_eaddrinuse_hardening": "completed gateway bind collisions now fail deterministically with explicit error handling and TUI auto-start treats EADDRINUSE as attach race with connect retry"
"pi_embedded_canary_spike": "completed \u2014 added optional pi_embedded backend adapter, canary-safe no-tools routing guard, backend success/fallback latency audit events, and docs/diagram updates while native remains default",
"pi_embedded_evaluation_phase": "completed \u2014 final decision rollback (applied in runtime config): Window A failed latency/fallback gates (p50 +259ms, p95 +5695ms, fallback 25%, categories: pi_module_interface/empty_assistant_text); Window B remained sample-insufficient; controlled probes verified guard coverage (pi_no_tools_mode/capability_query/attachments_present each hit once)",
"pi_embedded_manual_mode": "completed \u2014 added persisted runtime backend controls for manual Pi activation/deactivation (`/runtime` preferred, `/backend` alias; `status`, `activate pi`, `deactivate pi`, `use config`) while keeping config-driven default routing",
"openclaw_gateway_first_tui_runtime_unification": "completed \u2014 shared `/runtime` backend-mode command service across channel router + gateway, plus TUI `/runtime` forwarding through a gateway bridge with daemon/gateway auto-start attach",
"gateway_startup_eaddrinuse_hardening": "completed \u2014 gateway bind collisions now fail deterministically with explicit error handling and TUI auto-start treats EADDRINUSE as attach race with connect retry",
"deeper_surfaces_phase1_run_control": "completed \u2014 interrupt queue mode now enforces latest-wins semantics with channel-path preemption, and gateway emits run_state lifecycle events rendered in the web UI"
},
"soul_md_and_cron_create": {
"date": "2026-02-11",
@@ -6715,7 +6738,7 @@
},
"local-model-message-normalization": {
"date": "2026-02-11",
"summary": "Ollama & llama.cpp tool calling message normalization normalizeMessagesForOllama() converts tool_use/tool_result content blocks to Ollama's native role:tool format, normalizeMessagesForLlamaCpp() converts to OpenAI-style tool_calls arrays with hybrid fallback for GGUF templates that drop role:tool messages.",
"summary": "Ollama & llama.cpp tool calling message normalization \u2014 normalizeMessagesForOllama() converts tool_use/tool_result content blocks to Ollama's native role:tool format, normalizeMessagesForLlamaCpp() converts to OpenAI-style tool_calls arrays with hybrid fallback for GGUF templates that drop role:tool messages.",
"files_modified": [
"src/models/local/ollama.ts",
"src/models/local/ollama.test.ts",
@@ -6734,7 +6757,7 @@
"native-audio-support": {
"status": "completed",
"date": "2026-02-11",
"summary": "Native audio input support voice messages passed directly to audio-capable models (Gemini, OpenAI, GitHub) instead of always transcribing via Whisper. Smart routing decides per-model whether to pass raw audio or transcribe first.",
"summary": "Native audio input support \u2014 voice messages passed directly to audio-capable models (Gemini, OpenAI, GitHub) instead of always transcribing via Whisper. Smart routing decides per-model whether to pass raw audio or transcribe first.",
"phases": {
"audio_transcribe_tool": {
"status": "completed",
@@ -6771,7 +6794,7 @@
},
"tests_and_token_estimation": {
"status": "completed",
"description": "Audio tests for media helpers, audio token estimation (base64→bytes→durationtokens at 32 tokens/sec), supports_audio config override wiring",
"description": "Audio tests for media helpers, audio token estimation (base64\u2192bytes\u2192duration\u2192tokens at 32 tokens/sec), supports_audio config override wiring",
"files_modified": [
"src/models/media.test.ts",
"src/context/tokens.ts",
@@ -6783,7 +6806,7 @@
},
"stopreason-normalization": {
"date": "2026-02-11",
"summary": "Normalize OpenAI/GitHub finish_reason to Flynn stopReason conventions. OpenAI 'stop' 'end_turn', 'length' 'max_tokens', 'tool_calls' with tools 'tool_use', 'tool_calls' without tools 'end_turn'. Fixes premature agent loop exit when falling back to GitHub Copilot (Anthropic API quota exhausted). Agent loop now accepts both 'tool_use' and 'tool_calls' as belt-and-suspenders.",
"summary": "Normalize OpenAI/GitHub finish_reason to Flynn stopReason conventions. OpenAI 'stop' \u2192 'end_turn', 'length' \u2192 'max_tokens', 'tool_calls' with tools \u2192 'tool_use', 'tool_calls' without tools \u2192 'end_turn'. Fixes premature agent loop exit when falling back to GitHub Copilot (Anthropic API quota exhausted). Agent loop now accepts both 'tool_use' and 'tool_calls' as belt-and-suspenders.",
"files_modified": [
"src/models/openai.ts",
"src/models/openai.test.ts",