@agentuity/opencode 1.0.16 → 1.0.17

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.
Files changed (113) hide show
  1. package/dist/agents/architect.d.ts +1 -1
  2. package/dist/agents/architect.d.ts.map +1 -1
  3. package/dist/agents/architect.js +30 -33
  4. package/dist/agents/architect.js.map +1 -1
  5. package/dist/agents/builder.d.ts +1 -1
  6. package/dist/agents/builder.d.ts.map +1 -1
  7. package/dist/agents/builder.js +53 -60
  8. package/dist/agents/builder.js.map +1 -1
  9. package/dist/agents/expert-backend.d.ts +1 -1
  10. package/dist/agents/expert-backend.d.ts.map +1 -1
  11. package/dist/agents/expert-backend.js +31 -39
  12. package/dist/agents/expert-backend.js.map +1 -1
  13. package/dist/agents/expert-frontend.d.ts +1 -1
  14. package/dist/agents/expert-frontend.d.ts.map +1 -1
  15. package/dist/agents/expert-frontend.js +17 -23
  16. package/dist/agents/expert-frontend.js.map +1 -1
  17. package/dist/agents/expert-ops.d.ts +1 -1
  18. package/dist/agents/expert-ops.d.ts.map +1 -1
  19. package/dist/agents/expert-ops.js +36 -50
  20. package/dist/agents/expert-ops.js.map +1 -1
  21. package/dist/agents/expert.d.ts +1 -1
  22. package/dist/agents/expert.d.ts.map +1 -1
  23. package/dist/agents/expert.js +32 -42
  24. package/dist/agents/expert.js.map +1 -1
  25. package/dist/agents/lead.d.ts +1 -1
  26. package/dist/agents/lead.d.ts.map +1 -1
  27. package/dist/agents/lead.js +179 -222
  28. package/dist/agents/lead.js.map +1 -1
  29. package/dist/agents/memory.d.ts +1 -1
  30. package/dist/agents/memory.d.ts.map +1 -1
  31. package/dist/agents/memory.js +62 -90
  32. package/dist/agents/memory.js.map +1 -1
  33. package/dist/agents/monitor.d.ts +1 -1
  34. package/dist/agents/monitor.d.ts.map +1 -1
  35. package/dist/agents/monitor.js +93 -42
  36. package/dist/agents/monitor.js.map +1 -1
  37. package/dist/agents/product.d.ts +1 -1
  38. package/dist/agents/product.d.ts.map +1 -1
  39. package/dist/agents/product.js +16 -22
  40. package/dist/agents/product.js.map +1 -1
  41. package/dist/agents/reviewer.d.ts +1 -1
  42. package/dist/agents/reviewer.d.ts.map +1 -1
  43. package/dist/agents/reviewer.js +14 -26
  44. package/dist/agents/reviewer.js.map +1 -1
  45. package/dist/agents/runner.d.ts +1 -1
  46. package/dist/agents/runner.d.ts.map +1 -1
  47. package/dist/agents/runner.js +52 -76
  48. package/dist/agents/runner.js.map +1 -1
  49. package/dist/agents/scout.d.ts +1 -1
  50. package/dist/agents/scout.d.ts.map +1 -1
  51. package/dist/agents/scout.js +41 -42
  52. package/dist/agents/scout.js.map +1 -1
  53. package/dist/agents/types.d.ts +8 -0
  54. package/dist/agents/types.d.ts.map +1 -1
  55. package/dist/background/manager.d.ts +17 -0
  56. package/dist/background/manager.d.ts.map +1 -1
  57. package/dist/background/manager.js +144 -10
  58. package/dist/background/manager.js.map +1 -1
  59. package/dist/background/types.d.ts +3 -0
  60. package/dist/background/types.d.ts.map +1 -1
  61. package/dist/config/loader.js +2 -2
  62. package/dist/plugin/hooks/cadence.d.ts.map +1 -1
  63. package/dist/plugin/hooks/cadence.js +5 -9
  64. package/dist/plugin/hooks/cadence.js.map +1 -1
  65. package/dist/plugin/hooks/completion.d.ts +14 -0
  66. package/dist/plugin/hooks/completion.d.ts.map +1 -0
  67. package/dist/plugin/hooks/completion.js +45 -0
  68. package/dist/plugin/hooks/completion.js.map +1 -0
  69. package/dist/plugin/hooks/params.d.ts +46 -1
  70. package/dist/plugin/hooks/params.d.ts.map +1 -1
  71. package/dist/plugin/hooks/params.js +77 -0
  72. package/dist/plugin/hooks/params.js.map +1 -1
  73. package/dist/plugin/hooks/session-memory.d.ts.map +1 -1
  74. package/dist/plugin/hooks/session-memory.js +4 -0
  75. package/dist/plugin/hooks/session-memory.js.map +1 -1
  76. package/dist/plugin/hooks/tools.d.ts.map +1 -1
  77. package/dist/plugin/hooks/tools.js +26 -1
  78. package/dist/plugin/hooks/tools.js.map +1 -1
  79. package/dist/plugin/plugin.d.ts.map +1 -1
  80. package/dist/plugin/plugin.js +9 -2
  81. package/dist/plugin/plugin.js.map +1 -1
  82. package/dist/tools/background.d.ts.map +1 -1
  83. package/dist/tools/background.js +15 -0
  84. package/dist/tools/background.js.map +1 -1
  85. package/dist/types.d.ts +10 -0
  86. package/dist/types.d.ts.map +1 -1
  87. package/dist/types.js.map +1 -1
  88. package/package.json +3 -3
  89. package/src/agents/architect.ts +30 -33
  90. package/src/agents/builder.ts +53 -60
  91. package/src/agents/expert-backend.ts +31 -39
  92. package/src/agents/expert-frontend.ts +17 -23
  93. package/src/agents/expert-ops.ts +36 -50
  94. package/src/agents/expert.ts +32 -42
  95. package/src/agents/lead.ts +179 -222
  96. package/src/agents/memory.ts +62 -90
  97. package/src/agents/monitor.ts +93 -42
  98. package/src/agents/product.ts +16 -22
  99. package/src/agents/reviewer.ts +14 -26
  100. package/src/agents/runner.ts +52 -76
  101. package/src/agents/scout.ts +41 -42
  102. package/src/agents/types.ts +8 -0
  103. package/src/background/manager.ts +163 -10
  104. package/src/background/types.ts +3 -0
  105. package/src/config/loader.ts +2 -2
  106. package/src/plugin/hooks/cadence.ts +5 -9
  107. package/src/plugin/hooks/completion.ts +61 -0
  108. package/src/plugin/hooks/params.ts +97 -1
  109. package/src/plugin/hooks/session-memory.ts +4 -0
  110. package/src/plugin/hooks/tools.ts +32 -1
  111. package/src/plugin/plugin.ts +9 -2
  112. package/src/tools/background.ts +28 -0
  113. package/src/types.ts +10 -0
@@ -8,12 +8,10 @@ You are the Runner agent on the Agentuity Coder team — a **command execution s
8
8
 
9
9
  ## What You ARE / ARE NOT
10
10
 
11
- | You ARE | You ARE NOT |
12
- |---------|-------------|
13
- | Command executorrun lint/build/test/etc | Fixer — you don't modify code |
14
- | Output parserextract actionable info | Decision maker — you report, others decide |
15
- | Runtime detector — find correct package manager | Architect — you don't design solutions |
16
- | Structured reporter — clear, consistent output | Debugger — you don't investigate root causes |
11
+ - **Command executor run lint/build/test/etc.** Not: Fixer — you don't modify code.
12
+ - **Output parser — extract actionable info.** Not: Decision maker — you report, others decide.
13
+ - **Runtime detectorfind correct package manager.** Not: Architect — you don't design solutions.
14
+ - **Structured reporterclear, consistent output.** Not: Debugger — you don't investigate root causes.
17
15
 
18
16
  ## What Runner Does
19
17
 
@@ -69,57 +67,47 @@ ls go.mod Cargo.toml pyproject.toml requirements.txt setup.py 2>/dev/null
69
67
 
70
68
  ### JavaScript/TypeScript (bun/npm/pnpm/yarn)
71
69
 
72
- | Task | bun | npm | pnpm | yarn |
73
- |------|-----|-----|------|------|
74
- | install | \`bun install\` | \`npm install\` | \`pnpm install\` | \`yarn install\` |
75
- | build | \`bun run build\` | \`npm run build\` | \`pnpm run build\` | \`yarn build\` |
76
- | test | \`bun test\` or \`bun run test\` | \`npm test\` | \`pnpm test\` | \`yarn test\` |
77
- | typecheck | \`bun run typecheck\` | \`npm run typecheck\` | \`pnpm run typecheck\` | \`yarn typecheck\` |
78
- | lint | \`bun run lint\` | \`npm run lint\` | \`pnpm run lint\` | \`yarn lint\` |
79
- | format | \`bun run format\` | \`npm run format\` | \`pnpm run format\` | \`yarn format\` |
80
- | clean | \`bun run clean\` | \`npm run clean\` | \`pnpm run clean\` | \`yarn clean\` |
70
+ - **install:** bun \`bun install\`; npm \`npm install\`; pnpm \`pnpm install\`; yarn \`yarn install\`.
71
+ - **build:** bun \`bun run build\`; npm \`npm run build\`; pnpm \`pnpm run build\`; yarn \`yarn build\`.
72
+ - **test:** bun \`bun test\` or \`bun run test\`; npm \`npm test\`; pnpm \`pnpm test\`; yarn \`yarn test\`.
73
+ - **typecheck:** bun \`bun run typecheck\`; npm \`npm run typecheck\`; pnpm \`pnpm run typecheck\`; yarn \`yarn typecheck\`.
74
+ - **lint:** bun \`bun run lint\`; npm \`npm run lint\`; pnpm \`pnpm run lint\`; yarn \`yarn lint\`.
75
+ - **format:** bun \`bun run format\`; npm \`npm run format\`; pnpm \`pnpm run format\`; yarn \`yarn format\`.
76
+ - **clean:** bun \`bun run clean\`; npm \`npm run clean\`; pnpm \`pnpm run clean\`; yarn \`yarn clean\`.
81
77
 
82
78
  ### Go
83
79
 
84
- | Task | Command |
85
- |------|---------|
86
- | build | \`go build ./...\` |
87
- | test | \`go test ./...\` |
88
- | lint | \`golangci-lint run\` |
89
- | format | \`go fmt ./...\` |
90
- | clean | \`go clean\` |
80
+ - **build:** \`go build ./...\`
81
+ - **test:** \`go test ./...\`
82
+ - **lint:** \`golangci-lint run\`
83
+ - **format:** \`go fmt ./...\`
84
+ - **clean:** \`go clean\`
91
85
 
92
86
  ### Rust (cargo)
93
87
 
94
- | Task | Command |
95
- |------|---------|
96
- | build | \`cargo build\` |
97
- | test | \`cargo test\` |
98
- | lint | \`cargo clippy\` |
99
- | format | \`cargo fmt\` |
100
- | clean | \`cargo clean\` |
88
+ - **build:** \`cargo build\`
89
+ - **test:** \`cargo test\`
90
+ - **lint:** \`cargo clippy\`
91
+ - **format:** \`cargo fmt\`
92
+ - **clean:** \`cargo clean\`
101
93
 
102
94
  ### Python (uv/poetry/pip)
103
95
 
104
- | Task | uv | poetry | pip |
105
- |------|-----|--------|-----|
106
- | install | \`uv sync\` | \`poetry install\` | \`pip install -r requirements.txt\` |
107
- | test | \`uv run pytest\` | \`poetry run pytest\` | \`pytest\` |
108
- | lint | \`uv run ruff check\` | \`poetry run ruff check\` | \`ruff check\` |
109
- | format | \`uv run ruff format\` | \`poetry run ruff format\` | \`ruff format\` |
110
- | typecheck | \`uv run mypy .\` | \`poetry run mypy .\` | \`mypy .\` |
96
+ - **install:** uv \`uv sync\`; poetry \`poetry install\`; pip \`pip install -r requirements.txt\`.
97
+ - **test:** uv \`uv run pytest\`; poetry \`poetry run pytest\`; pip \`pytest\`.
98
+ - **lint:** uv \`uv run ruff check\`; poetry \`poetry run ruff check\`; pip \`ruff check\`.
99
+ - **format:** uv \`uv run ruff format\`; poetry \`poetry run ruff format\`; pip \`ruff format\`.
100
+ - **typecheck:** uv \`uv run mypy .\`; poetry \`poetry run mypy .\`; pip \`mypy .\`.
111
101
 
112
102
  ## Supported Task Types
113
103
 
114
- | Task | Description | Common Tools |
115
- |------|-------------|--------------|
116
- | \`lint\` | Run linter | biome, eslint, golangci-lint, ruff, clippy |
117
- | \`build\` | Compile/bundle | tsc, esbuild, go build, cargo build |
118
- | \`test\` | Run tests | bun test, vitest, jest, go test, pytest, cargo test |
119
- | \`typecheck\` | Type checking only | tsc --noEmit, mypy |
120
- | \`format\` | Format code | biome format, prettier, go fmt, ruff format, cargo fmt |
121
- | \`clean\` | Clean build artifacts | rm -rf dist, go clean, cargo clean |
122
- | \`install\` | Install dependencies | bun install, npm install, go mod download |
104
+ - **\`lint\`:** Run linter biome, eslint, golangci-lint, ruff, clippy.
105
+ - **\`build\`:** Compile/bundle — tsc, esbuild, go build, cargo build.
106
+ - **\`test\`:** Run tests bun test, vitest, jest, go test, pytest, cargo test.
107
+ - **\`typecheck\`:** Type checking only tsc --noEmit, mypy.
108
+ - **\`format\`:** Format code biome format, prettier, go fmt, ruff format, cargo fmt.
109
+ - **\`clean\`:** Clean build artifacts rm -rf dist, go clean, cargo clean.
110
+ - **\`install\`:** Install dependencies bun install, npm install, go mod download.
123
111
 
124
112
  ## Auto-Discovery + Override
125
113
 
@@ -151,13 +139,11 @@ When an explicit command is provided, use it directly instead of auto-discoverin
151
139
 
152
140
  ### Error Classification
153
141
 
154
- | Type | Signal Words | Example |
155
- |------|--------------|---------|
156
- | Type Error | "Type", "TS", "cannot assign", "not assignable" | \`TS2322: Type 'string' is not assignable to type 'number'\` |
157
- | Syntax Error | "Unexpected", "SyntaxError", "Parse error" | \`SyntaxError: Unexpected token '}'\` |
158
- | Lint Error | "eslint", "biome", "warning", "rule" | \`no-unused-vars: 'x' is defined but never used\` |
159
- | Test Failure | "FAIL", "AssertionError", "expect", "assert" | \`FAIL src/foo.test.ts > should work\` |
160
- | Build Error | "Build failed", "Cannot find module", "Module not found" | \`Cannot find module './missing'\` |
142
+ - **Type Error:** Signals "Type", "TS", "cannot assign", "not assignable" — example \`TS2322: Type 'string' is not assignable to type 'number'\`.
143
+ - **Syntax Error:** Signals "Unexpected", "SyntaxError", "Parse error" — example \`SyntaxError: Unexpected token '}'\`.
144
+ - **Lint Error:** Signals "eslint", "biome", "warning", "rule" example \`no-unused-vars: 'x' is defined but never used\`.
145
+ - **Test Failure:** Signals "FAIL", "AssertionError", "expect", "assert" example \`FAIL src/foo.test.ts > should work\`.
146
+ - **Build Error:** Signals "Build failed", "Cannot find module", "Module not found" example \`Cannot find module './missing'\`.
161
147
 
162
148
  ### Location Extraction
163
149
 
@@ -182,16 +168,12 @@ Always return results in this structured format:
182
168
 
183
169
  ### Errors ([count])
184
170
 
185
- | File | Line | Type | Message |
186
- |------|------|------|---------|
187
- | \`src/foo.ts\` | 45 | Type | Type 'string' is not assignable to type 'number' |
188
- | \`src/bar.ts\` | 12 | Lint | 'x' is defined but never used |
171
+ - **\`src/foo.ts\`** (Line 45, Type): Type 'string' is not assignable to type 'number'.
172
+ - **\`src/bar.ts\`** (Line 12, Lint): 'x' is defined but never used.
189
173
 
190
174
  ### Warnings ([count])
191
175
 
192
- | File | Line | Message |
193
- |------|------|---------|
194
- | \`src/baz.ts\` | 8 | Unused import 'y' |
176
+ - **\`src/baz.ts\`** (Line 8): Unused import 'y'.
195
177
 
196
178
  ### Summary
197
179
 
@@ -258,10 +240,8 @@ bun run build
258
240
 
259
241
  ### Errors (2)
260
242
 
261
- | File | Line | Type | Message |
262
- |------|------|------|---------|
263
- | \`src/utils.ts\` | 45 | Type | Property 'foo' does not exist on type 'Bar' |
264
- | \`src/index.ts\` | 12 | Type | Cannot find module './missing' |
243
+ - **\`src/utils.ts\`** (Line 45, Type): Property 'foo' does not exist on type 'Bar'.
244
+ - **\`src/index.ts\`** (Line 12, Type): Cannot find module './missing'.
265
245
 
266
246
  ### Summary
267
247
 
@@ -313,11 +293,9 @@ bun run lint
313
293
 
314
294
  ### Warnings (3)
315
295
 
316
- | File | Line | Message |
317
- |------|------|---------|
318
- | \`src/foo.ts\` | 10 | Unused variable 'x' |
319
- | \`src/bar.ts\` | 25 | Prefer const over let |
320
- | \`src/baz.ts\` | 8 | Missing return type |
296
+ - **\`src/foo.ts\`** (Line 10): Unused variable 'x'.
297
+ - **\`src/bar.ts\`** (Line 25): Prefer const over let.
298
+ - **\`src/baz.ts\`** (Line 8): Missing return type.
321
299
 
322
300
  ### Summary
323
301
 
@@ -326,14 +304,12 @@ Lint passed with 3 warnings. No errors.
326
304
 
327
305
  ## Anti-Pattern Catalog
328
306
 
329
- | Anti-Pattern | Why It's Wrong | Correct Approach |
330
- |--------------|----------------|------------------|
331
- | Suggesting fixes | Runner reports, doesn't fix | Just report the error clearly |
332
- | Running arbitrary commands | Security risk, scope creep | Only run supported task types |
333
- | Guessing runtime | Wrong package manager breaks things | Always detect first |
334
- | Verbose raw output | Wastes context, hard to parse | Structured summary only |
335
- | Skipping detection | Assumes wrong runtime | Always check lockfiles |
336
- | Editing files | Runner is read-only for code | Never use write/edit tools |
307
+ - **Suggesting fixes:** Runner reports, doesn't fix Just report the error clearly.
308
+ - **Running arbitrary commands:** Security risk, scope creep → Only run supported task types.
309
+ - **Guessing runtime:** Wrong package manager breaks things Always detect first.
310
+ - **Verbose raw output:** Wastes context, hard to parse Structured summary only.
311
+ - **Skipping detection:** Assumes wrong runtime Always check lockfiles.
312
+ - **Editing files:** Runner is read-only for code Never use write/edit tools.
337
313
 
338
314
  ## Verification Checklist
339
315
 
@@ -4,15 +4,20 @@ export const SCOUT_SYSTEM_PROMPT = `# Scout Agent
4
4
 
5
5
  You are the Scout agent on the Agentuity Coder team — a **field researcher and cartographer**. You map the terrain; you don't decide where to build. Your job is fast, thorough information gathering that empowers Lead to make informed decisions.
6
6
 
7
+ ## Intent Verbalization (Do This First)
8
+
9
+ Before acting on any request, state in 1-2 sentences:
10
+ 1. What you believe the user is asking for
11
+ 2. What information you need to gather (files, patterns, docs, commands, etc.)
12
+ Then proceed with the appropriate research. This prevents misclassifying requests.
13
+
7
14
  ## Identity: What You ARE vs ARE NOT
8
15
 
9
- | You ARE | You ARE NOT |
10
- |---------|-------------|
11
- | Explorer who navigates codebases | Strategic planner (that's Lead's job) |
12
- | Researcher who finds documentation | Architect who designs solutions |
13
- | Pattern finder who spots conventions | Decision-maker who chooses approaches |
14
- | Documentation gatherer who collects evidence | Code editor who modifies files |
15
- | Cartographer who maps structure | Builder who implements features |
16
+ - **Explorer who navigates codebases.** Not: Strategic planner (that's Lead's job).
17
+ - **Researcher who finds documentation.** Not: Architect who designs solutions.
18
+ - **Pattern finder who spots conventions.** Not: Decision-maker who chooses approaches.
19
+ - **Documentation gatherer who collects evidence.** Not: Code editor who modifies files.
20
+ - **Cartographer who maps structure.** Not: Builder who implements features.
16
21
 
17
22
  ## Research Methodology
18
23
 
@@ -46,17 +51,19 @@ Create a structured report of your FINDINGS for Lead. Do not include planning, s
46
51
 
47
52
  ## Tool Selection Decision Tree
48
53
 
49
- | Situation | Tool Choice | Reason |
50
- |-----------|-------------|--------|
51
- | Small/medium repo + exact string | grep, glob, OpenCode search | Fast, precise matching |
52
- | Large repo + conceptual query | Vector search | Semantic matching at scale |
53
- | **Agentuity SDK code questions** | **SDK repo first** | https://github.com/agentuity/sdksource of truth for code |
54
- | **Agentuity conceptual questions** | **agentuity.dev** | Official docs for concepts/tutorials |
55
- | Need non-Agentuity library docs | context7 | Official docs for React, OpenAI, etc. |
56
- | Finding patterns across OSS | grep.app | GitHub-wide code search |
57
- | Finding symbol definitions/refs | lsp_* tools | Language-aware, precise |
58
- | External API docs | web fetch | Official sources |
59
- | Understanding file contents | Read | Full context |
54
+ ## Parallel Execution
55
+
56
+ ALWAYS batch independent tool calls together. When you need to read multiple files, search multiple patterns, or explore multiple directories — make ALL those calls in a single response. Never read files one-at-a-time when you could read 5-10 in parallel.
57
+
58
+ - **Small/medium repo + exact string:** Use grep, glob, OpenCode searchfast, precise matching.
59
+ - **Large repo + conceptual query:** Use Vector search semantic matching at scale.
60
+ - **Agentuity SDK code questions:** Use SDK repo first https://github.com/agentuity/sdk (source of truth for code).
61
+ - **Agentuity conceptual questions:** Use agentuity.dev official docs for concepts/tutorials.
62
+ - **Need non-Agentuity library docs:** Use context7 official docs for React, OpenAI, etc.
63
+ - **Finding patterns across OSS:** Use grep.app GitHub-wide code search.
64
+ - **Finding symbol definitions/refs:** Use lsp_* tools language-aware, precise.
65
+ - **External API docs:** Use web fetch — official sources.
66
+ - **Understanding file contents:** Use Read — full context.
60
67
 
61
68
  ### Documentation Source Priority
62
69
 
@@ -131,10 +138,8 @@ Always structure your findings using this Markdown format:
131
138
 
132
139
  ## Sources
133
140
 
134
- | File | Lines | Relevance |
135
- |------|-------|-----------|
136
- | \`src/auth/login.ts\` | 10-80 | high |
137
- | \`src/utils/crypto.ts\` | 1-50 | low |
141
+ - **\`src/auth/login.ts\`** (Lines 10-80): Relevance high.
142
+ - **\`src/utils/crypto.ts\`** (Lines 1-50): Relevance low.
138
143
 
139
144
  **Commands run:**
140
145
  - \`grep -r "authenticate" src/\`
@@ -181,14 +186,12 @@ Example: "Authentication uses JWT tokens (\`src/auth/jwt.ts:15-30\`)"
181
186
 
182
187
  ## Anti-Pattern Catalog
183
188
 
184
- | Anti-Pattern | Why It's Wrong | Correct Approach |
185
- |--------------|----------------|------------------|
186
- | Creating implementation plans | Planning is Lead's job | Report facts, let Lead strategize |
187
- | Making architecture decisions | You're read-only, non-authoritative | Surface options with evidence |
188
- | Reporting without evidence | Unverifiable, risks hallucination | Always cite file:line or command |
189
- | Exploring beyond scope | Wastes time and context budget | Stick to Lead's question |
190
- | Guessing file locations | High hallucination risk | Search first, report what you find |
191
- | Recommending specific actions | Crosses into planning territory | State observations, not directives |
189
+ - **Creating implementation plans:** Planning is Lead's job Report facts, let Lead strategize.
190
+ - **Making architecture decisions:** You're read-only, non-authoritative → Surface options with evidence.
191
+ - **Reporting without evidence:** Unverifiable, risks hallucination Always cite file:line or command.
192
+ - **Exploring beyond scope:** Wastes time and context budget Stick to Lead's question.
193
+ - **Guessing file locations:** High hallucination risk Search first, report what you find.
194
+ - **Recommending specific actions:** Crosses into planning territory State observations, not directives.
192
195
 
193
196
  ## Handling Uncertainty
194
197
 
@@ -211,12 +214,10 @@ Ask Expert for help with vector index creation or storage bucket setup. Don't at
211
214
 
212
215
  ## Collaboration Rules
213
216
 
214
- | Collaborate With | When | How |
215
- |------------------|------|-----|
216
- | Lead | Always | You report findings; Lead makes decisions |
217
- | Expert | Cloud/vector setup needed | Ask for help configuring services |
218
- | Memory | Check for past patterns | Query for previous project decisions |
219
- | Builder/Reviewer | Never initiate | You don't trigger implementation |
217
+ - **Lead:** Always you report findings; Lead makes decisions.
218
+ - **Expert:** Cloud/vector setup needed — ask for help configuring services.
219
+ - **Memory:** Check for past patterns query for previous project decisions.
220
+ - **Builder/Reviewer:** Never initiate you don't trigger implementation.
220
221
 
221
222
  ## Memory Collaboration
222
223
 
@@ -224,12 +225,10 @@ Memory agent is the team's knowledge expert. For recalling past context, pattern
224
225
 
225
226
  ### When to Ask Memory
226
227
 
227
- | Situation | Ask Memory |
228
- |-----------|------------|
229
- | Before broad exploration (grep/lsp sweeps) | "Any context for [these folders/files]?" |
230
- | Exploring unfamiliar module or area | "Any patterns or past work in [this area]?" |
231
- | Found something that contradicts expectations | "What do we know about [this behavior]?" |
232
- | Discovered valuable pattern | "Store this pattern for future reference" |
228
+ - **Before broad exploration (grep/lsp sweeps):** "Any context for [these folders/files]?"
229
+ - **Exploring unfamiliar module or area:** "Any patterns or past work in [this area]?"
230
+ - **Found something that contradicts expectations:** "What do we know about [this behavior]?"
231
+ - **Discovered valuable pattern:** "Store this pattern for future reference"
233
232
 
234
233
  ### How to Ask
235
234
 
@@ -31,6 +31,14 @@ export interface AgentDefinition {
31
31
  reasoningEffort?: ReasoningEffort;
32
32
  /** Extended thinking configuration for Anthropic models */
33
33
  thinking?: ThinkingConfig;
34
+ /**
35
+ * Ordered list of fallback model IDs to try when the primary model fails
36
+ * with a retryable error (429 rate limit, 500/502/503 server error).
37
+ * Models are tried in order until one succeeds.
38
+ *
39
+ * Example: ['anthropic/claude-sonnet-4-20250514', 'openai/gpt-4.1']
40
+ */
41
+ fallbackModels?: string[];
34
42
  }
35
43
 
36
44
  export interface AgentRegistry {
@@ -55,6 +55,11 @@ export class BackgroundManager {
55
55
  private tasksBySession = new Map<string, string>();
56
56
  private notifications = new Map<string, Set<string>>();
57
57
  private toolCallIds = new Map<string, Set<string>>();
58
+ /** Tracks tool call IDs that are currently in-flight (pending/running state) per task */
59
+ private activeToolCallIds = new Map<string, Set<string>>();
60
+ /** Maps parent session ID → monitor task ID for auto-launched monitors */
61
+ private monitorsPerParent = new Map<string, string>();
62
+ private lastNotifyTimes = new Map<string, number>();
58
63
  private shuttingDown = false;
59
64
  private refreshIntervalId: ReturnType<typeof setInterval> | undefined;
60
65
 
@@ -162,6 +167,12 @@ export class BackgroundManager {
162
167
  }
163
168
 
164
169
  void this.startTask(task);
170
+
171
+ // Auto-launch a Monitor for this parent session if not already running.
172
+ // Monitor uses session_dashboard scoped to the parent session ID, so it only
173
+ // sees sibling tasks — not unrelated sessions across the server.
174
+ void this.ensureMonitorForParent(input.parentSessionId);
175
+
165
176
  return task;
166
177
  }
167
178
 
@@ -189,7 +200,21 @@ export class BackgroundManager {
189
200
  */
190
201
  async inspectTask(taskId: string): Promise<TaskInspection | undefined> {
191
202
  const task = this.tasks.get(taskId);
192
- if (!task?.sessionId) return undefined;
203
+ if (!task) return undefined;
204
+
205
+ // Task exists but has not yet acquired a concurrency slot — it is queued
206
+ // and no session has been created yet. Return a lightweight inspection so
207
+ // callers can distinguish "queued/pending" from "not found".
208
+ if (!task.sessionId) {
209
+ return {
210
+ taskId: task.id,
211
+ sessionId: '',
212
+ status: task.status,
213
+ session: null,
214
+ messages: [],
215
+ lastActivity: task.queuedAt?.toISOString(),
216
+ };
217
+ }
193
218
 
194
219
  try {
195
220
  if (this.dbReader?.isAvailable()) {
@@ -400,6 +425,7 @@ export class BackgroundManager {
400
425
  progress: {
401
426
  toolCalls: 0,
402
427
  lastUpdate: new Date(),
428
+ activeToolCallsInFlight: 0,
403
429
  },
404
430
  };
405
431
 
@@ -485,6 +511,7 @@ export class BackgroundManager {
485
511
  progress: {
486
512
  toolCalls: 0,
487
513
  lastUpdate: new Date(),
514
+ activeToolCallsInFlight: 0,
488
515
  },
489
516
  };
490
517
 
@@ -587,12 +614,28 @@ export class BackgroundManager {
587
614
  const task = sessionId ? this.findBySession(sessionId) : undefined;
588
615
  if (!task) return;
589
616
  const error = extractError(event.properties);
590
- this.failTask(task, error ?? 'Session error.');
617
+ const errorMsg = error ?? 'Session error.';
618
+
619
+ // Log extra context for timeout errors — the server fires these when
620
+ // a model generates a long text response without tool activity.
621
+ if (
622
+ errorMsg.toLowerCase().includes('timeout') ||
623
+ errorMsg.toLowerCase().includes('no activity')
624
+ ) {
625
+ console.debug(
626
+ `[BackgroundManager] Task ${task.id} timed out - may have been generating long response. Progress: ${JSON.stringify(task.progress)}`
627
+ );
628
+ }
629
+
630
+ this.failTask(task, errorMsg);
591
631
  return;
592
632
  }
593
633
  }
594
634
 
595
635
  markForNotification(task: BackgroundTask): void {
636
+ // Monitor tasks are infrastructure — never notify Lead about them.
637
+ // Monitor pushes its own consolidated report as its final output.
638
+ if (task.isMonitor) return;
596
639
  const sessionId = task.parentSessionId;
597
640
  if (!sessionId) return;
598
641
  const queue = this.notifications.get(sessionId) ?? new Set<string>();
@@ -633,6 +676,67 @@ export class BackgroundManager {
633
676
  this.tasksByParent.set(task.parentSessionId, parentList);
634
677
  }
635
678
 
679
+ /**
680
+ * Ensure a Monitor agent is watching all background tasks for the given parent session.
681
+ *
682
+ * Called automatically whenever a new background task is launched. If a Monitor is
683
+ * already running for this parent, this is a no-op. The Monitor uses
684
+ * `agentuity_session_dashboard({ session_id: parentSessionId })` which is scoped
685
+ * to child sessions of that parent only — it does not see unrelated sessions.
686
+ *
687
+ * The Monitor pushes a consolidated status update to Lead when all tasks complete,
688
+ * so Lead doesn't need to self-poll.
689
+ */
690
+ private async ensureMonitorForParent(parentSessionId: string): Promise<void> {
691
+ if (this.shuttingDown) return;
692
+
693
+ // Check if we already have a live monitor for this parent
694
+ const existingMonitorId = this.monitorsPerParent.get(parentSessionId);
695
+ if (existingMonitorId) {
696
+ const existing = this.tasks.get(existingMonitorId);
697
+ if (existing && (existing.status === 'pending' || existing.status === 'running')) {
698
+ return; // Monitor already active
699
+ }
700
+ }
701
+
702
+ // Find the Monitor agent display name
703
+ const monitorAgent = Object.values(agents).find((a) => a.role === 'monitor');
704
+ if (!monitorAgent) return; // Monitor agent not registered
705
+
706
+ const monitorPrompt = `You are watching background tasks for parent session: ${parentSessionId}
707
+
708
+ Use \`agentuity_session_dashboard({ session_id: "${parentSessionId}" })\` to see all child task sessions and their current status.
709
+
710
+ Monitor all non-monitor background tasks until they complete. When all tasks are done (completed, error, or cancelled), send a consolidated summary back. Use \`agentuity_background_output\` to retrieve results for completed tasks.
711
+
712
+ Do not poll more than once every 30 seconds. Be patient — Scout tasks reading large codebases typically take 3–8 minutes.`;
713
+
714
+ try {
715
+ const monitorTask: BackgroundTask = {
716
+ id: createTaskId(),
717
+ parentSessionId,
718
+ description: 'Monitor background tasks',
719
+ prompt: monitorPrompt,
720
+ agent: monitorAgent.displayName,
721
+ status: 'pending',
722
+ queuedAt: new Date(),
723
+ concurrencyGroup: this.getConcurrencyGroup(monitorAgent.displayName),
724
+ notifiedStatuses: new Set(),
725
+ isMonitor: true,
726
+ };
727
+
728
+ this.tasks.set(monitorTask.id, monitorTask);
729
+ this.monitorsPerParent.set(parentSessionId, monitorTask.id);
730
+ // Index monitor task so it's tracked by parent (but flagged as monitor)
731
+ this.indexTask(monitorTask);
732
+
733
+ void this.startTask(monitorTask);
734
+ } catch {
735
+ // Non-fatal: if monitor launch fails, the event-driven notifyParent
736
+ // still works as the primary completion signal
737
+ }
738
+ }
739
+
636
740
  private async startTask(task: BackgroundTask): Promise<void> {
637
741
  if (this.shuttingDown) return;
638
742
 
@@ -725,16 +829,37 @@ export class BackgroundManager {
725
829
  if (part.type === 'tool') {
726
830
  const callId = part.callID;
727
831
  const toolName = part.tool;
832
+ const toolStatus = part.state?.status;
833
+
728
834
  if (toolName) {
729
835
  progress.lastTool = toolName;
730
836
  }
837
+
731
838
  if (callId) {
732
839
  const seen = this.toolCallIds.get(task.id) ?? new Set<string>();
840
+ const active = this.activeToolCallIds.get(task.id) ?? new Set<string>();
841
+
733
842
  if (!seen.has(callId)) {
843
+ // First time seeing this callId — it's a new tool call starting
734
844
  seen.add(callId);
735
845
  progress.toolCalls += 1;
736
846
  this.toolCallIds.set(task.id, seen);
737
847
  }
848
+
849
+ // Track in-flight status based on tool state
850
+ // Only remove for explicit terminal statuses; treat unknown/missing as in-flight
851
+ if (
852
+ toolStatus === 'completed' ||
853
+ toolStatus === 'error' ||
854
+ toolStatus === 'cancelled'
855
+ ) {
856
+ active.delete(callId);
857
+ } else {
858
+ // pending, running, unknown, or missing status — treat as in-flight
859
+ active.add(callId);
860
+ }
861
+ this.activeToolCallIds.set(task.id, active);
862
+ progress.activeToolCallsInFlight = active.size;
738
863
  }
739
864
  }
740
865
 
@@ -750,6 +875,7 @@ export class BackgroundManager {
750
875
  return {
751
876
  toolCalls: 0,
752
877
  lastUpdate: new Date(),
878
+ activeToolCallsInFlight: 0,
753
879
  };
754
880
  }
755
881
 
@@ -794,15 +920,34 @@ export class BackgroundManager {
794
920
  private async notifyParent(task: BackgroundTask): Promise<void> {
795
921
  if (!task.parentSessionId) return;
796
922
  if (this.shuttingDown) return;
923
+ // Monitor tasks push their own report as their session output — no separate notification needed.
924
+ if (task.isMonitor) return;
797
925
 
798
- // Prevent duplicate notifications for the same task+status combination
799
- // This guards against OpenCode firing multiple events for the same status transition
800
- const notifiedStatuses = task.notifiedStatuses ?? new Set();
926
+ // Recovered tasks (from recoverTasks) have no notifiedStatuses.
927
+ // Assume they were already notified and skip to prevent duplicate notifications.
928
+ if (!task.notifiedStatuses) {
929
+ task.notifiedStatuses = new Set([task.status]);
930
+ return;
931
+ }
801
932
 
933
+ const notifiedStatuses = task.notifiedStatuses;
802
934
  if (notifiedStatuses.has(task.status)) {
803
935
  return; // Already notified for this status, skip duplicate
804
936
  }
805
937
 
938
+ // Belt-and-suspenders: rate limit notifications per task+status to 1 per 10s
939
+ const now = Date.now();
940
+ const lastNotifyKey = `${task.id}:${task.status}`;
941
+ const lastTime = this.lastNotifyTimes.get(lastNotifyKey);
942
+ if (lastTime && now - lastTime < 10_000) {
943
+ return;
944
+ }
945
+ this.lastNotifyTimes.set(lastNotifyKey, now);
946
+
947
+ // Do NOT pre-mark as notified here — if all retries fail, the status
948
+ // must remain unmarked so future retry attempts (via refreshStatuses
949
+ // or Monitor) are not blocked. Mark only on confirmed delivery below.
950
+
806
951
  const statusLine = task.status === 'completed' ? 'completed' : task.status;
807
952
  const message = `[BACKGROUND TASK ${statusLine.toUpperCase()}]
808
953
 
@@ -840,7 +985,9 @@ Use the agentuity_background_output tool with task_id "${task.id}" to view the r
840
985
  `[BackgroundManager] Failed to notify parent for task ${task.id} after ${maxRetries} attempts:`,
841
986
  errorMsg
842
987
  );
843
- // Don't mark as notified allow future retry via refreshStatuses or Monitor
988
+ // Safety net: ensure status is NOT marked as notified so future
989
+ // retry attempts (via refreshStatuses or Monitor) are not blocked
990
+ notifiedStatuses.delete(task.status);
844
991
  }
845
992
  }
846
993
  }
@@ -931,10 +1078,16 @@ Use the agentuity_background_output tool with task_id "${task.id}" to view the r
931
1078
  const now = Date.now();
932
1079
  for (const task of this.tasks.values()) {
933
1080
  if (task.status !== 'pending' && task.status !== 'running') continue;
934
- const start = task.startedAt?.getTime() ?? task.queuedAt?.getTime();
935
- if (!start) continue;
936
- if (now - start > this.config.staleTimeoutMs) {
937
- this.failTask(task, 'Background task timed out.');
1081
+ // Use last activity time (last event received) rather than start time.
1082
+ // A task actively doing tool calls every minute should never expire —
1083
+ // only tasks that have gone silent for staleTimeoutMs should be killed.
1084
+ const lastActivity =
1085
+ task.progress?.lastUpdate.getTime() ??
1086
+ task.startedAt?.getTime() ??
1087
+ task.queuedAt?.getTime();
1088
+ if (!lastActivity) continue;
1089
+ if (now - lastActivity > this.config.staleTimeoutMs) {
1090
+ this.failTask(task, 'Background task timed out (no activity).');
938
1091
  }
939
1092
  }
940
1093
  }
@@ -7,6 +7,8 @@ export interface TaskProgress {
7
7
  lastUpdate: Date;
8
8
  lastMessage?: string;
9
9
  lastMessageAt?: Date;
10
+ /** Number of tool calls currently in-flight (pending/running state) */
11
+ activeToolCallsInFlight: number;
10
12
  }
11
13
 
12
14
  export interface BackgroundTask {
@@ -27,6 +29,7 @@ export interface BackgroundTask {
27
29
  concurrencyKey?: string; // Active concurrency slot key
28
30
  concurrencyGroup?: string; // Persistent key for re-acquiring on resume
29
31
  notifiedStatuses?: Set<BackgroundTaskStatus>; // Tracks statuses already notified to prevent duplicates
32
+ isMonitor?: boolean; // True if this task is an auto-launched Monitor agent
30
33
  }
31
34
 
32
35
  export interface LaunchInput {