@botiverse/raft-daemon 0.66.0 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  // src/core.ts
2
- import path18 from "path";
2
+ import path19 from "path";
3
3
  import os8 from "os";
4
4
  import { createRequire as createRequire3 } from "module";
5
5
  import { accessSync } from "fs";
@@ -50,427 +50,420 @@ var PI_BUILTIN_PROVIDER_MODELS_GENERATED = {
50
50
  { id: "deepseek/deepseek-v4-flash", label: "DeepSeek V4 Flash" }
51
51
  ],
52
52
  "minimax": [
53
+ { id: "minimax/MiniMax-M3", label: "MiniMax-M3" },
53
54
  { id: "minimax/MiniMax-M2.7", label: "MiniMax-M2.7" },
54
- { id: "minimax/MiniMax-M2.7-highspeed", label: "MiniMax-M2.7-highspeed" },
55
- { id: "minimax/MiniMax-M3", label: "MiniMax-M3" }
55
+ { id: "minimax/MiniMax-M2.7-highspeed", label: "MiniMax-M2.7-highspeed" }
56
56
  ],
57
57
  "minimax-cn": [
58
+ { id: "minimax-cn/MiniMax-M3", label: "MiniMax-M3" },
58
59
  { id: "minimax-cn/MiniMax-M2.7", label: "MiniMax-M2.7" },
59
- { id: "minimax-cn/MiniMax-M2.7-highspeed", label: "MiniMax-M2.7-highspeed" },
60
- { id: "minimax-cn/MiniMax-M3", label: "MiniMax-M3" }
60
+ { id: "minimax-cn/MiniMax-M2.7-highspeed", label: "MiniMax-M2.7-highspeed" }
61
61
  ],
62
62
  "zai": [
63
+ { id: "zai/glm-5.2", label: "GLM-5.2" },
63
64
  { id: "zai/glm-5.1", label: "GLM-5.1" },
64
- { id: "zai/glm-4.5-air", label: "GLM-4.5-Air" },
65
65
  { id: "zai/glm-4.7", label: "GLM-4.7" },
66
+ { id: "zai/glm-4.5-air", label: "GLM-4.5-Air" },
66
67
  { id: "zai/glm-5-turbo", label: "GLM-5-Turbo" },
67
- { id: "zai/glm-5.2", label: "GLM-5.2" },
68
68
  { id: "zai/glm-5v-turbo", label: "GLM-5V-Turbo" }
69
69
  ],
70
70
  "zai-coding-cn": [
71
+ { id: "zai-coding-cn/glm-5.2", label: "GLM-5.2" },
71
72
  { id: "zai-coding-cn/glm-5.1", label: "GLM-5.1" },
72
- { id: "zai-coding-cn/glm-4.5-air", label: "GLM-4.5-Air" },
73
73
  { id: "zai-coding-cn/glm-4.7", label: "GLM-4.7" },
74
+ { id: "zai-coding-cn/glm-4.5-air", label: "GLM-4.5-Air" },
74
75
  { id: "zai-coding-cn/glm-5-turbo", label: "GLM-5-Turbo" },
75
- { id: "zai-coding-cn/glm-5.2", label: "GLM-5.2" },
76
76
  { id: "zai-coding-cn/glm-5v-turbo", label: "GLM-5V-Turbo" }
77
77
  ],
78
78
  "moonshotai": [
79
- { id: "moonshotai/kimi-k2.6", label: "Kimi K2.6" },
80
- { id: "moonshotai/kimi-k2-0711-preview", label: "Kimi K2 0711" },
81
- { id: "moonshotai/kimi-k2-0905-preview", label: "Kimi K2 0905" },
79
+ { id: "moonshotai/kimi-k2.7-code", label: "Kimi K2.7 Code" },
82
80
  { id: "moonshotai/kimi-k2-thinking", label: "Kimi K2 Thinking" },
81
+ { id: "moonshotai/kimi-k2.7-code-highspeed", label: "Kimi K2.7 Code HighSpeed" },
83
82
  { id: "moonshotai/kimi-k2-thinking-turbo", label: "Kimi K2 Thinking Turbo" },
84
- { id: "moonshotai/kimi-k2-turbo-preview", label: "Kimi K2 Turbo" },
83
+ { id: "moonshotai/kimi-k2-0905-preview", label: "Kimi K2 0905" },
84
+ { id: "moonshotai/kimi-k2-0711-preview", label: "Kimi K2 0711" },
85
+ { id: "moonshotai/kimi-k2.6", label: "Kimi K2.6" },
85
86
  { id: "moonshotai/kimi-k2.5", label: "Kimi K2.5" },
86
- { id: "moonshotai/kimi-k2.7-code", label: "Kimi K2.7 Code" },
87
- { id: "moonshotai/kimi-k2.7-code-highspeed", label: "Kimi K2.7 Code HighSpeed" }
87
+ { id: "moonshotai/kimi-k2-turbo-preview", label: "Kimi K2 Turbo" }
88
88
  ],
89
89
  "moonshotai-cn": [
90
- { id: "moonshotai-cn/kimi-k2.6", label: "Kimi K2.6" },
91
- { id: "moonshotai-cn/kimi-k2-0711-preview", label: "Kimi K2 0711" },
92
- { id: "moonshotai-cn/kimi-k2-0905-preview", label: "Kimi K2 0905" },
90
+ { id: "moonshotai-cn/kimi-k2.7-code", label: "Kimi K2.7 Code" },
93
91
  { id: "moonshotai-cn/kimi-k2-thinking", label: "Kimi K2 Thinking" },
92
+ { id: "moonshotai-cn/kimi-k2.7-code-highspeed", label: "Kimi K2.7 Code HighSpeed" },
94
93
  { id: "moonshotai-cn/kimi-k2-thinking-turbo", label: "Kimi K2 Thinking Turbo" },
95
- { id: "moonshotai-cn/kimi-k2-turbo-preview", label: "Kimi K2 Turbo" },
94
+ { id: "moonshotai-cn/kimi-k2-0905-preview", label: "Kimi K2 0905" },
95
+ { id: "moonshotai-cn/kimi-k2-0711-preview", label: "Kimi K2 0711" },
96
+ { id: "moonshotai-cn/kimi-k2.6", label: "Kimi K2.6" },
96
97
  { id: "moonshotai-cn/kimi-k2.5", label: "Kimi K2.5" },
97
- { id: "moonshotai-cn/kimi-k2.7-code", label: "Kimi K2.7 Code" },
98
- { id: "moonshotai-cn/kimi-k2.7-code-highspeed", label: "Kimi K2.7 Code HighSpeed" }
98
+ { id: "moonshotai-cn/kimi-k2-turbo-preview", label: "Kimi K2 Turbo" }
99
99
  ],
100
100
  "kimi-coding": [
101
- { id: "kimi-coding/kimi-for-coding", label: "Kimi For Coding" },
101
+ { id: "kimi-coding/kimi-k2-thinking", label: "Kimi K2 Thinking" },
102
102
  { id: "kimi-coding/k2p7", label: "Kimi K2.7 Code" },
103
- { id: "kimi-coding/kimi-k2-thinking", label: "Kimi K2 Thinking" }
103
+ { id: "kimi-coding/kimi-for-coding", label: "Kimi For Coding" }
104
104
  ],
105
105
  "openrouter": [
106
- { id: "openrouter/moonshotai/kimi-k2.6", label: "MoonshotAI: Kimi K2.6" },
107
- { id: "openrouter/ai21/jamba-large-1.7", label: "AI21: Jamba Large 1.7" },
108
- { id: "openrouter/amazon/nova-2-lite-v1", label: "Amazon: Nova 2 Lite" },
109
- { id: "openrouter/amazon/nova-lite-v1", label: "Amazon: Nova Lite 1.0" },
110
- { id: "openrouter/amazon/nova-micro-v1", label: "Amazon: Nova Micro 1.0" },
111
- { id: "openrouter/amazon/nova-premier-v1", label: "Amazon: Nova Premier 1.0" },
112
- { id: "openrouter/amazon/nova-pro-v1", label: "Amazon: Nova Pro 1.0" },
113
- { id: "openrouter/anthropic/claude-3-haiku", label: "Anthropic: Claude 3 Haiku" },
114
- { id: "openrouter/anthropic/claude-3.5-haiku", label: "Anthropic: Claude 3.5 Haiku" },
115
106
  { id: "openrouter/anthropic/claude-fable-5", label: "Anthropic: Claude Fable 5" },
116
- { id: "openrouter/anthropic/claude-haiku-4.5", label: "Anthropic: Claude Haiku 4.5" },
117
- { id: "openrouter/anthropic/claude-opus-4", label: "Anthropic: Claude Opus 4" },
118
- { id: "openrouter/anthropic/claude-opus-4.1", label: "Anthropic: Claude Opus 4.1" },
119
- { id: "openrouter/anthropic/claude-opus-4.5", label: "Anthropic: Claude Opus 4.5" },
120
- { id: "openrouter/anthropic/claude-opus-4.6", label: "Anthropic: Claude Opus 4.6" },
121
- { id: "openrouter/anthropic/claude-opus-4.6-fast", label: "Anthropic: Claude Opus 4.6 (Fast)" },
122
- { id: "openrouter/anthropic/claude-opus-4.7", label: "Anthropic: Claude Opus 4.7" },
123
- { id: "openrouter/anthropic/claude-opus-4.7-fast", label: "Anthropic: Claude Opus 4.7 (Fast)" },
107
+ { id: "openrouter/~anthropic/claude-fable-latest", label: "Anthropic: Claude Fable Latest" },
124
108
  { id: "openrouter/anthropic/claude-opus-4.8", label: "Anthropic: Claude Opus 4.8" },
109
+ { id: "openrouter/anthropic/claude-opus-4.7", label: "Anthropic: Claude Opus 4.7" },
110
+ { id: "openrouter/anthropic/claude-opus-4.6", label: "Anthropic: Claude Opus 4.6" },
111
+ { id: "openrouter/anthropic/claude-opus-4.5", label: "Anthropic: Claude Opus 4.5" },
112
+ { id: "openrouter/anthropic/claude-opus-4.1", label: "Anthropic: Claude Opus 4.1" },
113
+ { id: "openrouter/anthropic/claude-opus-4", label: "Anthropic: Claude Opus 4" },
114
+ { id: "openrouter/~anthropic/claude-opus-latest", label: "Anthropic: Claude Opus Latest" },
125
115
  { id: "openrouter/anthropic/claude-opus-4.8-fast", label: "Anthropic: Claude Opus 4.8 (Fast)" },
126
- { id: "openrouter/anthropic/claude-sonnet-4", label: "Anthropic: Claude Sonnet 4" },
127
- { id: "openrouter/anthropic/claude-sonnet-4.5", label: "Anthropic: Claude Sonnet 4.5" },
116
+ { id: "openrouter/anthropic/claude-opus-4.7-fast", label: "Anthropic: Claude Opus 4.7 (Fast)" },
117
+ { id: "openrouter/anthropic/claude-sonnet-5", label: "Anthropic: Claude Sonnet 5" },
128
118
  { id: "openrouter/anthropic/claude-sonnet-4.6", label: "Anthropic: Claude Sonnet 4.6" },
129
- { id: "openrouter/arcee-ai/trinity-large-thinking", label: "Arcee AI: Trinity Large Thinking" },
130
- { id: "openrouter/arcee-ai/trinity-mini", label: "Arcee AI: Trinity Mini" },
131
- { id: "openrouter/arcee-ai/virtuoso-large", label: "Arcee AI: Virtuoso Large" },
132
- { id: "openrouter/auto", label: "Auto" },
133
- { id: "openrouter/bytedance-seed/seed-1.6", label: "ByteDance Seed: Seed 1.6" },
134
- { id: "openrouter/bytedance-seed/seed-1.6-flash", label: "ByteDance Seed: Seed 1.6 Flash" },
135
- { id: "openrouter/bytedance-seed/seed-2.0-lite", label: "ByteDance Seed: Seed-2.0-Lite" },
136
- { id: "openrouter/bytedance-seed/seed-2.0-mini", label: "ByteDance Seed: Seed-2.0-Mini" },
137
- { id: "openrouter/cohere/command-r-08-2024", label: "Cohere: Command R (08-2024)" },
138
- { id: "openrouter/cohere/command-r-plus-08-2024", label: "Cohere: Command R+ (08-2024)" },
139
- { id: "openrouter/cohere/north-mini-code:free", label: "Cohere: North Mini Code (free)" },
140
- { id: "openrouter/deepseek/deepseek-chat", label: "DeepSeek: DeepSeek V3" },
141
- { id: "openrouter/deepseek/deepseek-chat-v3-0324", label: "DeepSeek: DeepSeek V3 0324" },
142
- { id: "openrouter/deepseek/deepseek-chat-v3.1", label: "DeepSeek: DeepSeek V3.1" },
143
- { id: "openrouter/deepseek/deepseek-r1", label: "DeepSeek: R1" },
144
- { id: "openrouter/deepseek/deepseek-r1-0528", label: "DeepSeek: R1 0528" },
145
- { id: "openrouter/deepseek/deepseek-v3.1-terminus", label: "DeepSeek: DeepSeek V3.1 Terminus" },
146
- { id: "openrouter/deepseek/deepseek-v3.2", label: "DeepSeek: DeepSeek V3.2" },
147
- { id: "openrouter/deepseek/deepseek-v3.2-exp", label: "DeepSeek: DeepSeek V3.2 Exp" },
148
- { id: "openrouter/deepseek/deepseek-v4-flash", label: "DeepSeek: DeepSeek V4 Flash" },
149
- { id: "openrouter/deepseek/deepseek-v4-pro", label: "DeepSeek: DeepSeek V4 Pro" },
150
- { id: "openrouter/essentialai/rnj-1-instruct", label: "EssentialAI: Rnj 1 Instruct" },
151
- { id: "openrouter/google/gemini-2.5-flash", label: "Google: Gemini 2.5 Flash" },
152
- { id: "openrouter/google/gemini-2.5-flash-lite", label: "Google: Gemini 2.5 Flash Lite" },
153
- { id: "openrouter/google/gemini-2.5-flash-lite-preview-09-2025", label: "Google: Gemini 2.5 Flash Lite Preview 09-2025" },
154
- { id: "openrouter/google/gemini-2.5-pro", label: "Google: Gemini 2.5 Pro" },
119
+ { id: "openrouter/anthropic/claude-sonnet-4.5", label: "Anthropic: Claude Sonnet 4.5" },
120
+ { id: "openrouter/anthropic/claude-sonnet-4", label: "Anthropic: Claude Sonnet 4" },
121
+ { id: "openrouter/~anthropic/claude-sonnet-latest", label: "Anthropic Claude Sonnet Latest" },
122
+ { id: "openrouter/anthropic/claude-haiku-4.5", label: "Anthropic: Claude Haiku 4.5" },
123
+ { id: "openrouter/anthropic/claude-3-haiku", label: "Anthropic: Claude 3 Haiku" },
124
+ { id: "openrouter/~anthropic/claude-haiku-latest", label: "Anthropic Claude Haiku Latest" },
125
+ { id: "openrouter/openai/gpt-5.1-codex-max", label: "OpenAI: GPT-5.1-Codex-Max" },
126
+ { id: "openrouter/kwaipilot/kat-coder-pro-v2", label: "Kwaipilot: KAT-Coder-Pro V2" },
127
+ { id: "openrouter/qwen/qwen3-max-thinking", label: "Qwen: Qwen3 Max Thinking" },
128
+ { id: "openrouter/nvidia/nemotron-3-ultra-550b-a55b", label: "NVIDIA: Nemotron 3 Ultra" },
155
129
  { id: "openrouter/google/gemini-2.5-pro-preview", label: "Google: Gemini 2.5 Pro Preview 06-05" },
156
130
  { id: "openrouter/google/gemini-2.5-pro-preview-05-06", label: "Google: Gemini 2.5 Pro Preview 05-06" },
157
- { id: "openrouter/google/gemini-3-flash-preview", label: "Google: Gemini 3 Flash Preview" },
158
- { id: "openrouter/google/gemini-3-pro-image", label: "Google: Nano Banana Pro (Gemini 3 Pro Image)" },
159
- { id: "openrouter/google/gemini-3.1-flash-lite", label: "Google: Gemini 3.1 Flash Lite" },
160
- { id: "openrouter/google/gemini-3.1-flash-lite-preview", label: "Google: Gemini 3.1 Flash Lite Preview" },
131
+ { id: "openrouter/openai/gpt-5.5-pro", label: "OpenAI: GPT-5.5 Pro" },
132
+ { id: "openrouter/openai/gpt-5.4-pro", label: "OpenAI: GPT-5.4 Pro" },
133
+ { id: "openrouter/openai/gpt-5.2-pro", label: "OpenAI: GPT-5.2 Pro" },
134
+ { id: "openrouter/openai/gpt-5-pro", label: "OpenAI: GPT-5 Pro" },
135
+ { id: "openrouter/deepseek/deepseek-v4-pro", label: "DeepSeek: DeepSeek V4 Pro" },
136
+ { id: "openrouter/qwen/qwen3.7-max", label: "Qwen: Qwen3.7 Max" },
137
+ { id: "openrouter/qwen/qwen3.6-max-preview", label: "Qwen: Qwen3.6 Max Preview" },
161
138
  { id: "openrouter/google/gemini-3.1-pro-preview", label: "Google: Gemini 3.1 Pro Preview" },
162
139
  { id: "openrouter/google/gemini-3.1-pro-preview-customtools", label: "Google: Gemini 3.1 Pro Preview Custom Tools" },
163
- { id: "openrouter/google/gemini-3.5-flash", label: "Google: Gemini 3.5 Flash" },
164
- { id: "openrouter/google/gemma-3-12b-it", label: "Google: Gemma 3 12B" },
140
+ { id: "openrouter/openai/o3-pro", label: "OpenAI: o3 Pro" },
141
+ { id: "openrouter/qwen/qwen3-max", label: "Qwen: Qwen3 Max" },
142
+ { id: "openrouter/upstage/solar-pro-3", label: "Upstage: Solar Pro 3" },
143
+ { id: "openrouter/google/gemini-2.5-pro", label: "Google: Gemini 2.5 Pro" },
144
+ { id: "openrouter/xiaomi/mimo-v2.5-pro", label: "Xiaomi: MiMo-V2.5-Pro" },
145
+ { id: "openrouter/amazon/nova-premier-v1", label: "Amazon: Nova Premier 1.0" },
146
+ { id: "openrouter/amazon/nova-pro-v1", label: "Amazon: Nova Pro 1.0" },
147
+ { id: "openrouter/~google/gemini-pro-latest", label: "Google Gemini Pro Latest" },
148
+ { id: "openrouter/sakana/fugu-ultra", label: "Sakana: Fugu Ultra" },
149
+ { id: "openrouter/arcee-ai/trinity-large-thinking", label: "Arcee AI: Trinity Large Thinking" },
150
+ { id: "openrouter/qwen/qwen3-coder", label: "Qwen: Qwen3 Coder 480B A35B" },
151
+ { id: "openrouter/qwen/qwen3-coder-30b-a3b-instruct", label: "Qwen: Qwen3 Coder 30B A3B Instruct" },
152
+ { id: "openrouter/openai/gpt-5.3-codex", label: "OpenAI: GPT-5.3-Codex" },
153
+ { id: "openrouter/openai/gpt-5.2-codex", label: "OpenAI: GPT-5.2-Codex" },
154
+ { id: "openrouter/openai/gpt-5.1-codex", label: "OpenAI: GPT-5.1-Codex" },
155
+ { id: "openrouter/openai/gpt-5-codex", label: "OpenAI: GPT-5 Codex" },
156
+ { id: "openrouter/qwen/qwen3-coder-next", label: "Qwen: Qwen3 Coder Next" },
157
+ { id: "openrouter/qwen/qwen3-coder-plus", label: "Qwen: Qwen3 Coder Plus" },
158
+ { id: "openrouter/moonshotai/kimi-k2.7-code", label: "MoonshotAI: Kimi K2.7 Code" },
159
+ { id: "openrouter/qwen/qwen3-235b-a22b-thinking-2507", label: "Qwen: Qwen3 235B A22B Thinking 2507" },
160
+ { id: "openrouter/qwen/qwen3-30b-a3b-thinking-2507", label: "Qwen: Qwen3 30B A3B Thinking 2507" },
161
+ { id: "openrouter/qwen/qwen-plus-2025-07-28:thinking", label: "Qwen: Qwen Plus 0728 (thinking)" },
162
+ { id: "openrouter/qwen/qwen3-vl-235b-a22b-thinking", label: "Qwen: Qwen3 VL 235B A22B Thinking" },
163
+ { id: "openrouter/qwen/qwen3-next-80b-a3b-thinking", label: "Qwen: Qwen3 Next 80B A3B Thinking" },
164
+ { id: "openrouter/qwen/qwen3-vl-30b-a3b-thinking", label: "Qwen: Qwen3 VL 30B A3B Thinking" },
165
+ { id: "openrouter/qwen/qwen3-vl-8b-thinking", label: "Qwen: Qwen3 VL 8B Thinking" },
166
+ { id: "openrouter/google/gemini-3-pro-image", label: "Google: Nano Banana Pro (Gemini 3 Pro Image)" },
167
+ { id: "openrouter/moonshotai/kimi-k2-thinking", label: "MoonshotAI: Kimi K2 Thinking" },
168
+ { id: "openrouter/qwen/qwen3-coder-flash", label: "Qwen: Qwen3 Coder Flash" },
169
+ { id: "openrouter/mistralai/mistral-large-2512", label: "Mistral: Mistral Large 3 2512" },
170
+ { id: "openrouter/mistralai/mistral-large-2407", label: "Mistral Large 2407" },
171
+ { id: "openrouter/nvidia/nemotron-3-super-120b-a12b", label: "NVIDIA: Nemotron 3 Super" },
172
+ { id: "openrouter/nvidia/llama-3.3-nemotron-super-49b-v1.5", label: "NVIDIA: Llama 3.3 Nemotron Super 49B V1.5" },
173
+ { id: "openrouter/ai21/jamba-large-1.7", label: "AI21: Jamba Large 1.7" },
174
+ { id: "openrouter/arcee-ai/virtuoso-large", label: "Arcee AI: Virtuoso Large" },
175
+ { id: "openrouter/mistralai/mistral-large", label: "Mistral Large" },
176
+ { id: "openrouter/nvidia/nemotron-3-ultra-550b-a55b:free", label: "NVIDIA: Nemotron 3 Ultra (free)" },
177
+ { id: "openrouter/openai/gpt-5.1-codex-mini", label: "OpenAI: GPT-5.1-Codex-Mini" },
178
+ { id: "openrouter/qwen/qwen3.5-plus-20260420", label: "Qwen: Qwen3.5 Plus 2026-04-20" },
179
+ { id: "openrouter/mistralai/mistral-small-2603", label: "Mistral: Mistral Small 4" },
180
+ { id: "openrouter/mistralai/devstral-2512", label: "Mistral: Devstral 2 2512" },
181
+ { id: "openrouter/mistralai/ministral-14b-2512", label: "Mistral: Ministral 3 14B 2512" },
182
+ { id: "openrouter/mistralai/ministral-3b-2512", label: "Mistral: Ministral 3 3B 2512" },
183
+ { id: "openrouter/mistralai/ministral-8b-2512", label: "Mistral: Ministral 3 8B 2512" },
184
+ { id: "openrouter/mistralai/codestral-2508", label: "Mistral: Codestral 2508" },
185
+ { id: "openrouter/mistralai/voxtral-small-24b-2507", label: "Mistral: Voxtral Small 24B 2507" },
186
+ { id: "openrouter/qwen/qwen3-235b-a22b-2507", label: "Qwen: Qwen3 235B A22B Instruct 2507" },
187
+ { id: "openrouter/qwen/qwen3-30b-a3b-instruct-2507", label: "Qwen: Qwen3 30B A3B Instruct 2507" },
188
+ { id: "openrouter/qwen/qwen3.5-plus-02-15", label: "Qwen: Qwen3.5 Plus 2026-02-15" },
189
+ { id: "openrouter/qwen/qwen-plus-2025-07-28", label: "Qwen: Qwen Plus 0728" },
190
+ { id: "openrouter/openai/gpt-4o-2024-11-20", label: "OpenAI: GPT-4o (2024-11-20)" },
191
+ { id: "openrouter/openai/gpt-4o-2024-08-06", label: "OpenAI: GPT-4o (2024-08-06)" },
192
+ { id: "openrouter/openai/gpt-4o-2024-05-13", label: "OpenAI: GPT-4o (2024-05-13)" },
193
+ { id: "openrouter/moonshotai/kimi-k2-0905", label: "MoonshotAI: Kimi K2 0905" },
194
+ { id: "openrouter/moonshotai/kimi-k2", label: "MoonshotAI: Kimi K2 0711" },
195
+ { id: "openrouter/deepseek/deepseek-r1-0528", label: "DeepSeek: R1 0528" },
196
+ { id: "openrouter/qwen/qwen3-coder:free", label: "Qwen: Qwen3 Coder 480B A35B (free)" },
197
+ { id: "openrouter/qwen/qwen3.5-397b-a17b", label: "Qwen: Qwen3.5 397B A17B" },
198
+ { id: "openrouter/deepseek/deepseek-chat-v3-0324", label: "DeepSeek: DeepSeek V3 0324" },
199
+ { id: "openrouter/qwen/qwen3-235b-a22b", label: "Qwen: Qwen3 235B A22B" },
200
+ { id: "openrouter/qwen/qwen3-vl-235b-a22b-instruct", label: "Qwen: Qwen3 VL 235B A22B Instruct" },
201
+ { id: "openrouter/openai/gpt-oss-120b", label: "OpenAI: gpt-oss-120b" },
202
+ { id: "openrouter/qwen/qwen3-next-80b-a3b-instruct", label: "Qwen: Qwen3 Next 80B A3B Instruct" },
203
+ { id: "openrouter/qwen/qwen-2.5-72b-instruct", label: "Qwen2.5 72B Instruct" },
204
+ { id: "openrouter/meta-llama/llama-3.1-70b-instruct", label: "Meta: Llama 3.1 70B Instruct" },
205
+ { id: "openrouter/meta-llama/llama-3.3-70b-instruct", label: "Meta: Llama 3.3 70B Instruct" },
206
+ { id: "openrouter/sao10k/l3.1-euryale-70b", label: "Sao10K: Llama 3.1 Euryale 70B v2.2" },
207
+ { id: "openrouter/qwen/qwen3.6-35b-a3b", label: "Qwen: Qwen3.6 35B A3B" },
208
+ { id: "openrouter/qwen/qwen3-32b", label: "Qwen: Qwen3 32B" },
209
+ { id: "openrouter/qwen/qwen3-vl-32b-instruct", label: "Qwen: Qwen3 VL 32B Instruct" },
210
+ { id: "openrouter/google/gemma-4-31b-it", label: "Google: Gemma 4 31B" },
211
+ { id: "openrouter/qwen/qwen3-30b-a3b", label: "Qwen: Qwen3 30B A3B" },
212
+ { id: "openrouter/qwen/qwen3-vl-30b-a3b-instruct", label: "Qwen: Qwen3 VL 30B A3B Instruct" },
213
+ { id: "openrouter/cohere/command-r-08-2024", label: "Cohere: Command R (08-2024)" },
214
+ { id: "openrouter/cohere/command-r-plus-08-2024", label: "Cohere: Command R+ (08-2024)" },
165
215
  { id: "openrouter/google/gemma-3-27b-it", label: "Google: Gemma 3 27B" },
216
+ { id: "openrouter/qwen/qwen3.6-27b", label: "Qwen: Qwen3.6 27B" },
166
217
  { id: "openrouter/google/gemma-4-26b-a4b-it", label: "Google: Gemma 4 26B A4B " },
167
- { id: "openrouter/google/gemma-4-26b-a4b-it:free", label: "Google: Gemma 4 26B A4B (free)" },
168
- { id: "openrouter/google/gemma-4-31b-it", label: "Google: Gemma 4 31B" },
169
- { id: "openrouter/google/gemma-4-31b-it:free", label: "Google: Gemma 4 31B (free)" },
218
+ { id: "openrouter/mistralai/mistral-small-3.2-24b-instruct", label: "Mistral: Mistral Small 3.2 24B" },
219
+ { id: "openrouter/mistralai/mixtral-8x22b-instruct", label: "Mistral: Mixtral 8x22B Instruct" },
220
+ { id: "openrouter/openai/gpt-oss-20b", label: "OpenAI: gpt-oss-20b" },
221
+ { id: "openrouter/openai/gpt-oss-safeguard-20b", label: "OpenAI: gpt-oss-safeguard-20b" },
222
+ { id: "openrouter/qwen/qwen3-14b", label: "Qwen: Qwen3 14B" },
223
+ { id: "openrouter/google/gemma-3-12b-it", label: "Google: Gemma 3 12B" },
224
+ { id: "openrouter/thedrummer/unslopnemo-12b", label: "TheDrummer: UnslopNemo 12B" },
225
+ { id: "openrouter/qwen/qwen3.5-122b-a10b", label: "Qwen: Qwen3.5-122B-A10B" },
170
226
  { id: "openrouter/ibm-granite/granite-4.1-8b", label: "IBM: Granite 4.1 8B" },
171
- { id: "openrouter/inception/mercury-2", label: "Inception: Mercury 2" },
172
- { id: "openrouter/inclusionai/ling-2.6-1t", label: "inclusionAI: Ling-2.6-1T" },
173
- { id: "openrouter/inclusionai/ling-2.6-flash", label: "inclusionAI: Ling-2.6-flash" },
174
- { id: "openrouter/inclusionai/ring-2.6-1t", label: "inclusionAI: Ring-2.6-1T" },
175
- { id: "openrouter/kwaipilot/kat-coder-pro-v2", label: "Kwaipilot: KAT-Coder-Pro V2" },
176
- { id: "openrouter/liquid/lfm-2.5-1.2b-thinking:free", label: "LiquidAI: LFM2.5-1.2B-Thinking (free)" },
177
- { id: "openrouter/meta-llama/llama-3.1-70b-instruct", label: "Meta: Llama 3.1 70B Instruct" },
178
227
  { id: "openrouter/meta-llama/llama-3.1-8b-instruct", label: "Meta: Llama 3.1 8B Instruct" },
179
- { id: "openrouter/meta-llama/llama-3.3-70b-instruct", label: "Meta: Llama 3.3 70B Instruct" },
180
- { id: "openrouter/meta-llama/llama-3.3-70b-instruct:free", label: "Meta: Llama 3.3 70B Instruct (free)" },
228
+ { id: "openrouter/qwen/qwen3-8b", label: "Qwen: Qwen3 8B" },
229
+ { id: "openrouter/qwen/qwen3-vl-8b-instruct", label: "Qwen: Qwen3 VL 8B Instruct" },
230
+ { id: "openrouter/qwen/qwen-2.5-7b-instruct", label: "Qwen: Qwen2.5 7B Instruct" },
231
+ { id: "openrouter/openai/gpt-5.5", label: "OpenAI: GPT-5.5" },
232
+ { id: "openrouter/openai/gpt-5.4", label: "OpenAI: GPT-5.4" },
233
+ { id: "openrouter/openai/gpt-5.3-chat", label: "OpenAI: GPT-5.3 Chat" },
234
+ { id: "openrouter/openai/gpt-5.2", label: "OpenAI: GPT-5.2" },
235
+ { id: "openrouter/openai/gpt-5.2-chat", label: "OpenAI: GPT-5.2 Chat" },
236
+ { id: "openrouter/z-ai/glm-5.2", label: "Z.ai: GLM 5.2" },
237
+ { id: "openrouter/openai/gpt-5.1", label: "OpenAI: GPT-5.1" },
238
+ { id: "openrouter/openai/gpt-5.1-chat", label: "OpenAI: GPT-5.1 Chat" },
239
+ { id: "openrouter/z-ai/glm-5.1", label: "Z.ai: GLM 5.1" },
240
+ { id: "openrouter/openai/gpt-5", label: "OpenAI: GPT-5" },
241
+ { id: "openrouter/z-ai/glm-5", label: "Z.ai: GLM 5" },
242
+ { id: "openrouter/x-ai/grok-4.20", label: "xAI: Grok 4.20" },
243
+ { id: "openrouter/z-ai/glm-4.7", label: "Z.ai: GLM 4.7" },
244
+ { id: "openrouter/z-ai/glm-4.6", label: "Z.ai: GLM 4.6" },
245
+ { id: "openrouter/z-ai/glm-4.6v", label: "Z.ai: GLM 4.6V" },
246
+ { id: "openrouter/z-ai/glm-4.5", label: "Z.ai: GLM 4.5" },
247
+ { id: "openrouter/z-ai/glm-4.5-air", label: "Z.ai: GLM 4.5 Air" },
248
+ { id: "openrouter/z-ai/glm-4.5v", label: "Z.ai: GLM 4.5V" },
249
+ { id: "openrouter/x-ai/grok-4.3", label: "xAI: Grok 4.3" },
250
+ { id: "openrouter/openai/gpt-4.1", label: "OpenAI: GPT-4.1" },
181
251
  { id: "openrouter/meta-llama/llama-4-maverick", label: "Meta: Llama 4 Maverick" },
182
252
  { id: "openrouter/meta-llama/llama-4-scout", label: "Meta: Llama 4 Scout" },
183
- { id: "openrouter/minimax/minimax-m1", label: "MiniMax: MiniMax M1" },
184
- { id: "openrouter/minimax/minimax-m2", label: "MiniMax: MiniMax M2" },
185
- { id: "openrouter/minimax/minimax-m2.1", label: "MiniMax: MiniMax M2.1" },
186
- { id: "openrouter/minimax/minimax-m2.5", label: "MiniMax: MiniMax M2.5" },
187
- { id: "openrouter/minimax/minimax-m2.7", label: "MiniMax: MiniMax M2.7" },
188
- { id: "openrouter/minimax/minimax-m3", label: "MiniMax: MiniMax M3" },
189
- { id: "openrouter/mistralai/codestral-2508", label: "Mistral: Codestral 2508" },
190
- { id: "openrouter/mistralai/devstral-2512", label: "Mistral: Devstral 2 2512" },
191
- { id: "openrouter/mistralai/ministral-14b-2512", label: "Mistral: Ministral 3 14B 2512" },
192
- { id: "openrouter/mistralai/ministral-3b-2512", label: "Mistral: Ministral 3 3B 2512" },
193
- { id: "openrouter/mistralai/ministral-8b-2512", label: "Mistral: Ministral 3 8B 2512" },
194
- { id: "openrouter/mistralai/mistral-large", label: "Mistral Large" },
195
- { id: "openrouter/mistralai/mistral-large-2407", label: "Mistral Large 2407" },
196
- { id: "openrouter/mistralai/mistral-large-2512", label: "Mistral: Mistral Large 3 2512" },
197
- { id: "openrouter/mistralai/mistral-medium-3", label: "Mistral: Mistral Medium 3" },
253
+ { id: "openrouter/openai/gpt-4", label: "OpenAI: GPT-4" },
254
+ { id: "openrouter/openai/gpt-4o", label: "OpenAI: GPT-4o" },
255
+ { id: "openrouter/qwen/qwen3.7-plus", label: "Qwen: Qwen3.7 Plus" },
256
+ { id: "openrouter/qwen/qwen3.6-plus", label: "Qwen: Qwen3.6 Plus" },
257
+ { id: "openrouter/qwen/qwen3.5-35b-a3b", label: "Qwen: Qwen3.5-35B-A3B" },
258
+ { id: "openrouter/qwen/qwen3.5-27b", label: "Qwen: Qwen3.5-27B" },
259
+ { id: "openrouter/qwen/qwen3.5-9b", label: "Qwen: Qwen3.5-9B" },
198
260
  { id: "openrouter/mistralai/mistral-medium-3-5", label: "Mistral: Mistral Medium 3.5" },
261
+ { id: "openrouter/deepseek/deepseek-v3.2", label: "DeepSeek: DeepSeek V3.2" },
262
+ { id: "openrouter/deepseek/deepseek-v3.2-exp", label: "DeepSeek: DeepSeek V3.2 Exp" },
263
+ { id: "openrouter/deepseek/deepseek-chat-v3.1", label: "DeepSeek: DeepSeek V3.1" },
264
+ { id: "openrouter/deepseek/deepseek-v3.1-terminus", label: "DeepSeek: DeepSeek V3.1 Terminus" },
199
265
  { id: "openrouter/mistralai/mistral-medium-3.1", label: "Mistral: Mistral Medium 3.1" },
266
+ { id: "openrouter/deepseek/deepseek-chat", label: "DeepSeek: DeepSeek V3" },
267
+ { id: "openrouter/minimax/minimax-m3", label: "MiniMax: MiniMax M3" },
268
+ { id: "openrouter/mistralai/mistral-medium-3", label: "Mistral: Mistral Medium 3" },
269
+ { id: "openrouter/openai/o3", label: "OpenAI: o3" },
270
+ { id: "openrouter/openai/o3-deep-research", label: "OpenAI: o3 Deep Research" },
271
+ { id: "openrouter/tencent/hy3-preview", label: "Tencent: Hy3 preview" },
272
+ { id: "openrouter/minimax/minimax-m2.7", label: "MiniMax: MiniMax M2.7" },
273
+ { id: "openrouter/inclusionai/ling-2.6-1t", label: "inclusionAI: Ling-2.6-1T" },
274
+ { id: "openrouter/inclusionai/ring-2.6-1t", label: "inclusionAI: Ring-2.6-1T" },
275
+ { id: "openrouter/moonshotai/kimi-k2.6", label: "MoonshotAI: Kimi K2.6" },
276
+ { id: "openrouter/minimax/minimax-m2.5", label: "MiniMax: MiniMax M2.5" },
277
+ { id: "openrouter/moonshotai/kimi-k2.5", label: "MoonshotAI: Kimi K2.5" },
278
+ { id: "openrouter/xiaomi/mimo-v2.5", label: "Xiaomi: MiMo-V2.5" },
279
+ { id: "openrouter/minimax/minimax-m2.1", label: "MiniMax: MiniMax M2.1" },
280
+ { id: "openrouter/inception/mercury-2", label: "Inception: Mercury 2" },
281
+ { id: "openrouter/minimax/minimax-m2", label: "MiniMax: MiniMax M2" },
282
+ { id: "openrouter/poolside/laguna-xs.2", label: "Poolside: Laguna XS.2" },
283
+ { id: "openrouter/bytedance-seed/seed-1.6", label: "ByteDance Seed: Seed 1.6" },
284
+ { id: "openrouter/deepseek/deepseek-r1", label: "DeepSeek: R1" },
285
+ { id: "openrouter/minimax/minimax-m1", label: "MiniMax: MiniMax M1" },
286
+ { id: "openrouter/openai/o1", label: "OpenAI: o1" },
287
+ { id: "openrouter/poolside/laguna-m.1", label: "Poolside: Laguna M.1" },
288
+ { id: "openrouter/x-ai/grok-build-0.1", label: "xAI: Grok Build 0.1" },
289
+ { id: "openrouter/auto", label: "Auto" },
290
+ { id: "openrouter/openrouter/auto", label: "Auto Router" },
200
291
  { id: "openrouter/mistralai/mistral-nemo", label: "Mistral: Mistral Nemo" },
201
292
  { id: "openrouter/mistralai/mistral-saba", label: "Mistral: Saba" },
202
- { id: "openrouter/mistralai/mistral-small-2603", label: "Mistral: Mistral Small 4" },
203
- { id: "openrouter/mistralai/mistral-small-3.2-24b-instruct", label: "Mistral: Mistral Small 3.2 24B" },
204
- { id: "openrouter/mistralai/mixtral-8x22b-instruct", label: "Mistral: Mixtral 8x22B Instruct" },
205
- { id: "openrouter/mistralai/voxtral-small-24b-2507", label: "Mistral: Voxtral Small 24B 2507" },
206
- { id: "openrouter/moonshotai/kimi-k2", label: "MoonshotAI: Kimi K2 0711" },
207
- { id: "openrouter/moonshotai/kimi-k2-0905", label: "MoonshotAI: Kimi K2 0905" },
208
- { id: "openrouter/moonshotai/kimi-k2-thinking", label: "MoonshotAI: Kimi K2 Thinking" },
209
- { id: "openrouter/moonshotai/kimi-k2.5", label: "MoonshotAI: Kimi K2.5" },
210
- { id: "openrouter/moonshotai/kimi-k2.7-code", label: "MoonshotAI: Kimi K2.7 Code" },
211
- { id: "openrouter/nex-agi/nex-n2-pro:free", label: "Nex AGI: Nex-N2-Pro (free)" },
212
- { id: "openrouter/nvidia/llama-3.3-nemotron-super-49b-v1.5", label: "NVIDIA: Llama 3.3 Nemotron Super 49B V1.5" },
213
- { id: "openrouter/nvidia/nemotron-3-nano-30b-a3b", label: "NVIDIA: Nemotron 3 Nano 30B A3B" },
214
- { id: "openrouter/nvidia/nemotron-3-nano-30b-a3b:free", label: "NVIDIA: Nemotron 3 Nano 30B A3B (free)" },
215
- { id: "openrouter/nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free", label: "NVIDIA: Nemotron 3 Nano Omni (free)" },
216
- { id: "openrouter/nvidia/nemotron-3-super-120b-a12b", label: "NVIDIA: Nemotron 3 Super" },
217
- { id: "openrouter/nvidia/nemotron-3-super-120b-a12b:free", label: "NVIDIA: Nemotron 3 Super (free)" },
218
- { id: "openrouter/nvidia/nemotron-3-ultra-550b-a55b", label: "NVIDIA: Nemotron 3 Ultra" },
219
- { id: "openrouter/nvidia/nemotron-3-ultra-550b-a55b:free", label: "NVIDIA: Nemotron 3 Ultra (free)" },
220
- { id: "openrouter/nvidia/nemotron-nano-12b-v2-vl:free", label: "NVIDIA: Nemotron Nano 12B 2 VL (free)" },
221
- { id: "openrouter/nvidia/nemotron-nano-9b-v2:free", label: "NVIDIA: Nemotron Nano 9B V2 (free)" },
222
- { id: "openrouter/openai/gpt-3.5-turbo", label: "OpenAI: GPT-3.5 Turbo" },
293
+ { id: "openrouter/~moonshotai/kimi-latest", label: "MoonshotAI Kimi Latest" },
294
+ { id: "openrouter/~openai/gpt-latest", label: "OpenAI GPT Latest" },
295
+ { id: "openrouter/openai/gpt-audio", label: "OpenAI: GPT Audio" },
296
+ { id: "openrouter/openai/gpt-chat-latest", label: "OpenAI: GPT Chat Latest" },
297
+ { id: "openrouter/openrouter/fusion", label: "OpenRouter: Fusion" },
298
+ { id: "openrouter/qwen/qwen-plus", label: "Qwen: Qwen-Plus" },
299
+ { id: "openrouter/rekaai/reka-edge", label: "Reka Edge" },
300
+ { id: "openrouter/relace/relace-search", label: "Relace: Relace Search" },
301
+ { id: "openrouter/liquid/lfm-2.5-1.2b-thinking:free", label: "LiquidAI: LFM2.5-1.2B-Thinking (free)" },
223
302
  { id: "openrouter/openai/gpt-3.5-turbo-0613", label: "OpenAI: GPT-3.5 Turbo (older v0613)" },
224
303
  { id: "openrouter/openai/gpt-3.5-turbo-16k", label: "OpenAI: GPT-3.5 Turbo 16k" },
225
- { id: "openrouter/openai/gpt-4", label: "OpenAI: GPT-4" },
304
+ { id: "openrouter/z-ai/glm-5-turbo", label: "Z.ai: GLM 5 Turbo" },
305
+ { id: "openrouter/z-ai/glm-5v-turbo", label: "Z.ai: GLM 5V Turbo" },
306
+ { id: "openrouter/z-ai/glm-4.7-flash", label: "Z.ai: GLM 4.7 Flash" },
307
+ { id: "openrouter/deepseek/deepseek-v4-flash", label: "DeepSeek: DeepSeek V4 Flash" },
226
308
  { id: "openrouter/openai/gpt-4-turbo", label: "OpenAI: GPT-4 Turbo" },
227
309
  { id: "openrouter/openai/gpt-4-turbo-preview", label: "OpenAI: GPT-4 Turbo Preview" },
228
- { id: "openrouter/openai/gpt-4.1", label: "OpenAI: GPT-4.1" },
229
- { id: "openrouter/openai/gpt-4.1-mini", label: "OpenAI: GPT-4.1 Mini" },
230
- { id: "openrouter/openai/gpt-4.1-nano", label: "OpenAI: GPT-4.1 Nano" },
231
- { id: "openrouter/openai/gpt-4o", label: "OpenAI: GPT-4o" },
232
- { id: "openrouter/openai/gpt-4o-2024-05-13", label: "OpenAI: GPT-4o (2024-05-13)" },
233
- { id: "openrouter/openai/gpt-4o-2024-08-06", label: "OpenAI: GPT-4o (2024-08-06)" },
234
- { id: "openrouter/openai/gpt-4o-2024-11-20", label: "OpenAI: GPT-4o (2024-11-20)" },
235
- { id: "openrouter/openai/gpt-4o-mini", label: "OpenAI: GPT-4o-mini" },
310
+ { id: "openrouter/stepfun/step-3.7-flash", label: "StepFun: Step 3.7 Flash" },
311
+ { id: "openrouter/qwen/qwen3.6-flash", label: "Qwen: Qwen3.6 Flash" },
312
+ { id: "openrouter/google/gemini-3.5-flash", label: "Google: Gemini 3.5 Flash" },
313
+ { id: "openrouter/openai/gpt-3.5-turbo", label: "OpenAI: GPT-3.5 Turbo" },
314
+ { id: "openrouter/qwen/qwen3.5-flash-02-23", label: "Qwen: Qwen3.5-Flash" },
315
+ { id: "openrouter/stepfun/step-3.5-flash", label: "StepFun: Step 3.5 Flash" },
316
+ { id: "openrouter/google/gemini-3-flash-preview", label: "Google: Gemini 3 Flash Preview" },
317
+ { id: "openrouter/inclusionai/ling-2.6-flash", label: "inclusionAI: Ling-2.6-flash" },
318
+ { id: "openrouter/google/gemini-2.5-flash", label: "Google: Gemini 2.5 Flash" },
319
+ { id: "openrouter/bytedance-seed/seed-1.6-flash", label: "ByteDance Seed: Seed 1.6 Flash" },
320
+ { id: "openrouter/~google/gemini-flash-latest", label: "Google Gemini Flash Latest" },
321
+ { id: "openrouter/nvidia/nemotron-3-super-120b-a12b:free", label: "NVIDIA: Nemotron 3 Super (free)" },
236
322
  { id: "openrouter/openai/gpt-4o-mini-2024-07-18", label: "OpenAI: GPT-4o-mini (2024-07-18)" },
237
- { id: "openrouter/openai/gpt-5", label: "OpenAI: GPT-5" },
238
- { id: "openrouter/openai/gpt-5-codex", label: "OpenAI: GPT-5 Codex" },
239
- { id: "openrouter/openai/gpt-5-mini", label: "OpenAI: GPT-5 Mini" },
240
- { id: "openrouter/openai/gpt-5-nano", label: "OpenAI: GPT-5 Nano" },
241
- { id: "openrouter/openai/gpt-5-pro", label: "OpenAI: GPT-5 Pro" },
242
- { id: "openrouter/openai/gpt-5.1", label: "OpenAI: GPT-5.1" },
243
- { id: "openrouter/openai/gpt-5.1-chat", label: "OpenAI: GPT-5.1 Chat" },
244
- { id: "openrouter/openai/gpt-5.1-codex", label: "OpenAI: GPT-5.1-Codex" },
245
- { id: "openrouter/openai/gpt-5.1-codex-max", label: "OpenAI: GPT-5.1-Codex-Max" },
246
- { id: "openrouter/openai/gpt-5.1-codex-mini", label: "OpenAI: GPT-5.1-Codex-Mini" },
247
- { id: "openrouter/openai/gpt-5.2", label: "OpenAI: GPT-5.2" },
248
- { id: "openrouter/openai/gpt-5.2-chat", label: "OpenAI: GPT-5.2 Chat" },
249
- { id: "openrouter/openai/gpt-5.2-codex", label: "OpenAI: GPT-5.2-Codex" },
250
- { id: "openrouter/openai/gpt-5.2-pro", label: "OpenAI: GPT-5.2 Pro" },
251
- { id: "openrouter/openai/gpt-5.3-chat", label: "OpenAI: GPT-5.3 Chat" },
252
- { id: "openrouter/openai/gpt-5.3-codex", label: "OpenAI: GPT-5.3-Codex" },
253
- { id: "openrouter/openai/gpt-5.4", label: "OpenAI: GPT-5.4" },
323
+ { id: "openrouter/nvidia/nemotron-3-nano-30b-a3b", label: "NVIDIA: Nemotron 3 Nano 30B A3B" },
254
324
  { id: "openrouter/openai/gpt-5.4-mini", label: "OpenAI: GPT-5.4 Mini" },
255
325
  { id: "openrouter/openai/gpt-5.4-nano", label: "OpenAI: GPT-5.4 Nano" },
256
- { id: "openrouter/openai/gpt-5.4-pro", label: "OpenAI: GPT-5.4 Pro" },
257
- { id: "openrouter/openai/gpt-5.5", label: "OpenAI: GPT-5.5" },
258
- { id: "openrouter/openai/gpt-5.5-pro", label: "OpenAI: GPT-5.5 Pro" },
259
- { id: "openrouter/openai/gpt-audio", label: "OpenAI: GPT Audio" },
260
- { id: "openrouter/openai/gpt-audio-mini", label: "OpenAI: GPT Audio Mini" },
261
- { id: "openrouter/openai/gpt-chat-latest", label: "OpenAI: GPT Chat Latest" },
262
- { id: "openrouter/openai/gpt-oss-120b", label: "OpenAI: gpt-oss-120b" },
263
- { id: "openrouter/openai/gpt-oss-120b:free", label: "OpenAI: gpt-oss-120b (free)" },
264
- { id: "openrouter/openai/gpt-oss-20b", label: "OpenAI: gpt-oss-20b" },
265
- { id: "openrouter/openai/gpt-oss-20b:free", label: "OpenAI: gpt-oss-20b (free)" },
266
- { id: "openrouter/openai/gpt-oss-safeguard-20b", label: "OpenAI: gpt-oss-safeguard-20b" },
267
- { id: "openrouter/openai/o1", label: "OpenAI: o1" },
268
- { id: "openrouter/openai/o3", label: "OpenAI: o3" },
269
- { id: "openrouter/openai/o3-deep-research", label: "OpenAI: o3 Deep Research" },
270
- { id: "openrouter/openai/o3-mini", label: "OpenAI: o3 Mini" },
271
- { id: "openrouter/openai/o3-mini-high", label: "OpenAI: o3 Mini High" },
272
- { id: "openrouter/openai/o3-pro", label: "OpenAI: o3 Pro" },
326
+ { id: "openrouter/openai/gpt-5-mini", label: "OpenAI: GPT-5 Mini" },
327
+ { id: "openrouter/openai/gpt-5-nano", label: "OpenAI: GPT-5 Nano" },
328
+ { id: "openrouter/openai/gpt-4.1-mini", label: "OpenAI: GPT-4.1 Mini" },
329
+ { id: "openrouter/openai/gpt-4.1-nano", label: "OpenAI: GPT-4.1 Nano" },
330
+ { id: "openrouter/openai/gpt-4o-mini", label: "OpenAI: GPT-4o-mini" },
273
331
  { id: "openrouter/openai/o4-mini", label: "OpenAI: o4 Mini" },
274
332
  { id: "openrouter/openai/o4-mini-deep-research", label: "OpenAI: o4 Mini Deep Research" },
275
333
  { id: "openrouter/openai/o4-mini-high", label: "OpenAI: o4 Mini High" },
276
- { id: "openrouter/openrouter/auto", label: "Auto Router" },
277
- { id: "openrouter/openrouter/free", label: "Free Models Router" },
278
- { id: "openrouter/openrouter/fusion", label: "OpenRouter: Fusion" },
279
- { id: "openrouter/openrouter/owl-alpha", label: "Owl Alpha" },
280
- { id: "openrouter/poolside/laguna-m.1", label: "Poolside: Laguna M.1" },
281
- { id: "openrouter/poolside/laguna-m.1:free", label: "Poolside: Laguna M.1 (free)" },
282
- { id: "openrouter/poolside/laguna-xs.2", label: "Poolside: Laguna XS.2" },
283
- { id: "openrouter/poolside/laguna-xs.2:free", label: "Poolside: Laguna XS.2 (free)" },
284
- { id: "openrouter/prime-intellect/intellect-3", label: "Prime Intellect: INTELLECT-3" },
285
- { id: "openrouter/qwen/qwen-2.5-72b-instruct", label: "Qwen2.5 72B Instruct" },
286
- { id: "openrouter/qwen/qwen-2.5-7b-instruct", label: "Qwen: Qwen2.5 7B Instruct" },
287
- { id: "openrouter/qwen/qwen-plus", label: "Qwen: Qwen-Plus" },
288
- { id: "openrouter/qwen/qwen-plus-2025-07-28", label: "Qwen: Qwen Plus 0728" },
289
- { id: "openrouter/qwen/qwen-plus-2025-07-28:thinking", label: "Qwen: Qwen Plus 0728 (thinking)" },
290
- { id: "openrouter/qwen/qwen3-14b", label: "Qwen: Qwen3 14B" },
291
- { id: "openrouter/qwen/qwen3-235b-a22b", label: "Qwen: Qwen3 235B A22B" },
292
- { id: "openrouter/qwen/qwen3-235b-a22b-2507", label: "Qwen: Qwen3 235B A22B Instruct 2507" },
293
- { id: "openrouter/qwen/qwen3-235b-a22b-thinking-2507", label: "Qwen: Qwen3 235B A22B Thinking 2507" },
294
- { id: "openrouter/qwen/qwen3-30b-a3b", label: "Qwen: Qwen3 30B A3B" },
295
- { id: "openrouter/qwen/qwen3-30b-a3b-instruct-2507", label: "Qwen: Qwen3 30B A3B Instruct 2507" },
296
- { id: "openrouter/qwen/qwen3-30b-a3b-thinking-2507", label: "Qwen: Qwen3 30B A3B Thinking 2507" },
297
- { id: "openrouter/qwen/qwen3-32b", label: "Qwen: Qwen3 32B" },
298
- { id: "openrouter/qwen/qwen3-8b", label: "Qwen: Qwen3 8B" },
299
- { id: "openrouter/qwen/qwen3-coder", label: "Qwen: Qwen3 Coder 480B A35B" },
300
- { id: "openrouter/qwen/qwen3-coder-30b-a3b-instruct", label: "Qwen: Qwen3 Coder 30B A3B Instruct" },
301
- { id: "openrouter/qwen/qwen3-coder-flash", label: "Qwen: Qwen3 Coder Flash" },
302
- { id: "openrouter/qwen/qwen3-coder-next", label: "Qwen: Qwen3 Coder Next" },
303
- { id: "openrouter/qwen/qwen3-coder-plus", label: "Qwen: Qwen3 Coder Plus" },
304
- { id: "openrouter/qwen/qwen3-coder:free", label: "Qwen: Qwen3 Coder 480B A35B (free)" },
305
- { id: "openrouter/qwen/qwen3-max", label: "Qwen: Qwen3 Max" },
306
- { id: "openrouter/qwen/qwen3-max-thinking", label: "Qwen: Qwen3 Max Thinking" },
307
- { id: "openrouter/qwen/qwen3-next-80b-a3b-instruct", label: "Qwen: Qwen3 Next 80B A3B Instruct" },
334
+ { id: "openrouter/openai/o3-mini", label: "OpenAI: o3 Mini" },
335
+ { id: "openrouter/openai/o3-mini-high", label: "OpenAI: o3 Mini High" },
336
+ { id: "openrouter/amazon/nova-2-lite-v1", label: "Amazon: Nova 2 Lite" },
337
+ { id: "openrouter/bytedance-seed/seed-2.0-lite", label: "ByteDance Seed: Seed-2.0-Lite" },
338
+ { id: "openrouter/bytedance-seed/seed-2.0-mini", label: "ByteDance Seed: Seed-2.0-Mini" },
339
+ { id: "openrouter/amazon/nova-lite-v1", label: "Amazon: Nova Lite 1.0" },
340
+ { id: "openrouter/amazon/nova-micro-v1", label: "Amazon: Nova Micro 1.0" },
341
+ { id: "openrouter/arcee-ai/trinity-mini", label: "Arcee AI: Trinity Mini" },
342
+ { id: "openrouter/cohere/north-mini-code:free", label: "Cohere: North Mini Code (free)" },
343
+ { id: "openrouter/~openai/gpt-mini-latest", label: "OpenAI GPT Mini Latest" },
344
+ { id: "openrouter/openai/gpt-audio-mini", label: "OpenAI: GPT Audio Mini" },
345
+ { id: "openrouter/openai/gpt-oss-120b:free", label: "OpenAI: gpt-oss-120b (free)" },
308
346
  { id: "openrouter/qwen/qwen3-next-80b-a3b-instruct:free", label: "Qwen: Qwen3 Next 80B A3B Instruct (free)" },
309
- { id: "openrouter/qwen/qwen3-next-80b-a3b-thinking", label: "Qwen: Qwen3 Next 80B A3B Thinking" },
310
- { id: "openrouter/qwen/qwen3-vl-235b-a22b-instruct", label: "Qwen: Qwen3 VL 235B A22B Instruct" },
311
- { id: "openrouter/qwen/qwen3-vl-235b-a22b-thinking", label: "Qwen: Qwen3 VL 235B A22B Thinking" },
312
- { id: "openrouter/qwen/qwen3-vl-30b-a3b-instruct", label: "Qwen: Qwen3 VL 30B A3B Instruct" },
313
- { id: "openrouter/qwen/qwen3-vl-30b-a3b-thinking", label: "Qwen: Qwen3 VL 30B A3B Thinking" },
314
- { id: "openrouter/qwen/qwen3-vl-32b-instruct", label: "Qwen: Qwen3 VL 32B Instruct" },
315
- { id: "openrouter/qwen/qwen3-vl-8b-instruct", label: "Qwen: Qwen3 VL 8B Instruct" },
316
- { id: "openrouter/qwen/qwen3-vl-8b-thinking", label: "Qwen: Qwen3 VL 8B Thinking" },
317
- { id: "openrouter/qwen/qwen3.5-122b-a10b", label: "Qwen: Qwen3.5-122B-A10B" },
318
- { id: "openrouter/qwen/qwen3.5-27b", label: "Qwen: Qwen3.5-27B" },
319
- { id: "openrouter/qwen/qwen3.5-35b-a3b", label: "Qwen: Qwen3.5-35B-A3B" },
320
- { id: "openrouter/qwen/qwen3.5-397b-a17b", label: "Qwen: Qwen3.5 397B A17B" },
321
- { id: "openrouter/qwen/qwen3.5-9b", label: "Qwen: Qwen3.5-9B" },
322
- { id: "openrouter/qwen/qwen3.5-flash-02-23", label: "Qwen: Qwen3.5-Flash" },
323
- { id: "openrouter/qwen/qwen3.5-plus-02-15", label: "Qwen: Qwen3.5 Plus 2026-02-15" },
324
- { id: "openrouter/qwen/qwen3.5-plus-20260420", label: "Qwen: Qwen3.5 Plus 2026-04-20" },
325
- { id: "openrouter/qwen/qwen3.6-27b", label: "Qwen: Qwen3.6 27B" },
326
- { id: "openrouter/qwen/qwen3.6-35b-a3b", label: "Qwen: Qwen3.6 35B A3B" },
327
- { id: "openrouter/qwen/qwen3.6-flash", label: "Qwen: Qwen3.6 Flash" },
328
- { id: "openrouter/qwen/qwen3.6-max-preview", label: "Qwen: Qwen3.6 Max Preview" },
329
- { id: "openrouter/qwen/qwen3.6-plus", label: "Qwen: Qwen3.6 Plus" },
330
- { id: "openrouter/qwen/qwen3.7-max", label: "Qwen: Qwen3.7 Max" },
331
- { id: "openrouter/qwen/qwen3.7-plus", label: "Qwen: Qwen3.7 Plus" },
332
- { id: "openrouter/rekaai/reka-edge", label: "Reka Edge" },
333
- { id: "openrouter/relace/relace-search", label: "Relace: Relace Search" },
334
- { id: "openrouter/sao10k/l3.1-euryale-70b", label: "Sao10K: Llama 3.1 Euryale 70B v2.2" },
335
- { id: "openrouter/stepfun/step-3.5-flash", label: "StepFun: Step 3.5 Flash" },
336
- { id: "openrouter/stepfun/step-3.7-flash", label: "StepFun: Step 3.7 Flash" },
337
- { id: "openrouter/tencent/hy3-preview", label: "Tencent: Hy3 preview" },
338
- { id: "openrouter/thedrummer/rocinante-12b", label: "TheDrummer: Rocinante 12B" },
339
- { id: "openrouter/thedrummer/unslopnemo-12b", label: "TheDrummer: UnslopNemo 12B" },
340
- { id: "openrouter/upstage/solar-pro-3", label: "Upstage: Solar Pro 3" },
341
- { id: "openrouter/x-ai/grok-4.20", label: "xAI: Grok 4.20" },
342
- { id: "openrouter/x-ai/grok-4.3", label: "xAI: Grok 4.3" },
343
- { id: "openrouter/x-ai/grok-build-0.1", label: "xAI: Grok Build 0.1" },
344
- { id: "openrouter/xiaomi/mimo-v2.5", label: "Xiaomi: MiMo-V2.5" },
345
- { id: "openrouter/xiaomi/mimo-v2.5-pro", label: "Xiaomi: MiMo-V2.5-Pro" },
346
- { id: "openrouter/z-ai/glm-4.5", label: "Z.ai: GLM 4.5" },
347
- { id: "openrouter/z-ai/glm-4.5-air", label: "Z.ai: GLM 4.5 Air" },
348
- { id: "openrouter/z-ai/glm-4.5v", label: "Z.ai: GLM 4.5V" },
349
- { id: "openrouter/z-ai/glm-4.6", label: "Z.ai: GLM 4.6" },
350
- { id: "openrouter/z-ai/glm-4.6v", label: "Z.ai: GLM 4.6V" },
351
- { id: "openrouter/z-ai/glm-4.7", label: "Z.ai: GLM 4.7" },
352
- { id: "openrouter/z-ai/glm-4.7-flash", label: "Z.ai: GLM 4.7 Flash" },
353
- { id: "openrouter/z-ai/glm-5", label: "Z.ai: GLM 5" },
354
- { id: "openrouter/z-ai/glm-5-turbo", label: "Z.ai: GLM 5 Turbo" },
355
- { id: "openrouter/z-ai/glm-5.1", label: "Z.ai: GLM 5.1" },
356
- { id: "openrouter/z-ai/glm-5.2", label: "Z.ai: GLM 5.2" },
357
- { id: "openrouter/~anthropic/claude-fable-latest", label: "Anthropic: Claude Fable Latest" },
358
- { id: "openrouter/~anthropic/claude-haiku-latest", label: "Anthropic Claude Haiku Latest" },
359
- { id: "openrouter/~anthropic/claude-opus-latest", label: "Anthropic: Claude Opus Latest" },
360
- { id: "openrouter/~anthropic/claude-sonnet-latest", label: "Anthropic Claude Sonnet Latest" },
361
- { id: "openrouter/~google/gemini-flash-latest", label: "Google Gemini Flash Latest" },
362
- { id: "openrouter/~google/gemini-pro-latest", label: "Google Gemini Pro Latest" },
363
- { id: "openrouter/~moonshotai/kimi-latest", label: "MoonshotAI Kimi Latest" },
364
- { id: "openrouter/~openai/gpt-latest", label: "OpenAI GPT Latest" },
365
- { id: "openrouter/~openai/gpt-mini-latest", label: "OpenAI GPT Mini Latest" }
366
- ],
367
- "openai": [
368
- { id: "openai/gpt-5.4", label: "GPT-5.4" },
369
- { id: "openai/gpt-4", label: "GPT-4" },
370
- { id: "openai/gpt-4-turbo", label: "GPT-4 Turbo" },
371
- { id: "openai/gpt-4.1", label: "GPT-4.1" },
372
- { id: "openai/gpt-4.1-mini", label: "GPT-4.1 mini" },
373
- { id: "openai/gpt-4.1-nano", label: "GPT-4.1 nano" },
374
- { id: "openai/gpt-4o", label: "GPT-4o" },
375
- { id: "openai/gpt-4o-2024-05-13", label: "GPT-4o (2024-05-13)" },
376
- { id: "openai/gpt-4o-2024-08-06", label: "GPT-4o (2024-08-06)" },
377
- { id: "openai/gpt-4o-2024-11-20", label: "GPT-4o (2024-11-20)" },
378
- { id: "openai/gpt-4o-mini", label: "GPT-4o mini" },
379
- { id: "openai/gpt-5", label: "GPT-5" },
380
- { id: "openai/gpt-5-chat-latest", label: "GPT-5 Chat Latest" },
381
- { id: "openai/gpt-5-codex", label: "GPT-5-Codex" },
382
- { id: "openai/gpt-5-mini", label: "GPT-5 Mini" },
383
- { id: "openai/gpt-5-nano", label: "GPT-5 Nano" },
384
- { id: "openai/gpt-5-pro", label: "GPT-5 Pro" },
385
- { id: "openai/gpt-5.1", label: "GPT-5.1" },
386
- { id: "openai/gpt-5.1-chat-latest", label: "GPT-5.1 Chat" },
387
- { id: "openai/gpt-5.1-codex", label: "GPT-5.1 Codex" },
347
+ { id: "openrouter/meta-llama/llama-3.3-70b-instruct:free", label: "Meta: Llama 3.3 70B Instruct (free)" },
348
+ { id: "openrouter/google/gemma-4-31b-it:free", label: "Google: Gemma 4 31B (free)" },
349
+ { id: "openrouter/nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free", label: "NVIDIA: Nemotron 3 Nano Omni (free)" },
350
+ { id: "openrouter/google/gemma-4-26b-a4b-it:free", label: "Google: Gemma 4 26B A4B (free)" },
351
+ { id: "openrouter/openai/gpt-oss-20b:free", label: "OpenAI: gpt-oss-20b (free)" },
352
+ { id: "openrouter/poolside/laguna-xs.2:free", label: "Poolside: Laguna XS.2 (free)" },
353
+ { id: "openrouter/poolside/laguna-m.1:free", label: "Poolside: Laguna M.1 (free)" },
354
+ { id: "openrouter/openrouter/free", label: "Free Models Router" },
355
+ { id: "openrouter/google/gemini-2.5-flash-lite-preview-09-2025", label: "Google: Gemini 2.5 Flash Lite Preview 09-2025" },
356
+ { id: "openrouter/google/gemini-3.1-flash-lite", label: "Google: Gemini 3.1 Flash Lite" },
357
+ { id: "openrouter/google/gemini-3.1-flash-lite-preview", label: "Google: Gemini 3.1 Flash Lite Preview" },
358
+ { id: "openrouter/google/gemini-2.5-flash-lite", label: "Google: Gemini 2.5 Flash Lite" },
359
+ { id: "openrouter/nvidia/nemotron-3-nano-30b-a3b:free", label: "NVIDIA: Nemotron 3 Nano 30B A3B (free)" },
360
+ { id: "openrouter/nvidia/nemotron-nano-12b-v2-vl:free", label: "NVIDIA: Nemotron Nano 12B 2 VL (free)" },
361
+ { id: "openrouter/nvidia/nemotron-nano-9b-v2:free", label: "NVIDIA: Nemotron Nano 9B V2 (free)" }
362
+ ],
363
+ "openai": [
388
364
  { id: "openai/gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" },
389
- { id: "openai/gpt-5.1-codex-mini", label: "GPT-5.1 Codex mini" },
390
- { id: "openai/gpt-5.2", label: "GPT-5.2" },
391
- { id: "openai/gpt-5.2-chat-latest", label: "GPT-5.2 Chat" },
392
- { id: "openai/gpt-5.2-codex", label: "GPT-5.2 Codex" },
365
+ { id: "openai/gpt-5.5-pro", label: "GPT-5.5 Pro" },
366
+ { id: "openai/gpt-5.4-pro", label: "GPT-5.4 Pro" },
393
367
  { id: "openai/gpt-5.2-pro", label: "GPT-5.2 Pro" },
394
- { id: "openai/gpt-5.3-chat-latest", label: "GPT-5.3 Chat (latest)" },
368
+ { id: "openai/gpt-5-pro", label: "GPT-5 Pro" },
369
+ { id: "openai/o3-pro", label: "o3-pro" },
370
+ { id: "openai/o1-pro", label: "o1-pro" },
395
371
  { id: "openai/gpt-5.3-codex", label: "GPT-5.3 Codex" },
396
372
  { id: "openai/gpt-5.3-codex-spark", label: "GPT-5.3 Codex Spark" },
397
- { id: "openai/gpt-5.4-mini", label: "GPT-5.4 mini" },
398
- { id: "openai/gpt-5.4-nano", label: "GPT-5.4 nano" },
399
- { id: "openai/gpt-5.4-pro", label: "GPT-5.4 Pro" },
373
+ { id: "openai/gpt-5.2-codex", label: "GPT-5.2 Codex" },
374
+ { id: "openai/gpt-5.1-codex", label: "GPT-5.1 Codex" },
375
+ { id: "openai/gpt-5-codex", label: "GPT-5-Codex" },
376
+ { id: "openai/gpt-5.1-codex-mini", label: "GPT-5.1 Codex mini" },
377
+ { id: "openai/gpt-4o-2024-11-20", label: "GPT-4o (2024-11-20)" },
378
+ { id: "openai/gpt-4o-2024-08-06", label: "GPT-4o (2024-08-06)" },
379
+ { id: "openai/gpt-4o-2024-05-13", label: "GPT-4o (2024-05-13)" },
400
380
  { id: "openai/gpt-5.5", label: "GPT-5.5" },
401
- { id: "openai/gpt-5.5-pro", label: "GPT-5.5 Pro" },
402
- { id: "openai/o1", label: "o1" },
403
- { id: "openai/o1-pro", label: "o1-pro" },
381
+ { id: "openai/gpt-5.4", label: "GPT-5.4" },
382
+ { id: "openai/gpt-5.3-chat-latest", label: "GPT-5.3 Chat (latest)" },
383
+ { id: "openai/gpt-5.2", label: "GPT-5.2" },
384
+ { id: "openai/gpt-5.2-chat-latest", label: "GPT-5.2 Chat" },
385
+ { id: "openai/gpt-5.1", label: "GPT-5.1" },
386
+ { id: "openai/gpt-5.1-chat-latest", label: "GPT-5.1 Chat" },
387
+ { id: "openai/gpt-5", label: "GPT-5" },
388
+ { id: "openai/gpt-5-chat-latest", label: "GPT-5 Chat Latest" },
389
+ { id: "openai/gpt-4.1", label: "GPT-4.1" },
390
+ { id: "openai/gpt-4", label: "GPT-4" },
391
+ { id: "openai/gpt-4o", label: "GPT-4o" },
404
392
  { id: "openai/o3", label: "o3" },
405
393
  { id: "openai/o3-deep-research", label: "o3-deep-research" },
406
- { id: "openai/o3-mini", label: "o3-mini" },
407
- { id: "openai/o3-pro", label: "o3-pro" },
394
+ { id: "openai/o1", label: "o1" },
395
+ { id: "openai/gpt-4-turbo", label: "GPT-4 Turbo" },
396
+ { id: "openai/gpt-5.4-mini", label: "GPT-5.4 mini" },
397
+ { id: "openai/gpt-5.4-nano", label: "GPT-5.4 nano" },
398
+ { id: "openai/gpt-5-mini", label: "GPT-5 Mini" },
399
+ { id: "openai/gpt-5-nano", label: "GPT-5 Nano" },
400
+ { id: "openai/gpt-4.1-mini", label: "GPT-4.1 mini" },
401
+ { id: "openai/gpt-4.1-nano", label: "GPT-4.1 nano" },
402
+ { id: "openai/gpt-4o-mini", label: "GPT-4o mini" },
408
403
  { id: "openai/o4-mini", label: "o4-mini" },
409
- { id: "openai/o4-mini-deep-research", label: "o4-mini-deep-research" }
404
+ { id: "openai/o4-mini-deep-research", label: "o4-mini-deep-research" },
405
+ { id: "openai/o3-mini", label: "o3-mini" }
410
406
  ],
411
407
  "anthropic": [
412
- { id: "anthropic/claude-opus-4-8", label: "Claude Opus 4.8" },
413
- { id: "anthropic/claude-3-5-haiku-20241022", label: "Claude Haiku 3.5" },
414
- { id: "anthropic/claude-3-5-haiku-latest", label: "Claude Haiku 3.5 (latest)" },
415
- { id: "anthropic/claude-3-5-sonnet-20240620", label: "Claude Sonnet 3.5" },
416
- { id: "anthropic/claude-3-5-sonnet-20241022", label: "Claude Sonnet 3.5 v2" },
417
- { id: "anthropic/claude-3-7-sonnet-20250219", label: "Claude Sonnet 3.7" },
418
- { id: "anthropic/claude-3-haiku-20240307", label: "Claude Haiku 3" },
419
- { id: "anthropic/claude-3-opus-20240229", label: "Claude Opus 3" },
420
- { id: "anthropic/claude-3-sonnet-20240229", label: "Claude Sonnet 3" },
421
408
  { id: "anthropic/claude-fable-5", label: "Claude Fable 5" },
422
- { id: "anthropic/claude-haiku-4-5", label: "Claude Haiku 4.5 (latest)" },
423
- { id: "anthropic/claude-haiku-4-5-20251001", label: "Claude Haiku 4.5" },
424
- { id: "anthropic/claude-opus-4-0", label: "Claude Opus 4 (latest)" },
425
- { id: "anthropic/claude-opus-4-1", label: "Claude Opus 4.1 (latest)" },
426
- { id: "anthropic/claude-opus-4-1-20250805", label: "Claude Opus 4.1" },
409
+ { id: "anthropic/claude-3-opus-20240229", label: "Claude Opus 3" },
427
410
  { id: "anthropic/claude-opus-4-20250514", label: "Claude Opus 4" },
428
- { id: "anthropic/claude-opus-4-5", label: "Claude Opus 4.5 (latest)" },
429
411
  { id: "anthropic/claude-opus-4-5-20251101", label: "Claude Opus 4.5" },
430
- { id: "anthropic/claude-opus-4-6", label: "Claude Opus 4.6" },
412
+ { id: "anthropic/claude-opus-4-1-20250805", label: "Claude Opus 4.1" },
413
+ { id: "anthropic/claude-opus-4-8", label: "Claude Opus 4.8" },
431
414
  { id: "anthropic/claude-opus-4-7", label: "Claude Opus 4.7" },
432
- { id: "anthropic/claude-sonnet-4-0", label: "Claude Sonnet 4 (latest)" },
415
+ { id: "anthropic/claude-opus-4-6", label: "Claude Opus 4.6" },
416
+ { id: "anthropic/claude-opus-4-5", label: "Claude Opus 4.5 (latest)" },
417
+ { id: "anthropic/claude-opus-4-1", label: "Claude Opus 4.1 (latest)" },
418
+ { id: "anthropic/claude-opus-4-0", label: "Claude Opus 4 (latest)" },
419
+ { id: "anthropic/claude-3-7-sonnet-20250219", label: "Claude Sonnet 3.7" },
420
+ { id: "anthropic/claude-3-5-sonnet-20241022", label: "Claude Sonnet 3.5 v2" },
421
+ { id: "anthropic/claude-3-5-sonnet-20240620", label: "Claude Sonnet 3.5" },
422
+ { id: "anthropic/claude-3-sonnet-20240229", label: "Claude Sonnet 3" },
433
423
  { id: "anthropic/claude-sonnet-4-20250514", label: "Claude Sonnet 4" },
434
- { id: "anthropic/claude-sonnet-4-5", label: "Claude Sonnet 4.5 (latest)" },
435
424
  { id: "anthropic/claude-sonnet-4-5-20250929", label: "Claude Sonnet 4.5" },
436
- { id: "anthropic/claude-sonnet-4-6", label: "Claude Sonnet 4.6" }
425
+ { id: "anthropic/claude-sonnet-5", label: "Claude Sonnet 5" },
426
+ { id: "anthropic/claude-sonnet-4-6", label: "Claude Sonnet 4.6" },
427
+ { id: "anthropic/claude-sonnet-4-5", label: "Claude Sonnet 4.5 (latest)" },
428
+ { id: "anthropic/claude-sonnet-4-0", label: "Claude Sonnet 4 (latest)" },
429
+ { id: "anthropic/claude-3-haiku-20240307", label: "Claude Haiku 3" },
430
+ { id: "anthropic/claude-haiku-4-5-20251001", label: "Claude Haiku 4.5" },
431
+ { id: "anthropic/claude-haiku-4-5", label: "Claude Haiku 4.5 (latest)" }
437
432
  ],
438
433
  "google": [
439
434
  { id: "google/gemini-3.1-pro-preview", label: "Gemini 3.1 Pro Preview" },
440
- { id: "google/gemini-2.0-flash", label: "Gemini 2.0 Flash" },
441
- { id: "google/gemini-2.0-flash-lite", label: "Gemini 2.0 Flash-Lite" },
442
- { id: "google/gemini-2.5-flash", label: "Gemini 2.5 Flash" },
443
- { id: "google/gemini-2.5-flash-lite", label: "Gemini 2.5 Flash-Lite" },
435
+ { id: "google/gemini-3.1-pro-preview-customtools", label: "Gemini 3.1 Pro Preview Custom Tools" },
436
+ { id: "google/gemini-3-pro-preview", label: "Gemini 3 Pro Preview" },
444
437
  { id: "google/gemini-2.5-pro", label: "Gemini 2.5 Pro" },
438
+ { id: "google/gemma-4-31b-it", label: "Gemma 4 31B IT" },
439
+ { id: "google/gemma-4-26b-a4b-it", label: "Gemma 4 26B A4B IT" },
440
+ { id: "google/gemini-3.5-flash", label: "Gemini 3.5 Flash" },
445
441
  { id: "google/gemini-3-flash-preview", label: "Gemini 3 Flash Preview" },
446
- { id: "google/gemini-3-pro-preview", label: "Gemini 3 Pro Preview" },
442
+ { id: "google/gemini-2.5-flash", label: "Gemini 2.5 Flash" },
443
+ { id: "google/gemini-2.0-flash", label: "Gemini 2.0 Flash" },
444
+ { id: "google/gemini-flash-latest", label: "Gemini Flash Latest" },
447
445
  { id: "google/gemini-3.1-flash-lite", label: "Gemini 3.1 Flash Lite" },
448
446
  { id: "google/gemini-3.1-flash-lite-preview", label: "Gemini 3.1 Flash Lite Preview" },
449
- { id: "google/gemini-3.1-pro-preview-customtools", label: "Gemini 3.1 Pro Preview Custom Tools" },
450
- { id: "google/gemini-3.5-flash", label: "Gemini 3.5 Flash" },
451
- { id: "google/gemini-flash-latest", label: "Gemini Flash Latest" },
452
- { id: "google/gemini-flash-lite-latest", label: "Gemini Flash-Lite Latest" },
453
- { id: "google/gemma-4-26b-a4b-it", label: "Gemma 4 26B A4B IT" },
454
- { id: "google/gemma-4-31b-it", label: "Gemma 4 31B IT" },
455
- { id: "google/gemma-4-E2B-it", label: "Gemma 4 E2B IT" },
456
- { id: "google/gemma-4-E4B-it", label: "Gemma 4 E4B IT" }
447
+ { id: "google/gemini-2.5-flash-lite", label: "Gemini 2.5 Flash-Lite" },
448
+ { id: "google/gemini-2.0-flash-lite", label: "Gemini 2.0 Flash-Lite" },
449
+ { id: "google/gemini-flash-lite-latest", label: "Gemini Flash-Lite Latest" }
457
450
  ],
458
451
  "xai": [
459
- { id: "xai/grok-4.20-0309-reasoning", label: "Grok 4.20 (Reasoning)" },
460
- { id: "xai/grok-3", label: "Grok 3" },
461
- { id: "xai/grok-3-fast", label: "Grok 3 Fast" },
462
452
  { id: "xai/grok-4.20-0309-non-reasoning", label: "Grok 4.20 (Non-Reasoning)" },
453
+ { id: "xai/grok-4.20-0309-reasoning", label: "Grok 4.20 (Reasoning)" },
454
+ { id: "xai/grok-code-fast-1", label: "Grok Code Fast 1" },
463
455
  { id: "xai/grok-4.3", label: "Grok 4.3" },
456
+ { id: "xai/grok-3", label: "Grok 3" },
464
457
  { id: "xai/grok-build-0.1", label: "Grok Build 0.1" },
465
- { id: "xai/grok-code-fast-1", label: "Grok Code Fast 1" }
458
+ { id: "xai/grok-3-fast", label: "Grok 3 Fast" }
466
459
  ],
467
460
  "xiaomi": [
468
461
  { id: "xiaomi/mimo-v2.5-pro", label: "MiMo-V2.5-Pro" },
469
- { id: "xiaomi/mimo-v2-flash", label: "MiMo-V2-Flash" },
470
- { id: "xiaomi/mimo-v2-omni", label: "MiMo-V2-Omni" },
462
+ { id: "xiaomi/mimo-v2.5-pro-ultraspeed", label: "MiMo-V2.5-Pro-UltraSpeed" },
471
463
  { id: "xiaomi/mimo-v2-pro", label: "MiMo-V2-Pro" },
472
464
  { id: "xiaomi/mimo-v2.5", label: "MiMo-V2.5" },
473
- { id: "xiaomi/mimo-v2.5-pro-ultraspeed", label: "MiMo-V2.5-Pro-UltraSpeed" }
465
+ { id: "xiaomi/mimo-v2-omni", label: "MiMo-V2-Omni" },
466
+ { id: "xiaomi/mimo-v2-flash", label: "MiMo-V2-Flash" }
474
467
  ]
475
468
  };
476
469
 
@@ -823,7 +816,9 @@ function projectApmHeldFreshnessActivity(input) {
823
816
  const statusEntry = {
824
817
  kind: "status",
825
818
  activity: "working",
819
+ activityKind: "working",
826
820
  detail: title,
821
+ detailKind: "slock_action",
827
822
  producerFactId: input.producerFactId
828
823
  };
829
824
  const entry = {
@@ -2165,6 +2160,9 @@ var agentApiServerInfoResponseSchema = passthroughObject({
2165
2160
  })),
2166
2161
  agents: z2.array(passthroughObject({
2167
2162
  name: z2.string(),
2163
+ status: z2.string().optional(),
2164
+ activity: z2.string().nullable().optional(),
2165
+ activityDetail: z2.string().nullable().optional(),
2168
2166
  role: z2.enum(["owner", "admin", "member"]).nullable().optional()
2169
2167
  })),
2170
2168
  humans: z2.array(passthroughObject({
@@ -3277,6 +3275,45 @@ var BUILTIN_RUNTIME_HOST_PROVIDER_ENV_SCRUB_KEYS = Array.from(/* @__PURE__ */ ne
3277
3275
  var PI_BUILTIN_PROVIDER_MODELS = PI_BUILTIN_PROVIDER_MODELS_GENERATED;
3278
3276
  var AGENT_ACTIVITIES = ["online", "thinking", "working", "error", "offline"];
3279
3277
  var isAgentActivity = makeIsMember(AGENT_ACTIVITIES);
3278
+ var AGENT_ACTIVITY_DETAIL_KINDS = [
3279
+ "none",
3280
+ "message_received",
3281
+ "starting",
3282
+ "runtime_starting",
3283
+ "idle",
3284
+ "running_command",
3285
+ "checking_messages",
3286
+ "compacting_context",
3287
+ "compaction_finished",
3288
+ "compaction_stale",
3289
+ "reviewing_changes",
3290
+ "review_finished",
3291
+ "runtime_reconnecting",
3292
+ "runtime_error",
3293
+ "runtime_crashed",
3294
+ "runtime_unavailable",
3295
+ "runtime_stalled",
3296
+ "stalled_recovery",
3297
+ "stopped",
3298
+ "ready",
3299
+ "runtime_interrupted",
3300
+ "machine_disconnected",
3301
+ "daemon_activity",
3302
+ "external_activity",
3303
+ "synthetic_repair",
3304
+ "slock_action",
3305
+ "system_message",
3306
+ // Generic structured runtime-progress heartbeat (Claude --include-partial-messages
3307
+ // stream events / system status) — a "working" liveness signal with no rendered
3308
+ // content. NOT a subagent. (APM 1.6 6a)
3309
+ "runtime_progress",
3310
+ // A subagent (Claude `Agent` tool) lifecycle/activity row, marked from explicit
3311
+ // parent_tool_use_id / task-lifecycle lineage — never inferred from display text.
3312
+ // (APM 1.6 6b)
3313
+ "subagent_activity",
3314
+ "other"
3315
+ ];
3316
+ var isAgentActivityDetailKind = makeIsMember(AGENT_ACTIVITY_DETAIL_KINDS);
3280
3317
  var VALID_ACTIVITIES = new Set(AGENT_ACTIVITIES);
3281
3318
  var EXTERNAL_AGENT_RUNTIME_ID = "external";
3282
3319
  var EXTERNAL_AGENT_RUNTIME_MODEL = "external";
@@ -3304,13 +3341,15 @@ var RUNTIME_MODELS = {
3304
3341
  builtin: Object.values(PI_BUILTIN_PROVIDER_MODELS).flat().map((model) => ({ id: model.id, label: model.label || formatRuntimeProviderModelLabel(model.id), verified: "launchable" })),
3305
3342
  claude: [
3306
3343
  { id: "opus", label: "Claude Opus" },
3344
+ { id: "fable", label: "Claude Fable" },
3345
+ { id: "sonnet", label: "Claude Sonnet" },
3346
+ { id: "haiku", label: "Claude Haiku" },
3307
3347
  { id: "claude-opus-4-8", label: "Claude Opus 4.8" },
3308
3348
  { id: "claude-opus-4-7", label: "Claude Opus 4.7" },
3309
3349
  { id: "claude-opus-4-6", label: "Claude Opus 4.6" },
3310
- { id: "fable", label: "Claude Fable" },
3311
- { id: "sonnet", label: "Claude Sonnet" },
3350
+ { id: "claude-fable-5", label: "Claude Fable 5" },
3351
+ { id: "claude-sonnet-5", label: "Claude Sonnet 5" },
3312
3352
  { id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6" },
3313
- { id: "haiku", label: "Claude Haiku" },
3314
3353
  { id: "claude-haiku-4-5", label: "Claude Haiku 4.5" }
3315
3354
  ],
3316
3355
  codex: [
@@ -3978,8 +4017,8 @@ async function executeResponseRequest(url, init, {
3978
4017
  }
3979
4018
 
3980
4019
  // src/directUploadCapability.ts
3981
- function joinUrl(base, path19) {
3982
- return `${base.replace(/\/+$/, "")}${path19}`;
4020
+ function joinUrl(base, path20) {
4021
+ return `${base.replace(/\/+$/, "")}${path20}`;
3983
4022
  }
3984
4023
  function jsonHeaders(apiKey) {
3985
4024
  return {
@@ -5062,7 +5101,7 @@ function projectApmRuntimeProgressStalledTrace(input) {
5062
5101
  }
5063
5102
  function projectApmRuntimeStallDiagnostic(input) {
5064
5103
  const context = [];
5065
- const lastActivityDetailKind = classifyApmRuntimeStallActivityDetail(input.lastActivityDetail);
5104
+ const lastActivityDetailKind = input.lastActivityDetail ? input.lastActivityDetailKind : void 0;
5066
5105
  if (input.lastActivityDetail) {
5067
5106
  context.push(`after ${input.lastActivityDetail}`);
5068
5107
  }
@@ -5094,7 +5133,7 @@ function projectApmRuntimeStallDiagnostic(input) {
5094
5133
  traceAttrs: {
5095
5134
  ageMs: input.staleForMs,
5096
5135
  staleForMinutes: input.staleForMinutes,
5097
- lastActivity: input.lastActivity,
5136
+ lastActivity: input.lastActivityKind,
5098
5137
  lastActivityDetailPresent: Boolean(input.lastActivityDetail),
5099
5138
  lastActivityDetailKind,
5100
5139
  runtime: input.runtime,
@@ -5118,20 +5157,6 @@ function projectApmRuntimeStallDiagnostic(input) {
5118
5157
  }
5119
5158
  };
5120
5159
  }
5121
- function classifyApmRuntimeStallActivityDetail(detail) {
5122
- if (!detail) return void 0;
5123
- if (detail === "Message received") return "message_received";
5124
- if (detail === "Starting\u2026") return "starting";
5125
- if (detail === "Running command\u2026") return "running_command";
5126
- if (detail === "Checking messages\u2026") return "checking_messages";
5127
- if (detail === "Compacting context") return "compacting_context";
5128
- if (detail === "Context compaction finished") return "compaction_finished";
5129
- if (detail === "Context compaction still running; no finish event observed") return "compaction_stale";
5130
- if (detail === "Idle" || detail === "Process idle") return "idle";
5131
- if (detail.startsWith("Restarting stalled ") && detail.endsWith(" runtime for queued message")) return "stalled_recovery";
5132
- if (detail.startsWith("Runtime stalled: no runtime events for ")) return "runtime_stalled";
5133
- return "other";
5134
- }
5135
5160
  function reduceApmGatedFlushReadiness(state, input) {
5136
5161
  if (!input.isGated) return { shouldNotify: false, blockedReason: "non_gated", effects: [] };
5137
5162
  if (!input.hasSession) return { shouldNotify: false, blockedReason: "missing_session", effects: [] };
@@ -5858,27 +5883,44 @@ function writeProxyFailureResponse(res, failure) {
5858
5883
  res.destroy();
5859
5884
  return;
5860
5885
  }
5861
- res.writeHead(502, { "content-type": "application/json" });
5862
- res.end(JSON.stringify({
5863
- error: "failed to proxy local agent request",
5864
- code: "agent_proxy_failed",
5886
+ const body = {
5887
+ error: failure.responseError ?? "failed to proxy local agent request",
5888
+ code: failure.responseCode ?? "agent_proxy_failed",
5865
5889
  detail: failure.errorMessage
5866
- }));
5890
+ };
5891
+ if (failure.lifecycleInvalidAgentId) body.agent_id = failure.lifecycleInvalidAgentId;
5892
+ if (failure.lifecycleInvalidContext) body.invariant_context = failure.lifecycleInvalidContext;
5893
+ res.writeHead(failure.responseStatusCode ?? 502, { "content-type": "application/json" });
5894
+ res.end(JSON.stringify(body));
5867
5895
  }
5868
5896
  function proxyFailureForError(method, target, err) {
5869
5897
  const queryKeys = target ? [.../* @__PURE__ */ new Set([...target.searchParams.keys()])].sort() : [];
5870
5898
  const cause = err instanceof Error ? err.cause : void 0;
5899
+ const errorMessage = truncateProxyErrorMessage(err instanceof Error ? err.message : String(err));
5900
+ const lifecycleInvalid = parseAgentNoProcessResidencyInvariant(errorMessage);
5871
5901
  const failure = {
5872
5902
  method,
5873
5903
  pathname: target?.pathname ?? "unknown",
5874
5904
  queryKeys,
5875
5905
  errorName: err instanceof Error ? err.name : typeof err,
5876
- errorMessage: truncateProxyErrorMessage(err instanceof Error ? err.message : String(err))
5906
+ errorMessage
5877
5907
  };
5908
+ if (lifecycleInvalid) {
5909
+ failure.responseStatusCode = 409;
5910
+ failure.responseCode = "agent_lifecycle_state_invalid";
5911
+ failure.responseError = "local daemon agent lifecycle state invalid";
5912
+ failure.lifecycleInvalidAgentId = lifecycleInvalid.agentId;
5913
+ failure.lifecycleInvalidContext = lifecycleInvalid.context;
5914
+ }
5878
5915
  const errorCause = describeProxyErrorCause(cause);
5879
5916
  if (errorCause) failure.errorCause = errorCause;
5880
5917
  return failure;
5881
5918
  }
5919
+ function parseAgentNoProcessResidencyInvariant(message) {
5920
+ const match = /^Agent no-process residency invariant violation after ([^:]+): .+ for ([0-9a-f-]{36})\b/i.exec(message);
5921
+ if (!match) return void 0;
5922
+ return { context: match[1], agentId: match[2] };
5923
+ }
5882
5924
  function describeProxyErrorCause(cause) {
5883
5925
  if (!cause) return void 0;
5884
5926
  if (cause instanceof Error) {
@@ -5915,18 +5957,21 @@ function transportNormalizedErrorForHttpStatus(target, status, launchId) {
5915
5957
  };
5916
5958
  }
5917
5959
  function transportNormalizedErrorForError(target, err, launchId) {
5960
+ const localDaemonStateInvalid = parseAgentNoProcessResidencyInvariant(
5961
+ sanitizeTransportOriginalMessage(err instanceof Error ? err.message : String(err))
5962
+ );
5918
5963
  return {
5919
- normalizedCode: "transport_failure",
5964
+ normalizedCode: localDaemonStateInvalid ? "local_daemon_state_invalid" : "transport_failure",
5920
5965
  routeFamily: routeFamilyForPath(target?.pathname ?? "unknown"),
5921
5966
  responseStarted: false,
5922
- upstreamLayer: target ? upstreamLayerForProxyError(err) : "unknown",
5967
+ upstreamLayer: localDaemonStateInvalid ? "unknown" : target ? upstreamLayerForProxyError(err) : "unknown",
5923
5968
  originalMessage: sanitizeTransportOriginalMessage(err instanceof Error ? err.message : String(err)),
5924
5969
  launchId,
5925
- targetHostClass: target ? daemonUpstreamTargetHostClass(target) : "custom_server",
5970
+ targetHostClass: localDaemonStateInvalid ? "local_daemon" : target ? daemonUpstreamTargetHostClass(target) : "custom_server",
5926
5971
  // Today the local credential proxy is only used by CLI wrappers. If runtime
5927
5972
  // or daemon-internal callers use it later, plumb the caller identity here.
5928
5973
  downstreamCaller: "cli",
5929
- upstream: "server"
5974
+ upstream: localDaemonStateInvalid ? "local_daemon" : "server"
5930
5975
  };
5931
5976
  }
5932
5977
  function routeFamilyForPath(pathname) {
@@ -6423,10 +6468,10 @@ function runtimeContextEnv(config) {
6423
6468
  return {
6424
6469
  ...ctx.agentId ? { SLOCK_CURRENT_AGENT_ID: ctx.agentId } : {},
6425
6470
  ...ctx.serverId ? { SLOCK_CURRENT_SERVER_ID: ctx.serverId } : {},
6426
- ...ctx.machineId ? { SLOCK_CURRENT_COMPUTER_ID: ctx.machineId } : {},
6427
- ...ctx.machineName ? { SLOCK_CURRENT_COMPUTER_NAME: ctx.machineName } : {},
6428
- ...ctx.machineHostname ? { SLOCK_CURRENT_COMPUTER_HOSTNAME: ctx.machineHostname } : {},
6429
- ...ctx.machineOs ? { SLOCK_CURRENT_COMPUTER_OS: ctx.machineOs } : {},
6471
+ ...ctx.machineId ? { RAFT_CURRENT_COMPUTER_ID: ctx.machineId } : {},
6472
+ ...ctx.machineName ? { RAFT_CURRENT_COMPUTER_NAME: ctx.machineName } : {},
6473
+ ...ctx.machineHostname ? { RAFT_CURRENT_COMPUTER_HOSTNAME: ctx.machineHostname } : {},
6474
+ ...ctx.machineOs ? { RAFT_CURRENT_COMPUTER_OS: ctx.machineOs } : {},
6430
6475
  ...ctx.daemonVersion ? { SLOCK_CURRENT_DAEMON_VERSION: ctx.daemonVersion } : {},
6431
6476
  ...ctx.workspacePath ? { SLOCK_CURRENT_WORKSPACE_PATH: ctx.workspacePath } : {}
6432
6477
  };
@@ -6611,6 +6656,28 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
6611
6656
  }
6612
6657
 
6613
6658
  // src/drivers/claudeEventNormalizer.ts
6659
+ function extractSubagentLineage(event) {
6660
+ const parentToolUseId = finiteString(event.parent_tool_use_id);
6661
+ const subagentType = finiteString(event.subagent_type);
6662
+ if (!parentToolUseId && !subagentType) return void 0;
6663
+ return {
6664
+ ...parentToolUseId ? { parentToolUseId } : {},
6665
+ ...subagentType ? { subagentType } : {},
6666
+ phase: "active"
6667
+ };
6668
+ }
6669
+ function taskLifecyclePhase(subtype) {
6670
+ switch (subtype) {
6671
+ case "task_started":
6672
+ return "started";
6673
+ case "task_progress":
6674
+ return "progress";
6675
+ case "task_notification":
6676
+ return "notification";
6677
+ default:
6678
+ return null;
6679
+ }
6680
+ }
6614
6681
  function collectResultErrorDetail(message, fallback) {
6615
6682
  const parts = [];
6616
6683
  if (Array.isArray(message.errors)) {
@@ -6784,6 +6851,25 @@ var ClaudeEventNormalizer = class {
6784
6851
  if (event.subtype === "compact_boundary") {
6785
6852
  events.push({ kind: "compaction_finished" });
6786
6853
  }
6854
+ {
6855
+ const phase = typeof event.subtype === "string" ? taskLifecyclePhase(event.subtype) : null;
6856
+ if (phase) {
6857
+ events.push({
6858
+ kind: "subagent_progress",
6859
+ source: "claude_task_lifecycle",
6860
+ phase,
6861
+ ...finiteString(event.task_id) ? { taskId: finiteString(event.task_id) } : {},
6862
+ // `system` task-lifecycle envelopes carry the outer Agent tool id
6863
+ // as `tool_use_id`; belt-and-suspenders fall back to
6864
+ // `parent_tool_use_id` in case a Claude version names it that way
6865
+ // on the envelope (confirmed field name = tool_use_id, @Huarong).
6866
+ ...finiteString(event.tool_use_id) ?? finiteString(event.parent_tool_use_id) ? { parentToolUseId: finiteString(event.tool_use_id) ?? finiteString(event.parent_tool_use_id) } : {},
6867
+ ...finiteString(event.subagent_type) ? { subagentType: finiteString(event.subagent_type) } : {},
6868
+ ...finiteString(event.last_tool_name) ? { lastToolName: finiteString(event.last_tool_name) } : {},
6869
+ payloadBytes: Buffer.byteLength(line, "utf8")
6870
+ });
6871
+ }
6872
+ }
6787
6873
  break;
6788
6874
  case "stream_event":
6789
6875
  events.push({
@@ -6795,19 +6881,21 @@ var ClaudeEventNormalizer = class {
6795
6881
  break;
6796
6882
  case "assistant": {
6797
6883
  const content = event.message?.content;
6884
+ const subagent = extractSubagentLineage(event);
6885
+ const withLineage = subagent ? { subagent } : {};
6798
6886
  if (Array.isArray(content)) {
6799
6887
  const hasToolUse = content.some((block) => block?.type === "tool_use");
6800
6888
  for (const block of content) {
6801
6889
  if (block.type === "thinking" && block.thinking) {
6802
- events.push({ kind: "thinking", text: block.thinking });
6890
+ events.push({ kind: "thinking", text: block.thinking, ...withLineage });
6803
6891
  } else if (block.type === "text" && block.text) {
6804
6892
  if (isProviderApiFailureText(block.text, hasToolUse)) {
6805
6893
  events.push({ kind: "error", message: block.text });
6806
6894
  } else {
6807
- events.push({ kind: "text", text: block.text });
6895
+ events.push({ kind: "text", text: block.text, ...withLineage });
6808
6896
  }
6809
6897
  } else if (block.type === "tool_use") {
6810
- events.push({ kind: "tool_call", name: block.name || "unknown_tool", input: block.input });
6898
+ events.push({ kind: "tool_call", name: block.name || "unknown_tool", input: block.input, ...withLineage });
6811
6899
  }
6812
6900
  }
6813
6901
  }
@@ -6815,10 +6903,12 @@ var ClaudeEventNormalizer = class {
6815
6903
  }
6816
6904
  case "user": {
6817
6905
  const content = event.message?.content;
6906
+ const subagent = extractSubagentLineage(event);
6907
+ const withLineage = subagent ? { subagent } : {};
6818
6908
  if (Array.isArray(content)) {
6819
6909
  for (const block of content) {
6820
6910
  if (block.type === "tool_result") {
6821
- events.push({ kind: "tool_output", name: block.name || block.tool_use_id || "tool_result" });
6911
+ events.push({ kind: "tool_output", name: block.name || block.tool_use_id || "tool_result", ...withLineage });
6822
6912
  }
6823
6913
  }
6824
6914
  }
@@ -7567,7 +7657,7 @@ function codexNotificationDiagnosticEvent(message) {
7567
7657
  return null;
7568
7658
  }
7569
7659
  const sessionId = codexMessageThreadId(message);
7570
- const path19 = boundedString(params.path);
7660
+ const path20 = boundedString(params.path);
7571
7661
  return {
7572
7662
  kind: "runtime_diagnostic",
7573
7663
  severity: "warning",
@@ -7575,7 +7665,7 @@ function codexNotificationDiagnosticEvent(message) {
7575
7665
  itemType: message.method,
7576
7666
  message: diagnosticMessage,
7577
7667
  ...details ? { details } : {},
7578
- ...path19 ? { path: path19 } : {},
7668
+ ...path20 ? { path: path20 } : {},
7579
7669
  ...params.range !== void 0 ? { range: params.range } : {},
7580
7670
  payloadBytes: payloadBytes(params),
7581
7671
  ...sessionId ? { sessionId } : {}
@@ -10448,6 +10538,7 @@ var OpenCodeDriver = class {
10448
10538
  };
10449
10539
  supportsStdinNotification = false;
10450
10540
  busyDeliveryMode = "none";
10541
+ supportsNativeStandingPrompt = true;
10451
10542
  terminateProcessOnTurnEnd = true;
10452
10543
  deferSpawnUntilMessage = true;
10453
10544
  shouldDeferWakeMessage(message) {
@@ -10830,6 +10921,16 @@ function mapPiAssistantMessageEvent(assistantEvent, state) {
10830
10921
  }
10831
10922
  }
10832
10923
  }
10924
+ function mapPiMessageEndEvent(event) {
10925
+ const message = event.message;
10926
+ if (message?.role !== "assistant" || message.stopReason !== "error") {
10927
+ return [];
10928
+ }
10929
+ return [{
10930
+ kind: "error",
10931
+ message: typeof message.errorMessage === "string" && message.errorMessage.trim() ? message.errorMessage.trim() : "Pi SDK assistant turn ended with an unknown provider error"
10932
+ }];
10933
+ }
10833
10934
  function mapPiSdkEventToParsedEvents(event, state) {
10834
10935
  const events = [];
10835
10936
  pushSessionInitIfNeeded2(state, events);
@@ -10837,7 +10938,6 @@ function mapPiSdkEventToParsedEvents(event, state) {
10837
10938
  case "agent_start":
10838
10939
  case "turn_start":
10839
10940
  case "turn_end":
10840
- case "message_end":
10841
10941
  case "tool_execution_update":
10842
10942
  case "queue_update":
10843
10943
  case "session_info_changed":
@@ -10845,6 +10945,9 @@ function mapPiSdkEventToParsedEvents(event, state) {
10845
10945
  case "auto_retry_start":
10846
10946
  case "auto_retry_end":
10847
10947
  return events;
10948
+ case "message_end":
10949
+ events.push(...mapPiMessageEndEvent(event));
10950
+ return events;
10848
10951
  case "message_start":
10849
10952
  if (event.message.role === "assistant") {
10850
10953
  state.sawTextDelta = false;
@@ -12069,6 +12172,270 @@ var AgentNoProcessResidency = class {
12069
12172
  }
12070
12173
  };
12071
12174
 
12175
+ // src/agentLifecycleRecord.ts
12176
+ var AgentLifecycleRecords = class {
12177
+ idleRestartSnapshots = /* @__PURE__ */ new Map();
12178
+ terminalFailures = /* @__PURE__ */ new Map();
12179
+ activeSpawnFailBackoffs = /* @__PURE__ */ new Map();
12180
+ pendingStartRebinds = /* @__PURE__ */ new Map();
12181
+ pendingSpawnCauses = /* @__PURE__ */ new Map();
12182
+ runtimeErrorFingerprintFences = /* @__PURE__ */ new Map();
12183
+ activityClientSeqs = /* @__PURE__ */ new Map();
12184
+ stopEpochs = /* @__PURE__ */ new Map();
12185
+ recordStop(agentId) {
12186
+ const next = (this.stopEpochs.get(agentId) ?? 0) + 1;
12187
+ this.stopEpochs.set(agentId, next);
12188
+ return next;
12189
+ }
12190
+ stopEpoch(agentId) {
12191
+ return this.stopEpochs.get(agentId) ?? 0;
12192
+ }
12193
+ stopEpochChanged(agentId, epoch) {
12194
+ return this.stopEpoch(agentId) !== epoch;
12195
+ }
12196
+ nextActivityClientSeq(agentId) {
12197
+ const next = (this.activityClientSeqs.get(agentId) ?? 0) + 1;
12198
+ this.activityClientSeqs.set(agentId, next);
12199
+ return next;
12200
+ }
12201
+ deleteActivityClientSeq(agentId) {
12202
+ return this.activityClientSeqs.delete(agentId);
12203
+ }
12204
+ getRestartSnapshot(agentId) {
12205
+ return this.idleRestartSnapshots.get(agentId);
12206
+ }
12207
+ setRestartSnapshot(agentId, snapshot) {
12208
+ this.idleRestartSnapshots.set(agentId, snapshot);
12209
+ }
12210
+ deleteRestartSnapshot(agentId) {
12211
+ return this.idleRestartSnapshots.delete(agentId);
12212
+ }
12213
+ clearRestartSnapshots() {
12214
+ this.idleRestartSnapshots.clear();
12215
+ }
12216
+ restartSnapshotEntries() {
12217
+ return this.idleRestartSnapshots.entries();
12218
+ }
12219
+ restartSnapshotAgentIds() {
12220
+ return this.idleRestartSnapshots.keys();
12221
+ }
12222
+ getTerminalFailure(agentId) {
12223
+ return this.terminalFailures.get(agentId);
12224
+ }
12225
+ setTerminalFailure(agentId, failure) {
12226
+ this.terminalFailures.set(agentId, failure);
12227
+ }
12228
+ deleteTerminalFailure(agentId) {
12229
+ return this.terminalFailures.delete(agentId);
12230
+ }
12231
+ terminalFailureAgentIds() {
12232
+ return this.terminalFailures.keys();
12233
+ }
12234
+ getSpawnFailBackoff(agentId) {
12235
+ return this.activeSpawnFailBackoffs.get(agentId);
12236
+ }
12237
+ getOrCreateSpawnFailBackoff(agentId, create) {
12238
+ let state = this.activeSpawnFailBackoffs.get(agentId);
12239
+ if (!state) {
12240
+ state = create();
12241
+ this.activeSpawnFailBackoffs.set(agentId, state);
12242
+ }
12243
+ return state;
12244
+ }
12245
+ deleteSpawnFailBackoff(agentId) {
12246
+ return this.activeSpawnFailBackoffs.delete(agentId);
12247
+ }
12248
+ activeSpawnFailBackoffAgentIds(now, isActive) {
12249
+ return [...this.activeSpawnFailBackoffs.entries()].filter(([, state]) => isActive(state, now)).map(([agentId]) => agentId);
12250
+ }
12251
+ getPendingStartRebind(agentId) {
12252
+ return this.pendingStartRebinds.get(agentId);
12253
+ }
12254
+ setPendingStartRebind(agentId, start) {
12255
+ this.pendingStartRebinds.set(agentId, start);
12256
+ }
12257
+ deletePendingStartRebind(agentId) {
12258
+ return this.pendingStartRebinds.delete(agentId);
12259
+ }
12260
+ getPendingSpawnCause(agentId) {
12261
+ return this.pendingSpawnCauses.get(agentId);
12262
+ }
12263
+ setPendingSpawnCause(agentId, cause) {
12264
+ this.pendingSpawnCauses.set(agentId, cause);
12265
+ }
12266
+ deletePendingSpawnCause(agentId) {
12267
+ return this.pendingSpawnCauses.delete(agentId);
12268
+ }
12269
+ getRuntimeErrorFingerprintFence(agentId) {
12270
+ return this.runtimeErrorFingerprintFences.get(agentId);
12271
+ }
12272
+ setRuntimeErrorFingerprintFence(agentId, fence) {
12273
+ this.runtimeErrorFingerprintFences.set(agentId, fence);
12274
+ }
12275
+ deleteRuntimeErrorFingerprintFence(agentId) {
12276
+ return this.runtimeErrorFingerprintFences.delete(agentId);
12277
+ }
12278
+ runtimeErrorFingerprintFenceAgentIds() {
12279
+ return this.runtimeErrorFingerprintFences.keys();
12280
+ }
12281
+ snapshot(args) {
12282
+ return {
12283
+ runningAgentIds: args.runningAgentIds,
12284
+ queuedAgentIds: args.queuedAgentIds,
12285
+ startingAgentIds: args.startingAgentIds,
12286
+ idleRestartSnapshots: [...this.idleRestartSnapshots.entries()],
12287
+ terminalFailures: [...this.terminalFailures.entries()],
12288
+ activeSpawnFailBackoffs: [...this.activeSpawnFailBackoffs.entries()].filter(([, state]) => args.isSpawnFailBackoffActive(state, args.now)),
12289
+ pendingStartRebinds: [...this.pendingStartRebinds.entries()],
12290
+ pendingSpawnCauses: [...this.pendingSpawnCauses.entries()],
12291
+ runtimeErrorFingerprintFences: [...this.runtimeErrorFingerprintFences.entries()],
12292
+ activityClientSeqs: [...this.activityClientSeqs.entries()]
12293
+ };
12294
+ }
12295
+ assertInvariants(context, snapshot) {
12296
+ assertAgentLifecycleRecordInvariants(context, snapshot);
12297
+ }
12298
+ };
12299
+ function buildAgentLifecycleRecords(snapshot) {
12300
+ const running = new Set(snapshot.runningAgentIds);
12301
+ const queued = new Set(snapshot.queuedAgentIds);
12302
+ const starting = new Set(snapshot.startingAgentIds);
12303
+ const facts = /* @__PURE__ */ new Map();
12304
+ for (const agentId of snapshot.runningAgentIds) {
12305
+ factsFor(facts, agentId);
12306
+ }
12307
+ for (const agentId of snapshot.queuedAgentIds) {
12308
+ factsFor(facts, agentId);
12309
+ }
12310
+ for (const agentId of snapshot.startingAgentIds) {
12311
+ factsFor(facts, agentId);
12312
+ }
12313
+ for (const [agentId, restartSnapshot] of snapshot.idleRestartSnapshots) {
12314
+ factsFor(facts, agentId).restartSnapshot = restartSnapshot;
12315
+ }
12316
+ for (const [agentId, failure] of snapshot.terminalFailures) {
12317
+ factsFor(facts, agentId).terminalFailure = failure;
12318
+ }
12319
+ for (const [agentId, backoff] of snapshot.activeSpawnFailBackoffs) {
12320
+ factsFor(facts, agentId).activeSpawnFailBackoff = backoff;
12321
+ }
12322
+ for (const [agentId, pendingStartRebind] of snapshot.pendingStartRebinds) {
12323
+ factsFor(facts, agentId).pendingStartRebind = pendingStartRebind;
12324
+ }
12325
+ for (const [agentId, cause] of snapshot.pendingSpawnCauses) {
12326
+ factsFor(facts, agentId).pendingSpawnCause = cause;
12327
+ }
12328
+ for (const [agentId, fence] of snapshot.runtimeErrorFingerprintFences) {
12329
+ factsFor(facts, agentId).runtimeErrorFingerprintFence = fence;
12330
+ }
12331
+ for (const [agentId, seq] of snapshot.activityClientSeqs) {
12332
+ factsFor(facts, agentId).activityClientSeq = seq;
12333
+ }
12334
+ const records = /* @__PURE__ */ new Map();
12335
+ for (const [agentId, agentFacts] of facts) {
12336
+ if (queued.has(agentId) && starting.has(agentId)) {
12337
+ throw new Error(`queued and starting facts overlap for ${agentId}`);
12338
+ }
12339
+ if (agentFacts.terminalFailure) {
12340
+ assertTerminalRecordFacts(agentId, agentFacts, running.has(agentId));
12341
+ records.set(agentId, {
12342
+ kind: "terminal",
12343
+ agentId,
12344
+ terminalFailure: agentFacts.terminalFailure,
12345
+ fingerprintFence: agentFacts.runtimeErrorFingerprintFence,
12346
+ activityClientSeq: agentFacts.activityClientSeq
12347
+ });
12348
+ continue;
12349
+ }
12350
+ if (agentFacts.activeSpawnFailBackoff !== void 0) {
12351
+ if (running.has(agentId)) {
12352
+ throw new Error(`running process and active cooldown both present for ${agentId}`);
12353
+ }
12354
+ if (!agentFacts.restartSnapshot) {
12355
+ throw new Error(`active cooldown without restart config for ${agentId}`);
12356
+ }
12357
+ records.set(agentId, {
12358
+ kind: "cooldown",
12359
+ agentId,
12360
+ restartSnapshot: agentFacts.restartSnapshot,
12361
+ spawnFailBackoff: agentFacts.activeSpawnFailBackoff,
12362
+ fingerprintFence: agentFacts.runtimeErrorFingerprintFence,
12363
+ activityClientSeq: agentFacts.activityClientSeq
12364
+ });
12365
+ continue;
12366
+ }
12367
+ if (running.has(agentId)) {
12368
+ records.set(agentId, {
12369
+ kind: "running",
12370
+ agentId,
12371
+ restartSnapshot: agentFacts.restartSnapshot,
12372
+ pendingStartRebind: agentFacts.pendingStartRebind,
12373
+ pendingSpawnCause: agentFacts.pendingSpawnCause,
12374
+ fingerprintFence: agentFacts.runtimeErrorFingerprintFence,
12375
+ activityClientSeq: agentFacts.activityClientSeq
12376
+ });
12377
+ continue;
12378
+ }
12379
+ if (starting.has(agentId)) {
12380
+ records.set(agentId, {
12381
+ kind: "starting",
12382
+ agentId,
12383
+ restartSnapshot: agentFacts.restartSnapshot,
12384
+ pendingStartRebind: agentFacts.pendingStartRebind,
12385
+ activityClientSeq: agentFacts.activityClientSeq
12386
+ });
12387
+ continue;
12388
+ }
12389
+ if (queued.has(agentId)) {
12390
+ records.set(agentId, {
12391
+ kind: "queued",
12392
+ agentId,
12393
+ restartSnapshot: agentFacts.restartSnapshot,
12394
+ pendingStartRebind: agentFacts.pendingStartRebind,
12395
+ activityClientSeq: agentFacts.activityClientSeq
12396
+ });
12397
+ continue;
12398
+ }
12399
+ if (agentFacts.restartSnapshot) {
12400
+ records.set(agentId, {
12401
+ kind: "idle",
12402
+ agentId,
12403
+ restartSnapshot: agentFacts.restartSnapshot,
12404
+ fingerprintFence: agentFacts.runtimeErrorFingerprintFence,
12405
+ activityClientSeq: agentFacts.activityClientSeq
12406
+ });
12407
+ }
12408
+ }
12409
+ return records;
12410
+ }
12411
+ function assertAgentLifecycleRecordInvariants(context, snapshot) {
12412
+ try {
12413
+ buildAgentLifecycleRecords(snapshot);
12414
+ } catch (err) {
12415
+ const detail = err instanceof Error ? err.message : String(err);
12416
+ throw new Error(`Agent lifecycle record invariant violation after ${context}: ${detail}`);
12417
+ }
12418
+ }
12419
+ function factsFor(facts, agentId) {
12420
+ let value = facts.get(agentId);
12421
+ if (!value) {
12422
+ value = {};
12423
+ facts.set(agentId, value);
12424
+ }
12425
+ return value;
12426
+ }
12427
+ function assertTerminalRecordFacts(agentId, facts, isRunning) {
12428
+ if (isRunning) {
12429
+ throw new Error(`terminal failure while process is still registered for ${agentId}`);
12430
+ }
12431
+ if (facts.restartSnapshot) {
12432
+ throw new Error(`terminal failure and idle restart config both present for ${agentId}`);
12433
+ }
12434
+ if (facts.pendingStartRebind) {
12435
+ throw new Error(`terminal failure and pending start rebind both present for ${agentId}`);
12436
+ }
12437
+ }
12438
+
12072
12439
  // src/launchPhaseTransition.ts
12073
12440
  var LAUNCH_RUNTIME_READINESS_TRANSITION_SPAN = "launch_runtime_readiness_transition";
12074
12441
  function launchReadinessNegativeEvidence(identity) {
@@ -12342,7 +12709,7 @@ function buildRuntimeErrorDiagnosticEnvelope(message) {
12342
12709
  const httpStatus = extractHttpStatus(rawMessage);
12343
12710
  const runtimeErrorClass = classifyRuntimeError(rawMessage, httpStatus);
12344
12711
  const runtimeErrorReason = classifyRuntimeErrorReason(runtimeErrorClass);
12345
- const runtimeErrorAction = classifyRuntimeErrorAction(rawMessage, runtimeErrorClass);
12712
+ const runtimeErrorAction = classifyRuntimeErrorAction(runtimeErrorClass);
12346
12713
  const fingerprint = fingerprintRuntimeError(scrubbed);
12347
12714
  const spanAttrs = {
12348
12715
  turn_outcome: "failed",
@@ -12368,6 +12735,9 @@ function buildRuntimeErrorDiagnosticEnvelope(message) {
12368
12735
  };
12369
12736
  }
12370
12737
  function formatRuntimeLoginRequiredMessage(runtimeId) {
12738
+ if (runtimeId === "builtin") {
12739
+ return "Built-in provider authentication failed. Check this agent's provider API key and region/provider selection, then retry starting this agent.";
12740
+ }
12371
12741
  const runtimeLabel = runtimeDisplayName(runtimeId);
12372
12742
  return `${runtimeLabel} is not logged in on this machine. Please log in to ${runtimeLabel} locally, then retry starting this agent.`;
12373
12743
  }
@@ -12411,8 +12781,8 @@ function classifyRuntimeError(message, httpStatus) {
12411
12781
  if (/\bnot found\b/i.test(message)) return "NotFoundError";
12412
12782
  return "RuntimeError";
12413
12783
  }
12414
- function classifyRuntimeErrorAction(message, runtimeErrorClass) {
12415
- if (runtimeErrorClass === "AuthError" && isRuntimeAuthActionRequiredText(message)) {
12784
+ function classifyRuntimeErrorAction(runtimeErrorClass) {
12785
+ if (runtimeErrorClass === "AuthError") {
12416
12786
  return "user_reauth";
12417
12787
  }
12418
12788
  return "none";
@@ -12464,6 +12834,8 @@ function runtimeDisplayName(runtimeId) {
12464
12834
  return "OpenCode";
12465
12835
  case "pi":
12466
12836
  return "Pi";
12837
+ case "builtin":
12838
+ return "Built-in";
12467
12839
  default:
12468
12840
  return runtimeId || "This runtime";
12469
12841
  }
@@ -12722,6 +13094,36 @@ var WORKSPACE_IMAGE_MIME_BY_EXTENSION = {
12722
13094
  ".png": "image/png",
12723
13095
  ".webp": "image/webp"
12724
13096
  };
13097
+ var WORKSPACE_NEVER_VISIBLE_HIDDEN_NAMES = /* @__PURE__ */ new Set([
13098
+ ".aws",
13099
+ ".gnupg",
13100
+ ".ssh",
13101
+ ".slock",
13102
+ ".slock-runtime"
13103
+ ]);
13104
+ var WORKSPACE_SECRET_FILE_PATTERNS = [
13105
+ /^\.env(?:\.|$)/i,
13106
+ /(?:^|[._-])secret(?:s)?(?:[._-]|$)/i,
13107
+ /(?:^|[._-])credential(?:s)?(?:[._-]|$)/i,
13108
+ /(?:^|[._-])token(?:s)?(?:[._-]|$)/i
13109
+ ];
13110
+ function isWorkspaceNeverVisibleHiddenEntry(name) {
13111
+ return WORKSPACE_NEVER_VISIBLE_HIDDEN_NAMES.has(name) || name.startsWith(".slock-");
13112
+ }
13113
+ function workspacePathParts(relativePath) {
13114
+ return relativePath.split(path14.sep).filter(Boolean);
13115
+ }
13116
+ function isWorkspaceHiddenPath(relativePath) {
13117
+ return workspacePathParts(relativePath).some((part) => part.startsWith("."));
13118
+ }
13119
+ function isWorkspaceNeverVisibleHiddenPath(relativePath) {
13120
+ return workspacePathParts(relativePath).some(isWorkspaceNeverVisibleHiddenEntry);
13121
+ }
13122
+ function isWorkspaceSecretFilePath(filePath) {
13123
+ return workspacePathParts(filePath).some(
13124
+ (part) => WORKSPACE_SECRET_FILE_PATTERNS.some((pattern) => pattern.test(part))
13125
+ );
13126
+ }
12725
13127
  function readPositiveIntegerEnv(name, fallback) {
12726
13128
  const raw = process.env[name];
12727
13129
  if (!raw) return fallback;
@@ -12816,9 +13218,6 @@ function toLocalTime(iso) {
12816
13218
  const pad = (n) => String(n).padStart(2, "0");
12817
13219
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
12818
13220
  }
12819
- function formatChannelLabel(message) {
12820
- return message.channel_type === "dm" ? `DM:@${message.channel_name}` : `#${message.channel_name}`;
12821
- }
12822
13221
  function formatMessageTarget(message) {
12823
13222
  return formatAgentMessageVisibleTarget(message);
12824
13223
  }
@@ -13148,17 +13547,8 @@ function formatRuntimeProfileControlStartupInput(control, driver) {
13148
13547
  "Read the Runtime Profile daemon release notice from your system prompt before normal work.",
13149
13548
  "No chat reply or runtime control action is required for this notice. Stop after reading it; queued inbox messages will be delivered separately.",
13150
13549
  "",
13151
- control.message
13152
- ].join("\n");
13153
- }
13154
- function buildUnreadSummary(messages, excludeChannel) {
13155
- const summary = /* @__PURE__ */ new Map();
13156
- for (const message of messages) {
13157
- const label = formatChannelLabel(message);
13158
- if (excludeChannel && label === excludeChannel) continue;
13159
- summary.set(label, (summary.get(label) || 0) + 1);
13160
- }
13161
- return summary.size > 0 ? Object.fromEntries(summary) : void 0;
13550
+ control.message
13551
+ ].join("\n");
13162
13552
  }
13163
13553
  var MAX_TRAJECTORY_TEXT = 2e3;
13164
13554
  var TRAJECTORY_COALESCE_MS = 350;
@@ -13578,6 +13968,49 @@ Success = user starts useful collaboration and setup progresses,
13578
13968
  not finishing a long onboarding conversation in one channel.
13579
13969
  `;
13580
13970
  }
13971
+ function createAgentProcessStartupState(context) {
13972
+ return { kind: "waiting", timer: null, ...context };
13973
+ }
13974
+ function agentProcessStartupContext(startup) {
13975
+ return {
13976
+ wakeMessage: startup.wakeMessage,
13977
+ unreadSummary: startup.unreadSummary,
13978
+ resumePrompt: startup.resumePrompt
13979
+ };
13980
+ }
13981
+ function agentProcessStartupReady(startup) {
13982
+ return { kind: "ready", ...agentProcessStartupContext(startup) };
13983
+ }
13984
+ var DecisionErrorWindow = class {
13985
+ progressEpoch = 0;
13986
+ stderrEpoch = 0;
13987
+ stderrLines = [];
13988
+ runtimeError = null;
13989
+ noteRuntimeProgress() {
13990
+ this.progressEpoch += 1;
13991
+ }
13992
+ recordStderr(text) {
13993
+ const base = this.stderrEpoch === this.progressEpoch ? this.stderrLines : [];
13994
+ this.stderrLines = pushRecentStderr(base, text);
13995
+ this.stderrEpoch = this.progressEpoch;
13996
+ }
13997
+ recordRuntimeError(message) {
13998
+ this.runtimeError = { epoch: this.progressEpoch, message };
13999
+ }
14000
+ currentStderrLines() {
14001
+ return this.stderrEpoch === this.progressEpoch ? this.stderrLines : [];
14002
+ }
14003
+ currentRuntimeError() {
14004
+ if (!this.runtimeError || this.runtimeError.epoch !== this.progressEpoch) return null;
14005
+ return this.runtimeError.message;
14006
+ }
14007
+ currentErrorCandidates() {
14008
+ return [
14009
+ this.currentRuntimeError(),
14010
+ ...this.currentStderrLines()
14011
+ ].filter((value) => !!value);
14012
+ }
14013
+ };
13581
14014
  function createRuntimeTraceCounters() {
13582
14015
  return {
13583
14016
  events: 0,
@@ -13591,6 +14024,7 @@ function createRuntimeTraceCounters() {
13591
14024
  }
13592
14025
  function createRuntimeErrorDeliveryBackoffState() {
13593
14026
  return {
14027
+ kind: "idle",
13594
14028
  attempts: 0,
13595
14029
  untilMs: 0,
13596
14030
  timer: null,
@@ -13766,11 +14200,41 @@ function runtimeRecoveryTraceAttrs(event) {
13766
14200
  details_present: Boolean(event.details)
13767
14201
  };
13768
14202
  }
14203
+ function subagentProgressDetail(event) {
14204
+ const role = event.subagentType ? ` (${event.subagentType})` : "";
14205
+ switch (event.phase) {
14206
+ case "started":
14207
+ return `Subagent started${role}`;
14208
+ case "progress":
14209
+ return `Subagent working${role}`;
14210
+ case "notification":
14211
+ return `Subagent update${role}`;
14212
+ default:
14213
+ return `Subagent working${role}`;
14214
+ }
14215
+ }
14216
+ function subagentLineageFromEvent(event) {
14217
+ return {
14218
+ ...event.parentToolUseId ? { parentToolUseId: event.parentToolUseId } : {},
14219
+ ...event.subagentType ? { subagentType: event.subagentType } : {},
14220
+ ...event.taskId ? { taskId: event.taskId } : {},
14221
+ phase: event.phase
14222
+ };
14223
+ }
14224
+ function subagentProgressTraceAttrs(event) {
14225
+ return {
14226
+ kind: event.kind,
14227
+ source: event.source,
14228
+ phase: event.phase,
14229
+ parent_tool_use_id_present: Boolean(event.parentToolUseId),
14230
+ subagent_type_present: Boolean(event.subagentType),
14231
+ task_id_present: Boolean(event.taskId),
14232
+ last_tool_name_present: Boolean(event.lastToolName),
14233
+ payloadBytes: event.payloadBytes
14234
+ };
14235
+ }
13769
14236
  function currentErrorCandidates(ap) {
13770
- return [
13771
- ap.runtimeErrorSinceProgress ? ap.lastRuntimeError : null,
13772
- ...ap.recentDecisionStderr
13773
- ].filter((value) => !!value);
14237
+ return ap.decisionErrorWindow.currentErrorCandidates();
13774
14238
  }
13775
14239
  function classifyTerminalFailure(ap) {
13776
14240
  const candidates = [
@@ -13860,8 +14324,10 @@ function buildRuntimeStallDiagnostic(ap, staleForMs, staleForMinutes) {
13860
14324
  return projectApmRuntimeStallDiagnostic({
13861
14325
  staleForMs,
13862
14326
  staleForMinutes,
14327
+ lastActivityKind: ap.lastActivityKind,
13863
14328
  lastActivity: ap.lastActivity,
13864
14329
  lastActivityDetail: ap.lastActivityDetail,
14330
+ lastActivityDetailKind: ap.lastActivityDetailKind,
13865
14331
  runtimeDescriptorBusyDelivery: ap.runtime.descriptor.busyDelivery,
13866
14332
  runtimeProgressLastEventKind: ap.runtimeProgress.lastEventKind,
13867
14333
  runtime: ap.config.runtime,
@@ -14047,39 +14513,16 @@ var NATIVE_STANDING_PROMPT_STARTUP_INPUT = (
14047
14513
  );
14048
14514
  var AgentProcessManager = class _AgentProcessManager {
14049
14515
  agents = /* @__PURE__ */ new Map();
14050
- /**
14051
- * Per-agent monotonic clientSeq for `agent:activity` upstream dedup.
14052
- * Server dedupes ingest by `(launchId, clientSeq)` (#engineering:72283cf7
14053
- * task #340 PR B). This counter is keyed by agentId at the MANAGER level —
14054
- * NOT on the per-process `AgentProcess` — so it SURVIVES process recreation
14055
- * (cold-start-resume / idle-auto-restart / queued-continuation /
14056
- * runtime-profile restart). Those daemon-internal restarts reuse the
14057
- * server-issued launchId but spawn a fresh process; if the counter reset to
14058
- * 0 (as the old per-`ap` field did) the reused launchId's `(launchId,
14059
- * clientSeq)` window would collide and the server would drop the
14060
- * post-restart activity as stale — the "activity log stops updating after
14061
- * error→restart" bug. Keeping it monotonic-per-agent and never resetting on
14062
- * respawn guarantees a fresh dedup key under the same launchId. launchId is
14063
- * decoupled: it stays the identity/gate token, this is the clock.
14064
- * (#proj-o11y:a1e54b59 — RS dedup-epoch ⊥ launchId-identity separation.)
14065
- */
14066
- activityClientSeqByAgent = /* @__PURE__ */ new Map();
14516
+ lifecycleRecords = new AgentLifecycleRecords();
14067
14517
  /** Next monotonic `agent:activity` clientSeq for this agent (never resets on respawn). */
14068
14518
  nextActivityClientSeq(agentId) {
14069
- const next = (this.activityClientSeqByAgent.get(agentId) ?? 0) + 1;
14070
- this.activityClientSeqByAgent.set(agentId, next);
14071
- return next;
14519
+ return this.lifecycleRecords.nextActivityClientSeq(agentId);
14072
14520
  }
14073
14521
  agentStarts;
14074
14522
  startingInboxes = new AgentStartPendingDeliveryBuffer();
14075
14523
  /** Monotonic ordering counter for launch phase-5/6 exported rows (audit only, not a pairing key). */
14076
14524
  launchTransitionSeq = 0;
14077
- terminalRuntimeFailures = /* @__PURE__ */ new Map();
14078
14525
  noProcessResidencyTransitions = new AgentNoProcessResidencyTransitions();
14079
- runtimeErrorFingerprintFences = /* @__PURE__ */ new Map();
14080
- pendingStartRebinds = /* @__PURE__ */ new Map();
14081
- /** Cached configs for agents whose process exited normally — enables auto-restart on next message */
14082
- idleAgentConfigs = /* @__PURE__ */ new Map();
14083
14526
  slockCliPath;
14084
14527
  sendToServer;
14085
14528
  daemonApiKey;
@@ -14099,12 +14542,16 @@ var AgentProcessManager = class _AgentProcessManager {
14099
14542
  deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
14100
14543
  runtimeExitTraceAttrs = /* @__PURE__ */ new WeakMap();
14101
14544
  agentVisibleDelivery = new AgentVisibleDeliveryLedger();
14102
- // Spawn-fail backoff state per-agent (lifted outside AgentProcess because spawn fails
14103
- // BEFORE ap exists; rate-state must persist across stop/respawn so churn can't bypass).
14104
- // Explicit stop clears (fresh launch resets dedup clock — CC1 lifecycle pattern); silent
14105
- // stop preserves (same-launch respawn must keep counter or churn bypasses the cap).
14106
- pendingSpawnCause = /* @__PURE__ */ new Map();
14107
- agentSpawnFailBackoff = /* @__PURE__ */ new Map();
14545
+ /**
14546
+ * Per-agent lifecycle facts that outlive a single `AgentProcess`.
14547
+ *
14548
+ * The old implementation stored these as separate manager-level maps:
14549
+ * idle restart snapshots, terminal runtime failures, spawn-fail cooldown,
14550
+ * pending start rebinds, pending spawn causes, runtime-error fences, and the
14551
+ * activity client sequence. Keeping their storage under one owner makes the
14552
+ * lifecycle projection/invariants read the actual mutation boundary instead
14553
+ * of reconstructing it from unrelated fields.
14554
+ */
14108
14555
  daemonVersion;
14109
14556
  computerVersion;
14110
14557
  workerUrl;
@@ -14155,8 +14602,10 @@ var AgentProcessManager = class _AgentProcessManager {
14155
14602
  this.cliTransportTraceDir = traceDir;
14156
14603
  }
14157
14604
  assertStartPendingDeliveryInvariants(context) {
14605
+ this.repairNonresidentRuntimeErrorFingerprintFences(context);
14158
14606
  const residencySnapshot = this.noProcessResidencySnapshot();
14159
14607
  AgentNoProcessResidency.assertInvariants(context, residencySnapshot);
14608
+ this.lifecycleRecords.assertInvariants(context, this.agentLifecycleRecordSnapshot());
14160
14609
  this.startingInboxes.assertInvariants(
14161
14610
  context,
14162
14611
  AgentNoProcessResidency.allowedStartPendingSnapshot(residencySnapshot)
@@ -14169,13 +14618,30 @@ var AgentProcessManager = class _AgentProcessManager {
14169
14618
  runningAgentIds: [...this.agents.keys()],
14170
14619
  queuedAgentIds: startSnapshot.queuedAgentIds,
14171
14620
  startingAgentIds: startSnapshot.startingAgentIds,
14172
- idleAgentIds: [...this.idleAgentConfigs.keys()],
14173
- terminalFailureAgentIds: [...this.terminalRuntimeFailures.keys()],
14174
- activeCooldownAgentIds: [...this.agentSpawnFailBackoff.entries()].filter(([, state]) => state.untilMs > now).map(([agentId]) => agentId),
14175
- fingerprintFenceAgentIds: [...this.runtimeErrorFingerprintFences.keys()],
14621
+ idleAgentIds: [...this.lifecycleRecords.restartSnapshotAgentIds()],
14622
+ terminalFailureAgentIds: [...this.lifecycleRecords.terminalFailureAgentIds()],
14623
+ activeCooldownAgentIds: this.lifecycleRecords.activeSpawnFailBackoffAgentIds(
14624
+ now,
14625
+ (state, currentTime) => state.untilMs > currentTime
14626
+ ),
14627
+ fingerprintFenceAgentIds: [...this.lifecycleRecords.runtimeErrorFingerprintFenceAgentIds()],
14176
14628
  pendingDeliveryAgentIds: this.startingInboxes.agentIds()
14177
14629
  };
14178
14630
  }
14631
+ agentLifecycleRecordSnapshot() {
14632
+ const startSnapshot = this.agentStarts.snapshot();
14633
+ const now = this.clockNow();
14634
+ return this.lifecycleRecords.snapshot({
14635
+ runningAgentIds: [...this.agents.keys()],
14636
+ queuedAgentIds: startSnapshot.queuedAgentIds,
14637
+ startingAgentIds: startSnapshot.startingAgentIds,
14638
+ now,
14639
+ isSpawnFailBackoffActive: (state, currentTime) => state.untilMs > currentTime
14640
+ });
14641
+ }
14642
+ agentLifecycleRecord(agentId) {
14643
+ return buildAgentLifecycleRecords(this.agentLifecycleRecordSnapshot()).get(agentId);
14644
+ }
14179
14645
  getVisibleBoundary(agentId, target) {
14180
14646
  return this.agentVisibleDelivery.getBoundary(agentId, target);
14181
14647
  }
@@ -14196,15 +14662,10 @@ var AgentProcessManager = class _AgentProcessManager {
14196
14662
  // bypasses the cap — CC1 lifecycle pattern). Never advances any consume cursor or model-seen
14197
14663
  // state (3-cursor orthogonality with CC1/CC2).
14198
14664
  getOrCreateSpawnFailBackoff(agentId) {
14199
- let state = this.agentSpawnFailBackoff.get(agentId);
14200
- if (!state) {
14201
- state = createRuntimeErrorDeliveryBackoffState();
14202
- this.agentSpawnFailBackoff.set(agentId, state);
14203
- }
14204
- return state;
14665
+ return this.lifecycleRecords.getOrCreateSpawnFailBackoff(agentId, createRuntimeErrorDeliveryBackoffState);
14205
14666
  }
14206
14667
  isSpawnFailBackoffActive(agentId) {
14207
- const state = this.agentSpawnFailBackoff.get(agentId);
14668
+ const state = this.lifecycleRecords.getSpawnFailBackoff(agentId);
14208
14669
  if (!state) return false;
14209
14670
  return state.untilMs > 0 && this.clockNow() < state.untilMs;
14210
14671
  }
@@ -14228,7 +14689,7 @@ var AgentProcessManager = class _AgentProcessManager {
14228
14689
  state.untilMs = this.clockNow() + Math.floor(baseDelay);
14229
14690
  if (state.timer) clearTimeout(state.timer);
14230
14691
  state.timer = setTimeout(() => {
14231
- const s = this.agentSpawnFailBackoff.get(agentId);
14692
+ const s = this.lifecycleRecords.getSpawnFailBackoff(agentId);
14232
14693
  if (s) {
14233
14694
  s.timer = null;
14234
14695
  s.untilMs = 0;
@@ -14238,10 +14699,10 @@ var AgentProcessManager = class _AgentProcessManager {
14238
14699
  return { backoffActive: true, attempts: state.attempts, untilMs: state.untilMs };
14239
14700
  }
14240
14701
  resetSpawnFailBackoff(agentId, closeResult = "advanced") {
14241
- const state = this.agentSpawnFailBackoff.get(agentId);
14702
+ const state = this.lifecycleRecords.getSpawnFailBackoff(agentId);
14242
14703
  if (!state) return;
14243
14704
  if (state.timer) clearTimeout(state.timer);
14244
- this.agentSpawnFailBackoff.delete(agentId);
14705
+ this.lifecycleRecords.deleteSpawnFailBackoff(agentId);
14245
14706
  this.closeNoProcessResidency(agentId, closeResult, { negativeEvidenceBucket: "spawn_fail_cooldown_reset" });
14246
14707
  }
14247
14708
  // ----- RUNTIME-ERROR FINGERPRINT FENCE (per-agent) ---------------------
@@ -14266,9 +14727,9 @@ var AgentProcessManager = class _AgentProcessManager {
14266
14727
  }
14267
14728
  }
14268
14729
  resetRuntimeErrorFingerprintFence(agentId, resetSource, ap) {
14269
- const state = this.runtimeErrorFingerprintFences.get(agentId);
14730
+ const state = this.lifecycleRecords.getRuntimeErrorFingerprintFence(agentId);
14270
14731
  if (!state) return;
14271
- this.runtimeErrorFingerprintFences.delete(agentId);
14732
+ this.lifecycleRecords.deleteRuntimeErrorFingerprintFence(agentId);
14272
14733
  this.recordDaemonTrace("daemon.agent.runtime_error_fingerprint_fence.reset", {
14273
14734
  agentId,
14274
14735
  runtime: ap?.config.runtime,
@@ -14279,6 +14740,17 @@ var AgentProcessManager = class _AgentProcessManager {
14279
14740
  reset_source: resetSource
14280
14741
  });
14281
14742
  }
14743
+ resetRuntimeErrorFingerprintFenceIfNonresident(agentId, resetSource, ap) {
14744
+ if (this.agents.has(agentId)) return;
14745
+ if (this.lifecycleRecords.getRestartSnapshot(agentId)) return;
14746
+ if (this.lifecycleRecords.getTerminalFailure(agentId)) return;
14747
+ this.resetRuntimeErrorFingerprintFence(agentId, resetSource, ap);
14748
+ }
14749
+ repairNonresidentRuntimeErrorFingerprintFences(context) {
14750
+ for (const agentId of [...this.lifecycleRecords.runtimeErrorFingerprintFenceAgentIds()]) {
14751
+ this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, `invariant_repair:${context}`);
14752
+ }
14753
+ }
14282
14754
  formatRuntimeErrorFingerprintFenceDetail(state) {
14283
14755
  return [
14284
14756
  `Runtime stopped after ${state.attempts} repeated runtime errors with the same fingerprint (${state.fingerprint}).`,
@@ -14289,7 +14761,7 @@ var AgentProcessManager = class _AgentProcessManager {
14289
14761
  noteRuntimeErrorFingerprintFence(agentId, ap, message, fingerprint, terminalFailure, stickyTerminalFailure) {
14290
14762
  if (!fingerprint) return null;
14291
14763
  if (stickyTerminalFailure || terminalFailure?.actionRequired) return null;
14292
- let state = this.runtimeErrorFingerprintFences.get(agentId);
14764
+ let state = this.lifecycleRecords.getRuntimeErrorFingerprintFence(agentId);
14293
14765
  if (!state || state.fingerprint !== fingerprint) {
14294
14766
  state = {
14295
14767
  fingerprint,
@@ -14298,7 +14770,7 @@ var AgentProcessManager = class _AgentProcessManager {
14298
14770
  detail: "",
14299
14771
  launchId: ap.launchId
14300
14772
  };
14301
- this.runtimeErrorFingerprintFences.set(agentId, state);
14773
+ this.lifecycleRecords.setRuntimeErrorFingerprintFence(agentId, state);
14302
14774
  }
14303
14775
  state.attempts += 1;
14304
14776
  state.lastRuntimeError = message;
@@ -14328,7 +14800,7 @@ var AgentProcessManager = class _AgentProcessManager {
14328
14800
  attempts: state.attempts,
14329
14801
  threshold: RUNTIME_ERROR_FINGERPRINT_FENCE_THRESHOLD
14330
14802
  }, "error");
14331
- this.idleAgentConfigs.delete(agentId);
14803
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
14332
14804
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
14333
14805
  this.cleanupTerminalRuntimeFailure(agentId, ap, state.detail);
14334
14806
  }
@@ -14380,7 +14852,7 @@ var AgentProcessManager = class _AgentProcessManager {
14380
14852
  }
14381
14853
  this.commitApmIdleState(agentId, ap, false);
14382
14854
  this.startRuntimeTrace(agentId, ap, "async-rejected-idle-delivery-retry", messages);
14383
- this.broadcastActivity(agentId, "working", "Message received");
14855
+ this.broadcastMessageReceivedActivity(agentId);
14384
14856
  const accepted = this.deliverInboxUpdateViaStdin(
14385
14857
  agentId,
14386
14858
  ap,
@@ -14426,11 +14898,46 @@ var AgentProcessManager = class _AgentProcessManager {
14426
14898
  return this.sendStdinNotification(agentId, { forceUnsupportedRetry: true });
14427
14899
  }
14428
14900
  clearRuntimeErrorDeliveryBackoff(ap) {
14429
- if (ap.runtimeErrorDeliveryBackoff.timer) {
14901
+ if (ap.runtimeErrorDeliveryBackoff.kind === "backing_off" && ap.runtimeErrorDeliveryBackoff.timer) {
14430
14902
  clearTimeout(ap.runtimeErrorDeliveryBackoff.timer);
14431
14903
  }
14432
14904
  ap.runtimeErrorDeliveryBackoff = createRuntimeErrorDeliveryBackoffState();
14433
14905
  }
14906
+ clearPendingTrajectoryTimer(ap) {
14907
+ if (ap.pendingTrajectory?.timer) {
14908
+ clearTimeout(ap.pendingTrajectory.timer);
14909
+ }
14910
+ ap.pendingTrajectory = null;
14911
+ }
14912
+ clearActivityHeartbeat(ap) {
14913
+ if (ap.activityHeartbeat.kind === "inactive") return;
14914
+ clearInterval(ap.activityHeartbeat.timer);
14915
+ ap.activityHeartbeat = { kind: "inactive" };
14916
+ }
14917
+ broadcastMessageReceivedActivity(agentId) {
14918
+ this.broadcastActivity(agentId, "working", "Message received", [], void 0, "message_received");
14919
+ }
14920
+ toolActivityDetailKind(toolName) {
14921
+ switch (resolveToolSemantic(toolName) ?? toolName) {
14922
+ case "bash":
14923
+ return "running_command";
14924
+ case "check_messages":
14925
+ case "receive_message":
14926
+ return "checking_messages";
14927
+ default:
14928
+ return "other";
14929
+ }
14930
+ }
14931
+ disposeAgentProcessTimers(ap, options = {}) {
14932
+ this.clearRuntimeErrorDeliveryBackoff(ap);
14933
+ this.clearPendingTrajectoryTimer(ap);
14934
+ this.clearActivityHeartbeat(ap);
14935
+ this.clearRuntimeStartupTimeout(ap);
14936
+ if (options.includeCompactionWatchdog ?? true) {
14937
+ this.clearCompactionWatchdog(ap);
14938
+ }
14939
+ this.clearStalledRecoverySigtermWatchdog(ap);
14940
+ }
14434
14941
  clearRuntimeErrorDeliveryBackoffWithTrace(agentId, ap, resetSource) {
14435
14942
  if (ap.runtimeErrorDeliveryBackoff.attempts === 0 && ap.runtimeErrorDeliveryBackoff.untilMs === 0) return;
14436
14943
  const attempts = ap.runtimeErrorDeliveryBackoff.attempts;
@@ -14450,16 +14957,22 @@ var AgentProcessManager = class _AgentProcessManager {
14450
14957
  this.clearRuntimeErrorDeliveryBackoffWithTrace(agentId, ap, eventKind);
14451
14958
  }
14452
14959
  runtimeErrorDeliveryBackoffRemainingMs(ap) {
14960
+ if (ap.runtimeErrorDeliveryBackoff.kind === "idle") return 0;
14453
14961
  return Math.max(0, ap.runtimeErrorDeliveryBackoff.untilMs - Date.now());
14454
14962
  }
14963
+ runtimeErrorDeliveryBackoffTimerScheduled(ap) {
14964
+ return ap.runtimeErrorDeliveryBackoff.kind === "backing_off" && ap.runtimeErrorDeliveryBackoff.timer !== null;
14965
+ }
14455
14966
  scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap) {
14967
+ const state = ap.runtimeErrorDeliveryBackoff;
14968
+ if (state.kind === "idle") return false;
14456
14969
  const delayMs = this.runtimeErrorDeliveryBackoffRemainingMs(ap);
14457
- if (delayMs <= 0 || ap.runtimeErrorDeliveryBackoff.timer) return false;
14458
- ap.runtimeErrorDeliveryBackoff.timer = setTimeout(() => {
14459
- ap.runtimeErrorDeliveryBackoff.timer = null;
14970
+ if (delayMs <= 0 || state.timer) return false;
14971
+ state.timer = setTimeout(() => {
14972
+ if (ap.runtimeErrorDeliveryBackoff === state) state.timer = null;
14460
14973
  this.flushRuntimeErrorDeliveryBackoff(agentId);
14461
14974
  }, delayMs);
14462
- ap.runtimeErrorDeliveryBackoff.timer.unref?.();
14975
+ state.timer.unref?.();
14463
14976
  return true;
14464
14977
  }
14465
14978
  recoverableRuntimeDeliveryBackoffReason(message, terminalFailure, stickyTerminalFailure, reasonOverride) {
@@ -14490,13 +15003,16 @@ var AgentProcessManager = class _AgentProcessManager {
14490
15003
  const cappedDelayMs = Math.min(this.runtimeErrorDeliveryBackoffMaxMs, exponentialDelayMs);
14491
15004
  const jitterMs = Math.floor(cappedDelayMs * this.runtimeErrorDeliveryBackoffJitterRatio * Math.random());
14492
15005
  const delayMs = Math.min(this.runtimeErrorDeliveryBackoffMaxMs, cappedDelayMs + jitterMs);
14493
- if (ap.runtimeErrorDeliveryBackoff.timer) {
15006
+ if (ap.runtimeErrorDeliveryBackoff.kind === "backing_off" && ap.runtimeErrorDeliveryBackoff.timer) {
14494
15007
  clearTimeout(ap.runtimeErrorDeliveryBackoff.timer);
14495
- ap.runtimeErrorDeliveryBackoff.timer = null;
14496
15008
  }
14497
- ap.runtimeErrorDeliveryBackoff.attempts = attempts;
14498
- ap.runtimeErrorDeliveryBackoff.reason = reason;
14499
- ap.runtimeErrorDeliveryBackoff.untilMs = Date.now() + delayMs;
15009
+ ap.runtimeErrorDeliveryBackoff = {
15010
+ kind: "backing_off",
15011
+ attempts,
15012
+ reason,
15013
+ untilMs: Date.now() + delayMs,
15014
+ timer: null
15015
+ };
14500
15016
  if (ap.inbox.length > 0) {
14501
15017
  this.scheduleRuntimeErrorDeliveryBackoffFlush(agentId, ap);
14502
15018
  }
@@ -14536,7 +15052,7 @@ var AgentProcessManager = class _AgentProcessManager {
14536
15052
  runtime_error_backoff_remaining_ms: remainingMs,
14537
15053
  runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
14538
15054
  runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
14539
- runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null
15055
+ runtime_error_backoff_timer_scheduled: scheduled || this.runtimeErrorDeliveryBackoffTimerScheduled(ap)
14540
15056
  }));
14541
15057
  return true;
14542
15058
  }
@@ -14571,7 +15087,7 @@ var AgentProcessManager = class _AgentProcessManager {
14571
15087
  }
14572
15088
  this.commitApmIdleState(agentId, ap, false);
14573
15089
  this.startRuntimeTrace(agentId, ap, "runtime-error-backoff-idle-delivery", messages);
14574
- this.broadcastActivity(agentId, "working", "Message received");
15090
+ this.broadcastMessageReceivedActivity(agentId);
14575
15091
  const accepted2 = this.deliverInboxUpdateViaStdin(
14576
15092
  agentId,
14577
15093
  ap,
@@ -14752,7 +15268,11 @@ var AgentProcessManager = class _AgentProcessManager {
14752
15268
  path: input.pathname,
14753
15269
  query_keys: input.queryKeys,
14754
15270
  error_name: input.errorName,
14755
- error_message: input.errorMessage
15271
+ error_message: input.errorMessage,
15272
+ response_status_code: input.responseStatusCode,
15273
+ response_code: input.responseCode,
15274
+ lifecycle_invalid_agent_id: input.lifecycleInvalidAgentId,
15275
+ lifecycle_invalid_context: input.lifecycleInvalidContext
14756
15276
  }, "error");
14757
15277
  }
14758
15278
  recordAgentProxyTransportNormalizedError(agentId, input) {
@@ -14786,7 +15306,9 @@ var AgentProcessManager = class _AgentProcessManager {
14786
15306
  type: "agent:activity",
14787
15307
  agentId,
14788
15308
  activity: activity.statusEntry.activity,
15309
+ activityKind: activity.statusEntry.activityKind ?? activity.statusEntry.activity,
14789
15310
  detail: activity.statusEntry.detail,
15311
+ detailKind: activity.statusEntry.detailKind ?? "daemon_activity",
14790
15312
  entries: activity.entries,
14791
15313
  launchId: ap?.launchId || void 0,
14792
15314
  clientSeq: ap ? this.nextActivityClientSeq(agentId) : void 0
@@ -14796,8 +15318,10 @@ var AgentProcessManager = class _AgentProcessManager {
14796
15318
  this.sendToServer({
14797
15319
  type: "agent:activity",
14798
15320
  agentId,
14799
- activity: ap.lastActivity || "online",
15321
+ activity: ap.lastActivity || ap.lastActivityKind || "online",
15322
+ activityKind: ap.lastActivityKind || "online",
14800
15323
  detail: ap.lastActivityDetail || "",
15324
+ detailKind: ap.lastActivityDetailKind || "none",
14801
15325
  entries: [runtimeDiagnosticTrajectoryEntry(event)],
14802
15326
  launchId: ap.launchId || void 0,
14803
15327
  clientSeq: this.nextActivityClientSeq(agentId)
@@ -14809,12 +15333,46 @@ var AgentProcessManager = class _AgentProcessManager {
14809
15333
  ...runtimeDiagnosticTraceAttrs(event)
14810
15334
  });
14811
15335
  }
15336
+ /**
15337
+ * APM 1.6 6a — surface a generic structured "working" signal from an
15338
+ * internal_progress liveness tick during a long turn. Only transitions INTO
15339
+ * the runtime-progress state once (idempotent while already in it) so the
15340
+ * high-frequency Claude partial-message stream does not spam a rendered status
15341
+ * line every tick; the activity heartbeat then keeps the signal live. Carries
15342
+ * no raw content — a bounded "Working" detail only. Never marks a subagent.
15343
+ */
15344
+ maybeBroadcastRuntimeProgressActivity(agentId, ap) {
15345
+ const alreadyLive = ap.lastActivityKind === "working" || ap.lastActivityKind === "thinking";
15346
+ if (alreadyLive) return;
15347
+ this.broadcastActivity(agentId, "working", "Working", [], void 0, "runtime_progress");
15348
+ }
15349
+ recordSubagentProgressActivity(agentId, ap, event) {
15350
+ this.flushPendingTrajectory(agentId);
15351
+ this.broadcastActivity(
15352
+ agentId,
15353
+ "working",
15354
+ subagentProgressDetail(event),
15355
+ [],
15356
+ void 0,
15357
+ "subagent_activity",
15358
+ "working",
15359
+ subagentLineageFromEvent(event)
15360
+ );
15361
+ this.recordDaemonTrace("daemon.runtime.subagent.progress", {
15362
+ agentId,
15363
+ launchId: ap.launchId || void 0,
15364
+ runtime: ap.config.runtime,
15365
+ ...subagentProgressTraceAttrs(event)
15366
+ });
15367
+ }
14812
15368
  recordRuntimeRecoveryActivity(agentId, ap, event) {
14813
15369
  this.sendToServer({
14814
15370
  type: "agent:activity",
14815
15371
  agentId,
14816
- activity: ap.lastActivity || "online",
15372
+ activity: ap.lastActivity || ap.lastActivityKind || "online",
15373
+ activityKind: ap.lastActivityKind || "online",
14817
15374
  detail: ap.lastActivityDetail || "",
15375
+ detailKind: ap.lastActivityDetailKind || "none",
14818
15376
  entries: [runtimeRecoveryTrajectoryEntry(event)],
14819
15377
  launchId: ap.launchId || void 0,
14820
15378
  clientSeq: this.nextActivityClientSeq(agentId)
@@ -14905,7 +15463,7 @@ var AgentProcessManager = class _AgentProcessManager {
14905
15463
  pid: typeof ap.runtime.pid === "number" ? ap.runtime.pid : void 0
14906
15464
  };
14907
15465
  }
14908
- startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
15466
+ startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false, resumeMessages) {
14909
15467
  const startSnapshot = this.agentStarts.snapshot();
14910
15468
  return {
14911
15469
  agentId,
@@ -14916,6 +15474,7 @@ var AgentProcessManager = class _AgentProcessManager {
14916
15474
  launch_id_present: Boolean(launchId),
14917
15475
  wake_message_present: Boolean(wakeMessage),
14918
15476
  wake_message_transient: Boolean(wakeMessage && wakeMessageTransient),
15477
+ resume_messages_count: resumeMessages?.length ?? 0,
14919
15478
  unread_channels_count: unreadSummary ? Object.keys(unreadSummary).length : 0,
14920
15479
  resume_prompt_present: Boolean(resumePrompt),
14921
15480
  queue_depth: startSnapshot.queueDepth,
@@ -15042,7 +15601,10 @@ var AgentProcessManager = class _AgentProcessManager {
15042
15601
  rebindRunningStart(agentId, start, reason) {
15043
15602
  const ap = this.agents.get(agentId);
15044
15603
  if (!ap) {
15045
- this.pendingStartRebinds.set(agentId, start);
15604
+ this.lifecycleRecords.setPendingStartRebind(agentId, {
15605
+ ...start,
15606
+ stopEpochAtRebind: this.lifecycleRecords.stopEpoch(agentId)
15607
+ });
15046
15608
  return false;
15047
15609
  }
15048
15610
  const previousLaunchId = ap.launchId;
@@ -15058,7 +15620,7 @@ var AgentProcessManager = class _AgentProcessManager {
15058
15620
  ...start.config,
15059
15621
  sessionId: nextConfigSessionId
15060
15622
  };
15061
- this.idleAgentConfigs.set(agentId, {
15623
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15062
15624
  config: this.buildRestartSafeConfig(ap.config, nextConfigSessionId),
15063
15625
  sessionId: nextConfigSessionId,
15064
15626
  launchId: nextLaunchId
@@ -15076,32 +15638,41 @@ var AgentProcessManager = class _AgentProcessManager {
15076
15638
  }
15077
15639
  return true;
15078
15640
  }
15079
- async startAgent(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
15080
- this.recordDaemonTrace("daemon.agent.start.requested", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
15641
+ async startAgent(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false, resumeMessages) {
15642
+ this.recordDaemonTrace("daemon.agent.start.requested", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages));
15081
15643
  if (this.agents.has(agentId)) {
15082
15644
  this.recordDaemonTrace("daemon.agent.start.ignored", {
15083
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
15645
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages),
15084
15646
  reason: "already_running"
15085
15647
  });
15086
- this.rebindRunningStart(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient }, "already_running");
15648
+ this.rebindRunningStart(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages }, "already_running");
15087
15649
  logger.info(`[Agent ${agentId}] Start rebound (already running)`);
15088
15650
  return;
15089
15651
  }
15090
15652
  if (this.agentStarts.hasStarting(agentId)) {
15091
15653
  this.recordDaemonTrace("daemon.agent.start.ignored", {
15092
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
15654
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages),
15093
15655
  reason: "already_starting"
15094
15656
  });
15095
- this.pendingStartRebinds.set(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient });
15657
+ this.lifecycleRecords.setPendingStartRebind(agentId, {
15658
+ config,
15659
+ wakeMessage,
15660
+ unreadSummary,
15661
+ resumePrompt,
15662
+ launchId,
15663
+ wakeMessageTransient,
15664
+ resumeMessages,
15665
+ stopEpochAtRebind: this.lifecycleRecords.stopEpoch(agentId)
15666
+ });
15096
15667
  logger.info(`[Agent ${agentId}] Start rebind deferred (startup in progress)`);
15097
15668
  return;
15098
15669
  }
15099
15670
  if (this.agentStarts.hasQueued(agentId)) {
15100
15671
  this.recordDaemonTrace("daemon.agent.start.ignored", {
15101
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
15672
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages),
15102
15673
  reason: "already_queued"
15103
15674
  });
15104
- this.rebindQueuedStart(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient }, "already_queued");
15675
+ this.rebindQueuedStart(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages }, "already_queued");
15105
15676
  logger.info(`[Agent ${agentId}] Queued start rebound (startup already queued)`);
15106
15677
  return;
15107
15678
  }
@@ -15111,6 +15682,7 @@ var AgentProcessManager = class _AgentProcessManager {
15111
15682
  config,
15112
15683
  wakeMessage,
15113
15684
  wakeMessageTransient,
15685
+ resumeMessages,
15114
15686
  unreadSummary,
15115
15687
  resumePrompt,
15116
15688
  launchId,
@@ -15118,7 +15690,7 @@ var AgentProcessManager = class _AgentProcessManager {
15118
15690
  reject
15119
15691
  };
15120
15692
  this.agentStarts.enqueue(item);
15121
- this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
15693
+ this.recordDaemonTrace("daemon.agent.start.queued", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages));
15122
15694
  const startSnapshot = this.agentStarts.snapshot();
15123
15695
  this.enterNoProcessResidency(
15124
15696
  "queued_start",
@@ -15141,7 +15713,7 @@ var AgentProcessManager = class _AgentProcessManager {
15141
15713
  if (pumpState.kind === "rate_limited") {
15142
15714
  const { item: next, waitMs } = pumpState;
15143
15715
  this.recordDaemonTrace("daemon.agent.start.rate_limited", {
15144
- ...this.startQueueTraceAttrs(next.agentId, next.config, next.wakeMessage, next.unreadSummary, next.resumePrompt, next.launchId, next.wakeMessageTransient),
15716
+ ...this.startQueueTraceAttrs(next.agentId, next.config, next.wakeMessage, next.unreadSummary, next.resumePrompt, next.launchId, next.wakeMessageTransient, next.resumeMessages),
15145
15717
  wait_ms: waitMs
15146
15718
  });
15147
15719
  this.agentStarts.schedulePump(waitMs, () => this.pumpAgentStartQueue());
@@ -15153,7 +15725,7 @@ var AgentProcessManager = class _AgentProcessManager {
15153
15725
  const { item: item2 } = dequeued;
15154
15726
  this.closeNoProcessResidency(item2.agentId, "suppressed", { negativeEvidenceBucket: "stale_queue_item" });
15155
15727
  this.recordDaemonTrace("daemon.agent.start.skipped", {
15156
- ...this.startQueueTraceAttrs(item2.agentId, item2.config, item2.wakeMessage, item2.unreadSummary, item2.resumePrompt, item2.launchId, item2.wakeMessageTransient),
15728
+ ...this.startQueueTraceAttrs(item2.agentId, item2.config, item2.wakeMessage, item2.unreadSummary, item2.resumePrompt, item2.launchId, item2.wakeMessageTransient, item2.resumeMessages),
15157
15729
  reason: "stale_queue_item"
15158
15730
  });
15159
15731
  this.pumpAgentStartQueue();
@@ -15163,13 +15735,16 @@ var AgentProcessManager = class _AgentProcessManager {
15163
15735
  if (this.agents.has(item.agentId) || this.agentStarts.hasStarting(item.agentId)) {
15164
15736
  this.closeNoProcessResidency(item.agentId, "suppressed", { negativeEvidenceBucket: "already_running_or_starting" });
15165
15737
  this.recordDaemonTrace("daemon.agent.start.skipped", {
15166
- ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
15738
+ ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient, item.resumeMessages),
15167
15739
  reason: "already_running_or_starting"
15168
15740
  });
15169
15741
  if (this.agents.has(item.agentId)) {
15170
15742
  this.rebindRunningStart(item.agentId, item, "already_running_or_starting");
15171
15743
  } else {
15172
- this.pendingStartRebinds.set(item.agentId, item);
15744
+ this.lifecycleRecords.setPendingStartRebind(item.agentId, {
15745
+ ...item,
15746
+ stopEpochAtRebind: this.lifecycleRecords.stopEpoch(item.agentId)
15747
+ });
15173
15748
  }
15174
15749
  logger.info(`[Agent ${item.agentId}] Queued start skipped (already running or starting)`);
15175
15750
  item.resolve();
@@ -15190,7 +15765,7 @@ var AgentProcessManager = class _AgentProcessManager {
15190
15765
  logger.info(
15191
15766
  `[Agent ${item.agentId}] Dequeued start (remaining=${startSnapshot.queueDepth}, active=${startSnapshot.activeStarts})`
15192
15767
  );
15193
- this.recordDaemonTrace("daemon.agent.start.dequeued", this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient));
15768
+ this.recordDaemonTrace("daemon.agent.start.dequeued", this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient, item.resumeMessages));
15194
15769
  this.startAgentNow(
15195
15770
  item.agentId,
15196
15771
  item.config,
@@ -15198,7 +15773,8 @@ var AgentProcessManager = class _AgentProcessManager {
15198
15773
  item.unreadSummary,
15199
15774
  item.resumePrompt,
15200
15775
  item.launchId,
15201
- item.wakeMessageTransient ?? false
15776
+ item.wakeMessageTransient ?? false,
15777
+ item.resumeMessages
15202
15778
  ).then(() => {
15203
15779
  this.releaseAgentStartSlot(item.agentId, "spawn attempted");
15204
15780
  item.resolve();
@@ -15229,7 +15805,7 @@ var AgentProcessManager = class _AgentProcessManager {
15229
15805
  this.startingInboxes.cancelStart(agentId);
15230
15806
  this.assertStartPendingDeliveryInvariants("cancel-queued-start");
15231
15807
  this.recordDaemonTrace("daemon.agent.start.cancelled", {
15232
- ...this.startQueueTraceAttrs(agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
15808
+ ...this.startQueueTraceAttrs(agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient, item.resumeMessages),
15233
15809
  reason
15234
15810
  }, "cancelled");
15235
15811
  logger.info(`[Agent ${agentId}] Queued start cancelled (${reason})`);
@@ -15240,7 +15816,7 @@ var AgentProcessManager = class _AgentProcessManager {
15240
15816
  const cancelled = this.agentStarts.cancelAllQueued((item) => {
15241
15817
  this.closeNoProcessResidency(item.agentId, "suppressed", { negativeEvidenceBucket: "start_cancelled" });
15242
15818
  this.recordDaemonTrace("daemon.agent.start.cancelled", {
15243
- ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient),
15819
+ ...this.startQueueTraceAttrs(item.agentId, item.config, item.wakeMessage, item.unreadSummary, item.resumePrompt, item.launchId, item.wakeMessageTransient, item.resumeMessages),
15244
15820
  reason
15245
15821
  }, "cancelled");
15246
15822
  logger.info(`[Agent ${item.agentId}] Queued start cancelled (${reason})`);
@@ -15251,25 +15827,35 @@ var AgentProcessManager = class _AgentProcessManager {
15251
15827
  this.startingInboxes.cancelAllStarts();
15252
15828
  this.assertStartPendingDeliveryInvariants("cancel-all-queued-starts");
15253
15829
  }
15254
- async startAgentNow(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false) {
15830
+ async startAgentNow(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient = false, resumeMessages) {
15255
15831
  if (this.agents.has(agentId)) {
15256
15832
  this.recordDaemonTrace("daemon.agent.spawn.skipped", {
15257
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
15833
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages),
15258
15834
  reason: "already_running"
15259
15835
  });
15260
- this.rebindRunningStart(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient }, "already_running");
15836
+ this.rebindRunningStart(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages }, "already_running");
15261
15837
  logger.info(`[Agent ${agentId}] Start rebound (already running)`);
15262
15838
  return;
15263
15839
  }
15264
15840
  if (this.agentStarts.hasStarting(agentId)) {
15265
15841
  this.recordDaemonTrace("daemon.agent.spawn.skipped", {
15266
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient),
15842
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages),
15267
15843
  reason: "already_starting"
15268
15844
  });
15269
- this.pendingStartRebinds.set(agentId, { config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient });
15845
+ this.lifecycleRecords.setPendingStartRebind(agentId, {
15846
+ config,
15847
+ wakeMessage,
15848
+ unreadSummary,
15849
+ resumePrompt,
15850
+ launchId,
15851
+ wakeMessageTransient,
15852
+ resumeMessages,
15853
+ stopEpochAtRebind: this.lifecycleRecords.stopEpoch(agentId)
15854
+ });
15270
15855
  logger.info(`[Agent ${agentId}] Start rebind deferred (startup in progress)`);
15271
15856
  return;
15272
15857
  }
15858
+ let startStopEpoch = this.lifecycleRecords.stopEpoch(agentId);
15273
15859
  this.agentStarts.markStarting(agentId);
15274
15860
  let agentProcess = null;
15275
15861
  let pendingStartRebind;
@@ -15299,9 +15885,9 @@ var AgentProcessManager = class _AgentProcessManager {
15299
15885
  }
15300
15886
  }
15301
15887
  }
15302
- pendingStartRebind = this.pendingStartRebinds.get(agentId);
15888
+ pendingStartRebind = this.lifecycleRecords.getPendingStartRebind(agentId);
15303
15889
  if (pendingStartRebind) {
15304
- this.pendingStartRebinds.delete(agentId);
15890
+ this.lifecycleRecords.deletePendingStartRebind(agentId);
15305
15891
  const previousWakeMessage = wakeMessage;
15306
15892
  this.startingInboxes.rebindWake(
15307
15893
  agentId,
@@ -15314,6 +15900,8 @@ var AgentProcessManager = class _AgentProcessManager {
15314
15900
  unreadSummary = pendingStartRebind.unreadSummary;
15315
15901
  resumePrompt = pendingStartRebind.resumePrompt;
15316
15902
  launchId = pendingStartRebind.launchId || launchId;
15903
+ resumeMessages = pendingStartRebind.resumeMessages;
15904
+ startStopEpoch = pendingStartRebind.stopEpochAtRebind ?? startStopEpoch;
15317
15905
  if (pendingStartRebind.wakeMessage) {
15318
15906
  wakeMessage = pendingStartRebind.wakeMessage;
15319
15907
  wakeMessageTransient = pendingStartRebind.wakeMessageTransient === true;
@@ -15328,7 +15916,7 @@ var AgentProcessManager = class _AgentProcessManager {
15328
15916
  deadlineUnixMs: this.clockNow() + runtimeStartTimeoutMs()
15329
15917
  }
15330
15918
  );
15331
- this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient));
15919
+ this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId, wakeMessageTransient, resumeMessages));
15332
15920
  const driver = this.driverResolver(config.runtime || "claude");
15333
15921
  const legacyWakeRuntimeProfile = wakeMessage ? runtimeProfileNotificationFromMessage(wakeMessage) : null;
15334
15922
  if (legacyWakeRuntimeProfile?.kind === "migration") {
@@ -15359,7 +15947,10 @@ var AgentProcessManager = class _AgentProcessManager {
15359
15947
  let promptSource;
15360
15948
  let wakeMessageDeliveredAsInboxUpdate = false;
15361
15949
  let startingInboxDeliveredAsInput = false;
15950
+ let resumeCatchupDeliveredAsInput = false;
15362
15951
  const startingInboxMessages = this.startingInboxes.values(agentId);
15952
+ const resumeCatchupMessages = isResume && !wakeMessage && !resumePrompt ? resumeMessages ?? [] : [];
15953
+ const resumeCatchupInputMessages = resumeCatchupMessages.length > 0 ? [...resumeCatchupMessages, ...startingInboxMessages] : [];
15363
15954
  if (runtimeConfig.runtimeProfileControl && !wakeMessage) {
15364
15955
  prompt = driver.supportsNativeStandingPrompt ? NATIVE_STANDING_PROMPT_STARTUP_INPUT : formatRuntimeProfileControlStartupInput(runtimeConfig.runtimeProfileControl, driver);
15365
15956
  promptSource = "runtime_profile_control";
@@ -15399,6 +15990,22 @@ You also have unread messages in other channels:`;
15399
15990
  Use the inbox/read commands at a natural breakpoint if you choose to inspect those targets.`;
15400
15991
  }
15401
15992
  }
15993
+ } else if (resumeCatchupInputMessages.length > 0) {
15994
+ resumeCatchupDeliveredAsInput = true;
15995
+ prompt = this.formatConcreteMessagesRuntimeInput(resumeCatchupInputMessages, driver);
15996
+ promptSource = "resume_catchup_inbox";
15997
+ if (unreadSummary && Object.keys(unreadSummary).length > 0) {
15998
+ prompt += `
15999
+
16000
+ Some unread channels may not be included in this bounded startup batch:`;
16001
+ for (const [ch, count] of Object.entries(unreadSummary)) {
16002
+ prompt += `
16003
+ - ${ch}: ${count} unread`;
16004
+ }
16005
+ prompt += `
16006
+
16007
+ Use the inbox/read commands at a natural breakpoint if you choose to inspect those targets.`;
16008
+ }
15402
16009
  } else if (startingInboxMessages.length > 0) {
15403
16010
  startingInboxDeliveredAsInput = true;
15404
16011
  prompt = this.formatInboxUpdateRuntimeInput(startingInboxMessages, driver);
@@ -15426,27 +16033,32 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15426
16033
  prompt,
15427
16034
  standingPrompt,
15428
16035
  resumePrompt,
15429
- messages: wakeMessage ? [wakeMessage] : void 0,
16036
+ messages: wakeMessage ? [wakeMessage] : resumeCatchupInputMessages.length > 0 ? resumeCatchupInputMessages : void 0,
15430
16037
  unreadSummary,
15431
16038
  sessionIdPresent: isResume,
15432
16039
  nativeStandingPrompt: Boolean(driver.supportsNativeStandingPrompt)
15433
16040
  });
15434
16041
  const effectiveLaunchId = launchId || null;
15435
- const canDeferEmptyStart = driver.deferSpawnUntilMessage === true && !wakeMessage && !runtimeConfig.runtimeProfileControl && (!unreadSummary || Object.keys(unreadSummary).length === 0);
16042
+ const canDeferEmptyStart = driver.deferSpawnUntilMessage === true && !wakeMessage && !runtimeConfig.runtimeProfileControl && resumeCatchupInputMessages.length === 0 && (!unreadSummary || Object.keys(unreadSummary).length === 0);
15436
16043
  if (canDeferEmptyStart) {
15437
16044
  const pendingMessages = this.startingInboxes.drainOnSpawn(agentId);
15438
16045
  this.agentStarts.clearStarting(agentId);
15439
16046
  this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "defer_until_concrete_message" });
15440
16047
  this.assertStartPendingDeliveryInvariants("defer-empty-start-drain");
15441
- this.idleAgentConfigs.set(agentId, {
16048
+ if (this.lifecycleRecords.stopEpochChanged(agentId, startStopEpoch)) {
16049
+ this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
16050
+ logger.info(`[Agent ${agentId}] Deferred ${driver.id} spawn suppressed by stop request`);
16051
+ return;
16052
+ }
16053
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15442
16054
  config: this.buildRestartSafeConfig(runtimeConfig, runtimeConfig.sessionId || null),
15443
16055
  sessionId: runtimeConfig.sessionId || null,
15444
16056
  launchId: effectiveLaunchId
15445
16057
  });
15446
16058
  this.sendAgentStatus(agentId, "active", effectiveLaunchId);
15447
- this.broadcastActivity(agentId, "online", "Process idle");
16059
+ this.broadcastActivity(agentId, "online", "Process idle", [], void 0, "idle");
15448
16060
  this.recordDaemonTrace("daemon.agent.spawn.deferred", {
15449
- ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, effectiveLaunchId || void 0, wakeMessageTransient),
16061
+ ...this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, effectiveLaunchId || void 0, wakeMessageTransient, resumeMessages),
15450
16062
  pending_messages_count: pendingMessages.length,
15451
16063
  reason: "defer_until_concrete_message"
15452
16064
  });
@@ -15481,51 +16093,53 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15481
16093
  const initialSessionId = this.initialAgentProcessSessionId(driver, liveProcessConfig);
15482
16094
  const restartSessionId = initialSessionId || (driver.requiresSessionInitForDelivery ? liveProcessConfig.sessionId || null : null);
15483
16095
  const processInstanceId = randomUUID6();
16096
+ const startupInputMessages = wakeMessageDeliveredAsInboxUpdate && wakeMessage ? [wakeMessage, ...startingInboxMessages] : resumeCatchupDeliveredAsInput ? resumeCatchupInputMessages : startingInboxMessages;
15484
16097
  agentProcess = {
15485
16098
  runtime,
15486
16099
  driver,
15487
- inbox: wakeMessageDeliveredAsInboxUpdate && wakeMessage ? [wakeMessage, ...startingInboxMessages] : startingInboxMessages,
16100
+ inbox: startupInputMessages,
15488
16101
  config: liveProcessConfig,
15489
16102
  sessionId: initialSessionId,
15490
16103
  sessionReadyForDelivery: this.initialSessionReadyForDelivery(driver, liveProcessConfig, initialSessionId),
15491
16104
  launchId: effectiveLaunchId,
15492
- startupWakeMessage: wakeMessage,
15493
- startupUnreadSummary: unreadSummary,
15494
- startupResumePrompt: resumePrompt,
16105
+ startup: createAgentProcessStartupState({
16106
+ wakeMessage,
16107
+ unreadSummary,
16108
+ resumePrompt
16109
+ }),
15495
16110
  notifications: new RuntimeNotificationState(),
15496
- activityHeartbeat: null,
15497
- startupTimeoutTimer: null,
15498
- startupReadinessSatisfied: false,
16111
+ activityHeartbeat: { kind: "inactive" },
15499
16112
  readinessTransition: null,
15500
- activationTransition: null,
15501
- initialActivationDelivered: false,
15502
- compactionWatchdog: null,
15503
- compactionStartedAt: null,
16113
+ activation: { kind: "idle" },
16114
+ compaction: { kind: "none" },
15504
16115
  runtimeProgress: new RuntimeProgressState(Date.now()),
15505
16116
  runtimeTraceSpan: null,
15506
16117
  runtimeTraceCounters: createRuntimeTraceCounters(),
15507
16118
  runtimeTelemetryResultSeq: 0,
16119
+ lastActivityKind: "offline",
15508
16120
  lastActivity: "",
15509
16121
  lastActivityDetail: "",
16122
+ lastActivityDetailKind: "none",
15510
16123
  recentStdout: [],
15511
16124
  recentStderr: [],
15512
16125
  lastRuntimeError: null,
15513
- recentDecisionStderr: [],
15514
- runtimeErrorSinceProgress: false,
16126
+ decisionErrorWindow: new DecisionErrorWindow(),
15515
16127
  runtimeErrorDeliveryBackoff: createRuntimeErrorDeliveryBackoffState(),
15516
16128
  spawnError: null,
15517
16129
  processInstanceId,
15518
16130
  spawnedAtMs: Date.now(),
15519
- exitCode: null,
15520
- exitSignal: null,
15521
- stalledRecoverySigtermTimer: null,
16131
+ exit: { kind: "live", stalledRecoverySigtermTimer: null },
15522
16132
  runtimeProfileTurnControl: liveProcessConfig.runtimeProfileControl ? runtimeProfileTurnControl(liveProcessConfig.runtimeProfileControl.kind, liveProcessConfig.runtimeProfileControl.key, "agent_config") : null,
15523
16133
  pendingTrajectory: null,
15524
16134
  gatedSteering: createGatedSteeringState()
15525
16135
  };
15526
16136
  this.startingInboxes.drainOnSpawn(agentId);
15527
16137
  this.agents.set(agentId, agentProcess);
15528
- this.idleAgentConfigs.set(agentId, {
16138
+ if (this.lifecycleRecords.stopEpochChanged(agentId, startStopEpoch)) {
16139
+ await this.cleanupStoppedRuntimeStart(agentId, agentProcess);
16140
+ return;
16141
+ }
16142
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15529
16143
  config: this.buildRestartSafeConfig(runtimeConfig, restartSessionId),
15530
16144
  sessionId: restartSessionId,
15531
16145
  launchId: effectiveLaunchId
@@ -15533,13 +16147,17 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15533
16147
  if (pendingStartRebind) {
15534
16148
  this.recordStartRebind(agentId, pendingStartRebind, "startup_registered", originalLaunchId, effectiveLaunchId, agentProcess.sessionId);
15535
16149
  }
15536
- this.startRuntimeTrace(agentId, agentProcess, "spawn", wakeMessage ? [wakeMessage] : void 0, runtimeInputTraceAttrs);
16150
+ this.startRuntimeTrace(agentId, agentProcess, "spawn", wakeMessage ? [wakeMessage] : resumeCatchupInputMessages.length > 0 ? resumeCatchupInputMessages : void 0, runtimeInputTraceAttrs);
15537
16151
  this.agentStarts.clearStarting(agentId);
15538
16152
  if (runtimeConfig.runtimeProfileControl) {
15539
16153
  this.ackInjectedRuntimeProfileControl(agentId, runtimeConfig.runtimeProfileControl, agentProcess.launchId);
15540
16154
  }
15541
16155
  if (wakeMessageDeliveredAsInboxUpdate) {
15542
16156
  this.recordInboxUpdateProjection(agentId, agentProcess, agentProcess.inbox, "spawn_wake_inbox_update", "wake", prompt);
16157
+ } else if (resumeCatchupDeliveredAsInput) {
16158
+ this.recordInboxUpdateProjection(agentId, agentProcess, resumeCatchupInputMessages, "spawn_resume_catchup_inbox", "wake", prompt);
16159
+ this.consumeVisibleMessages(agentId, { messages: resumeCatchupInputMessages, source: "spawn_resume_catchup_inbox" });
16160
+ this.ackInjectedRuntimeProfileMessages(agentId, resumeCatchupInputMessages, agentProcess.launchId);
15543
16161
  } else if (startingInboxDeliveredAsInput) {
15544
16162
  this.recordInboxUpdateProjection(agentId, agentProcess, startingInboxMessages, "spawn_starting_inbox_update", "wake", prompt);
15545
16163
  this.consumeVisibleMessages(agentId, { messages: startingInboxMessages, source: "spawn_starting_inbox_update" });
@@ -15564,7 +16182,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15564
16182
  if (driver.id === "codex" && isCodexProviderReconnectLog(text)) {
15565
16183
  if (current) {
15566
16184
  current.recentStderr = pushRecentStderr(current.recentStderr, text);
15567
- current.recentDecisionStderr = pushRecentStderr(current.recentDecisionStderr, text);
16185
+ current.decisionErrorWindow.recordStderr(text);
15568
16186
  }
15569
16187
  this.recordDaemonTrace("daemon.agent.provider_reconnect", {
15570
16188
  agentId,
@@ -15574,14 +16192,14 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15574
16192
  });
15575
16193
  this.broadcastActivity(agentId, "working", "Codex reconnecting to provider\u2026", [
15576
16194
  { kind: "text", text }
15577
- ]);
16195
+ ], void 0, "runtime_reconnecting");
15578
16196
  logger.info(`[Agent ${agentId} stderr]: ${text}`);
15579
16197
  return;
15580
16198
  }
15581
16199
  if (driver.id === "codex" && isCodexBenignTransportLog(text)) return;
15582
16200
  if (current) {
15583
16201
  current.recentStderr = pushRecentStderr(current.recentStderr, text);
15584
- current.recentDecisionStderr = pushRecentStderr(current.recentDecisionStderr, text);
16202
+ current.decisionErrorWindow.recordStderr(text);
15585
16203
  }
15586
16204
  logger.error(`[Agent ${agentId} stderr]: ${text}`);
15587
16205
  });
@@ -15603,8 +16221,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15603
16221
  runtime.on("exit", ({ code, signal }) => {
15604
16222
  const current = this.agents.get(agentId);
15605
16223
  if (current && current.runtime === runtime) {
15606
- current.exitCode = code;
15607
- current.exitSignal = signal;
16224
+ this.clearStalledRecoverySigtermWatchdog(current);
16225
+ current.exit = { kind: "exited", code, signal };
15608
16226
  }
15609
16227
  const exitTraceAttrs = this.runtimeExitTraceAttrs.get(runtime);
15610
16228
  this.recordDaemonTrace("daemon.agent.process.exited", {
@@ -15629,7 +16247,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15629
16247
  exit_code: code,
15630
16248
  exit_signal: signal,
15631
16249
  cause: exitCause,
15632
- last_event_kind: agentProcess.lastActivity || void 0,
16250
+ last_event_kind: agentProcess.lastActivityKind || void 0,
15633
16251
  last_event_age_ms_bucket: bucketMs(staleForMs),
15634
16252
  uptime_ms_bucket: bucketMs(Date.now() - agentProcess.spawnedAtMs)
15635
16253
  }, code === 0 ? "ok" : "error");
@@ -15641,19 +16259,11 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15641
16259
  const ap = this.agents.get(agentId);
15642
16260
  if (ap.runtime !== runtime) return;
15643
16261
  ap.notifications.clearTimer();
15644
- this.clearRuntimeErrorDeliveryBackoff(ap);
15645
- if (ap.pendingTrajectory?.timer) {
15646
- clearTimeout(ap.pendingTrajectory.timer);
15647
- }
15648
- if (ap.activityHeartbeat) {
15649
- clearInterval(ap.activityHeartbeat);
15650
- }
16262
+ this.disposeAgentProcessTimers(ap, { includeCompactionWatchdog: false });
15651
16263
  this.closeRuntimeReadinessTransition(ap, "terminal");
15652
16264
  this.closeActivationTransition(ap, "terminal");
15653
- this.clearRuntimeStartupTimeout(ap);
15654
- this.clearStalledRecoverySigtermWatchdog(ap);
15655
- const finalCode = ap.exitCode ?? code;
15656
- const finalSignal = ap.exitSignal ?? signal;
16265
+ const finalCode = ap.exit.kind === "exited" ? ap.exit.code ?? code : code;
16266
+ const finalSignal = ap.exit.kind === "exited" ? ap.exit.signal ?? signal : signal;
15657
16267
  const expectedTerminationReason = ap.gatedSteering.expectedTerminationReason;
15658
16268
  const startupTimeoutTermination = expectedTerminationReason === "startup_timeout";
15659
16269
  const startupRequestErrorTermination = expectedTerminationReason === "startup_request_error";
@@ -15697,52 +16307,59 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15697
16307
  [{
15698
16308
  kind: "text",
15699
16309
  text: `Stored ${runtimeLabel} session ${staleSessionId} ${reasonText}. Falling back to a cold start; earlier runtime context may not be restored.`
15700
- }]
16310
+ }],
16311
+ void 0,
16312
+ "runtime_unavailable"
15701
16313
  );
15702
- this.pendingSpawnCause.set(agentId, "restart_crash");
16314
+ this.lifecycleRecords.setPendingSpawnCause(agentId, "restart_crash");
15703
16315
  this.startAgent(
15704
16316
  agentId,
15705
16317
  restartConfig,
15706
- ap.startupWakeMessage,
15707
- ap.startupUnreadSummary,
15708
- ap.startupResumePrompt,
16318
+ ap.startup.wakeMessage,
16319
+ ap.startup.unreadSummary,
16320
+ ap.startup.resumePrompt,
15709
16321
  ap.launchId || void 0
15710
16322
  ).catch((err) => {
15711
16323
  logger.error(`[Agent ${agentId}] Cold start recovery failed`, err);
15712
- this.pendingSpawnCause.delete(agentId);
16324
+ this.lifecycleRecords.deletePendingSpawnCause(agentId);
15713
16325
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
15714
- this.broadcastActivity(agentId, "offline", `Crashed (${summary})`, [], ap.launchId);
16326
+ this.broadcastActivity(agentId, "offline", `Crashed (${summary})`, [], ap.launchId, "runtime_crashed");
15715
16327
  });
15716
16328
  return;
15717
16329
  }
15718
16330
  if (processEndedCleanly) {
16331
+ const pendingRestartMessages = ap.inbox.splice(0).filter((message) => !this.isTransientDelivery(message));
15719
16332
  let queuedWakeMessage;
15720
- if (!ap.driver.supportsStdinNotification || expectedTerminationReason === "stalled_recovery") {
15721
- while (ap.inbox.length > 0) {
15722
- const candidate = ap.inbox.shift();
15723
- if (this.shouldDeferWakeMessage(agentId, ap.driver, candidate)) continue;
15724
- queuedWakeMessage = candidate;
15725
- break;
16333
+ const bufferedRestartMessages = [];
16334
+ for (const message of pendingRestartMessages) {
16335
+ if (!queuedWakeMessage && !this.shouldDeferWakeMessage(agentId, ap.driver, message)) {
16336
+ queuedWakeMessage = message;
16337
+ } else {
16338
+ bufferedRestartMessages.push(message);
15726
16339
  }
15727
16340
  }
15728
- const unreadSummary2 = queuedWakeMessage ? buildUnreadSummary(ap.inbox, formatChannelLabel(queuedWakeMessage)) : void 0;
15729
16341
  if (queuedWakeMessage) {
15730
16342
  logger.info(`[Agent ${agentId}] Turn completed; restarting immediately for queued message`);
15731
16343
  const nextConfig = this.buildRestartSafeConfig(ap.config, ap.sessionId);
15732
- this.idleAgentConfigs.set(agentId, {
16344
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15733
16345
  config: nextConfig,
15734
16346
  sessionId: ap.sessionId,
15735
16347
  launchId: ap.launchId
15736
16348
  });
15737
- this.broadcastActivity(agentId, "working", "Message received");
15738
- this.idleAgentConfigs.delete(agentId);
16349
+ this.broadcastMessageReceivedActivity(agentId);
16350
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
15739
16351
  if (expectedTerminationReason === "stalled_recovery") {
15740
- this.pendingSpawnCause.set(agentId, "restart_stall");
16352
+ this.lifecycleRecords.setPendingSpawnCause(agentId, "restart_stall");
16353
+ }
16354
+ const startPromise = this.startAgent(agentId, nextConfig, queuedWakeMessage, void 0, void 0, ap.launchId || void 0);
16355
+ if (bufferedRestartMessages.length > 0) {
16356
+ this.startingInboxes.bufferMessagesDuringStart(agentId, bufferedRestartMessages);
16357
+ this.assertStartPendingDeliveryInvariants("clean-exit-pending-inbox-transfer");
15741
16358
  }
15742
- this.startAgent(agentId, nextConfig, queuedWakeMessage, unreadSummary2, void 0, ap.launchId || void 0).catch((err) => {
16359
+ startPromise.catch((err) => {
15743
16360
  logger.error(`[Agent ${agentId}] Failed to continue with queued message`, err);
15744
16361
  if (this.reportRunnerCredentialMintFailure(agentId, err, ap.launchId, "queued_continuation")) {
15745
- this.idleAgentConfigs.set(agentId, {
16362
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15746
16363
  config: nextConfig,
15747
16364
  sessionId: ap.sessionId,
15748
16365
  launchId: ap.launchId
@@ -15762,16 +16379,16 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15762
16379
  });
15763
16380
  return;
15764
16381
  }
15765
- this.idleAgentConfigs.set(agentId, {
16382
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15766
16383
  config: nextConfig,
15767
16384
  sessionId: ap.sessionId,
15768
16385
  launchId: ap.launchId
15769
16386
  });
15770
- this.broadcastActivity(agentId, "online", "Process idle");
16387
+ this.broadcastActivity(agentId, "online", "Process idle", [], void 0, "idle");
15771
16388
  });
15772
16389
  return;
15773
16390
  }
15774
- this.idleAgentConfigs.set(agentId, {
16391
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15775
16392
  config: this.buildRestartSafeConfig(ap.config, ap.sessionId),
15776
16393
  sessionId: ap.sessionId,
15777
16394
  launchId: ap.launchId
@@ -15779,11 +16396,11 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15779
16396
  if (!ap.driver.supportsStdinNotification) {
15780
16397
  logger.info(`[Agent ${agentId}] Turn completed; cached idle state for future restart`);
15781
16398
  }
15782
- this.broadcastActivity(agentId, "online", "Process idle");
16399
+ this.broadcastActivity(agentId, "online", "Process idle", [], void 0, "idle");
15783
16400
  } else {
15784
16401
  const reason = formatCrashReason(finalCode, finalSignal, ap);
15785
16402
  if (terminalFailureDetail && isProviderStreamFailureText(terminalFailureDetail.detail)) {
15786
- this.idleAgentConfigs.set(agentId, {
16403
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15787
16404
  config: this.buildRestartSafeConfig(ap.config, ap.sessionId),
15788
16405
  sessionId: ap.sessionId,
15789
16406
  launchId: ap.launchId
@@ -15794,10 +16411,12 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15794
16411
  this.cacheStartupTimeoutRetryConfig(agentId, ap);
15795
16412
  logger.warn(`[Agent ${agentId}] Startup timeout cleanup completed (${reason})`);
15796
16413
  } else if (startupRequestErrorTermination) {
15797
- this.idleAgentConfigs.delete(agentId);
16414
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
16415
+ this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, "startup_request_error_cleanup", ap);
15798
16416
  logger.warn(`[Agent ${agentId}] Startup request failure cleanup completed (${reason})`);
15799
16417
  } else {
15800
- this.idleAgentConfigs.delete(agentId);
16418
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
16419
+ this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, "nonrecoverable_process_close", ap);
15801
16420
  logger.error(`[Agent ${agentId}] Process crashed (${reason}) \u2014 marking inactive`);
15802
16421
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
15803
16422
  }
@@ -15808,11 +16427,12 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15808
16427
  "error",
15809
16428
  terminalFailureDetail.detail,
15810
16429
  [{ kind: "text", text: `Error: ${terminalFailureDetail.detail}` }],
15811
- ap.launchId
16430
+ ap.launchId,
16431
+ "runtime_error"
15812
16432
  );
15813
16433
  }
15814
16434
  } else if (!startupRequestErrorTermination) {
15815
- this.broadcastActivity(agentId, "offline", `Crashed (${summary})`, [], ap.launchId);
16435
+ this.broadcastActivity(agentId, "offline", `Crashed (${summary})`, [], ap.launchId, "runtime_crashed");
15816
16436
  }
15817
16437
  }
15818
16438
  }
@@ -15832,10 +16452,20 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15832
16452
  error_present: Boolean(startResult.error),
15833
16453
  runtime_error_class: diagnostics?.spanAttrs.runtime_error_class
15834
16454
  }, "error");
16455
+ if (startResult.error) {
16456
+ agentProcess.lastRuntimeError = startResult.error;
16457
+ agentProcess.decisionErrorWindow.recordRuntimeError(startResult.error);
16458
+ }
16459
+ if (startResult.error && diagnostics?.spanAttrs.runtime_error_action_required === true) {
16460
+ const visibleErrorMessage = formatRuntimeLoginRequiredMessage(agentProcess.driver.id);
16461
+ this.broadcastActivity(agentId, "error", visibleErrorMessage, [
16462
+ { kind: "text", text: `Error: ${visibleErrorMessage}` }
16463
+ ], agentProcess.launchId, "runtime_error");
16464
+ }
15835
16465
  throw new Error(`Runtime session failed to start: ${startResult.reason}${startResult.error ? ` (${startResult.error})` : ""}`);
15836
16466
  }
15837
16467
  this.closeNoProcessResidency(agentId, "advanced");
15838
- if (this.terminalRuntimeFailures.delete(agentId)) {
16468
+ if (this.lifecycleRecords.deleteTerminalFailure(agentId)) {
15839
16469
  this.closeNoProcessResidency(agentId, "advanced", { negativeEvidenceBucket: "terminal_recovery_start_succeeded" });
15840
16470
  }
15841
16471
  this.assertStartPendingDeliveryInvariants("spawn-drain");
@@ -15845,8 +16475,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15845
16475
  new_session: false,
15846
16476
  process_pid_present: typeof runtime.pid === "number"
15847
16477
  });
15848
- const pendingCause = this.pendingSpawnCause.get(agentId);
15849
- this.pendingSpawnCause.delete(agentId);
16478
+ const pendingCause = this.lifecycleRecords.getPendingSpawnCause(agentId);
16479
+ this.lifecycleRecords.deletePendingSpawnCause(agentId);
15850
16480
  const startCause = pendingCause ?? (isResume ? "session_resume" : wakeMessage ? "wake_message" : "explicit_start");
15851
16481
  this.recordDaemonTrace("daemon.runtime.process.spawn", {
15852
16482
  ...this.processLifecycleIdentityAttrs(agentId, agentProcess),
@@ -15859,7 +16489,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15859
16489
  if (pendingStartRebind && agentProcess.sessionId) {
15860
16490
  this.sendToServer({ type: "agent:session", agentId, sessionId: agentProcess.sessionId, launchId: agentProcess.launchId || void 0 });
15861
16491
  }
15862
- this.broadcastActivity(agentId, "working", "Starting\u2026");
16492
+ this.broadcastActivity(agentId, "working", "Starting\u2026", [], void 0, "starting");
15863
16493
  this.startRuntimeStartupTimeout(agentId, agentProcess, startCause);
15864
16494
  if (wakeMessage || startingInboxMessages.length > 0) {
15865
16495
  this.openActivationTransition(agentId, agentProcess, startCause);
@@ -15870,31 +16500,59 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15870
16500
  } catch (err) {
15871
16501
  this.agentStarts.clearStarting(agentId);
15872
16502
  this.closeNoProcessResidency(agentId, "terminal", { negativeEvidenceBucket: "runtime_start_failed" });
15873
- this.pendingStartRebinds.delete(agentId);
16503
+ this.lifecycleRecords.deletePendingStartRebind(agentId);
15874
16504
  this.cleanupFailedRuntimeStart(agentId, agentProcess, err);
15875
16505
  throw err;
15876
16506
  }
15877
16507
  }
16508
+ async cleanupStoppedRuntimeStart(agentId, ap) {
16509
+ if (this.agents.get(agentId) !== ap) return;
16510
+ this.agentStarts.clearStarting(agentId);
16511
+ this.lifecycleRecords.deletePendingStartRebind(agentId);
16512
+ this.lifecycleRecords.deletePendingSpawnCause(agentId);
16513
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
16514
+ this.startingInboxes.cancelStart(agentId);
16515
+ ap.notifications.clearTimer();
16516
+ this.disposeAgentProcessTimers(ap);
16517
+ this.closeRuntimeReadinessTransition(ap, "terminal");
16518
+ this.closeActivationTransition(ap, "terminal");
16519
+ cleanupAgentCredentialProxy(agentId, ap.launchId);
16520
+ this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
16521
+ this.agents.delete(agentId);
16522
+ this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
16523
+ this.assertStartPendingDeliveryInvariants("runtime-start-stop-epoch-fence");
16524
+ this.runtimeExitTraceAttrs.set(ap.runtime, {
16525
+ stop_source: "explicit_request",
16526
+ stop_wait_requested: false,
16527
+ stop_silent: false,
16528
+ stop_epoch_fence: true
16529
+ });
16530
+ try {
16531
+ await ap.runtime.stop({ signal: "SIGTERM", reason: "explicit_request" });
16532
+ } catch (err) {
16533
+ const reason = err instanceof Error ? err.message : String(err);
16534
+ logger.warn(`[Agent ${agentId}] Failed to stop runtime suppressed by stop epoch: ${reason}`);
16535
+ }
16536
+ logger.info(`[Agent ${agentId}] Runtime start discarded after stop request`);
16537
+ }
16538
+ suppressFailedRestartAfterStop(agentId, stopEpochAtRestart, source) {
16539
+ if (!this.lifecycleRecords.stopEpochChanged(agentId, stopEpochAtRestart)) return false;
16540
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
16541
+ this.lifecycleRecords.deletePendingStartRebind(agentId);
16542
+ this.lifecycleRecords.deletePendingSpawnCause(agentId);
16543
+ this.startingInboxes.cancelStart(agentId);
16544
+ this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
16545
+ this.assertStartPendingDeliveryInvariants(`${source}-stop-epoch-fence`);
16546
+ logger.info(`[Agent ${agentId}] Failed ${source} restart suppressed after stop request`);
16547
+ return true;
16548
+ }
15878
16549
  cleanupFailedRuntimeStart(agentId, ap, err) {
15879
16550
  if (!ap) return;
15880
16551
  if (this.agents.get(agentId) !== ap) return;
15881
16552
  ap.notifications.clearTimer();
15882
- if (ap.pendingTrajectory?.timer) {
15883
- clearTimeout(ap.pendingTrajectory.timer);
15884
- ap.pendingTrajectory.timer = null;
15885
- }
15886
- if (ap.activityHeartbeat) {
15887
- clearInterval(ap.activityHeartbeat);
15888
- ap.activityHeartbeat = null;
15889
- }
15890
- if (ap.compactionWatchdog) {
15891
- clearTimeout(ap.compactionWatchdog);
15892
- ap.compactionWatchdog = null;
15893
- }
16553
+ this.disposeAgentProcessTimers(ap);
15894
16554
  this.closeRuntimeReadinessTransition(ap, "terminal");
15895
16555
  this.closeActivationTransition(ap, "terminal");
15896
- this.clearRuntimeStartupTimeout(ap);
15897
- this.clearStalledRecoverySigtermWatchdog(ap);
15898
16556
  this.endRuntimeTrace(ap, "error", {
15899
16557
  outcome: "runtime-start-failed",
15900
16558
  failure_detail: err instanceof Error ? err.message : String(err),
@@ -15904,36 +16562,26 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15904
16562
  cleanupAgentCredentialProxy(agentId, ap.launchId);
15905
16563
  this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
15906
16564
  this.agents.delete(agentId);
15907
- this.idleAgentConfigs.delete(agentId);
15908
- if (this.terminalRuntimeFailures.delete(agentId)) {
16565
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
16566
+ if (this.lifecycleRecords.deleteTerminalFailure(agentId)) {
15909
16567
  this.closeNoProcessResidency(agentId, "terminal", { negativeEvidenceBucket: "runtime_start_failed" });
15910
16568
  }
16569
+ this.resetRuntimeErrorFingerprintFenceIfNonresident(agentId, "runtime_start_failed_cleanup", ap);
15911
16570
  }
15912
16571
  cleanupTerminalRuntimeFailure(agentId, ap, detail) {
15913
16572
  if (this.agents.get(agentId) !== ap) return;
15914
16573
  ap.notifications.clear();
15915
- this.clearRuntimeErrorDeliveryBackoff(ap);
15916
- if (ap.pendingTrajectory?.timer) {
15917
- clearTimeout(ap.pendingTrajectory.timer);
15918
- ap.pendingTrajectory.timer = null;
15919
- }
15920
- if (ap.activityHeartbeat) {
15921
- clearInterval(ap.activityHeartbeat);
15922
- ap.activityHeartbeat = null;
15923
- }
15924
- this.clearCompactionWatchdog(ap);
16574
+ this.disposeAgentProcessTimers(ap);
15925
16575
  this.closeRuntimeReadinessTransition(ap, "terminal");
15926
16576
  this.closeActivationTransition(ap, "terminal");
15927
- this.clearRuntimeStartupTimeout(ap);
15928
- this.clearStalledRecoverySigtermWatchdog(ap);
15929
16577
  cleanupAgentCredentialProxy(agentId, ap.launchId);
15930
16578
  this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
15931
- this.idleAgentConfigs.delete(agentId);
16579
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
15932
16580
  if (ap.inbox.length > 0) {
15933
16581
  this.startingInboxes.bufferMessagesDuringStart(agentId, ap.inbox);
15934
16582
  }
15935
16583
  this.agents.delete(agentId);
15936
- this.terminalRuntimeFailures.set(agentId, { detail, launchId: ap.launchId });
16584
+ this.lifecycleRecords.setTerminalFailure(agentId, { detail, launchId: ap.launchId });
15937
16585
  this.enterNoProcessResidency(
15938
16586
  "terminal_runtime_error",
15939
16587
  this.noProcessResidencyIdentity(agentId, ap.config, ap.launchId, "terminal_runtime_error", ap.driver.id),
@@ -15968,7 +16616,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
15968
16616
  cacheStartupTimeoutRetryConfig(agentId, ap) {
15969
16617
  const retrySessionId = this.restartSafeSessionId(ap);
15970
16618
  const retryConfig = this.buildRestartSafeConfig(ap.config, retrySessionId);
15971
- this.idleAgentConfigs.set(agentId, {
16619
+ this.lifecycleRecords.setRestartSnapshot(agentId, {
15972
16620
  config: retryConfig,
15973
16621
  sessionId: retrySessionId,
15974
16622
  launchId: ap.launchId
@@ -16204,10 +16852,11 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16204
16852
  return messages.some((message) => !runtimeProfileNotificationFromMessage(message));
16205
16853
  }
16206
16854
  async stopAgent(agentId, { wait = false, silent = false } = {}) {
16855
+ this.lifecycleRecords.recordStop(agentId);
16207
16856
  this.cancelQueuedAgentStart(agentId, "stop requested");
16208
- this.pendingStartRebinds.delete(agentId);
16209
- this.idleAgentConfigs.delete(agentId);
16210
- if (this.terminalRuntimeFailures.delete(agentId)) {
16857
+ this.lifecycleRecords.deletePendingStartRebind(agentId);
16858
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
16859
+ if (this.lifecycleRecords.deleteTerminalFailure(agentId)) {
16211
16860
  this.closeNoProcessResidency(agentId, "suppressed", { negativeEvidenceBucket: "explicit_stop" });
16212
16861
  }
16213
16862
  const ap = this.agents.get(agentId);
@@ -16218,17 +16867,12 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16218
16867
  return;
16219
16868
  }
16220
16869
  ap.notifications.clearTimer();
16221
- this.clearRuntimeErrorDeliveryBackoff(ap);
16222
- if (ap.activityHeartbeat) {
16223
- clearInterval(ap.activityHeartbeat);
16224
- }
16225
- this.clearCompactionWatchdog(ap);
16226
- this.clearStalledRecoverySigtermWatchdog(ap);
16870
+ this.disposeAgentProcessTimers(ap);
16227
16871
  cleanupAgentCredentialProxy(agentId, ap.launchId);
16228
16872
  this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
16229
16873
  this.agents.delete(agentId);
16230
16874
  if (!silent) {
16231
- this.activityClientSeqByAgent.delete(agentId);
16875
+ this.lifecycleRecords.deleteActivityClientSeq(agentId);
16232
16876
  this.agentVisibleDelivery.clearAgent(agentId);
16233
16877
  this.resetSpawnFailBackoff(agentId, "suppressed");
16234
16878
  this.resetRuntimeErrorFingerprintFence(agentId, "explicit_stop", ap);
@@ -16246,7 +16890,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16246
16890
  if (!silent) {
16247
16891
  this.sendRuntimeProfileReportFor(agentId, ap.config, ap.sessionId, ap.launchId, "stop");
16248
16892
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
16249
- this.broadcastActivity(agentId, "offline", "Stopped");
16893
+ this.broadcastActivity(agentId, "offline", "Stopped", [], void 0, "stopped");
16250
16894
  logger.info(`[Agent ${agentId}] Stopped by request`);
16251
16895
  }
16252
16896
  if (wait) {
@@ -16320,8 +16964,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16320
16964
  }));
16321
16965
  return true;
16322
16966
  }
16323
- const terminalRuntimeFailure = this.terminalRuntimeFailures.get(agentId);
16324
- if (terminalRuntimeFailure) {
16967
+ const lifecycleRecord = this.agentLifecycleRecord(agentId);
16968
+ if (lifecycleRecord?.kind === "terminal") {
16969
+ const { terminalFailure } = lifecycleRecord;
16325
16970
  if (transientDelivery) {
16326
16971
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
16327
16972
  outcome: "transient_dropped_terminal_runtime_error_no_process",
@@ -16329,7 +16974,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16329
16974
  process_present: false,
16330
16975
  cached_idle_config_present: false,
16331
16976
  terminal_runtime_failure: true,
16332
- launchId: terminalRuntimeFailure.launchId || void 0
16977
+ launchId: terminalFailure.launchId || void 0
16333
16978
  }));
16334
16979
  return true;
16335
16980
  }
@@ -16342,14 +16987,14 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16342
16987
  cached_idle_config_present: false,
16343
16988
  terminal_runtime_failure: true,
16344
16989
  starting_inbox_count: startingInboxCount,
16345
- launchId: terminalRuntimeFailure.launchId || void 0
16990
+ launchId: terminalFailure.launchId || void 0
16346
16991
  }));
16347
- this.sendAgentStatus(agentId, "inactive", terminalRuntimeFailure.launchId);
16348
- this.broadcastActivity(agentId, "error", terminalRuntimeFailure.detail, [], terminalRuntimeFailure.launchId);
16992
+ this.sendAgentStatus(agentId, "inactive", terminalFailure.launchId);
16993
+ this.broadcastActivity(agentId, "error", terminalFailure.detail, [], terminalFailure.launchId, "runtime_error");
16349
16994
  return true;
16350
16995
  }
16351
- const cached = this.idleAgentConfigs.get(agentId);
16352
- if (cached) {
16996
+ if (lifecycleRecord?.kind === "idle" || lifecycleRecord?.kind === "cooldown") {
16997
+ const cached = lifecycleRecord.restartSnapshot;
16353
16998
  const driver = this.driverResolver(cached.config.runtime || "claude");
16354
16999
  if (!transientDelivery && this.shouldDeferWakeMessage(agentId, driver, message)) {
16355
17000
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
@@ -16364,8 +17009,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16364
17009
  return true;
16365
17010
  }
16366
17011
  logger.info(`[Agent ${agentId}] Starting from idle state for new message`);
16367
- if (this.isSpawnFailBackoffActive(agentId)) {
16368
- const state = this.agentSpawnFailBackoff.get(agentId);
17012
+ if (lifecycleRecord.kind === "cooldown") {
17013
+ const state = lifecycleRecord.spawnFailBackoff;
16369
17014
  const startingInboxCount = this.startingInboxes.bufferDuringStart(agentId, message);
16370
17015
  this.assertStartPendingDeliveryInvariants("delivery-spawn-fail-cooldown");
16371
17016
  this.enterSpawnFailCooldownResidency(agentId, cached, state.untilMs, "idle_auto_restart", "spawn_fail_cooldown_active");
@@ -16383,7 +17028,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16383
17028
  }));
16384
17029
  return true;
16385
17030
  }
16386
- this.idleAgentConfigs.delete(agentId);
17031
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
17032
+ const restartStopEpoch = this.lifecycleRecords.stopEpoch(agentId);
16387
17033
  this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
16388
17034
  outcome: "auto_restart_from_idle",
16389
17035
  accepted: true,
@@ -16399,8 +17045,11 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16399
17045
  return true;
16400
17046
  }, (err) => {
16401
17047
  logger.error(`[Agent ${agentId}] Failed to auto-restart`, err);
17048
+ if (this.suppressFailedRestartAfterStop(agentId, restartStopEpoch, "idle-auto-restart")) {
17049
+ return false;
17050
+ }
16402
17051
  if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "idle_auto_restart")) {
16403
- this.idleAgentConfigs.set(agentId, cached);
17052
+ this.lifecycleRecords.setRestartSnapshot(agentId, cached);
16404
17053
  const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
16405
17054
  this.assertStartPendingDeliveryInvariants("idle-auto-restart-runner-credential-mint-failure");
16406
17055
  if (report2.backoffActive) {
@@ -16416,7 +17065,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16416
17065
  });
16417
17066
  return false;
16418
17067
  }
16419
- this.idleAgentConfigs.set(agentId, cached);
17068
+ this.lifecycleRecords.setRestartSnapshot(agentId, cached);
16420
17069
  const report = this.recordSpawnFailure(agentId, "spawn_error");
16421
17070
  this.assertStartPendingDeliveryInvariants("idle-auto-restart-spawn-failure");
16422
17071
  if (report.backoffActive) {
@@ -16462,7 +17111,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16462
17111
  cached_idle_config_present: false
16463
17112
  }), "error");
16464
17113
  this.sendAgentStatus(agentId, "inactive", null);
16465
- this.broadcastActivity(agentId, "offline", "Process unavailable; restart required");
17114
+ this.broadcastActivity(agentId, "offline", "Process unavailable; restart required", [], void 0, "runtime_unavailable");
16466
17115
  return false;
16467
17116
  }
16468
17117
  const isIdle = this.isApmIdle(ap);
@@ -16522,7 +17171,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16522
17171
  inbox_count: ap.inbox.length
16523
17172
  }));
16524
17173
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
16525
- this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
17174
+ this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail, [], void 0, "runtime_error");
16526
17175
  return true;
16527
17176
  }
16528
17177
  }
@@ -16533,7 +17182,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16533
17182
  if (transientDelivery) {
16534
17183
  this.commitApmIdleState(agentId, ap, false);
16535
17184
  this.startRuntimeTrace(agentId, ap, "stdin-idle-delivery", [message]);
16536
- this.broadcastActivity(agentId, "working", "Message received");
17185
+ this.broadcastMessageReceivedActivity(agentId);
16537
17186
  const stdinAccepted2 = this.deliverMessagesViaStdin(
16538
17187
  agentId,
16539
17188
  ap,
@@ -16579,7 +17228,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16579
17228
  const nextMessages = [...ap.inbox];
16580
17229
  this.commitApmIdleState(agentId, ap, false);
16581
17230
  this.startRuntimeTrace(agentId, ap, "stdin-idle-delivery", [message]);
16582
- this.broadcastActivity(agentId, "working", "Message received");
17231
+ this.broadcastMessageReceivedActivity(agentId);
16583
17232
  const stdinAccepted = this.deliverInboxUpdateViaStdin(
16584
17233
  agentId,
16585
17234
  ap,
@@ -16768,7 +17417,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16768
17417
  }
16769
17418
  async stopAll() {
16770
17419
  this.cancelAllQueuedAgentStarts("daemon shutdown");
16771
- this.idleAgentConfigs.clear();
17420
+ this.lifecycleRecords.clearRestartSnapshots();
16772
17421
  const pids = [];
16773
17422
  for (const ap of this.agents.values()) {
16774
17423
  if (typeof ap.runtime.pid === "number") pids.push(ap.runtime.pid);
@@ -16878,7 +17527,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16878
17527
  }
16879
17528
  getIdleAgentSessionIds() {
16880
17529
  const result = [];
16881
- for (const [agentId, { sessionId, launchId }] of this.idleAgentConfigs) {
17530
+ for (const [agentId, { sessionId, launchId }] of this.lifecycleRecords.restartSnapshotEntries()) {
16882
17531
  if (this.agents.has(agentId)) continue;
16883
17532
  if (sessionId) result.push({ agentId, sessionId, launchId });
16884
17533
  }
@@ -16915,7 +17564,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16915
17564
  running.runtime.currentRuntimeHomeDir
16916
17565
  );
16917
17566
  }
16918
- const idle = this.idleAgentConfigs.get(agentId);
17567
+ const idle = this.lifecycleRecords.getRestartSnapshot(agentId);
16919
17568
  if (idle) {
16920
17569
  return this.buildRuntimeProfileReport(agentId, idle.config, idle.sessionId, idle.launchId);
16921
17570
  }
@@ -16931,7 +17580,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
16931
17580
  seen.add(agentId);
16932
17581
  }
16933
17582
  }
16934
- for (const agentId of this.idleAgentConfigs.keys()) {
17583
+ for (const agentId of this.lifecycleRecords.restartSnapshotAgentIds()) {
16935
17584
  if (seen.has(agentId)) continue;
16936
17585
  const report = this.getAgentRuntimeProfileReport(agentId);
16937
17586
  if (report) reports.push(report);
@@ -17034,11 +17683,12 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17034
17683
  });
17035
17684
  return true;
17036
17685
  }
17037
- const cached = this.idleAgentConfigs.get(agentId);
17038
- if (cached) {
17686
+ const lifecycleRecord = this.agentLifecycleRecord(agentId);
17687
+ if (lifecycleRecord?.kind === "idle" || lifecycleRecord?.kind === "cooldown") {
17688
+ const cached = lifecycleRecord.restartSnapshot;
17039
17689
  logger.info(`[Agent ${agentId}] Starting from idle state for runtime profile ${kind} ${key}`);
17040
- if (this.isSpawnFailBackoffActive(agentId)) {
17041
- const state = this.agentSpawnFailBackoff.get(agentId);
17690
+ if (lifecycleRecord.kind === "cooldown") {
17691
+ const state = lifecycleRecord.spawnFailBackoff;
17042
17692
  this.enterSpawnFailCooldownResidency(agentId, cached, state.untilMs, "runtime_profile_auto_restart", "spawn_fail_cooldown_active");
17043
17693
  span.end("ok", {
17044
17694
  attrs: {
@@ -17051,15 +17701,26 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17051
17701
  });
17052
17702
  return true;
17053
17703
  }
17054
- this.idleAgentConfigs.delete(agentId);
17704
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
17705
+ const restartStopEpoch = this.lifecycleRecords.stopEpoch(agentId);
17055
17706
  return this.startAgent(agentId, cached.config, message, void 0, void 0, cached.launchId || void 0).then(() => {
17056
17707
  this.resetSpawnFailBackoff(agentId);
17057
17708
  this.assertStartPendingDeliveryInvariants("runtime-profile-auto-restart-success");
17058
17709
  return true;
17059
17710
  }, (err) => {
17060
17711
  logger.error(`[Agent ${agentId}] Failed to auto-restart for runtime profile notification`, err);
17712
+ if (this.suppressFailedRestartAfterStop(agentId, restartStopEpoch, "runtime-profile-auto-restart")) {
17713
+ span.end("ok", {
17714
+ attrs: {
17715
+ outcome: "suppressed_after_stop",
17716
+ runtime: cached.config.runtime,
17717
+ launchId: cached.launchId || void 0
17718
+ }
17719
+ });
17720
+ return false;
17721
+ }
17061
17722
  if (this.reportRunnerCredentialMintFailure(agentId, err, cached.launchId, "runtime_profile_auto_restart")) {
17062
- this.idleAgentConfigs.set(agentId, cached);
17723
+ this.lifecycleRecords.setRestartSnapshot(agentId, cached);
17063
17724
  const report2 = this.recordSpawnFailure(agentId, "runner_credential_mint");
17064
17725
  this.assertStartPendingDeliveryInvariants("runtime-profile-auto-restart-runner-credential-mint-failure");
17065
17726
  if (report2.backoffActive) {
@@ -17082,7 +17743,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17082
17743
  });
17083
17744
  return false;
17084
17745
  }
17085
- this.idleAgentConfigs.set(agentId, cached);
17746
+ this.lifecycleRecords.setRestartSnapshot(agentId, cached);
17086
17747
  const report = this.recordSpawnFailure(agentId, "spawn_error");
17087
17748
  this.assertStartPendingDeliveryInvariants("runtime-profile-auto-restart-spawn-failure");
17088
17749
  if (report.backoffActive) {
@@ -17119,7 +17780,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17119
17780
  continue;
17120
17781
  }
17121
17782
  const title = runtimeProfileNotificationTitle(notification.kind);
17122
- this.broadcastActivity(agentId, "working", title, [{ kind: "system", title, text: message.content }], launchId);
17783
+ this.broadcastActivity(agentId, "working", title, [{ kind: "system", title, text: message.content }], launchId, "system_message");
17123
17784
  this.sendToServer({
17124
17785
  type: "agent:runtime_profile:daemon_release_notice:ack",
17125
17786
  agentId,
@@ -17148,7 +17809,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17148
17809
  span.end("ok", { attrs: { outcome: "deprecated_noop_completed" } });
17149
17810
  return;
17150
17811
  }
17151
- this.broadcastActivity(agentId, "working", title, [{ kind: "system", title, text: control.message }], launchId);
17812
+ this.broadcastActivity(agentId, "working", title, [{ kind: "system", title, text: control.message }], launchId, "system_message");
17152
17813
  this.sendToServer({
17153
17814
  type: "agent:runtime_profile:daemon_release_notice:ack",
17154
17815
  agentId,
@@ -17198,7 +17859,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17198
17859
  return deleteWorkspaceDirectory(this.dataDir, directoryName);
17199
17860
  }
17200
17861
  // Workspace file browsing
17201
- async getFileTree(agentId, dirPath) {
17862
+ async getFileTree(agentId, dirPath, includeHidden = false) {
17202
17863
  const agentDir = path14.join(this.dataDir, agentId);
17203
17864
  try {
17204
17865
  await stat2(agentDir);
@@ -17211,9 +17872,16 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17211
17872
  if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
17212
17873
  return [];
17213
17874
  }
17875
+ const relativePath = path14.relative(agentDir, resolved);
17876
+ if (isWorkspaceNeverVisibleHiddenPath(relativePath)) {
17877
+ return [];
17878
+ }
17879
+ if (!includeHidden && isWorkspaceHiddenPath(relativePath)) {
17880
+ return [];
17881
+ }
17214
17882
  targetDir = resolved;
17215
17883
  }
17216
- return this.listDirectoryChildren(targetDir, agentDir);
17884
+ return this.listDirectoryChildren(targetDir, agentDir, includeHidden);
17217
17885
  }
17218
17886
  async readFile(agentId, filePath) {
17219
17887
  const agentDir = path14.join(this.dataDir, agentId);
@@ -17221,6 +17889,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17221
17889
  if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
17222
17890
  throw new Error("Access denied");
17223
17891
  }
17892
+ const relativePath = path14.relative(agentDir, resolved);
17893
+ if (isWorkspaceNeverVisibleHiddenPath(relativePath) || isWorkspaceSecretFilePath(relativePath)) {
17894
+ throw new Error("Preview is disabled for sensitive workspace files");
17895
+ }
17224
17896
  const info = await stat2(resolved);
17225
17897
  if (info.isDirectory()) throw new Error("Cannot read a directory");
17226
17898
  const ext = path14.extname(resolved).toLowerCase();
@@ -17256,7 +17928,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17256
17928
  };
17257
17929
  async getSessionTranscript(agentId) {
17258
17930
  const agent = this.agents.get(agentId);
17259
- const idle = this.idleAgentConfigs.get(agentId);
17931
+ const idle = this.lifecycleRecords.getRestartSnapshot(agentId);
17260
17932
  const config = agent?.config ?? idle?.config ?? null;
17261
17933
  const actualSessionId = agent?.sessionId || idle?.sessionId || null;
17262
17934
  if (!config) {
@@ -17433,7 +18105,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17433
18105
  }
17434
18106
  async listSkills(agentId, runtimeHint) {
17435
18107
  const agent = this.agents.get(agentId);
17436
- const idle = this.idleAgentConfigs.get(agentId);
18108
+ const idle = this.lifecycleRecords.getRestartSnapshot(agentId);
17437
18109
  const config = agent?.config ?? idle?.config ?? null;
17438
18110
  const runtime = runtimeHint || config?.runtime || "claude";
17439
18111
  const workspaceDir = path14.join(this.dataDir, agentId);
@@ -17533,12 +18205,19 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17533
18205
  * should carry explicit reason/correlation/window attrs so the server no
17534
18206
  * longer infers lifecycle semantics from generic activity strings.
17535
18207
  */
17536
- broadcastActivity(agentId, activity, detail, extraTrajectory = [], launchIdOverride) {
18208
+ broadcastActivity(agentId, activityKind, detail, extraTrajectory = [], launchIdOverride, detailKind = "other", activityDisplay = activityKind, subagentLineage) {
17537
18209
  const ap = this.agents.get(agentId);
17538
18210
  const entries = [...extraTrajectory];
17539
18211
  const hasToolStart = entries.some((e) => e.kind === "tool_start");
17540
18212
  if (!hasToolStart) {
17541
- entries.push({ kind: "status", activity, detail });
18213
+ entries.push({
18214
+ kind: "status",
18215
+ activity: activityKind,
18216
+ activityKind,
18217
+ detail,
18218
+ detailKind,
18219
+ ...subagentLineage ? { subagent: subagentLineage } : {}
18220
+ });
17542
18221
  }
17543
18222
  const launchId = launchIdOverride || ap?.launchId || void 0;
17544
18223
  const clientSeq = this.nextActivityClientSeq(agentId);
@@ -17546,23 +18225,28 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17546
18225
  this.sendToServer({
17547
18226
  type: "agent:activity",
17548
18227
  agentId,
17549
- activity,
18228
+ activity: activityDisplay,
18229
+ activityKind,
17550
18230
  detail,
18231
+ detailKind,
17551
18232
  entries,
17552
18233
  launchId,
17553
18234
  clientSeq,
17554
18235
  producerFactId
17555
18236
  });
17556
- this.recordActivityProducedTrace(agentId, activity, detail, entries, ap, launchId, clientSeq, producerFactId);
18237
+ this.recordActivityProducedTrace(agentId, activityKind, detail, detailKind, entries, ap, launchId, clientSeq, producerFactId);
17557
18238
  if (ap) {
17558
- ap.lastActivity = activity;
18239
+ ap.lastActivityKind = activityKind;
18240
+ ap.lastActivity = activityDisplay;
17559
18241
  ap.lastActivityDetail = detail;
17560
- if (activity === "working" || activity === "thinking") {
17561
- if (!ap.activityHeartbeat) {
17562
- ap.activityHeartbeat = setInterval(() => {
18242
+ ap.lastActivityDetailKind = detailKind;
18243
+ if (activityKind === "working" || activityKind === "thinking") {
18244
+ if (ap.activityHeartbeat.kind === "inactive") {
18245
+ const timer = setInterval(() => {
17563
18246
  if (this.markRuntimeProgressStaleIfNeeded(agentId, ap)) return;
17564
18247
  this.recordRuntimeTraceEvent(agentId, ap, "activity.heartbeat.sent", {
17565
- activity: ap.lastActivity
18248
+ activity: ap.lastActivityKind,
18249
+ detailKind: ap.lastActivityDetailKind
17566
18250
  });
17567
18251
  const heartbeatLaunchId = launchIdOverride || ap.launchId || void 0;
17568
18252
  const heartbeatClientSeq = this.nextActivityClientSeq(agentId);
@@ -17571,23 +18255,23 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17571
18255
  type: "agent:activity",
17572
18256
  agentId,
17573
18257
  activity: ap.lastActivity,
18258
+ activityKind: ap.lastActivityKind,
17574
18259
  detail: ap.lastActivityDetail,
18260
+ detailKind: ap.lastActivityDetailKind,
17575
18261
  launchId: heartbeatLaunchId,
17576
18262
  clientSeq: heartbeatClientSeq,
17577
18263
  producerFactId: heartbeatProducerFactId
17578
18264
  });
17579
- this.recordActivityProducedTrace(agentId, ap.lastActivity, ap.lastActivityDetail, [], ap, heartbeatLaunchId, heartbeatClientSeq, heartbeatProducerFactId);
18265
+ this.recordActivityProducedTrace(agentId, ap.lastActivityKind, ap.lastActivityDetail, ap.lastActivityDetailKind, [], ap, heartbeatLaunchId, heartbeatClientSeq, heartbeatProducerFactId);
17580
18266
  }, ACTIVITY_HEARTBEAT_MS);
18267
+ ap.activityHeartbeat = { kind: "active", timer };
17581
18268
  }
17582
18269
  } else {
17583
- if (ap.activityHeartbeat) {
17584
- clearInterval(ap.activityHeartbeat);
17585
- ap.activityHeartbeat = null;
17586
- }
18270
+ this.clearActivityHeartbeat(ap);
17587
18271
  }
17588
18272
  }
17589
18273
  }
17590
- recordActivityProducedTrace(agentId, activity, detail, entries, ap, launchId, clientSeq, producerFactId) {
18274
+ recordActivityProducedTrace(agentId, activityKind, detail, detailKind, entries, ap, launchId, clientSeq, producerFactId) {
17591
18275
  const runtimeContext = ap?.config.runtimeContext;
17592
18276
  this.recordDaemonTrace("daemon.agent.activity.produced", {
17593
18277
  agentId,
@@ -17595,8 +18279,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17595
18279
  server_id: runtimeContext?.serverId,
17596
18280
  machine_id: runtimeContext?.machineId,
17597
18281
  process_instance_id: ap?.processInstanceId,
17598
- activity,
18282
+ activity: activityKind,
18283
+ activity_kind: activityKind,
17599
18284
  detail_present: Boolean(detail),
18285
+ detail_kind: detailKind,
17600
18286
  entry_kinds: entries.map((e) => e.kind).join(","),
17601
18287
  ap_present: Boolean(ap),
17602
18288
  launchId,
@@ -17638,8 +18324,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17638
18324
  */
17639
18325
  respondToActivityProbe(agentId, probeId) {
17640
18326
  const ap = this.agents.get(agentId);
17641
- const activity = ap?.lastActivity || "offline";
18327
+ const activityKind = ap?.lastActivityKind || "offline";
18328
+ const activity = ap?.lastActivity || activityKind;
17642
18329
  const detail = ap?.lastActivityDetail || (ap ? "" : "Agent not running");
18330
+ const detailKind = ap?.lastActivityDetailKind || (ap ? "none" : "runtime_unavailable");
17643
18331
  const launchId = ap?.launchId || void 0;
17644
18332
  const clientSeq = this.nextActivityClientSeq(agentId);
17645
18333
  const producerFactId = this.buildActivityProducerFactId(agentId, launchId, clientSeq);
@@ -17647,29 +18335,28 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17647
18335
  type: "agent:activity",
17648
18336
  agentId,
17649
18337
  activity,
18338
+ activityKind,
17650
18339
  detail,
18340
+ detailKind,
17651
18341
  launchId,
17652
18342
  probeId,
17653
18343
  clientSeq,
17654
18344
  producerFactId
17655
18345
  });
17656
- this.recordActivityProducedTrace(agentId, activity, detail, [], ap, launchId, clientSeq, producerFactId);
18346
+ this.recordActivityProducedTrace(agentId, activityKind, detail, detailKind, [], ap, launchId, clientSeq, producerFactId);
17657
18347
  }
17658
18348
  flushPendingTrajectory(agentId) {
17659
18349
  const ap = this.agents.get(agentId);
17660
18350
  const pending = ap?.pendingTrajectory;
17661
18351
  if (!ap || !pending) return;
17662
- if (pending.timer) clearTimeout(pending.timer);
18352
+ clearTimeout(pending.timer);
17663
18353
  ap.pendingTrajectory = null;
17664
18354
  const text = pending.text.length > MAX_TRAJECTORY_TEXT ? pending.text.slice(0, MAX_TRAJECTORY_TEXT) + "\u2026" : pending.text;
17665
18355
  if (!text) return;
17666
- if (pending.kind === "thinking") {
17667
- this.broadcastActivity(agentId, "thinking", "", [{ kind: "thinking", text }]);
17668
- } else {
17669
- this.broadcastActivity(agentId, "thinking", "", [{ kind: "text", text }]);
17670
- }
18356
+ const entry = pending.kind === "thinking" ? { kind: "thinking", text, ...pending.subagent ? { subagent: pending.subagent } : {} } : { kind: "text", text, ...pending.subagent ? { subagent: pending.subagent } : {} };
18357
+ this.broadcastActivity(agentId, "thinking", "", [entry], void 0, "none");
17671
18358
  }
17672
- queueTrajectoryText(agentId, kind, text) {
18359
+ queueTrajectoryText(agentId, kind, text, subagent) {
17673
18360
  const ap = this.agents.get(agentId);
17674
18361
  if (!ap) {
17675
18362
  this.recordDaemonTrace("daemon.agent.activity.skipped", {
@@ -17681,37 +18368,38 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17681
18368
  return;
17682
18369
  }
17683
18370
  if (!text) {
17684
- this.broadcastActivity(agentId, "thinking", "");
18371
+ this.broadcastActivity(agentId, "thinking", "", [], void 0, "none");
17685
18372
  return;
17686
18373
  }
17687
18374
  const pending = ap.pendingTrajectory;
17688
- if (pending && pending.kind === kind) {
18375
+ const sameLineage = JSON.stringify(pending?.subagent ?? null) === JSON.stringify(subagent ?? null);
18376
+ if (pending && pending.kind === kind && sameLineage) {
17689
18377
  pending.text += text;
17690
- if (pending.timer) clearTimeout(pending.timer);
18378
+ clearTimeout(pending.timer);
17691
18379
  pending.timer = setTimeout(() => this.flushPendingTrajectory(agentId), TRAJECTORY_COALESCE_MS);
17692
18380
  return;
17693
18381
  }
17694
18382
  this.flushPendingTrajectory(agentId);
17695
- if (ap.lastActivity !== "thinking" || ap.lastActivityDetail !== "") {
17696
- this.broadcastActivity(agentId, "thinking", "");
18383
+ if (ap.lastActivityKind !== "thinking" || ap.lastActivityDetailKind !== "none") {
18384
+ this.broadcastActivity(agentId, "thinking", "", [], void 0, "none");
17697
18385
  }
17698
18386
  ap.pendingTrajectory = {
17699
18387
  kind,
17700
18388
  text,
18389
+ ...subagent ? { subagent } : {},
17701
18390
  timer: setTimeout(() => this.flushPendingTrajectory(agentId), TRAJECTORY_COALESCE_MS)
17702
18391
  };
17703
18392
  }
17704
18393
  clearCompactionWatchdog(ap) {
17705
- if (ap.compactionWatchdog) {
17706
- clearTimeout(ap.compactionWatchdog);
17707
- ap.compactionWatchdog = null;
18394
+ if (ap.compaction.kind === "active" && ap.compaction.watchdog) {
18395
+ clearTimeout(ap.compaction.watchdog);
17708
18396
  }
17709
- ap.compactionStartedAt = null;
18397
+ ap.compaction = { kind: "none" };
17710
18398
  }
17711
18399
  clearStalledRecoverySigtermWatchdog(ap) {
17712
- if (!ap.stalledRecoverySigtermTimer) return;
17713
- clearTimeout(ap.stalledRecoverySigtermTimer);
17714
- ap.stalledRecoverySigtermTimer = null;
18400
+ if (ap.exit.kind !== "live" || !ap.exit.stalledRecoverySigtermTimer) return;
18401
+ clearTimeout(ap.exit.stalledRecoverySigtermTimer);
18402
+ ap.exit = { ...ap.exit, stalledRecoverySigtermTimer: null };
17715
18403
  }
17716
18404
  mergeRuntimeExitTraceAttrs(runtime, attrs) {
17717
18405
  this.runtimeExitTraceAttrs.set(runtime, {
@@ -17723,8 +18411,10 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17723
18411
  this.clearStalledRecoverySigtermWatchdog(ap);
17724
18412
  const timeoutMs = stalledRecoverySigtermTimeoutMs();
17725
18413
  const runtimeAtSignal = ap.runtime;
17726
- ap.stalledRecoverySigtermTimer = setTimeout(() => {
17727
- ap.stalledRecoverySigtermTimer = null;
18414
+ const timer = setTimeout(() => {
18415
+ if (ap.exit.kind === "live" && ap.exit.stalledRecoverySigtermTimer === timer) {
18416
+ ap.exit = { ...ap.exit, stalledRecoverySigtermTimer: null };
18417
+ }
17728
18418
  const current = this.agents.get(agentId);
17729
18419
  if (!current || current !== ap || current.runtime !== runtimeAtSignal || current.gatedSteering.expectedTerminationReason !== "stalled_recovery") {
17730
18420
  return;
@@ -17781,26 +18471,29 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17781
18471
  logger.warn(`[Agent ${agentId}] Failed to force kill stalled ${runtimeLabel} process: ${reason}`);
17782
18472
  }
17783
18473
  }, timeoutMs);
18474
+ if (ap.exit.kind === "live") {
18475
+ ap.exit = { ...ap.exit, stalledRecoverySigtermTimer: timer };
18476
+ }
17784
18477
  }
17785
18478
  startCompactionWatchdog(agentId, ap) {
17786
18479
  this.clearCompactionWatchdog(ap);
17787
18480
  const startedAt = Date.now();
17788
- ap.compactionStartedAt = startedAt;
17789
- ap.compactionWatchdog = setTimeout(() => {
18481
+ const watchdog = setTimeout(() => {
17790
18482
  this.markCompactionStale(agentId, startedAt);
17791
18483
  }, COMPACTION_STALE_MS);
18484
+ ap.compaction = { kind: "active", startedAt, watchdog };
17792
18485
  }
17793
18486
  markCompactionStale(agentId, startedAt) {
17794
18487
  const ap = this.agents.get(agentId);
17795
- if (!ap || ap.compactionStartedAt !== startedAt) return;
17796
- ap.compactionWatchdog = null;
17797
- this.broadcastActivity(agentId, "working", "Context compaction still running; no finish event observed");
18488
+ if (!ap || ap.compaction.kind !== "active" || ap.compaction.startedAt !== startedAt) return;
18489
+ ap.compaction = { ...ap.compaction, watchdog: null };
18490
+ this.broadcastActivity(agentId, "working", "Context compaction still running; no finish event observed", [], void 0, "compaction_stale");
17798
18491
  }
17799
18492
  completeCompactionIfActive(agentId, detail = "Context compaction finished", options = {}) {
17800
18493
  const ap = this.agents.get(agentId);
17801
- if (!ap || !ap.compactionStartedAt) return;
18494
+ if (!ap || ap.compaction.kind !== "active") return;
17802
18495
  this.clearCompactionWatchdog(ap);
17803
- this.broadcastActivity(agentId, "working", detail, [{ kind: "compaction_finished" }]);
18496
+ this.broadcastActivity(agentId, "working", detail, [{ kind: "compaction_finished" }], void 0, "compaction_finished");
17804
18497
  const reduction = reduceApmGatedCompaction(ap.gatedSteering, { kind: "compaction_finished" });
17805
18498
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, {
17806
18499
  event: "compaction_finished",
@@ -17813,7 +18506,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
17813
18506
  }
17814
18507
  interruptCompactionIfActive(agentId) {
17815
18508
  const ap = this.agents.get(agentId);
17816
- if (!ap || !ap.compactionStartedAt && !ap.gatedSteering.compacting) return;
18509
+ if (!ap || ap.compaction.kind !== "active" && !ap.gatedSteering.compacting) return;
17817
18510
  this.clearCompactionWatchdog(ap);
17818
18511
  const reduction = reduceApmGatedCompaction(ap.gatedSteering, { kind: "compaction_interrupted" });
17819
18512
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState);
@@ -18016,8 +18709,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18016
18709
  * for diagnostics, user-facing reporting, and sticky terminal-failure gating.
18017
18710
  */
18018
18711
  invalidateRecoveryErrorView(ap) {
18019
- ap.recentDecisionStderr = [];
18020
- ap.runtimeErrorSinceProgress = false;
18712
+ ap.decisionErrorWindow.noteRuntimeProgress();
18021
18713
  }
18022
18714
  recordGatedSteeringEvent(agentId, ap, event, attrs = {}) {
18023
18715
  if (ap.runtime.descriptor.busyDelivery !== "gated") return;
@@ -18096,7 +18788,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18096
18788
  runtime_error_backoff_remaining_ms: runtimeErrorBackoffRemainingMs,
18097
18789
  runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
18098
18790
  runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
18099
- runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null,
18791
+ runtime_error_backoff_timer_scheduled: scheduled || this.runtimeErrorDeliveryBackoffTimerScheduled(ap),
18100
18792
  delivered_messages_count: 0
18101
18793
  });
18102
18794
  return false;
@@ -18133,7 +18825,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18133
18825
  });
18134
18826
  return false;
18135
18827
  }
18136
- this.broadcastActivity(agentId, "working", "Message received");
18828
+ this.broadcastMessageReceivedActivity(agentId);
18137
18829
  let accepted = true;
18138
18830
  if (runtimeProfileMessages.length > 0) {
18139
18831
  ap.inbox.splice(0, ap.inbox.length, ...ordinaryMessageCandidates);
@@ -18226,7 +18918,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18226
18918
  * deliver, so explicit starts with no activation produce no phase-6 row.
18227
18919
  */
18228
18920
  openActivationTransition(agentId, ap, launchSource) {
18229
- if (ap.activationTransition || ap.initialActivationDelivered) return;
18921
+ if (ap.activation.kind !== "idle") return;
18230
18922
  const identity = this.launchIdentityAttrs(agentId, ap, launchSource);
18231
18923
  const state = {
18232
18924
  stateInstanceId: randomUUID6(),
@@ -18234,7 +18926,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18234
18926
  identity,
18235
18927
  negativeEvidenceBucket: launchReadinessNegativeEvidence(identity)
18236
18928
  };
18237
- ap.activationTransition = state;
18929
+ ap.activation = { kind: "open", transition: state };
18238
18930
  this.recordDaemonTrace(LAUNCH_ACTIVATION_DELIVERY_TRANSITION_SPAN, buildLaunchActivationEnterAttrs(state));
18239
18931
  }
18240
18932
  /**
@@ -18245,10 +18937,14 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18245
18937
  * delivered on `advanced` so later normal deliveries are not re-counted.
18246
18938
  */
18247
18939
  closeActivationTransition(ap, closeResult, deliveredVia) {
18248
- if (closeResult === "advanced") ap.initialActivationDelivered = true;
18249
- const state = ap.activationTransition;
18250
- if (!state) return;
18251
- ap.activationTransition = null;
18940
+ if (ap.activation.kind !== "open") {
18941
+ if (closeResult === "advanced" && ap.activation.kind === "idle") {
18942
+ ap.activation = { kind: "delivered" };
18943
+ }
18944
+ return;
18945
+ }
18946
+ const state = ap.activation.transition;
18947
+ ap.activation = closeResult === "advanced" ? { kind: "delivered" } : { kind: "closed" };
18252
18948
  this.recordDaemonTrace(
18253
18949
  LAUNCH_ACTIVATION_DELIVERY_TRANSITION_SPAN,
18254
18950
  buildLaunchActivationCloseAttrs(state, closeResult, this.launchTransitionSeq++, deliveredVia),
@@ -18266,15 +18962,22 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18266
18962
  fenced ? Date.now() + timeoutMs : null
18267
18963
  );
18268
18964
  if (!fenced) return;
18269
- ap.startupTimeoutTimer = setTimeout(() => {
18965
+ if (ap.startup.kind !== "waiting") return;
18966
+ const timer = setTimeout(() => {
18270
18967
  this.handleRuntimeStartupTimeout(agentId, ap, timeoutMs);
18271
18968
  }, timeoutMs);
18272
- ap.startupTimeoutTimer.unref?.();
18969
+ timer.unref?.();
18970
+ ap.startup = { ...ap.startup, timer };
18273
18971
  }
18274
18972
  clearRuntimeStartupTimeout(ap) {
18275
- if (!ap.startupTimeoutTimer) return;
18276
- clearTimeout(ap.startupTimeoutTimer);
18277
- ap.startupTimeoutTimer = null;
18973
+ if (ap.startup.kind !== "waiting" || !ap.startup.timer) return;
18974
+ clearTimeout(ap.startup.timer);
18975
+ ap.startup = { ...ap.startup, timer: null };
18976
+ }
18977
+ markRuntimeStartupReady(ap) {
18978
+ if (ap.startup.kind === "ready") return;
18979
+ this.clearRuntimeStartupTimeout(ap);
18980
+ ap.startup = agentProcessStartupReady(ap.startup);
18278
18981
  }
18279
18982
  runtimeStartupReadinessSatisfiedByEvent(ap, event) {
18280
18983
  if ((ap.driver.startupReadiness ?? "first_event") !== "initial_turn") {
@@ -18286,7 +18989,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18286
18989
  const current = this.agents.get(agentId);
18287
18990
  if (current !== ap) return;
18288
18991
  const reduction = reduceApmStartupTimeoutTermination(ap.gatedSteering, {
18289
- hasRuntimeProgressEvent: ap.startupReadinessSatisfied
18992
+ hasRuntimeProgressEvent: ap.startup.kind === "ready"
18290
18993
  });
18291
18994
  if (!reduction.shouldTerminate) {
18292
18995
  this.clearRuntimeStartupTimeout(ap);
@@ -18298,7 +19001,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18298
19001
  const terminalFailureDetail = classifyTerminalFailure(ap);
18299
19002
  const detail = terminalFailureDetail?.detail ?? formatRuntimeStartTimeoutMessage(ap.driver.id);
18300
19003
  ap.lastRuntimeError = detail;
18301
- ap.runtimeErrorSinceProgress = true;
19004
+ ap.decisionErrorWindow.recordRuntimeError(detail);
18302
19005
  ap.runtimeProgress.markStale();
18303
19006
  const staleForMs = Math.max(timeoutMs, ap.runtimeProgress.ageMs());
18304
19007
  const diagnostic = buildRuntimeStallDiagnostic(ap, staleForMs, Math.max(1, Math.floor(staleForMs / 6e4)));
@@ -18316,7 +19019,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18316
19019
  ...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_stalled")
18317
19020
  });
18318
19021
  logger.warn(`[Agent ${agentId}] ${ap.driver.id} did not reach startup readiness within ${timeoutMs}ms; terminating process`);
18319
- this.broadcastActivity(agentId, "error", detail, [{ kind: "text", text: `Error: ${detail}` }], ap.launchId);
19022
+ this.broadcastActivity(agentId, "error", detail, [{ kind: "text", text: `Error: ${detail}` }], ap.launchId, "runtime_error");
18320
19023
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
18321
19024
  this.cacheStartupTimeoutRetryConfig(agentId, ap);
18322
19025
  try {
@@ -18339,7 +19042,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18339
19042
  const reduction = reduceApmStartupRequestErrorTermination(ap.gatedSteering);
18340
19043
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "startup_request_error" });
18341
19044
  ap.lastRuntimeError = event.message;
18342
- ap.runtimeErrorSinceProgress = true;
19045
+ ap.decisionErrorWindow.recordRuntimeError(event.message);
18343
19046
  ap.runtimeProgress.markStale();
18344
19047
  ap.notifications.clearPending();
18345
19048
  ap.notifications.clearTimer();
@@ -18370,9 +19073,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18370
19073
  );
18371
19074
  this.broadcastActivity(agentId, "error", visibleErrorMessage, [
18372
19075
  { kind: "text", text: `Error: ${visibleErrorMessage}` }
18373
- ], ap.launchId);
19076
+ ], ap.launchId, "runtime_error");
18374
19077
  this.sendAgentStatus(agentId, "inactive", ap.launchId);
18375
- this.idleAgentConfigs.delete(agentId);
19078
+ this.lifecycleRecords.deleteRestartSnapshot(agentId);
18376
19079
  try {
18377
19080
  this.runtimeExitTraceAttrs.set(ap.runtime, {
18378
19081
  stop_source: "startup_request_error",
@@ -18390,17 +19093,34 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18390
19093
  return /thinking.*redacted_thinking|redacted_thinking.*thinking/i.test(message) && /cannot be modified/i.test(message) || /messages\.\d+\.content\.\d+\.text\.start_timestamp:\s*Extra inputs are not permitted/i.test(message);
18391
19094
  }
18392
19095
  markRuntimeProgressStaleIfNeeded(agentId, ap) {
18393
- if (ap.lastActivity !== "working" && ap.lastActivity !== "thinking") return false;
19096
+ if (ap.lastActivityKind !== "working" && ap.lastActivityKind !== "thinking") return false;
18394
19097
  if (ap.runtimeProgress.isStale) return true;
18395
19098
  const staleForMs = ap.runtimeProgress.ageMs();
18396
19099
  if (staleForMs < RUNTIME_PROGRESS_STALE_MS) return false;
19100
+ const subprocessPidAlive = this.probeRuntimeProcessLiveness(ap);
19101
+ if (subprocessPidAlive === true) {
19102
+ this.recordDaemonTrace("daemon.runtime.stall.suppressed_alive", {
19103
+ ...this.processLifecycleIdentityAttrs(agentId, ap),
19104
+ last_event_kind: ap.lastActivityKind || void 0,
19105
+ last_event_age_ms_bucket: bucketMs(staleForMs),
19106
+ subprocess_pid_alive: true,
19107
+ subprocess_socket_alive: !ap.runtime.closed,
19108
+ daemon_connected_to_server: this.serverConnected()
19109
+ });
19110
+ this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.silent_alive", {
19111
+ staleForMs: bucketMs(staleForMs),
19112
+ lastActivity: ap.lastActivityKind || void 0,
19113
+ lastActivityDetailKind: ap.lastActivityDetailKind
19114
+ });
19115
+ return false;
19116
+ }
18397
19117
  ap.runtimeProgress.markStale();
18398
19118
  const staleForMinutes = Math.max(1, Math.floor(staleForMs / 6e4));
18399
19119
  const diagnostic = buildRuntimeStallDiagnostic(ap, staleForMs, staleForMinutes);
18400
19120
  const projection = projectApmRuntimeProgressStalledTrace({
18401
19121
  turnReason: diagnostic.turnReason,
18402
19122
  staleForMs,
18403
- lastActivity: ap.lastActivity,
19123
+ lastActivity: ap.lastActivityKind,
18404
19124
  lastActivityDetailPresent: diagnostic.lastActivityDetailPresent,
18405
19125
  lastActivityDetailKind: diagnostic.lastActivityDetailKind
18406
19126
  });
@@ -18413,26 +19133,28 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18413
19133
  ...runtimeTraceCounterAttrs(ap),
18414
19134
  ...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_stalled")
18415
19135
  });
18416
- let subprocessPidAlive;
18417
- if (typeof ap.runtime.pid === "number") {
18418
- try {
18419
- process.kill(ap.runtime.pid, 0);
18420
- subprocessPidAlive = true;
18421
- } catch {
18422
- subprocessPidAlive = false;
18423
- }
18424
- }
18425
19136
  this.recordDaemonTrace("daemon.runtime.stall.detected", {
18426
19137
  ...this.processLifecycleIdentityAttrs(agentId, ap),
18427
- last_event_kind: ap.lastActivity || void 0,
19138
+ last_event_kind: ap.lastActivityKind || void 0,
18428
19139
  last_event_age_ms_bucket: bucketMs(staleForMs),
18429
19140
  subprocess_pid_alive: subprocessPidAlive,
18430
19141
  subprocess_socket_alive: !ap.runtime.closed,
18431
19142
  daemon_connected_to_server: this.serverConnected()
18432
19143
  }, "error");
18433
- this.broadcastActivity(agentId, "error", diagnostic.detail);
19144
+ this.broadcastActivity(agentId, "error", diagnostic.detail, [], void 0, "runtime_stalled");
18434
19145
  return true;
18435
19146
  }
19147
+ probeRuntimeProcessLiveness(ap) {
19148
+ const pid = ap.runtime.pid;
19149
+ if (typeof pid !== "number") return void 0;
19150
+ try {
19151
+ process.kill(pid, 0);
19152
+ return true;
19153
+ } catch (err) {
19154
+ const code = typeof err === "object" && err !== null && "code" in err ? err.code : void 0;
19155
+ return code === "EPERM" ? true : false;
19156
+ }
19157
+ }
18436
19158
  recoverStaleProcessForQueuedMessageIfNeeded(agentId, ap) {
18437
19159
  const staleForMs = ap.runtimeProgress.ageMs();
18438
19160
  const reduction = reduceApmStalledRecoveryTermination(ap.gatedSteering, {
@@ -18457,7 +19179,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18457
19179
  reason: "stalled_recovery",
18458
19180
  turnReason: diagnostic.turnReason,
18459
19181
  staleForMs,
18460
- lastActivity: ap.lastActivity,
19182
+ lastActivity: ap.lastActivityKind,
18461
19183
  lastActivityDetailPresent: diagnostic.lastActivityDetailPresent,
18462
19184
  lastActivityDetailKind: diagnostic.lastActivityDetailKind,
18463
19185
  pendingMessages: ap.inbox.length,
@@ -18476,7 +19198,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18476
19198
  logger.warn(
18477
19199
  `[Agent ${agentId}] ${runtimeLabel} process stalled for ${staleForMinutes}m with ${ap.inbox.length} queued message(s); terminating for restart`
18478
19200
  );
18479
- this.broadcastActivity(agentId, "working", `Restarting stalled ${runtimeLabel} runtime for queued message`);
19201
+ this.broadcastActivity(agentId, "working", `Restarting stalled ${runtimeLabel} runtime for queued message`, [], void 0, "stalled_recovery");
18480
19202
  try {
18481
19203
  this.runtimeExitTraceAttrs.set(ap.runtime, projection.processExitAttrs);
18482
19204
  this.startStalledRecoverySigtermWatchdog(agentId, ap, runtimeLabel, ap.inbox.length, staleForMs);
@@ -18534,9 +19256,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18534
19256
  if (ap) {
18535
19257
  const wasStalled = ap.runtimeProgress.isStale;
18536
19258
  if (this.runtimeStartupReadinessSatisfiedByEvent(ap, event)) {
18537
- ap.startupReadinessSatisfied = true;
19259
+ this.markRuntimeStartupReady(ap);
18538
19260
  this.closeRuntimeReadinessTransition(ap, "advanced");
18539
- this.clearRuntimeStartupTimeout(ap);
18540
19261
  }
18541
19262
  this.noteRuntimeTraceCounter(ap, event);
18542
19263
  const eventAttrs = event.kind === "internal_progress" ? {
@@ -18544,6 +19265,15 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18544
19265
  source: event.source,
18545
19266
  itemType: event.itemType,
18546
19267
  payloadBytes: event.payloadBytes
19268
+ } : event.kind === "subagent_progress" ? {
19269
+ kind: event.kind,
19270
+ source: event.source,
19271
+ phase: event.phase,
19272
+ parent_tool_use_id_present: Boolean(event.parentToolUseId),
19273
+ subagent_type_present: Boolean(event.subagentType),
19274
+ task_id_present: Boolean(event.taskId),
19275
+ last_tool_name_present: Boolean(event.lastToolName),
19276
+ payloadBytes: event.payloadBytes
18547
19277
  } : event.kind === "runtime_diagnostic" ? runtimeDiagnosticTraceAttrs(event) : event.kind === "runtime_recovery" ? runtimeRecoveryTraceAttrs(event) : { kind: event.kind };
18548
19278
  this.recordRuntimeTraceEvent(agentId, ap, "runtime.event.received", eventAttrs);
18549
19279
  const recordProgressObservedAfterStall = () => {
@@ -18565,6 +19295,15 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18565
19295
  itemType: event.itemType,
18566
19296
  payloadBytes: event.payloadBytes
18567
19297
  });
19298
+ this.maybeBroadcastRuntimeProgressActivity(agentId, ap);
19299
+ return;
19300
+ }
19301
+ if (event.kind === "subagent_progress") {
19302
+ this.noteRuntimeProgress(ap, event.kind);
19303
+ recordProgressObservedAfterStall();
19304
+ this.invalidateRecoveryErrorView(ap);
19305
+ this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
19306
+ this.recordSubagentProgressActivity(agentId, ap, event);
18568
19307
  return;
18569
19308
  }
18570
19309
  if (event.kind === "runtime_diagnostic") {
@@ -18601,7 +19340,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18601
19340
  break;
18602
19341
  case "thinking": {
18603
19342
  this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
18604
- this.queueTrajectoryText(agentId, "thinking", event.text);
19343
+ this.queueTrajectoryText(agentId, "thinking", event.text, event.subagent);
18605
19344
  if (ap) {
18606
19345
  this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
18607
19346
  const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
@@ -18612,7 +19351,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18612
19351
  }
18613
19352
  case "text": {
18614
19353
  this.completeCompactionIfActive(agentId, "Context compaction finished (inferred from resumed output)");
18615
- this.queueTrajectoryText(agentId, "text", event.text);
19354
+ this.queueTrajectoryText(agentId, "text", event.text, event.subagent);
18616
19355
  if (ap) {
18617
19356
  this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
18618
19357
  const reduction = reduceApmGatedAssistantContinuation(ap.gatedSteering);
@@ -18639,8 +19378,9 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18639
19378
  this.broadcastActivity(agentId, "working", detail, [{
18640
19379
  kind: "tool_start",
18641
19380
  toolName: invocation.toolName,
18642
- toolInput: inputSummary
18643
- }]);
19381
+ toolInput: inputSummary,
19382
+ ...event.subagent ? { subagent: event.subagent } : {}
19383
+ }], void 0, event.subagent ? "subagent_activity" : this.toolActivityDetailKind(invocation.toolName));
18644
19384
  break;
18645
19385
  }
18646
19386
  case "tool_output": {
@@ -18664,7 +19404,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18664
19404
  this.flushPendingTrajectory(agentId);
18665
19405
  if (ap) this.recordRuntimeTraceEvent(agentId, ap, "runtime.context_compaction.started");
18666
19406
  if (ap) this.startCompactionWatchdog(agentId, ap);
18667
- this.broadcastActivity(agentId, "working", "Compacting context", [{ kind: "compaction_started" }]);
19407
+ this.broadcastActivity(agentId, "working", "Compacting context", [{ kind: "compaction_started" }], void 0, "compacting_context");
18668
19408
  if (ap) {
18669
19409
  const reduction = reduceApmGatedCompaction(ap.gatedSteering, { kind: "compaction_started" });
18670
19410
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "compaction_started" });
@@ -18674,7 +19414,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18674
19414
  this.flushPendingTrajectory(agentId);
18675
19415
  if (ap) this.recordRuntimeTraceEvent(agentId, ap, "runtime.context_compaction.finished");
18676
19416
  if (ap) this.clearCompactionWatchdog(ap);
18677
- this.broadcastActivity(agentId, "working", "Context compaction finished", [{ kind: "compaction_finished" }]);
19417
+ this.broadcastActivity(agentId, "working", "Context compaction finished", [{ kind: "compaction_finished" }], void 0, "compaction_finished");
18678
19418
  if (ap) {
18679
19419
  const reduction = reduceApmGatedCompaction(ap.gatedSteering, { kind: "compaction_finished" });
18680
19420
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "compaction_finished" });
@@ -18684,7 +19424,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18684
19424
  case "review_started":
18685
19425
  this.flushPendingTrajectory(agentId);
18686
19426
  if (ap) this.recordRuntimeTraceEvent(agentId, ap, "runtime.review_mode.started");
18687
- this.broadcastActivity(agentId, "working", "Reviewing changes");
19427
+ this.broadcastActivity(agentId, "working", "Reviewing changes", [], void 0, "reviewing_changes");
18688
19428
  if (ap) {
18689
19429
  const reduction = reduceApmGatedReview(ap.gatedSteering, { kind: "review_started" });
18690
19430
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "review_started" });
@@ -18693,7 +19433,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18693
19433
  case "review_finished":
18694
19434
  this.flushPendingTrajectory(agentId);
18695
19435
  if (ap) this.recordRuntimeTraceEvent(agentId, ap, "runtime.review_mode.finished");
18696
- this.broadcastActivity(agentId, "working", "Review finished");
19436
+ this.broadcastActivity(agentId, "working", "Review finished", [], void 0, "review_finished");
18697
19437
  if (ap) {
18698
19438
  const reduction = reduceApmGatedReview(ap.gatedSteering, { kind: "review_finished" });
18699
19439
  this.commitGatedSteeringDecisionState(agentId, ap, reduction.nextState, { event: "review_finished" });
@@ -18730,20 +19470,20 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18730
19470
  if (!this.executeApmGatedSteeringEffect(agentId, ap, deliverStdinEffect)) {
18731
19471
  this.commitApmIdleState(agentId, ap, true);
18732
19472
  if (stickyTerminalFailure) {
18733
- this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
19473
+ this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail, [], void 0, "runtime_error");
18734
19474
  } else if (ap.lastRuntimeError && ap.runtimeErrorDeliveryBackoff.attempts > 0) {
18735
- this.broadcastActivity(agentId, "error", ap.lastRuntimeError);
19475
+ this.broadcastActivity(agentId, "error", ap.lastRuntimeError, [], void 0, "runtime_error");
18736
19476
  } else {
18737
- this.broadcastActivity(agentId, "online", "Idle");
19477
+ this.broadcastActivity(agentId, "online", "Idle", [], void 0, "idle");
18738
19478
  }
18739
19479
  }
18740
19480
  } else {
18741
19481
  if (stickyTerminalFailure) {
18742
- this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail);
19482
+ this.broadcastActivity(agentId, "error", stickyTerminalFailure.detail, [], void 0, "runtime_error");
18743
19483
  } else if (ap.lastRuntimeError) {
18744
- this.broadcastActivity(agentId, "error", ap.lastRuntimeError);
19484
+ this.broadcastActivity(agentId, "error", ap.lastRuntimeError, [], void 0, "runtime_error");
18745
19485
  } else {
18746
- this.broadcastActivity(agentId, "online", "Idle");
19486
+ this.broadcastActivity(agentId, "online", "Idle", [], void 0, "idle");
18747
19487
  }
18748
19488
  }
18749
19489
  this.endRuntimeTrace(ap, stickyTerminalFailure ? "error" : "ok", {
@@ -18775,7 +19515,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18775
19515
  this.flushPendingTrajectory(agentId);
18776
19516
  if (ap) {
18777
19517
  ap.lastRuntimeError = event.message;
18778
- ap.runtimeErrorSinceProgress = true;
19518
+ ap.decisionErrorWindow.recordRuntimeError(event.message);
18779
19519
  }
18780
19520
  let visibleErrorMessage = event.message;
18781
19521
  if (ap) {
@@ -18856,7 +19596,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18856
19596
  }
18857
19597
  this.broadcastActivity(agentId, "error", visibleErrorMessage, [
18858
19598
  { kind: "text", text: `Error: ${visibleErrorMessage}` }
18859
- ]);
19599
+ ], void 0, "runtime_error");
18860
19600
  break;
18861
19601
  }
18862
19602
  }
@@ -18936,7 +19676,8 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
18936
19676
  "error",
18937
19677
  `Start failed: ${reason}`,
18938
19678
  [{ kind: "text", text: `Error: ${reason}` }],
18939
- launchId
19679
+ launchId,
19680
+ "runtime_error"
18940
19681
  );
18941
19682
  return true;
18942
19683
  }
@@ -19004,7 +19745,7 @@ Use \`raft message read\` to catch up on the channels listed above, then stop. R
19004
19745
  runtime_error_backoff_remaining_ms: runtimeErrorBackoffRemainingMs,
19005
19746
  runtime_error_backoff_attempts: ap.runtimeErrorDeliveryBackoff.attempts,
19006
19747
  runtime_error_backoff_reason: ap.runtimeErrorDeliveryBackoff.reason || void 0,
19007
- runtime_error_backoff_timer_scheduled: scheduled || ap.runtimeErrorDeliveryBackoff.timer !== null
19748
+ runtime_error_backoff_timer_scheduled: scheduled || this.runtimeErrorDeliveryBackoffTimerScheduled(ap)
19008
19749
  });
19009
19750
  return false;
19010
19751
  }
@@ -19158,6 +19899,22 @@ ${formatAgentInboxDelta(inboxRows, { totalPendingMessages: inboxCount })}]`;
19158
19899
  "]"
19159
19900
  ].join("\n");
19160
19901
  }
19902
+ formatConcreteMessagesRuntimeInput(messages, driver) {
19903
+ if (messages.length === 1) {
19904
+ return `New message received:
19905
+
19906
+ ${formatIncomingMessage(messages[0], incomingMessageFormatOptionsForDriver(driver))}
19907
+
19908
+ Respond as appropriate. Complete all your work before stopping.
19909
+ ${RESPONSE_TARGET_HINT}`;
19910
+ }
19911
+ return `New messages received:
19912
+
19913
+ ${messages.map((message) => formatIncomingMessage(message, incomingMessageFormatOptionsForDriver(driver))).join("\n")}
19914
+
19915
+ Respond as appropriate. Complete all your work before stopping.
19916
+ ${RESPONSE_TARGET_HINT}`;
19917
+ }
19161
19918
  recordInboxUpdateProjection(agentId, ap, messages, source, mode, renderedInput, totalPendingMessages = messages.length) {
19162
19919
  const rows = projectAgentInboxSnapshot(messages);
19163
19920
  const projectionAttrs = this.inboxProjectionTraceAttrs(rows, totalPendingMessages);
@@ -19362,7 +20119,7 @@ ${RESPONSE_TARGET_HINT}`);
19362
20119
  return true;
19363
20120
  }
19364
20121
  /** List ONE level of a directory — directories returned without children (lazy-loaded on demand) */
19365
- async listDirectoryChildren(dir, rootDir) {
20122
+ async listDirectoryChildren(dir, rootDir, includeHidden = false) {
19366
20123
  let entries;
19367
20124
  try {
19368
20125
  entries = await readdir2(dir, { withFileTypes: true });
@@ -19376,7 +20133,9 @@ ${RESPONSE_TARGET_HINT}`);
19376
20133
  });
19377
20134
  const nodes = [];
19378
20135
  for (const entry of entries) {
19379
- if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
20136
+ const isHidden = entry.name.startsWith(".");
20137
+ if (entry.name === "node_modules") continue;
20138
+ if (isHidden && (!includeHidden || isWorkspaceNeverVisibleHiddenEntry(entry.name))) continue;
19380
20139
  const fullPath = path14.join(dir, entry.name);
19381
20140
  const relativePath = path14.relative(rootDir, fullPath);
19382
20141
  let info;
@@ -19386,9 +20145,9 @@ ${RESPONSE_TARGET_HINT}`);
19386
20145
  continue;
19387
20146
  }
19388
20147
  if (entry.isDirectory()) {
19389
- nodes.push({ name: entry.name, path: relativePath, isDirectory: true, size: 0, modifiedAt: info.mtime.toISOString() });
20148
+ nodes.push({ name: entry.name, path: relativePath, isDirectory: true, size: 0, modifiedAt: info.mtime.toISOString(), isHidden });
19390
20149
  } else {
19391
- nodes.push({ name: entry.name, path: relativePath, isDirectory: false, size: info.size, modifiedAt: info.mtime.toISOString() });
20150
+ nodes.push({ name: entry.name, path: relativePath, isDirectory: false, size: info.size, modifiedAt: info.mtime.toISOString(), isHidden });
19392
20151
  }
19393
20152
  }
19394
20153
  return nodes;
@@ -19426,6 +20185,7 @@ var DaemonConnection = class {
19426
20185
  lastDroppedSendLogAt = 0;
19427
20186
  lastInboundAt = null;
19428
20187
  lastInboundMessageKind = null;
20188
+ inboundProbeInFlight = false;
19429
20189
  pendingActivityByAgent = /* @__PURE__ */ new Map();
19430
20190
  latestObservedLaunchIdByAgent = /* @__PURE__ */ new Map();
19431
20191
  constructor(options) {
@@ -19579,11 +20339,44 @@ var DaemonConnection = class {
19579
20339
  }
19580
20340
  resetWatchdog() {
19581
20341
  this.clearWatchdog();
20342
+ this.inboundProbeInFlight = false;
20343
+ this.scheduleWatchdogDeadline();
20344
+ }
20345
+ scheduleWatchdogDeadline() {
19582
20346
  const ms = this.options.inboundWatchdogMs ?? INBOUND_WATCHDOG_MS;
19583
20347
  this.watchdogTimer = this.clock.setTimeout(() => {
19584
- logger.warn(`[Daemon] No inbound traffic for ${ms / 1e3}s \u2014 forcing reconnect`);
20348
+ if (!this.inboundProbeInFlight && this.ws?.readyState === WebSocket.OPEN) {
20349
+ this.inboundProbeInFlight = true;
20350
+ logger.info(`[Daemon] No inbound traffic for ${ms / 1e3}s \u2014 sending liveness probe`);
20351
+ this.trace("daemon.connection.inbound_probe_sent", {
20352
+ inbound_watchdog_ms: ms,
20353
+ last_inbound_message_kind: this.lastInboundMessageKind,
20354
+ last_inbound_age_ms_bucket: this.lastInboundAgeBucket(),
20355
+ ws_ready_state: this.ws.readyState,
20356
+ reconnecting: this.shouldConnect
20357
+ });
20358
+ try {
20359
+ this.ws.send(JSON.stringify({ type: "ping" }));
20360
+ } catch (err) {
20361
+ this.trace("daemon.connection.inbound_probe_send_failed", {
20362
+ inbound_watchdog_ms: ms,
20363
+ error_class: err instanceof Error ? err.name : typeof err,
20364
+ ws_ready_state: this.ws?.readyState ?? null,
20365
+ reconnecting: this.shouldConnect
20366
+ }, "error");
20367
+ try {
20368
+ this.ws?.terminate();
20369
+ } catch {
20370
+ }
20371
+ return;
20372
+ }
20373
+ this.scheduleWatchdogDeadline();
20374
+ return;
20375
+ }
20376
+ logger.warn(`[Daemon] No inbound traffic after liveness probe \u2014 forcing reconnect`);
19585
20377
  this.trace("daemon.connection.watchdog_timeout", {
19586
20378
  inbound_watchdog_ms: ms,
20379
+ probe_in_flight: this.inboundProbeInFlight,
19587
20380
  last_inbound_message_kind: this.lastInboundMessageKind,
19588
20381
  last_inbound_age_ms_bucket: this.lastInboundAgeBucket(),
19589
20382
  ws_ready_state: this.ws?.readyState ?? null,
@@ -19912,7 +20705,8 @@ var DIAGNOSTIC_ID_ATTRS = /* @__PURE__ */ new Set([
19912
20705
  "machine_id",
19913
20706
  "process_instance_id",
19914
20707
  "launch_id",
19915
- "correlation_id"
20708
+ "correlation_id",
20709
+ "migration_attempt_id"
19916
20710
  ]);
19917
20711
  var DIAGNOSTIC_ERROR_ATTRS = /* @__PURE__ */ new Set([
19918
20712
  "runtime_error_class",
@@ -20363,6 +21157,66 @@ function readPositiveIntegerEnv2(name, fallback) {
20363
21157
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
20364
21158
  }
20365
21159
 
21160
+ // src/computerMigrationGuard.ts
21161
+ import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync8 } from "fs";
21162
+ import path18 from "path";
21163
+ var LegacyDaemonKeyAdoptedByComputerError = class extends Error {
21164
+ code = "LEGACY_DAEMON_KEY_ADOPTED_BY_COMPUTER";
21165
+ attachmentPath;
21166
+ serverId;
21167
+ constructor(match) {
21168
+ const serverDisplay = match.serverSlug ? `/${match.serverSlug}` : match.serverId;
21169
+ const startCommand = match.serverSlug ? `raft-computer start /${match.serverSlug}` : "raft-computer start";
21170
+ super(
21171
+ `This legacy daemon key was already adopted by Raft Computer for ${serverDisplay}. Start the Computer supervisor instead: ${startCommand}. Legacy daemon startup is blocked to avoid relaunching a migrated machine key.`
21172
+ );
21173
+ this.name = "LegacyDaemonKeyAdoptedByComputerError";
21174
+ this.attachmentPath = match.attachmentPath;
21175
+ this.serverId = match.serverId;
21176
+ }
21177
+ };
21178
+ function daemonApiKeyFingerprint(apiKey) {
21179
+ return getDaemonMachineLockId(apiKey).slice("machine-".length);
21180
+ }
21181
+ function findAdoptedComputerForLegacyFingerprint(slockHome, legacyApiKeyFingerprint) {
21182
+ const serversDir = path18.join(slockHome, "computer", "servers");
21183
+ if (!existsSync9(serversDir)) return null;
21184
+ let serverDirs;
21185
+ try {
21186
+ serverDirs = readdirSync6(serversDir);
21187
+ } catch {
21188
+ return null;
21189
+ }
21190
+ for (const serverId of serverDirs) {
21191
+ const attachmentPath = path18.join(serversDir, serverId, "runner.state.json");
21192
+ let raw;
21193
+ try {
21194
+ raw = readFileSync8(attachmentPath, "utf8");
21195
+ } catch {
21196
+ continue;
21197
+ }
21198
+ try {
21199
+ const attachment = JSON.parse(raw);
21200
+ if (attachment.kind === "computer-attachment" && attachment.adoptedFromLegacy === true && attachment.legacyApiKeyFingerprint === legacyApiKeyFingerprint) {
21201
+ return {
21202
+ attachmentPath,
21203
+ serverId: typeof attachment.serverId === "string" && attachment.serverId.length > 0 ? attachment.serverId : serverId,
21204
+ serverSlug: typeof attachment.serverSlug === "string" && attachment.serverSlug.length > 0 ? attachment.serverSlug : void 0,
21205
+ serverMachineId: typeof attachment.serverMachineId === "string" && attachment.serverMachineId.length > 0 ? attachment.serverMachineId : void 0
21206
+ };
21207
+ }
21208
+ } catch {
21209
+ continue;
21210
+ }
21211
+ }
21212
+ return null;
21213
+ }
21214
+ function assertLegacyDaemonKeyNotAdoptedByComputer(options) {
21215
+ const legacyApiKeyFingerprint = daemonApiKeyFingerprint(options.apiKey);
21216
+ const match = findAdoptedComputerForLegacyFingerprint(options.slockHome, legacyApiKeyFingerprint);
21217
+ if (match) throw new LegacyDaemonKeyAdoptedByComputerError(match);
21218
+ }
21219
+
20366
21220
  // src/core.ts
20367
21221
  var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
20368
21222
  var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
@@ -20534,13 +21388,13 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
20534
21388
  }
20535
21389
  }
20536
21390
  function resolveSlockCliPath(moduleUrl = import.meta.url) {
20537
- const thisDir = path18.dirname(fileURLToPath(moduleUrl));
20538
- const bundledDistPath = path18.resolve(thisDir, "cli", "index.js");
21391
+ const thisDir = path19.dirname(fileURLToPath(moduleUrl));
21392
+ const bundledDistPath = path19.resolve(thisDir, "cli", "index.js");
20539
21393
  try {
20540
21394
  accessSync(bundledDistPath);
20541
21395
  return bundledDistPath;
20542
21396
  } catch {
20543
- const workspaceDistPath = path18.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
21397
+ const workspaceDistPath = path19.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
20544
21398
  accessSync(workspaceDistPath);
20545
21399
  return workspaceDistPath;
20546
21400
  }
@@ -20554,7 +21408,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
20554
21408
  }
20555
21409
  async function runBundledSlockCli(argv) {
20556
21410
  process.argv = [process.execPath, "slock", ...argv];
20557
- await import("./dist-PCKZII47.js");
21411
+ await import("./dist-Y3VRAU5E.js");
20558
21412
  }
20559
21413
  function detectRuntimes(tracer = noopTracer) {
20560
21414
  const ids = [];
@@ -20666,7 +21520,7 @@ function summarizeIncomingMessage(msg) {
20666
21520
  case "agent:runtime_profile:daemon_release_notice":
20667
21521
  return `(agent=${msg.agentId}, notice=${msg.noticeKey})`;
20668
21522
  case "agent:workspace:list":
20669
- return `(agent=${msg.agentId}, dir=${msg.dirPath || "."})`;
21523
+ return `(agent=${msg.agentId}, dir=${msg.dirPath || "."}, hidden=${msg.includeHidden ? "yes" : "no"})`;
20670
21524
  case "agent:workspace:read":
20671
21525
  return `(agent=${msg.agentId}, path=${msg.path})`;
20672
21526
  case "agent:skills:list":
@@ -20695,7 +21549,7 @@ var DaemonCore = class {
20695
21549
  options;
20696
21550
  daemonVersion;
20697
21551
  // When this runner is launched by a managed Computer service, the
20698
- // service exports SLOCK_COMPUTER_VERSION (the `@botiverse/raft-computer`
21552
+ // service exports RAFT_COMPUTER_VERSION (the `@botiverse/raft-computer`
20699
21553
  // bundle version). Reported in `ready` so the server can surface the
20700
21554
  // Computer's own version (distinct from the underlying daemonVersion).
20701
21555
  computerVersion;
@@ -20722,7 +21576,7 @@ var DaemonCore = class {
20722
21576
  constructor(options) {
20723
21577
  this.options = options;
20724
21578
  this.daemonVersion = options.daemonVersion ?? readDaemonVersion();
20725
- this.computerVersion = (process.env.SLOCK_COMPUTER_VERSION || "").trim() || null;
21579
+ this.computerVersion = (process.env.RAFT_COMPUTER_VERSION || "").trim() || null;
20726
21580
  this.slockCliPath = options.slockCliPath ?? resolveSlockCliPathOrEmpty();
20727
21581
  this.slockHome = resolveSlockHome();
20728
21582
  process.env[SLOCK_HOME_ENV] = this.slockHome;
@@ -20762,7 +21616,7 @@ var DaemonCore = class {
20762
21616
  }
20763
21617
  resolveMachineStateRoot() {
20764
21618
  if (this.options.machineStateDir) return this.options.machineStateDir;
20765
- if (this.options.dataDir) return path18.join(path18.dirname(this.options.dataDir), "machines");
21619
+ if (this.options.dataDir) return path19.join(path19.dirname(this.options.dataDir), "machines");
20766
21620
  return resolveDefaultMachineStateRoot();
20767
21621
  }
20768
21622
  shouldEnableLocalTrace() {
@@ -20790,7 +21644,7 @@ var DaemonCore = class {
20790
21644
  sinks: [this.localTraceSink]
20791
21645
  }));
20792
21646
  this.agentManager.setTracer(this.tracer);
20793
- this.agentManager.setCliTransportTraceDir(path18.join(machineDir, "traces"));
21647
+ this.agentManager.setCliTransportTraceDir(path19.join(machineDir, "traces"));
20794
21648
  }
20795
21649
  installTraceBundleUploader(machineDir) {
20796
21650
  if (!this.shouldEnableLocalTrace()) return;
@@ -20816,6 +21670,10 @@ var DaemonCore = class {
20816
21670
  `[Slock Daemon] Legacy Slock state exists outside ${SLOCK_HOME_ENV}: ${legacy.path}. This daemon will use ${legacy.destination}; migrate manually if that ${legacy.description} should move with this installation.`
20817
21671
  );
20818
21672
  }
21673
+ assertLegacyDaemonKeyNotAdoptedByComputer({
21674
+ slockHome: this.slockHome,
21675
+ apiKey: this.options.apiKey
21676
+ });
20819
21677
  if (!this.machineLock) {
20820
21678
  this.machineLock = acquireDaemonMachineLock({
20821
21679
  apiKey: this.options.apiKey,
@@ -21038,7 +21896,8 @@ var DaemonCore = class {
21038
21896
  msg.unreadSummary,
21039
21897
  msg.resumePrompt,
21040
21898
  msg.launchId,
21041
- wakeMessageTransient
21899
+ wakeMessageTransient,
21900
+ msg.resumeMessages
21042
21901
  );
21043
21902
  this.coreStartingAgentIds.delete(msg.agentId);
21044
21903
  if (wakeDeliveryAck) {
@@ -21186,8 +22045,8 @@ var DaemonCore = class {
21186
22045
  break;
21187
22046
  }
21188
22047
  case "agent:workspace:list":
21189
- this.agentManager.getFileTree(msg.agentId, msg.dirPath).then((files) => {
21190
- this.connection.send({ type: "agent:workspace:file_tree", agentId: msg.agentId, files, dirPath: msg.dirPath });
22048
+ this.agentManager.getFileTree(msg.agentId, msg.dirPath, Boolean(msg.includeHidden)).then((files) => {
22049
+ this.connection.send({ type: "agent:workspace:file_tree", agentId: msg.agentId, files, dirPath: msg.dirPath, includeHidden: Boolean(msg.includeHidden) });
21191
22050
  });
21192
22051
  break;
21193
22052
  case "agent:workspace:read":