skimpyclaw 0.1.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.
- package/README.md +230 -0
- package/dist/__tests__/agent.test.d.ts +1 -0
- package/dist/__tests__/agent.test.js +131 -0
- package/dist/__tests__/api.test.d.ts +1 -0
- package/dist/__tests__/api.test.js +1227 -0
- package/dist/__tests__/audit.test.d.ts +1 -0
- package/dist/__tests__/audit.test.js +122 -0
- package/dist/__tests__/cache.test.d.ts +1 -0
- package/dist/__tests__/cache.test.js +65 -0
- package/dist/__tests__/channels.test.d.ts +1 -0
- package/dist/__tests__/channels.test.js +85 -0
- package/dist/__tests__/cli.integration.test.d.ts +1 -0
- package/dist/__tests__/cli.integration.test.js +16 -0
- package/dist/__tests__/cli.test.d.ts +1 -0
- package/dist/__tests__/cli.test.js +230 -0
- package/dist/__tests__/code-agents-executor.test.d.ts +1 -0
- package/dist/__tests__/code-agents-executor.test.js +75 -0
- package/dist/__tests__/code-agents-orchestrator.test.d.ts +1 -0
- package/dist/__tests__/code-agents-orchestrator.test.js +149 -0
- package/dist/__tests__/code-agents-parser.test.d.ts +1 -0
- package/dist/__tests__/code-agents-parser.test.js +39 -0
- package/dist/__tests__/code-agents-utils.test.d.ts +1 -0
- package/dist/__tests__/code-agents-utils.test.js +41 -0
- package/dist/__tests__/config.test.d.ts +1 -0
- package/dist/__tests__/config.test.js +46 -0
- package/dist/__tests__/cron.test.d.ts +1 -0
- package/dist/__tests__/cron.test.js +66 -0
- package/dist/__tests__/dashboard-mode.test.d.ts +1 -0
- package/dist/__tests__/dashboard-mode.test.js +145 -0
- package/dist/__tests__/dashboard.test.d.ts +1 -0
- package/dist/__tests__/dashboard.test.js +43 -0
- package/dist/__tests__/doctor.formatters.test.d.ts +1 -0
- package/dist/__tests__/doctor.formatters.test.js +65 -0
- package/dist/__tests__/doctor.index.test.d.ts +1 -0
- package/dist/__tests__/doctor.index.test.js +48 -0
- package/dist/__tests__/doctor.runner.test.d.ts +1 -0
- package/dist/__tests__/doctor.runner.test.js +204 -0
- package/dist/__tests__/exec-approval.test.d.ts +1 -0
- package/dist/__tests__/exec-approval.test.js +323 -0
- package/dist/__tests__/file-lock.test.d.ts +1 -0
- package/dist/__tests__/file-lock.test.js +92 -0
- package/dist/__tests__/langfuse.test.d.ts +1 -0
- package/dist/__tests__/langfuse.test.js +40 -0
- package/dist/__tests__/model-selection.test.d.ts +1 -0
- package/dist/__tests__/model-selection.test.js +62 -0
- package/dist/__tests__/orchestrator.test.d.ts +1 -0
- package/dist/__tests__/orchestrator.test.js +425 -0
- package/dist/__tests__/providers-init.test.d.ts +1 -0
- package/dist/__tests__/providers-init.test.js +32 -0
- package/dist/__tests__/providers-routing.test.d.ts +1 -0
- package/dist/__tests__/providers-routing.test.js +25 -0
- package/dist/__tests__/providers-utils.test.d.ts +1 -0
- package/dist/__tests__/providers-utils.test.js +54 -0
- package/dist/__tests__/security.test.d.ts +1 -0
- package/dist/__tests__/security.test.js +22 -0
- package/dist/__tests__/sessions.test.d.ts +1 -0
- package/dist/__tests__/sessions.test.js +147 -0
- package/dist/__tests__/setup.test.d.ts +1 -0
- package/dist/__tests__/setup.test.js +114 -0
- package/dist/__tests__/skills.test.d.ts +1 -0
- package/dist/__tests__/skills.test.js +333 -0
- package/dist/__tests__/subagent.test.d.ts +1 -0
- package/dist/__tests__/subagent.test.js +240 -0
- package/dist/__tests__/telegram-utils.test.d.ts +1 -0
- package/dist/__tests__/telegram-utils.test.js +22 -0
- package/dist/__tests__/telegram.test.d.ts +1 -0
- package/dist/__tests__/telegram.test.js +42 -0
- package/dist/__tests__/token-efficiency.test.d.ts +1 -0
- package/dist/__tests__/token-efficiency.test.js +38 -0
- package/dist/__tests__/tool-guard.test.d.ts +1 -0
- package/dist/__tests__/tool-guard.test.js +105 -0
- package/dist/__tests__/tools.test.d.ts +1 -0
- package/dist/__tests__/tools.test.js +589 -0
- package/dist/__tests__/usage.test.d.ts +1 -0
- package/dist/__tests__/usage.test.js +197 -0
- package/dist/__tests__/voice.test.d.ts +1 -0
- package/dist/__tests__/voice.test.js +214 -0
- package/dist/agent.d.ts +24 -0
- package/dist/agent.js +269 -0
- package/dist/api.d.ts +3 -0
- package/dist/api.js +943 -0
- package/dist/audit.d.ts +26 -0
- package/dist/audit.js +121 -0
- package/dist/cache.d.ts +8 -0
- package/dist/cache.js +24 -0
- package/dist/channels/telegram/handlers.d.ts +41 -0
- package/dist/channels/telegram/handlers.js +498 -0
- package/dist/channels/telegram/index.d.ts +14 -0
- package/dist/channels/telegram/index.js +326 -0
- package/dist/channels/telegram/types.d.ts +26 -0
- package/dist/channels/telegram/types.js +31 -0
- package/dist/channels/telegram/utils.d.ts +25 -0
- package/dist/channels/telegram/utils.js +256 -0
- package/dist/channels.d.ts +11 -0
- package/dist/channels.js +118 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +768 -0
- package/dist/code-agents/executor.d.ts +5 -0
- package/dist/code-agents/executor.js +463 -0
- package/dist/code-agents/index.d.ts +22 -0
- package/dist/code-agents/index.js +199 -0
- package/dist/code-agents/orchestrator.d.ts +23 -0
- package/dist/code-agents/orchestrator.js +403 -0
- package/dist/code-agents/parser.d.ts +21 -0
- package/dist/code-agents/parser.js +197 -0
- package/dist/code-agents/registry.d.ts +27 -0
- package/dist/code-agents/registry.js +147 -0
- package/dist/code-agents/types.d.ts +66 -0
- package/dist/code-agents/types.js +4 -0
- package/dist/code-agents/utils.d.ts +36 -0
- package/dist/code-agents/utils.js +236 -0
- package/dist/config.d.ts +19 -0
- package/dist/config.js +123 -0
- package/dist/cron.d.ts +49 -0
- package/dist/cron.js +400 -0
- package/dist/dashboard/assets/index-CZJCvMSN.js +65 -0
- package/dist/dashboard/assets/index-EAg6lqF5.css +1 -0
- package/dist/dashboard/favicon.svg +3 -0
- package/dist/dashboard/index.html +21 -0
- package/dist/dashboard-frontend.d.ts +7 -0
- package/dist/dashboard-frontend.js +86 -0
- package/dist/dashboard.d.ts +8 -0
- package/dist/dashboard.js +4071 -0
- package/dist/digests.d.ts +36 -0
- package/dist/digests.js +338 -0
- package/dist/discord.d.ts +8 -0
- package/dist/discord.js +828 -0
- package/dist/doctor/checks.d.ts +18 -0
- package/dist/doctor/checks.js +368 -0
- package/dist/doctor/formatters.d.ts +3 -0
- package/dist/doctor/formatters.js +44 -0
- package/dist/doctor/index.d.ts +8 -0
- package/dist/doctor/index.js +7 -0
- package/dist/doctor/runner.d.ts +3 -0
- package/dist/doctor/runner.js +109 -0
- package/dist/doctor/types.d.ts +20 -0
- package/dist/doctor/types.js +1 -0
- package/dist/exec-approval.d.ts +101 -0
- package/dist/exec-approval.js +432 -0
- package/dist/file-lock.d.ts +34 -0
- package/dist/file-lock.js +81 -0
- package/dist/gateway.d.ts +8 -0
- package/dist/gateway.js +114 -0
- package/dist/heartbeat.d.ts +4 -0
- package/dist/heartbeat.js +101 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +75 -0
- package/dist/langfuse.d.ts +34 -0
- package/dist/langfuse.js +145 -0
- package/dist/mcp-context-a8c.d.ts +13 -0
- package/dist/mcp-context-a8c.js +34 -0
- package/dist/model-selection.d.ts +18 -0
- package/dist/model-selection.js +50 -0
- package/dist/orchestrator.d.ts +15 -0
- package/dist/orchestrator.js +676 -0
- package/dist/providers/anthropic.d.ts +7 -0
- package/dist/providers/anthropic.js +319 -0
- package/dist/providers/codex.d.ts +17 -0
- package/dist/providers/codex.js +508 -0
- package/dist/providers/content.d.ts +21 -0
- package/dist/providers/content.js +55 -0
- package/dist/providers/index.d.ts +13 -0
- package/dist/providers/index.js +138 -0
- package/dist/providers/observability.d.ts +19 -0
- package/dist/providers/observability.js +94 -0
- package/dist/providers/openai.d.ts +10 -0
- package/dist/providers/openai.js +310 -0
- package/dist/providers/tool-guard.d.ts +30 -0
- package/dist/providers/tool-guard.js +89 -0
- package/dist/providers/types.d.ts +34 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/utils.d.ts +65 -0
- package/dist/providers/utils.js +199 -0
- package/dist/security.d.ts +8 -0
- package/dist/security.js +113 -0
- package/dist/service.d.ts +8 -0
- package/dist/service.js +38 -0
- package/dist/sessions.d.ts +35 -0
- package/dist/sessions.js +142 -0
- package/dist/setup.d.ts +36 -0
- package/dist/setup.js +821 -0
- package/dist/skills-types.d.ts +65 -0
- package/dist/skills-types.js +2 -0
- package/dist/skills.d.ts +32 -0
- package/dist/skills.js +260 -0
- package/dist/subagent.d.ts +19 -0
- package/dist/subagent.js +376 -0
- package/dist/telegram.d.ts +2 -0
- package/dist/telegram.js +11 -0
- package/dist/tools/bash-tool.d.ts +3 -0
- package/dist/tools/bash-tool.js +59 -0
- package/dist/tools/browser-tool.d.ts +3 -0
- package/dist/tools/browser-tool.js +265 -0
- package/dist/tools/definitions.d.ts +432 -0
- package/dist/tools/definitions.js +181 -0
- package/dist/tools/execute-context.d.ts +26 -0
- package/dist/tools/execute-context.js +1 -0
- package/dist/tools/file-tools.d.ts +8 -0
- package/dist/tools/file-tools.js +67 -0
- package/dist/tools/path-utils.d.ts +1 -0
- package/dist/tools/path-utils.js +8 -0
- package/dist/tools.d.ts +24 -0
- package/dist/tools.js +281 -0
- package/dist/types.d.ts +259 -0
- package/dist/types.js +2 -0
- package/dist/usage.d.ts +76 -0
- package/dist/usage.js +150 -0
- package/dist/voice.d.ts +37 -0
- package/dist/voice.js +461 -0
- package/package.json +70 -0
- package/templates/AGENTS.md +38 -0
- package/templates/BOOT.md +23 -0
- package/templates/BOOTSTRAP.md +26 -0
- package/templates/HEARTBEAT.md +5 -0
- package/templates/IDENTITY.md +5 -0
- package/templates/MEMORY.md +24 -0
- package/templates/SOUL.md +92 -0
- package/templates/TOOLS.md +30 -0
- package/templates/USER.md +31 -0
package/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# SkimpyClaw 👙🦞
|
|
2
|
+
|
|
3
|
+
Lightweight personal AI assistant (~20k LOC). Runs locally. Telegram/Discord chat, scheduled routines, a web dashboard, and a tool-enabled agent — all in one tiny service.
|
|
4
|
+
|
|
5
|
+
## Why SkimpyClaw vs OpenClaw
|
|
6
|
+
|
|
7
|
+
Both are personal AI assistants you run yourself. The difference is scope.
|
|
8
|
+
|
|
9
|
+
| | SkimpyClaw (~20k LOC) | OpenClaw (~700k LOC) |
|
|
10
|
+
| ------------------- | --------------------------------------- | -------------------------------------------------------- |
|
|
11
|
+
| **Channels** | Telegram, Discord | WhatsApp, Signal, iMessage, Slack, Teams, Matrix, + more |
|
|
12
|
+
| **Setup** | `skimpyclaw onboard` → done | Daemon + wizard + per-channel pairing |
|
|
13
|
+
| **Codebase** | Read it in an afternoon | Full platform with extensions, packages, native UI |
|
|
14
|
+
| **Model support** | Anthropic, OpenAI, Kimi, MiniMax, Codex | Same + more |
|
|
15
|
+
| **Release cadence** | Move fast, no stability guarantees | Stable / beta / dev channels |
|
|
16
|
+
|
|
17
|
+
Use SkimpyClaw if you live in Telegram or Discord, want to read and own every line, and don't need 13 channels. Use OpenClaw if you need to support multiple channels like WhatsApp, Signal, iMessage, or Slack — or want a more polished, maintained platform.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Chat interface** — Telegram and Discord bots with persistent conversation history
|
|
22
|
+
- **Tool-enabled agent** — file read/write, bash, browser (Playwright), MCP tools via mcporter
|
|
23
|
+
- **Multi-modal support** — voice messages (STT/TTS), image analysis
|
|
24
|
+
- **Subagents** — model autonomously spawns coding/research subagents with retry + concurrency control
|
|
25
|
+
- **Code agents** — delegate coding tasks to Claude Code, Codex, or Kimi CLI with `code_with_agent` and `code_with_team`
|
|
26
|
+
- **Cron scheduler** — run agent prompts or shell scripts on a schedule
|
|
27
|
+
- **Web dashboard** — Preact/Vite SPA with status, cron, audit log, memory, templates, config editor, skills, approvals
|
|
28
|
+
- **Heartbeat** — periodic keep-alive with Telegram/Discord alerts
|
|
29
|
+
- **Skills** — domain-specific capabilities loaded from `~/.skimpyclaw/skills/`
|
|
30
|
+
- **Exec approval** — human-in-the-loop approval for sensitive bash commands (tier 2-3 risks)
|
|
31
|
+
- **Voice** — optional TTS/STT support (ElevenLabs, OpenAI, macOS `say`, local Whisper)
|
|
32
|
+
- **Observability** — optional Langfuse tracing per agent turn
|
|
33
|
+
- **Audit logging** — JSONL-based audit traces for all agent interactions
|
|
34
|
+
- **Multiple model providers** — Anthropic, OpenAI, Kimi, MiniMax, Codex (ChatGPT backend), any OpenAI-compatible API
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
flowchart LR
|
|
40
|
+
subgraph Channels
|
|
41
|
+
user["Telegram / Discord"]
|
|
42
|
+
browser["Browser"]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
subgraph Gateway["Fastify :18790"]
|
|
46
|
+
dash["Dashboard"]
|
|
47
|
+
api["REST API"]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
subgraph Core
|
|
51
|
+
agent["Agent Runtime"]
|
|
52
|
+
subagents["Subagent Pool"]
|
|
53
|
+
cron["Cron"]
|
|
54
|
+
hb["Heartbeat"]
|
|
55
|
+
audit["Audit Log"]
|
|
56
|
+
skills["Skills System"]
|
|
57
|
+
approvals["Exec Approval"]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
user --> agent
|
|
61
|
+
browser --> dash --> api --> agent
|
|
62
|
+
cron --> agent
|
|
63
|
+
hb --> agent
|
|
64
|
+
agent --> subagents
|
|
65
|
+
agent --> audit
|
|
66
|
+
agent --> skills
|
|
67
|
+
agent --> approvals
|
|
68
|
+
agent --> models["Anthropic / OpenAI / Codex"]
|
|
69
|
+
agent --> mcp["MCP Servers"]
|
|
70
|
+
agent --> fs["~/.skimpyclaw"]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
See [docs/architecture.md](docs/architecture.md) for runtime flow and startup sequence diagrams.
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
**Install:**
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm install -g skimpyclaw
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Run onboarding:**
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
skimpyclaw onboard
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Onboarding validates your Telegram token, provider auth, and creates:
|
|
90
|
+
|
|
91
|
+
- `~/.skimpyclaw/config.json`
|
|
92
|
+
- `~/.skimpyclaw/agents/main/*.md` (from templates)
|
|
93
|
+
|
|
94
|
+
**Start:**
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
skimpyclaw start
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Verify:**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
curl http://127.0.0.1:18790/health
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Open dashboard:**
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
http://127.0.0.1:18790/dashboard
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Bearer token is shown in startup logs.
|
|
113
|
+
|
|
114
|
+
## Tech Stack
|
|
115
|
+
|
|
116
|
+
- **Backend:** TypeScript (ESM), Fastify, Vitest
|
|
117
|
+
- **Frontend:** Preact, Vite, TypeScript
|
|
118
|
+
- **Chat:** grammy (Telegram), discord.js (Discord)
|
|
119
|
+
- **Scheduling:** Croner
|
|
120
|
+
- **Browser:** Playwright
|
|
121
|
+
- **AI SDKs:** Anthropic SDK, OpenAI SDK
|
|
122
|
+
- **Observability:** Langfuse (optional)
|
|
123
|
+
|
|
124
|
+
## Project Structure
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
src/
|
|
128
|
+
index.ts # App entrypoint with logging setup
|
|
129
|
+
gateway.ts # Fastify server + top-level routes
|
|
130
|
+
agent.ts # Prompt assembly, model routing, tool loop, memory writes
|
|
131
|
+
tools.ts # Tool registry + dispatch
|
|
132
|
+
tools/ # Tool executors (bash, browser, file tools, path utils, execute context)
|
|
133
|
+
providers/ # Provider routing + provider implementations (anthropic/openai/codex)
|
|
134
|
+
code-agents/ # Background coding-agent runtime (executor/parser/orchestrator/registry)
|
|
135
|
+
channels/ # Channel adapters/utilities (telegram/discord)
|
|
136
|
+
subagent.ts # Background task dispatch: retry, concurrency, disk registry
|
|
137
|
+
file-lock.ts # In-memory file lock for concurrent subagent writes
|
|
138
|
+
audit.ts # Append-only audit log (trace/event model, JSONL storage)
|
|
139
|
+
cron.ts # Job scheduling + execution + cron logging
|
|
140
|
+
heartbeat.ts # Periodic health/attention checks
|
|
141
|
+
channels.ts # Active channel selection + proactive routing
|
|
142
|
+
telegram.ts # Telegram bot commands and message handling
|
|
143
|
+
discord.ts # Discord bot commands and message handling
|
|
144
|
+
voice.ts # Voice input/output (TTS/STT via providers)
|
|
145
|
+
digests.ts # Daily digest generation for cron job outputs
|
|
146
|
+
skills.ts # Skill loading, eligibility checks, and prompt injection
|
|
147
|
+
skills-types.ts # TypeScript types for skills system
|
|
148
|
+
exec-approval.ts # Human-in-the-loop exec approval flow with risk tiers
|
|
149
|
+
api.ts # Dashboard REST API under /api/dashboard/*
|
|
150
|
+
dashboard-frontend.ts # Dashboard static asset serving
|
|
151
|
+
security.ts # Auth, path validation, bash command blocklist, rate limiting
|
|
152
|
+
config.ts # Config loading and validation
|
|
153
|
+
types.ts # All TypeScript interfaces and types
|
|
154
|
+
setup.ts # Interactive setup wizard
|
|
155
|
+
langfuse.ts # Observability integration with cost tracking
|
|
156
|
+
usage.ts # Token usage tracking and aggregation
|
|
157
|
+
service.ts # Runtime service management
|
|
158
|
+
cli.ts # CLI command definitions
|
|
159
|
+
cache.ts # TTL cache utility
|
|
160
|
+
sessions.ts # Session persistence for chat history
|
|
161
|
+
doctor/ # Health check system
|
|
162
|
+
index.ts
|
|
163
|
+
checks.ts
|
|
164
|
+
formatters.ts
|
|
165
|
+
runner.ts
|
|
166
|
+
types.ts
|
|
167
|
+
|
|
168
|
+
web/dashboard/ # Preact/Vite dashboard frontend
|
|
169
|
+
src/
|
|
170
|
+
App.tsx
|
|
171
|
+
api/client.ts
|
|
172
|
+
components/
|
|
173
|
+
pages/ # Overview, Cron, Audit, Memory, Config, Skills, etc.
|
|
174
|
+
|
|
175
|
+
templates/ # Default template markdown files
|
|
176
|
+
SOUL.md
|
|
177
|
+
IDENTITY.md
|
|
178
|
+
USER.md
|
|
179
|
+
TOOLS.md
|
|
180
|
+
BOOT.md
|
|
181
|
+
HEARTBEAT.md
|
|
182
|
+
MEMORY.md
|
|
183
|
+
AGENTS.md
|
|
184
|
+
BOOTSTRAP.md
|
|
185
|
+
|
|
186
|
+
dist/ # Compiled output + built dashboard assets
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Documentation
|
|
190
|
+
|
|
191
|
+
| Doc | Contents |
|
|
192
|
+
| ---------------------------------------------- | ---------------------------------------------------------------- |
|
|
193
|
+
| [docs/architecture.md](docs/architecture.md) | Component diagram, runtime flow, startup sequence, source layout |
|
|
194
|
+
| [docs/configuration.md](docs/configuration.md) | Full config reference, all sections with examples |
|
|
195
|
+
| [docs/tools.md](docs/tools.md) | Built-in tools, browser tool, MCP integration, code agents |
|
|
196
|
+
| [docs/subagents.md](docs/subagents.md) | Subagent types, concurrency, file locking, flow diagram |
|
|
197
|
+
| [docs/dashboard.md](docs/dashboard.md) | Web dashboard, all HTTP endpoints + API routes |
|
|
198
|
+
| [docs/coding-agents.md](docs/coding-agents.md) | Coding-agent execution model and CLI backends |
|
|
199
|
+
| [docs/cli.md](docs/cli.md) | CLI commands, service management |
|
|
200
|
+
| [docs/chat-commands.md](docs/chat-commands.md) | Telegram/Discord bot commands |
|
|
201
|
+
| [docs/skills.md](docs/skills.md) | Skills system, built-in skills, creating custom skills |
|
|
202
|
+
| [docs/data-storage.md](docs/data-storage.md) | File layout, audit log format, security notes |
|
|
203
|
+
| [docs/setup-guide.md](docs/setup-guide.md) | Step-by-step installation and setup guide |
|
|
204
|
+
| [docs/troubleshooting.md](docs/troubleshooting.md) | Common issues and solutions |
|
|
205
|
+
|
|
206
|
+
## Development
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Install dependencies
|
|
210
|
+
pnpm install
|
|
211
|
+
|
|
212
|
+
# Run in development mode (hot reload)
|
|
213
|
+
pnpm dev
|
|
214
|
+
|
|
215
|
+
# Build TypeScript and dashboard
|
|
216
|
+
pnpm build
|
|
217
|
+
|
|
218
|
+
# Run tests
|
|
219
|
+
pnpm test
|
|
220
|
+
|
|
221
|
+
# Run full CI gate
|
|
222
|
+
pnpm ci
|
|
223
|
+
|
|
224
|
+
# Run doctor checks
|
|
225
|
+
pnpm run doctor
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { toOpenAITools, buildSystemParam, addToolCacheBreakpoint, setUsingOAuth } from '../agent.js';
|
|
3
|
+
describe('toOpenAITools', () => {
|
|
4
|
+
it('converts Anthropic tool format to OpenAI function format', () => {
|
|
5
|
+
const anthropicTools = [
|
|
6
|
+
{
|
|
7
|
+
name: 'Read',
|
|
8
|
+
description: 'Read a file',
|
|
9
|
+
input_schema: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
file_path: { type: 'string', description: 'Path to file' },
|
|
13
|
+
},
|
|
14
|
+
required: ['file_path'],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
const result = toOpenAITools(anthropicTools);
|
|
19
|
+
expect(result).toHaveLength(1);
|
|
20
|
+
expect(result[0]).toEqual({
|
|
21
|
+
type: 'function',
|
|
22
|
+
function: {
|
|
23
|
+
name: 'Read',
|
|
24
|
+
description: 'Read a file',
|
|
25
|
+
parameters: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
file_path: { type: 'string', description: 'Path to file' },
|
|
29
|
+
},
|
|
30
|
+
required: ['file_path'],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
it('converts multiple tools', () => {
|
|
36
|
+
const tools = [
|
|
37
|
+
{ name: 'Read', description: 'Read', input_schema: { type: 'object', properties: {} } },
|
|
38
|
+
{ name: 'Write', description: 'Write', input_schema: { type: 'object', properties: {} } },
|
|
39
|
+
{ name: 'Bash', description: 'Bash', input_schema: { type: 'object', properties: {} } },
|
|
40
|
+
];
|
|
41
|
+
const result = toOpenAITools(tools);
|
|
42
|
+
expect(result).toHaveLength(3);
|
|
43
|
+
expect(result.every((t) => t.type === 'function')).toBe(true);
|
|
44
|
+
expect(result.map((t) => t.function.name)).toEqual(['Read', 'Write', 'Bash']);
|
|
45
|
+
});
|
|
46
|
+
it('preserves input_schema as parameters unchanged', () => {
|
|
47
|
+
const schema = {
|
|
48
|
+
type: 'object',
|
|
49
|
+
properties: {
|
|
50
|
+
command: { type: 'string' },
|
|
51
|
+
cwd: { type: 'string' },
|
|
52
|
+
},
|
|
53
|
+
required: ['command'],
|
|
54
|
+
};
|
|
55
|
+
const result = toOpenAITools([{ name: 'Bash', description: 'Run command', input_schema: schema }]);
|
|
56
|
+
expect(result[0].function.parameters).toBe(schema); // same reference, not deep-copied
|
|
57
|
+
});
|
|
58
|
+
it('handles empty array', () => {
|
|
59
|
+
expect(toOpenAITools([])).toEqual([]);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe('buildSystemParam', () => {
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
setUsingOAuth(false);
|
|
65
|
+
});
|
|
66
|
+
it('returns undefined for empty content', () => {
|
|
67
|
+
expect(buildSystemParam(undefined)).toBeUndefined();
|
|
68
|
+
expect(buildSystemParam(undefined, true)).toBeUndefined();
|
|
69
|
+
});
|
|
70
|
+
it('returns plain string when caching disabled and not OAuth', () => {
|
|
71
|
+
const result = buildSystemParam('Hello system');
|
|
72
|
+
expect(result).toBe('Hello system');
|
|
73
|
+
});
|
|
74
|
+
it('returns plain string when caching explicitly disabled', () => {
|
|
75
|
+
const result = buildSystemParam('Hello system', false);
|
|
76
|
+
expect(result).toBe('Hello system');
|
|
77
|
+
});
|
|
78
|
+
it('returns array with cache_control when caching enabled (API key mode)', () => {
|
|
79
|
+
const result = buildSystemParam('Hello system', true);
|
|
80
|
+
expect(Array.isArray(result)).toBe(true);
|
|
81
|
+
expect(result).toHaveLength(1);
|
|
82
|
+
expect(result[0]).toEqual({
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: 'Hello system',
|
|
85
|
+
cache_control: { type: 'ephemeral' },
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
it('returns 3-block array with cache_control on last block (OAuth mode)', () => {
|
|
89
|
+
setUsingOAuth(true);
|
|
90
|
+
const result = buildSystemParam('My prompt', true);
|
|
91
|
+
expect(Array.isArray(result)).toBe(true);
|
|
92
|
+
expect(result).toHaveLength(3);
|
|
93
|
+
// First two blocks: no cache_control
|
|
94
|
+
expect(result[0].cache_control).toBeUndefined();
|
|
95
|
+
expect(result[1].cache_control).toBeUndefined();
|
|
96
|
+
// Last block: has cache_control
|
|
97
|
+
expect(result[2].cache_control).toEqual({ type: 'ephemeral' });
|
|
98
|
+
expect(result[2].text).toBe('My prompt');
|
|
99
|
+
});
|
|
100
|
+
it('returns 3-block array without cache_control when caching disabled (OAuth mode)', () => {
|
|
101
|
+
setUsingOAuth(true);
|
|
102
|
+
const result = buildSystemParam('My prompt', false);
|
|
103
|
+
expect(Array.isArray(result)).toBe(true);
|
|
104
|
+
expect(result).toHaveLength(3);
|
|
105
|
+
expect(result[0].cache_control).toBeUndefined();
|
|
106
|
+
expect(result[1].cache_control).toBeUndefined();
|
|
107
|
+
expect(result[2].cache_control).toBeUndefined();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('addToolCacheBreakpoint', () => {
|
|
111
|
+
it('adds cache_control to the last tool definition', () => {
|
|
112
|
+
const tools = [
|
|
113
|
+
{ name: 'Read', description: 'Read' },
|
|
114
|
+
{ name: 'Write', description: 'Write' },
|
|
115
|
+
{ name: 'Bash', description: 'Bash' },
|
|
116
|
+
];
|
|
117
|
+
addToolCacheBreakpoint(tools);
|
|
118
|
+
expect(tools[0].cache_control).toBeUndefined();
|
|
119
|
+
expect(tools[1].cache_control).toBeUndefined();
|
|
120
|
+
expect(tools[2].cache_control).toEqual({ type: 'ephemeral' });
|
|
121
|
+
});
|
|
122
|
+
it('handles single tool', () => {
|
|
123
|
+
const tools = [{ name: 'Read', description: 'Read' }];
|
|
124
|
+
addToolCacheBreakpoint(tools);
|
|
125
|
+
expect(tools[0].cache_control).toEqual({ type: 'ephemeral' });
|
|
126
|
+
});
|
|
127
|
+
it('handles empty array without error', () => {
|
|
128
|
+
const tools = [];
|
|
129
|
+
expect(() => addToolCacheBreakpoint(tools)).not.toThrow();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|