beth-copilot 1.0.15 → 1.0.16
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.
- package/README.md +197 -77
- package/bin/cli.js +47 -0
- package/dist/core/context.d.ts +171 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +353 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/context.test.d.ts +8 -0
- package/dist/core/context.test.d.ts.map +1 -0
- package/dist/core/context.test.js +253 -0
- package/dist/core/context.test.js.map +1 -0
- package/dist/core/handoffs.d.ts +151 -0
- package/dist/core/handoffs.d.ts.map +1 -0
- package/dist/core/handoffs.js +220 -0
- package/dist/core/handoffs.js.map +1 -0
- package/dist/core/handoffs.test.d.ts +8 -0
- package/dist/core/handoffs.test.d.ts.map +1 -0
- package/dist/core/handoffs.test.js +231 -0
- package/dist/core/handoffs.test.js.map +1 -0
- package/dist/core/orchestrator.d.ts +246 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +514 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/orchestrator.test.d.ts +8 -0
- package/dist/core/orchestrator.test.d.ts.map +1 -0
- package/dist/core/orchestrator.test.js +517 -0
- package/dist/core/orchestrator.test.js.map +1 -0
- package/dist/core/router.d.ts +102 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +178 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/router.test.d.ts +8 -0
- package/dist/core/router.test.d.ts.map +1 -0
- package/dist/core/router.test.js +215 -0
- package/dist/core/router.test.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/cli/beads.d.ts +27 -0
- package/dist/tools/cli/beads.d.ts.map +1 -0
- package/dist/tools/cli/beads.js +172 -0
- package/dist/tools/cli/beads.js.map +1 -0
- package/dist/tools/cli/beads.test.d.ts +8 -0
- package/dist/tools/cli/beads.test.d.ts.map +1 -0
- package/dist/tools/cli/beads.test.js +264 -0
- package/dist/tools/cli/beads.test.js.map +1 -0
- package/dist/tools/cli/editFile.d.ts +17 -0
- package/dist/tools/cli/editFile.d.ts.map +1 -0
- package/dist/tools/cli/editFile.js +125 -0
- package/dist/tools/cli/editFile.js.map +1 -0
- package/dist/tools/cli/editFile.test.d.ts +8 -0
- package/dist/tools/cli/editFile.test.d.ts.map +1 -0
- package/dist/tools/cli/editFile.test.js +177 -0
- package/dist/tools/cli/editFile.test.js.map +1 -0
- package/dist/tools/cli/readFile.d.ts +25 -0
- package/dist/tools/cli/readFile.d.ts.map +1 -0
- package/dist/tools/cli/readFile.js +118 -0
- package/dist/tools/cli/readFile.js.map +1 -0
- package/dist/tools/cli/readFile.test.d.ts +8 -0
- package/dist/tools/cli/readFile.test.d.ts.map +1 -0
- package/dist/tools/cli/readFile.test.js +194 -0
- package/dist/tools/cli/readFile.test.js.map +1 -0
- package/dist/tools/cli/search.d.ts +16 -0
- package/dist/tools/cli/search.d.ts.map +1 -0
- package/dist/tools/cli/search.js +261 -0
- package/dist/tools/cli/search.js.map +1 -0
- package/dist/tools/cli/search.test.d.ts +8 -0
- package/dist/tools/cli/search.test.d.ts.map +1 -0
- package/dist/tools/cli/search.test.js +172 -0
- package/dist/tools/cli/search.test.js.map +1 -0
- package/dist/tools/cli/subagent.d.ts +43 -0
- package/dist/tools/cli/subagent.d.ts.map +1 -0
- package/dist/tools/cli/subagent.js +99 -0
- package/dist/tools/cli/subagent.js.map +1 -0
- package/dist/tools/cli/subagent.test.d.ts +8 -0
- package/dist/tools/cli/subagent.test.d.ts.map +1 -0
- package/dist/tools/cli/subagent.test.js +190 -0
- package/dist/tools/cli/subagent.test.js.map +1 -0
- package/dist/tools/cli/terminal.d.ts +19 -0
- package/dist/tools/cli/terminal.d.ts.map +1 -0
- package/dist/tools/cli/terminal.js +164 -0
- package/dist/tools/cli/terminal.js.map +1 -0
- package/dist/tools/cli/terminal.test.d.ts +8 -0
- package/dist/tools/cli/terminal.test.d.ts.map +1 -0
- package/dist/tools/cli/terminal.test.js +161 -0
- package/dist/tools/cli/terminal.test.js.map +1 -0
- package/dist/tools/index.d.ts +25 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +41 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/interface.d.ts +64 -0
- package/dist/tools/interface.d.ts.map +1 -0
- package/dist/tools/interface.js +37 -0
- package/dist/tools/interface.js.map +1 -0
- package/dist/tools/interface.test.d.ts +7 -0
- package/dist/tools/interface.test.d.ts.map +1 -0
- package/dist/tools/interface.test.js +179 -0
- package/dist/tools/interface.test.js.map +1 -0
- package/dist/tools/mcp/bridge.d.ts +48 -0
- package/dist/tools/mcp/bridge.d.ts.map +1 -0
- package/dist/tools/mcp/bridge.js +128 -0
- package/dist/tools/mcp/bridge.js.map +1 -0
- package/dist/tools/mcp/bridge.test.d.ts +8 -0
- package/dist/tools/mcp/bridge.test.d.ts.map +1 -0
- package/dist/tools/mcp/bridge.test.js +300 -0
- package/dist/tools/mcp/bridge.test.js.map +1 -0
- package/dist/tools/mcp/client.d.ts +135 -0
- package/dist/tools/mcp/client.d.ts.map +1 -0
- package/dist/tools/mcp/client.js +263 -0
- package/dist/tools/mcp/client.js.map +1 -0
- package/dist/tools/mcp/client.test.d.ts +8 -0
- package/dist/tools/mcp/client.test.d.ts.map +1 -0
- package/dist/tools/mcp/client.test.js +390 -0
- package/dist/tools/mcp/client.test.js.map +1 -0
- package/dist/tools/registry.d.ts +82 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +99 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/registry.test.d.ts +7 -0
- package/dist/tools/registry.test.d.ts.map +1 -0
- package/dist/tools/registry.test.js +199 -0
- package/dist/tools/registry.test.js.map +1 -0
- package/dist/tools/suite.test.d.ts +11 -0
- package/dist/tools/suite.test.d.ts.map +1 -0
- package/dist/tools/suite.test.js +119 -0
- package/dist/tools/suite.test.js.map +1 -0
- package/dist/tools/types.d.ts +75 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +30 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/types.test.d.ts +7 -0
- package/dist/tools/types.test.d.ts.map +1 -0
- package/dist/tools/types.test.js +178 -0
- package/dist/tools/types.test.js.map +1 -0
- package/package.json +2 -2
- package/sbom.json +209 -209
package/README.md
CHANGED
|
@@ -14,102 +14,62 @@ They broke her wings once. They forgot she had claws.
|
|
|
14
14
|
|
|
15
15
|
Beth is a **multi-agent AI orchestrator** with a TypeScript runtime, CLI toolchain, MCP integrations, and agent-to-agent (A2A) delegation—all driven by a ruthless coordinator who runs your development team the way Beth Dutton runs Schwartz & Meyer.
|
|
16
16
|
|
|
17
|
-
She commands seven specialized agents, each with their own expertise, tools, and handoff chains. On top of the GitHub Copilot agent layer, Beth
|
|
17
|
+
She commands seven specialized agents, each with their own expertise, tools, and handoff chains. On top of the GitHub Copilot agent layer, Beth ships a **TypeScript core engine** with a full agentic loop: agent routing, conversation context management, tool calling, subagent spawning, and agent-to-agent handoffs—all backed by an Azure OpenAI LLM provider with streaming and retry.
|
|
18
18
|
|
|
19
|
-
**The system has
|
|
19
|
+
**The system has four execution layers:**
|
|
20
20
|
|
|
21
21
|
| Layer | What It Does | Status |
|
|
22
22
|
|-------|-------------|--------|
|
|
23
23
|
| **Copilot Agents** | `.agent.md` definitions running in VS Code Agent Mode | Live |
|
|
24
|
-
| **CLI Toolchain** | `beth init`, `beth doctor`, `beth quickstart` — TypeScript commands
|
|
24
|
+
| **CLI Toolchain** | `beth init`, `beth doctor`, `beth quickstart` — TypeScript commands | Live |
|
|
25
|
+
| **Orchestration Engine** | Fan-out routing, tool calling loop, subagent spawning, handoffs | Live |
|
|
26
|
+
| **Tool Abstraction** | 6 CLI tools + MCP bridge — uniform interface for all agent capabilities | Live |
|
|
25
27
|
| **LLM Provider** | Azure OpenAI with Entra ID auth, streaming, retry, tool calling | Live |
|
|
26
28
|
|
|
29
|
+
**814 tests.** 813 pass, 1 skip, 0 fail.
|
|
30
|
+
|
|
27
31
|
---
|
|
28
32
|
|
|
29
33
|
## Architecture
|
|
30
34
|
|
|
31
35
|
```mermaid
|
|
32
36
|
flowchart TB
|
|
33
|
-
subgraph
|
|
34
|
-
Copilot["VS Code Copilot Chat
|
|
35
|
-
CLI["Beth CLI
|
|
37
|
+
subgraph Input["Entry Points"]
|
|
38
|
+
Copilot["VS Code Copilot Chat"]
|
|
39
|
+
CLI["Beth CLI"]
|
|
36
40
|
end
|
|
37
41
|
|
|
38
|
-
subgraph
|
|
39
|
-
|
|
40
|
-
SkillLoader["Skill Loader<br/><i>Parse SKILL.md + triggers</i>"]
|
|
41
|
-
Types["Agent & Skill Types<br/><i>Typed schemas</i>"]
|
|
42
|
-
PathVal["Path Validation<br/><i>Traversal/injection guard</i>"]
|
|
42
|
+
subgraph Engine["Orchestration Engine"]
|
|
43
|
+
Orch["Orchestrator<br/><i>Route → LLM → Tools → Response</i>"]
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
subgraph Agents["Specialist Agents
|
|
46
|
-
Beth["@Beth
|
|
46
|
+
subgraph Agents["Specialist Agents"]
|
|
47
|
+
Beth["@Beth"]
|
|
47
48
|
PM["@product-manager"]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
UX["@ux-designer"]
|
|
50
|
+
Dev["@developer"]
|
|
51
|
+
Sec["@security-reviewer"]
|
|
52
|
+
Test["@tester"]
|
|
53
|
+
Res["@researcher"]
|
|
53
54
|
end
|
|
54
55
|
|
|
55
|
-
subgraph
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
WebDesign["Web Design<br/>Guidelines"]
|
|
60
|
-
Shadcn["shadcn/ui"]
|
|
61
|
-
SecAnalysis["Security Analysis"]
|
|
62
|
-
AzureOps["Azure Operations"]
|
|
63
|
-
WebSearch["Web Search"]
|
|
56
|
+
subgraph Capabilities["Capabilities"]
|
|
57
|
+
Tools["Tools<br/><i>files · terminal · search · beads</i>"]
|
|
58
|
+
Skills["Skills<br/><i>PRD · React · shadcn · security</i>"]
|
|
59
|
+
MCPs["MCP Servers<br/><i>shadcn · Playwright · Azure</i>"]
|
|
64
60
|
end
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
MCPShadcn["shadcn/ui"]
|
|
68
|
-
MCPPlaywright["Playwright"]
|
|
69
|
-
MCPAzure["Azure"]
|
|
70
|
-
MCPBrave["Brave Search"]
|
|
71
|
-
MCPDeepWiki["DeepWiki"]
|
|
72
|
-
end
|
|
62
|
+
LLM["Azure OpenAI<br/><i>Entra ID · Streaming</i>"]
|
|
73
63
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Config["Config Loader<br/><i>env → ~/.beth/.env</i>"]
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
subgraph Tracking["Work Tracking"]
|
|
83
|
-
Beads["beads (bd CLI)<br/><i>Agent coordination</i>"]
|
|
84
|
-
Backlog["Backlog.md<br/><i>Human changelog</i>"]
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
Copilot --> Beth
|
|
88
|
-
CLI --> Core
|
|
89
|
-
Core --> Agents
|
|
90
|
-
Beth -->|"routes"| PM & Researcher & Designer & Developer & Security & Tester
|
|
91
|
-
|
|
92
|
-
PM -.->|"loads"| PRD
|
|
93
|
-
Designer -.->|"loads"| Framer & WebDesign
|
|
94
|
-
Developer -.->|"loads"| React & Shadcn
|
|
95
|
-
Security -.->|"loads"| SecAnalysis
|
|
96
|
-
Researcher -.->|"loads"| WebSearch
|
|
97
|
-
Developer -.->|"uses"| MCPShadcn
|
|
98
|
-
Tester -.->|"uses"| MCPPlaywright
|
|
99
|
-
Security -.->|"uses"| MCPAzure
|
|
100
|
-
Researcher -.->|"uses"| MCPBrave
|
|
101
|
-
|
|
102
|
-
Azure --> Interface
|
|
103
|
-
Retry --> Azure
|
|
104
|
-
Stream --> Azure
|
|
105
|
-
Config --> Azure
|
|
106
|
-
|
|
107
|
-
Beth -.->|"tracks"| Beads
|
|
108
|
-
Beth -.->|"updates"| Backlog
|
|
64
|
+
Copilot & CLI --> Orch
|
|
65
|
+
Orch --> Beth
|
|
66
|
+
Beth -->|"delegates"| PM & UX & Dev & Sec & Test & Res
|
|
67
|
+
Orch <-->|"chat"| LLM
|
|
68
|
+
Orch --> Tools & Skills & MCPs
|
|
109
69
|
|
|
110
70
|
style Beth fill:#1e3a5f,color:#fff
|
|
111
|
-
style
|
|
112
|
-
style
|
|
71
|
+
style Engine fill:#fff3e0
|
|
72
|
+
style Capabilities fill:#e3f2fd
|
|
113
73
|
```
|
|
114
74
|
|
|
115
75
|
---
|
|
@@ -126,7 +86,7 @@ flowchart TB
|
|
|
126
86
|
| **LLM Provider** | Azure OpenAI via `openai` SDK | Entra ID auth (no API keys), streaming + tool calling |
|
|
127
87
|
| **Auth** | `@azure/identity` DefaultAzureCredential | az login, managed identity, VS Code creds |
|
|
128
88
|
| **Frontmatter** | `gray-matter` | Parses `.agent.md` and `SKILL.md` YAML |
|
|
129
|
-
| **Testing** | Node.js built-in test runner |
|
|
89
|
+
| **Testing** | Node.js built-in test runner | 814 tests — unit, integration, E2E |
|
|
130
90
|
| **Task Tracking** | beads (`bd` CLI) | Dependency-aware issue tracking for agents |
|
|
131
91
|
| **Package Manager** | pnpm | Lockfile committed |
|
|
132
92
|
|
|
@@ -331,6 +291,99 @@ Skills are domain-knowledge modules that agents load automatically when trigger
|
|
|
331
291
|
|
|
332
292
|
---
|
|
333
293
|
|
|
294
|
+
## Orchestration Engine (Fan-Out Pattern)
|
|
295
|
+
|
|
296
|
+
The orchestration engine is Beth's brain — the full agentic loop that processes user messages through routing, skill injection, LLM calls, tool execution, and subagent spawning.
|
|
297
|
+
|
|
298
|
+
```mermaid
|
|
299
|
+
flowchart TB
|
|
300
|
+
User["User Message"] --> Route["AgentRouter\n@mention · skill match · default"]
|
|
301
|
+
Route --> Context["ConversationContext\nBuild system prompt + history"]
|
|
302
|
+
Context --> Skills{"Skill triggers match?"}
|
|
303
|
+
Skills -->|yes| Inject["Inject skill into system prompt"]
|
|
304
|
+
Skills -->|no| LLM
|
|
305
|
+
Inject --> LLM["LLM Call\nAzure OpenAI"]
|
|
306
|
+
LLM --> Decision{"Response type?"}
|
|
307
|
+
Decision -->|text| Done["Return response"]
|
|
308
|
+
Decision -->|tool calls| ToolExec["Execute tools\nvia ToolRegistry"]
|
|
309
|
+
ToolExec --> SubCheck{"Subagent request?"}
|
|
310
|
+
SubCheck -->|yes| SubAgent["Spawn child loop\ndepth-limited"]
|
|
311
|
+
SubCheck -->|no| ToolResult["Return tool result"]
|
|
312
|
+
SubAgent --> ToolResult
|
|
313
|
+
ToolResult --> LLM
|
|
314
|
+
Decision -->|handoff| Handoff["HandoffManager\nContext transfer"]
|
|
315
|
+
Handoff --> Route
|
|
316
|
+
|
|
317
|
+
style User fill:#1e3a5f,color:#fff
|
|
318
|
+
style LLM fill:#e8f5e9
|
|
319
|
+
style ToolExec fill:#e3f2fd
|
|
320
|
+
style SubAgent fill:#fff3e0
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Key capabilities:**
|
|
324
|
+
- **Agent routing** — `@mention` parsing, skill trigger matching, current-agent stickiness
|
|
325
|
+
- **Fan-out tool calling** — Iterative LLM → tool call → result → LLM loop (up to 25 iterations)
|
|
326
|
+
- **Subagent spawning** — Nested agent loops with depth limiting (default: 3 levels deep)
|
|
327
|
+
- **Handoff management** — Context transfer between agents with conversation summaries, ping-pong loop detection
|
|
328
|
+
- **Context window management** — Token-estimated truncation with tool call/result consistency repair
|
|
329
|
+
- **Observer callbacks** — Hook into routing decisions, LLM calls, tool executions, handoffs for logging/UI
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
// Full orchestrator usage
|
|
333
|
+
import { Orchestrator, createDefaultRegistry } from 'beth-copilot';
|
|
334
|
+
|
|
335
|
+
const orchestrator = new Orchestrator({
|
|
336
|
+
agents: loadAgents('.github/agents'),
|
|
337
|
+
skills: loadSkills('.github/skills'),
|
|
338
|
+
provider: new AzureOpenAIProvider(config),
|
|
339
|
+
toolRegistry: createDefaultRegistry(),
|
|
340
|
+
toolContext: { workingDir: process.cwd(), permissions: { ... } },
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
const result = await orchestrator.processMessage('Implement the login page');
|
|
344
|
+
// result.response — final text
|
|
345
|
+
// result.agentId — who handled it
|
|
346
|
+
// result.toolCallsExecuted — what tools ran
|
|
347
|
+
// result.subagentResults — any nested agent work
|
|
348
|
+
// result.injectedSkills — skills loaded for this turn
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
## Tool Abstraction Layer
|
|
354
|
+
|
|
355
|
+
A uniform interface for all agent capabilities — file I/O, terminal, search, beads, subagent spawning, and MCP server tools. Tools expose OpenAI-compatible function calling schemas so the LLM can invoke them directly.
|
|
356
|
+
|
|
357
|
+
| Tool | What It Does | Key Features |
|
|
358
|
+
|------|-------------|-------------- |
|
|
359
|
+
| **readFile** | Read file contents | Line ranges, path validation, traversal guards |
|
|
360
|
+
| **editFile** | Atomic string replacement | Single-match enforcement, whitespace-safe |
|
|
361
|
+
| **search** | Ripgrep search | Node.js fallback, regex support, file filtering |
|
|
362
|
+
| **terminal** | Execute shell commands | `execFile('/bin/sh')` — no shell injection, timeouts |
|
|
363
|
+
| **beads** | Issue tracking | `bd create`, `bd close`, `bd list` via CLI wrapper |
|
|
364
|
+
| **subagent** | Spawn nested agents | Returns structured result for orchestrator to process |
|
|
365
|
+
| **MCP Bridge** | External tool servers | JSON-RPC 2.0 over stdio, JSONC config, namespaced tools |
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
import { createDefaultRegistry, ToolRegistry, loadAllMCPTools } from 'beth-copilot';
|
|
369
|
+
|
|
370
|
+
// Built-in tools
|
|
371
|
+
const registry = createDefaultRegistry();
|
|
372
|
+
// → readFile, editFile, search, terminal, beads, subagent
|
|
373
|
+
|
|
374
|
+
// Add MCP server tools
|
|
375
|
+
const { tools: mcpTools } = await loadAllMCPTools('.vscode/mcp.json');
|
|
376
|
+
for (const tool of mcpTools) {
|
|
377
|
+
registry.register(tool); // e.g., mcp_shadcn_listComponents
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Get OpenAI function calling definitions
|
|
381
|
+
const definitions = registry.getDefinitions();
|
|
382
|
+
// Pass to LLM as tools parameter
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
334
387
|
## LLM Provider Layer
|
|
335
388
|
|
|
336
389
|
The TypeScript core includes a production-ready provider abstraction for running Beth outside VS Code.
|
|
@@ -383,7 +436,7 @@ flowchart LR
|
|
|
383
436
|
|
|
384
437
|
## TypeScript Core
|
|
385
438
|
|
|
386
|
-
The engine that powers everything. Parses agent and skill definitions,
|
|
439
|
+
The engine that powers everything. Parses agent and skill definitions, manages conversations, routes requests, executes tools, and provides typed APIs for the full agentic loop.
|
|
387
440
|
|
|
388
441
|
### Project Structure
|
|
389
442
|
|
|
@@ -392,11 +445,15 @@ beth/
|
|
|
392
445
|
├── bin/
|
|
393
446
|
│ └── cli.js # CLI entry point (init, doctor, quickstart, help)
|
|
394
447
|
├── src/
|
|
395
|
-
│ ├── index.ts # Barrel exports
|
|
448
|
+
│ ├── index.ts # Barrel exports (all public API)
|
|
396
449
|
│ ├── cli/commands/
|
|
397
450
|
│ │ ├── doctor.ts # System health validation
|
|
398
451
|
│ │ └── quickstart.ts # Guided setup flow
|
|
399
452
|
│ ├── core/
|
|
453
|
+
│ │ ├── orchestrator.ts # Agentic loop: route → LLM → tools → response
|
|
454
|
+
│ │ ├── router.ts # @mention routing, skill matching, agent lookup
|
|
455
|
+
│ │ ├── context.ts # Conversation state, token truncation, skill injection
|
|
456
|
+
│ │ ├── handoffs.ts # Agent-to-agent transfers, loop detection
|
|
400
457
|
│ │ ├── agents/
|
|
401
458
|
│ │ │ ├── types.ts # AgentDefinition, AgentFrontmatter, AgentHandoff
|
|
402
459
|
│ │ │ └── loader.ts # Parse .agent.md → typed definitions
|
|
@@ -405,6 +462,20 @@ beth/
|
|
|
405
462
|
│ │ └── loader.ts # Parse SKILL.md, extract triggers, match queries
|
|
406
463
|
│ ├── lib/
|
|
407
464
|
│ │ └── pathValidation.ts # Traversal/injection guards
|
|
465
|
+
│ ├── tools/
|
|
466
|
+
│ │ ├── interface.ts # Tool interface + toToolDefinition()
|
|
467
|
+
│ │ ├── types.ts # ToolError, ToolResult, ToolContext, ToolPermissions
|
|
468
|
+
│ │ ├── registry.ts # ToolRegistry: register, get, list, getDefinitions
|
|
469
|
+
│ │ ├── cli/
|
|
470
|
+
│ │ │ ├── readFile.ts # File reading with line ranges
|
|
471
|
+
│ │ │ ├── editFile.ts # Atomic string replacement
|
|
472
|
+
│ │ │ ├── search.ts # Ripgrep with Node.js fallback
|
|
473
|
+
│ │ │ ├── terminal.ts # Secure command execution
|
|
474
|
+
│ │ │ ├── beads.ts # Issue tracking via bd CLI
|
|
475
|
+
│ │ │ └── subagent.ts # Agent spawning interface
|
|
476
|
+
│ │ └── mcp/
|
|
477
|
+
│ │ ├── client.ts # JSON-RPC 2.0 over stdio
|
|
478
|
+
│ │ └── bridge.ts # JSONC config, tool namespacing
|
|
408
479
|
│ └── providers/
|
|
409
480
|
│ ├── interface.ts # LLMProviderBase abstract class
|
|
410
481
|
│ ├── azure.ts # AzureOpenAIProvider (Entra ID, streaming, tools)
|
|
@@ -425,17 +496,36 @@ beth/
|
|
|
425
496
|
|
|
426
497
|
### Test Coverage
|
|
427
498
|
|
|
428
|
-
**
|
|
499
|
+
**814 tests** (813 pass, 1 skip, 0 fail):
|
|
429
500
|
|
|
430
501
|
| Suite | Tests | What It Covers |
|
|
431
502
|
|-------|-------|---------------|
|
|
432
|
-
|
|
|
433
|
-
|
|
|
503
|
+
| **Orchestration** | | |
|
|
504
|
+
| Orchestrator | 30+ | Agentic loop, tool calling, subagent spawning, iteration limits |
|
|
505
|
+
| AgentRouter | 30+ | @mention routing, skill matching, agent resolution |
|
|
506
|
+
| ConversationContext | 30+ | Token truncation, skill injection, tool call repair |
|
|
507
|
+
| HandoffManager | 30+ | Context transfer, depth limits, ping-pong detection |
|
|
508
|
+
| **Tools** | | |
|
|
509
|
+
| Tool interface | 20+ | Tool → ToolDefinition conversion, schema validation |
|
|
510
|
+
| ToolRegistry | 20+ | Register, get, list, definitions, duplicate detection |
|
|
511
|
+
| readFile | 30+ | Line ranges, path validation, encoding |
|
|
512
|
+
| editFile | 30+ | String replacement, single-match enforcement |
|
|
513
|
+
| search | 30+ | Ripgrep, Node.js fallback, regex, file filtering |
|
|
514
|
+
| terminal | 30+ | Command execution, timeouts, output capture |
|
|
515
|
+
| beads | 30+ | bd CLI wrapper, create/close/list/ready |
|
|
516
|
+
| subagent | 30+ | Spawn interface, result marking, agent validation |
|
|
517
|
+
| MCP client | 30+ | JSON-RPC 2.0, protocol handshake, tool listing |
|
|
518
|
+
| MCP bridge | 30+ | JSONC parsing, tool namespacing, error handling |
|
|
519
|
+
| Tool suite | 10+ | createDefaultRegistry, integration tests |
|
|
520
|
+
| **Providers** | | |
|
|
434
521
|
| Provider types | 40+ | LLMError codes, ChatMessage shapes, ToolDefinition schemas |
|
|
435
522
|
| Provider retry | 40+ | Exponential backoff, jitter, transient error detection |
|
|
436
523
|
| Provider config | 30+ | Env precedence, dotenv parsing, URL validation |
|
|
437
524
|
| Provider streaming | 40+ | Chunk accumulation, tool call delta assembly |
|
|
438
525
|
| Provider Azure | 30+ | Message mapping, response mapping, error wrapping |
|
|
526
|
+
| **Core & CLI** | | |
|
|
527
|
+
| Agent loader | 30+ | Frontmatter parsing, validation, code fence stripping, handoffs |
|
|
528
|
+
| Skill loader | 30+ | Trigger extraction, query matching, trigger map building |
|
|
439
529
|
| CLI E2E | 52 | Init/doctor pipeline, MCP template validation, help output |
|
|
440
530
|
| Path validation | 33 | Traversal detection, injection prevention, allowlists |
|
|
441
531
|
|
|
@@ -572,6 +662,36 @@ Is it magic? No. It's just competence with very good hair.
|
|
|
572
662
|
- **GitHub Copilot Chat** in Agent mode
|
|
573
663
|
- [**beads**](https://github.com/steveyegge/beads) for task tracking (`bd` CLI)
|
|
574
664
|
|
|
665
|
+
### Installing Beads
|
|
666
|
+
|
|
667
|
+
```bash
|
|
668
|
+
curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
**CGO Troubleshooting (Linux/WSL):** Beads uses Dolt (a Git-for-data database) which requires CGO. If `bd init` or `bd doctor` fails with CGO-related errors:
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
# Install C compiler toolchain (required for CGO)
|
|
675
|
+
sudo apt-get update && sudo apt-get install -y build-essential gcc
|
|
676
|
+
|
|
677
|
+
# Verify CGO is available
|
|
678
|
+
export CGO_ENABLED=1
|
|
679
|
+
go env CGO_ENABLED # should print 1
|
|
680
|
+
|
|
681
|
+
# Re-install beads
|
|
682
|
+
curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
**Common beads issues:**
|
|
686
|
+
- `bd: command not found` — Add `~/.local/bin` to your PATH: `export PATH="$HOME/.local/bin:$PATH"`
|
|
687
|
+
- `bd doctor` warnings about metadata — Run `bd doctor --fix` to auto-repair
|
|
688
|
+
- Dolt migration errors — Delete `.beads/` and re-initialize with `bd init`
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
# Verify beads is working
|
|
692
|
+
bd doctor
|
|
693
|
+
```
|
|
694
|
+
|
|
575
695
|
### Optional: MCP Servers
|
|
576
696
|
|
|
577
697
|
See [MCP Integrations](#mcp-integrations) above or [docs/MCP-SETUP.md](docs/MCP-SETUP.md) for setup.
|
package/bin/cli.js
CHANGED
|
@@ -733,6 +733,48 @@ async function initializeBeads(cwd) {
|
|
|
733
733
|
});
|
|
734
734
|
}
|
|
735
735
|
|
|
736
|
+
/**
|
|
737
|
+
* Runs `bd doctor` to verify beads configuration health.
|
|
738
|
+
*
|
|
739
|
+
* SECURITY NOTE - shell:true usage:
|
|
740
|
+
* - bdPath is validated via getBeadsPath() (same as initializeBeads)
|
|
741
|
+
* - Arguments are HARDCODED ('doctor') - no user input is passed to the shell
|
|
742
|
+
* - Command injection risk: LOW (bdPath is validated, no user input in args)
|
|
743
|
+
*
|
|
744
|
+
* @returns {Promise<boolean>} True if bd doctor passed
|
|
745
|
+
*/
|
|
746
|
+
async function runBeadsDoctor() {
|
|
747
|
+
log('\nRunning beads doctor to verify configuration...', COLORS.cyan);
|
|
748
|
+
|
|
749
|
+
const bdPath = getBeadsPath();
|
|
750
|
+
if (!bdPath) {
|
|
751
|
+
logWarning('Cannot run beads doctor: bd not found.');
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
return new Promise((resolve) => {
|
|
756
|
+
const child = spawn(bdPath, ['doctor'], {
|
|
757
|
+
stdio: 'inherit',
|
|
758
|
+
shell: true,
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
child.on('close', (code) => {
|
|
762
|
+
if (code === 0) {
|
|
763
|
+
logSuccess('beads doctor passed!');
|
|
764
|
+
resolve(true);
|
|
765
|
+
} else {
|
|
766
|
+
logWarning('beads doctor reported issues. Run "bd doctor" manually to investigate.');
|
|
767
|
+
resolve(false);
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
child.on('error', () => {
|
|
772
|
+
logWarning('Failed to run beads doctor. Run "bd doctor" manually.');
|
|
773
|
+
resolve(false);
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
736
778
|
function showHelp() {
|
|
737
779
|
showBethBannerStatic({ showQuickHelp: false });
|
|
738
780
|
console.log(`${COLORS.bright}Beth${COLORS.reset} - AI Orchestrator for GitHub Copilot
|
|
@@ -1048,6 +1090,11 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1048
1090
|
logWarning('Skipped beads check (--skip-beads). Beth may not function correctly.');
|
|
1049
1091
|
}
|
|
1050
1092
|
|
|
1093
|
+
// Run bd doctor to verify beads configuration
|
|
1094
|
+
if (!skipBeads && getBeadsPath() && isBeadsInitialized(cwd)) {
|
|
1095
|
+
await runBeadsDoctor();
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1051
1098
|
// Final verification
|
|
1052
1099
|
console.log('');
|
|
1053
1100
|
log('Verifying installation...', COLORS.cyan);
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation Context Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages conversation state for agent interactions:
|
|
5
|
+
* - Message history with role tracking
|
|
6
|
+
* - Context window management (token estimation + truncation)
|
|
7
|
+
* - System prompt construction from agent definitions + skills
|
|
8
|
+
* - Skill injection when trigger phrases match user input
|
|
9
|
+
*
|
|
10
|
+
* Each agent session gets its own ConversationContext. When handoffs occur,
|
|
11
|
+
* a summary can be extracted and injected into the new agent's context.
|
|
12
|
+
*/
|
|
13
|
+
import type { ChatMessage } from '../providers/types.js';
|
|
14
|
+
import type { AgentDefinition } from './agents/types.js';
|
|
15
|
+
import type { SkillDefinition } from './skills/types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Options for creating a ConversationContext.
|
|
18
|
+
*/
|
|
19
|
+
export interface ConversationContextOptions {
|
|
20
|
+
/** Maximum tokens for the context window (default: 128000) */
|
|
21
|
+
maxTokens?: number;
|
|
22
|
+
/** Tokens reserved for the model's response (default: 4096) */
|
|
23
|
+
responseReserve?: number;
|
|
24
|
+
/** Initial conversation history to restore (e.g., from a handoff) */
|
|
25
|
+
initialMessages?: ChatMessage[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Summary of a conversation for handoff purposes.
|
|
29
|
+
*/
|
|
30
|
+
export interface ConversationSummary {
|
|
31
|
+
/** The agent that was running this conversation */
|
|
32
|
+
agentId: string;
|
|
33
|
+
/** Key points from the conversation */
|
|
34
|
+
summary: string;
|
|
35
|
+
/** Number of turns in the original conversation */
|
|
36
|
+
turnCount: number;
|
|
37
|
+
/** Any tool calls that were made */
|
|
38
|
+
toolCallSummary: string[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Manages conversation state for a single agent session.
|
|
42
|
+
*
|
|
43
|
+
* Handles message accumulation, context window enforcement,
|
|
44
|
+
* and system prompt construction from agent definitions and skills.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* const ctx = new ConversationContext(developerAgent);
|
|
49
|
+
* ctx.addUserMessage('Implement the login page');
|
|
50
|
+
*
|
|
51
|
+
* const messages = ctx.getMessages(); // system + user message
|
|
52
|
+
* // Send to LLM...
|
|
53
|
+
*
|
|
54
|
+
* ctx.addAssistantMessage('I\'ll create the login component...');
|
|
55
|
+
* ctx.addAssistantToolCalls([{ id: '1', type: 'function', function: { name: 'editFile', arguments: '...' } }]);
|
|
56
|
+
* ctx.addToolResult('1', 'File updated successfully');
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare class ConversationContext {
|
|
60
|
+
/** The agent this context belongs to */
|
|
61
|
+
private readonly agent;
|
|
62
|
+
/** Conversation messages (excluding system prompt; it's built dynamically) */
|
|
63
|
+
private messages;
|
|
64
|
+
/** Skills injected into this context */
|
|
65
|
+
private injectedSkills;
|
|
66
|
+
/** Skill content appended to system prompt */
|
|
67
|
+
private skillContent;
|
|
68
|
+
/** Context window configuration */
|
|
69
|
+
private readonly maxTokens;
|
|
70
|
+
private readonly responseReserve;
|
|
71
|
+
/** Custom context additions (handoff summaries, etc.) */
|
|
72
|
+
private additionalContext;
|
|
73
|
+
constructor(agent: AgentDefinition, options?: ConversationContextOptions);
|
|
74
|
+
/**
|
|
75
|
+
* Add a user message to the conversation.
|
|
76
|
+
*/
|
|
77
|
+
addUserMessage(content: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Add an assistant text response to the conversation.
|
|
80
|
+
*/
|
|
81
|
+
addAssistantMessage(content: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Add an assistant message with tool calls.
|
|
84
|
+
*/
|
|
85
|
+
addAssistantToolCalls(toolCalls: ChatMessage['tool_calls'], content?: string): void;
|
|
86
|
+
/**
|
|
87
|
+
* Add a tool result message.
|
|
88
|
+
*/
|
|
89
|
+
addToolResult(toolCallId: string, result: string): void;
|
|
90
|
+
/**
|
|
91
|
+
* Get the full message array for sending to the LLM.
|
|
92
|
+
* Includes the constructed system prompt as the first message.
|
|
93
|
+
* Applies truncation if context window is exceeded.
|
|
94
|
+
*/
|
|
95
|
+
getMessages(): ChatMessage[];
|
|
96
|
+
/**
|
|
97
|
+
* Get just the conversation messages (without system prompt).
|
|
98
|
+
*/
|
|
99
|
+
getRawMessages(): ChatMessage[];
|
|
100
|
+
/**
|
|
101
|
+
* Get the number of conversation turns (user messages).
|
|
102
|
+
*/
|
|
103
|
+
getTurnCount(): number;
|
|
104
|
+
/**
|
|
105
|
+
* Get estimated token count for the current context.
|
|
106
|
+
*/
|
|
107
|
+
getEstimatedTokens(): number;
|
|
108
|
+
/**
|
|
109
|
+
* Clear the conversation history, keeping injected skills.
|
|
110
|
+
*/
|
|
111
|
+
clearHistory(): void;
|
|
112
|
+
/**
|
|
113
|
+
* Inject a skill's content into the system prompt.
|
|
114
|
+
* Each skill is only injected once per context.
|
|
115
|
+
*
|
|
116
|
+
* @param skill - The skill to inject
|
|
117
|
+
* @returns true if the skill was injected, false if already present
|
|
118
|
+
*/
|
|
119
|
+
injectSkill(skill: SkillDefinition): boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Check if a skill has been injected.
|
|
122
|
+
*/
|
|
123
|
+
hasSkill(skillId: string): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Get the IDs of all injected skills.
|
|
126
|
+
*/
|
|
127
|
+
getInjectedSkillIds(): string[];
|
|
128
|
+
/**
|
|
129
|
+
* Add additional context (e.g., handoff summary from previous agent).
|
|
130
|
+
*/
|
|
131
|
+
addContext(context: string): void;
|
|
132
|
+
/**
|
|
133
|
+
* Generate a summary of this conversation for handoff purposes.
|
|
134
|
+
*/
|
|
135
|
+
getSummary(): ConversationSummary;
|
|
136
|
+
/**
|
|
137
|
+
* Get the agent definition this context belongs to.
|
|
138
|
+
*/
|
|
139
|
+
getAgent(): AgentDefinition;
|
|
140
|
+
/**
|
|
141
|
+
* Build the full system prompt from the agent definition + injected content.
|
|
142
|
+
*/
|
|
143
|
+
buildSystemPrompt(): string;
|
|
144
|
+
/**
|
|
145
|
+
* Estimate token count for a string.
|
|
146
|
+
*/
|
|
147
|
+
private estimateTokens;
|
|
148
|
+
/**
|
|
149
|
+
* Estimate token count for a single message including structure overhead.
|
|
150
|
+
*/
|
|
151
|
+
private estimateMessageTokens;
|
|
152
|
+
/**
|
|
153
|
+
* Truncate messages to fit within the token budget.
|
|
154
|
+
*
|
|
155
|
+
* Strategy: Keep the most recent messages. Drop oldest messages first,
|
|
156
|
+
* but never drop tool results that are paired with a tool call in the
|
|
157
|
+
* retained messages (to avoid orphaned tool call references).
|
|
158
|
+
*
|
|
159
|
+
* @param messages - Messages to truncate
|
|
160
|
+
* @param maxTokens - Maximum tokens available
|
|
161
|
+
* @returns Truncated message array
|
|
162
|
+
*/
|
|
163
|
+
private truncateMessages;
|
|
164
|
+
/**
|
|
165
|
+
* Remove orphaned tool results (where the corresponding assistant
|
|
166
|
+
* tool_calls message was truncated) and orphaned tool calls
|
|
167
|
+
* (where the results were truncated).
|
|
168
|
+
*/
|
|
169
|
+
private repairToolCallConsistency;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAmBzD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,qEAAqE;IACrE,eAAe,CAAC,EAAE,WAAW,EAAE,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAEhB,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAEhB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAElB,oCAAoC;IACpC,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,mBAAmB;IAC9B,wCAAwC;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IAExC,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAAqB;IAErC,wCAAwC;IACxC,OAAO,CAAC,cAAc,CAA0B;IAEhD,8CAA8C;IAC9C,OAAO,CAAC,YAAY,CAAgB;IAEpC,mCAAmC;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IAEzC,yDAAyD;IACzD,OAAO,CAAC,iBAAiB,CAAgB;gBAE7B,KAAK,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,0BAA0B;IAcxE;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIrC;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI1C;;OAEG;IACH,qBAAqB,CAAC,SAAS,EAAE,WAAW,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAQnF;;OAEG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAQvD;;;;OAIG;IACH,WAAW,IAAI,WAAW,EAAE;IAY5B;;OAEG;IACH,cAAc,IAAI,WAAW,EAAE;IAI/B;;OAEG;IACH,YAAY,IAAI,MAAM;IAItB;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAU5B;;OAEG;IACH,YAAY,IAAI,IAAI;IAQpB;;;;;;OAMG;IACH,WAAW,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO;IAY5C;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIlC;;OAEG;IACH,mBAAmB,IAAI,MAAM,EAAE;IAQ/B;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQjC;;OAEG;IACH,UAAU,IAAI,mBAAmB;IA4BjC;;OAEG;IACH,QAAQ,IAAI,eAAe;IAQ3B;;OAEG;IACH,iBAAiB,IAAI,MAAM;IA0B3B;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAyB7B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,gBAAgB;IA6CxB;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;CAgClC"}
|