zubo 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/.github/workflows/ci.yml +35 -0
- package/README.md +149 -0
- package/bun.lock +216 -0
- package/desktop/README.md +57 -0
- package/desktop/package.json +12 -0
- package/desktop/src-tauri/Cargo.toml +25 -0
- package/desktop/src-tauri/build.rs +3 -0
- package/desktop/src-tauri/icons/README.md +17 -0
- package/desktop/src-tauri/icons/icon.png +0 -0
- package/desktop/src-tauri/src/main.rs +189 -0
- package/desktop/src-tauri/tauri.conf.json +68 -0
- package/docs/ROADMAP.md +490 -0
- package/migrations/001_init.sql +9 -0
- package/migrations/002_memory.sql +33 -0
- package/migrations/003_cron.sql +24 -0
- package/migrations/004_usage.sql +12 -0
- package/migrations/005_secrets.sql +8 -0
- package/migrations/006_agents.sql +1 -0
- package/migrations/007_workflows.sql +22 -0
- package/migrations/008_proactive.sql +24 -0
- package/migrations/009_uploads.sql +9 -0
- package/migrations/010_observability.sql +22 -0
- package/migrations/011_api_keys.sql +7 -0
- package/migrations/012_indexes.sql +5 -0
- package/migrations/013_budget.sql +11 -0
- package/migrations/014_usage_session_idx.sql +2 -0
- package/package.json +39 -0
- package/site/404.html +156 -0
- package/site/CNAME +1 -0
- package/site/docs/agents.html +294 -0
- package/site/docs/api.html +446 -0
- package/site/docs/channels.html +345 -0
- package/site/docs/cli.html +238 -0
- package/site/docs/config.html +1034 -0
- package/site/docs/index.html +433 -0
- package/site/docs/integrations.html +381 -0
- package/site/docs/memory.html +254 -0
- package/site/docs/security.html +375 -0
- package/site/docs/skills.html +322 -0
- package/site/docs.css +412 -0
- package/site/index.html +638 -0
- package/site/install.sh +98 -0
- package/site/logo.svg +1 -0
- package/site/og-image.png +0 -0
- package/site/robots.txt +4 -0
- package/site/script.js +361 -0
- package/site/sitemap.xml +63 -0
- package/site/skills.html +532 -0
- package/site/style.css +1686 -0
- package/src/agent/agents.ts +159 -0
- package/src/agent/compaction.ts +53 -0
- package/src/agent/context.ts +18 -0
- package/src/agent/delegate.ts +118 -0
- package/src/agent/loop.ts +318 -0
- package/src/agent/prompts.ts +111 -0
- package/src/agent/session.ts +87 -0
- package/src/agent/teams.ts +116 -0
- package/src/agent/workflow-executor.ts +192 -0
- package/src/agent/workflow.ts +175 -0
- package/src/channels/adapter.ts +21 -0
- package/src/channels/dashboard.html.ts +2969 -0
- package/src/channels/discord.ts +137 -0
- package/src/channels/optional-deps.d.ts +17 -0
- package/src/channels/router.ts +199 -0
- package/src/channels/signal.ts +133 -0
- package/src/channels/slack.ts +101 -0
- package/src/channels/telegram.ts +102 -0
- package/src/channels/utils.ts +18 -0
- package/src/channels/webchat.ts +1797 -0
- package/src/channels/whatsapp.ts +119 -0
- package/src/config/loader.ts +22 -0
- package/src/config/paths.ts +43 -0
- package/src/config/schema.ts +121 -0
- package/src/db/connection.ts +20 -0
- package/src/db/export.ts +148 -0
- package/src/db/migrations.ts +42 -0
- package/src/index.ts +261 -0
- package/src/llm/claude.ts +193 -0
- package/src/llm/factory.ts +115 -0
- package/src/llm/failover.ts +101 -0
- package/src/llm/openai-compat.ts +409 -0
- package/src/llm/provider.ts +83 -0
- package/src/llm/smart-router.ts +241 -0
- package/src/logs.ts +53 -0
- package/src/memory/chunker.ts +58 -0
- package/src/memory/document-parser.ts +115 -0
- package/src/memory/embedder.ts +235 -0
- package/src/memory/engine.ts +170 -0
- package/src/memory/fts-index.ts +55 -0
- package/src/memory/hybrid-search.ts +72 -0
- package/src/memory/store.ts +56 -0
- package/src/memory/vector-index.ts +72 -0
- package/src/model.ts +118 -0
- package/src/registry/cli.ts +43 -0
- package/src/registry/client.ts +54 -0
- package/src/registry/installer.ts +67 -0
- package/src/scheduler/briefing.ts +71 -0
- package/src/scheduler/cron.ts +258 -0
- package/src/scheduler/heartbeat.ts +58 -0
- package/src/scheduler/memory-triggers.ts +100 -0
- package/src/scheduler/natural-cron.ts +163 -0
- package/src/scheduler/proactive.ts +25 -0
- package/src/scheduler/recipes.ts +110 -0
- package/src/secrets/store.ts +64 -0
- package/src/setup.ts +413 -0
- package/src/skills.ts +293 -0
- package/src/start.ts +373 -0
- package/src/status.ts +165 -0
- package/src/tools/builtin/connect-service.ts +205 -0
- package/src/tools/builtin/cron.ts +126 -0
- package/src/tools/builtin/datetime.ts +36 -0
- package/src/tools/builtin/delegate-task.ts +81 -0
- package/src/tools/builtin/delegate.ts +42 -0
- package/src/tools/builtin/diagnose.ts +41 -0
- package/src/tools/builtin/google-oauth.ts +379 -0
- package/src/tools/builtin/manage-agents.ts +149 -0
- package/src/tools/builtin/manage-skills.ts +294 -0
- package/src/tools/builtin/manage-teams.ts +89 -0
- package/src/tools/builtin/manage-triggers.ts +94 -0
- package/src/tools/builtin/manage-workflows.ts +119 -0
- package/src/tools/builtin/memory-search.ts +38 -0
- package/src/tools/builtin/memory-write.ts +30 -0
- package/src/tools/builtin/run-workflow.ts +36 -0
- package/src/tools/builtin/secrets.ts +122 -0
- package/src/tools/builtin/skill-registry.ts +75 -0
- package/src/tools/builtin-integrations/api-helpers.ts +26 -0
- package/src/tools/builtin-integrations/github/github_issues/SKILL.md +56 -0
- package/src/tools/builtin-integrations/github/github_issues/handler.ts +108 -0
- package/src/tools/builtin-integrations/github/github_prs/SKILL.md +57 -0
- package/src/tools/builtin-integrations/github/github_prs/handler.ts +113 -0
- package/src/tools/builtin-integrations/github/github_repos/SKILL.md +37 -0
- package/src/tools/builtin-integrations/github/github_repos/handler.ts +88 -0
- package/src/tools/builtin-integrations/google/gmail/SKILL.md +51 -0
- package/src/tools/builtin-integrations/google/gmail/handler.ts +125 -0
- package/src/tools/builtin-integrations/google/google_calendar/SKILL.md +35 -0
- package/src/tools/builtin-integrations/google/google_calendar/handler.ts +105 -0
- package/src/tools/builtin-integrations/google/google_docs/SKILL.md +35 -0
- package/src/tools/builtin-integrations/google/google_docs/handler.ts +108 -0
- package/src/tools/builtin-integrations/google/google_drive/SKILL.md +39 -0
- package/src/tools/builtin-integrations/google/google_drive/handler.ts +106 -0
- package/src/tools/builtin-integrations/google/google_sheets/SKILL.md +36 -0
- package/src/tools/builtin-integrations/google/google_sheets/handler.ts +116 -0
- package/src/tools/builtin-integrations/jira/jira_boards/SKILL.md +21 -0
- package/src/tools/builtin-integrations/jira/jira_boards/handler.ts +74 -0
- package/src/tools/builtin-integrations/jira/jira_issues/SKILL.md +28 -0
- package/src/tools/builtin-integrations/jira/jira_issues/handler.ts +140 -0
- package/src/tools/builtin-integrations/linear/linear_issues/SKILL.md +30 -0
- package/src/tools/builtin-integrations/linear/linear_issues/handler.ts +75 -0
- package/src/tools/builtin-integrations/linear/linear_projects/SKILL.md +21 -0
- package/src/tools/builtin-integrations/linear/linear_projects/handler.ts +43 -0
- package/src/tools/builtin-integrations/notion/notion_databases/SKILL.md +39 -0
- package/src/tools/builtin-integrations/notion/notion_databases/handler.ts +83 -0
- package/src/tools/builtin-integrations/notion/notion_pages/SKILL.md +43 -0
- package/src/tools/builtin-integrations/notion/notion_pages/handler.ts +130 -0
- package/src/tools/builtin-integrations/notion/notion_search/SKILL.md +27 -0
- package/src/tools/builtin-integrations/notion/notion_search/handler.ts +69 -0
- package/src/tools/builtin-integrations/slack/slack_messages/SKILL.md +42 -0
- package/src/tools/builtin-integrations/slack/slack_messages/handler.ts +72 -0
- package/src/tools/builtin-integrations/twitter/twitter_posts/SKILL.md +24 -0
- package/src/tools/builtin-integrations/twitter/twitter_posts/handler.ts +133 -0
- package/src/tools/builtin-skills/file-read/SKILL.md +26 -0
- package/src/tools/builtin-skills/file-read/handler.ts +66 -0
- package/src/tools/builtin-skills/file-write/SKILL.md +30 -0
- package/src/tools/builtin-skills/file-write/handler.ts +64 -0
- package/src/tools/builtin-skills/http-request/SKILL.md +34 -0
- package/src/tools/builtin-skills/http-request/handler.ts +87 -0
- package/src/tools/builtin-skills/shell/SKILL.md +26 -0
- package/src/tools/builtin-skills/shell/handler.ts +96 -0
- package/src/tools/builtin-skills/url-fetch/SKILL.md +26 -0
- package/src/tools/builtin-skills/url-fetch/handler.ts +37 -0
- package/src/tools/builtin-skills/web-search/SKILL.md +26 -0
- package/src/tools/builtin-skills/web-search/handler.ts +50 -0
- package/src/tools/executor.ts +205 -0
- package/src/tools/integration-installer.ts +106 -0
- package/src/tools/permissions.ts +45 -0
- package/src/tools/registry.ts +39 -0
- package/src/tools/sandbox-runner.ts +56 -0
- package/src/tools/sandbox.ts +82 -0
- package/src/tools/skill-installer.ts +52 -0
- package/src/tools/skill-loader.ts +259 -0
- package/src/types/optional-deps.d.ts +23 -0
- package/src/util/auth.ts +121 -0
- package/src/util/costs.ts +59 -0
- package/src/util/error-buffer.ts +32 -0
- package/src/util/google-tokens.ts +180 -0
- package/src/util/logger.ts +73 -0
- package/src/util/perf-collector.ts +35 -0
- package/src/util/rate-limiter.ts +70 -0
- package/src/util/tokens.ts +17 -0
- package/src/voice/stt.ts +57 -0
- package/src/voice/tts.ts +103 -0
- package/tests/agent/session.test.ts +109 -0
- package/tests/agent-loop.test.ts +54 -0
- package/tests/auth.test.ts +89 -0
- package/tests/channels.test.ts +67 -0
- package/tests/compaction.test.ts +44 -0
- package/tests/config.test.ts +51 -0
- package/tests/costs.test.ts +19 -0
- package/tests/cron.test.ts +55 -0
- package/tests/db/export.test.ts +219 -0
- package/tests/executor.test.ts +144 -0
- package/tests/export.test.ts +137 -0
- package/tests/helpers/mock-llm.ts +34 -0
- package/tests/helpers/test-db.ts +74 -0
- package/tests/integration/chat-flow.test.ts +48 -0
- package/tests/integrations.test.ts +97 -0
- package/tests/memory/engine.test.ts +114 -0
- package/tests/memory-engine.test.ts +57 -0
- package/tests/permissions.test.ts +21 -0
- package/tests/rate-limiter.test.ts +70 -0
- package/tests/registry.test.ts +67 -0
- package/tests/router.test.ts +36 -0
- package/tests/session.test.ts +58 -0
- package/tests/skill-loader.test.ts +44 -0
- package/tests/tokens.test.ts +30 -0
- package/tests/tools/executor.test.ts +130 -0
- package/tests/util/auth.test.ts +75 -0
- package/tests/util/rate-limiter.test.ts +73 -0
- package/tests/voice.test.ts +60 -0
- package/tests/webchat.test.ts +88 -0
- package/tests/workflow.test.ts +38 -0
- package/tsconfig.json +16 -0
package/docs/ROADMAP.md
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
# Zubo Roadmap
|
|
2
|
+
|
|
3
|
+
> What makes OpenClaw a 145k-star project: multi-LLM with failover, 14+ channels
|
|
4
|
+
> through one agent, a skills ecosystem, local-first gateway, and progressive
|
|
5
|
+
> onboarding. Zubo takes the same ideas but stays lean — no gateway daemon,
|
|
6
|
+
> no monorepo, just a single Bun process you can run anywhere.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Phase 1 — Multi-LLM Provider System
|
|
11
|
+
|
|
12
|
+
**Goal:** Use any LLM — Claude, GPT, Ollama, LM Studio, Groq, Together — through
|
|
13
|
+
one config. Swap models without touching code.
|
|
14
|
+
|
|
15
|
+
### 1.1 OpenAI-Compatible Provider
|
|
16
|
+
|
|
17
|
+
The OpenAI chat completions API is the lingua franca. Ollama, LM Studio, Together,
|
|
18
|
+
Groq, and OpenRouter all expose it. One provider covers them all.
|
|
19
|
+
|
|
20
|
+
**Files:**
|
|
21
|
+
|
|
22
|
+
| File | Action |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `src/llm/provider.ts` | Add `providerName` field to interface |
|
|
25
|
+
| `src/llm/openai-compat.ts` | **New.** OpenAI-compatible provider (no SDK — raw `fetch`) |
|
|
26
|
+
| `src/llm/claude.ts` | Add `providerName = "anthropic"` |
|
|
27
|
+
|
|
28
|
+
**`src/llm/openai-compat.ts` design:**
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
export class OpenAICompatProvider implements LlmProvider {
|
|
32
|
+
providerName: string;
|
|
33
|
+
|
|
34
|
+
constructor(opts: {
|
|
35
|
+
name: string; // "openai" | "ollama" | "groq" | "lmstudio" | ...
|
|
36
|
+
baseUrl: string; // "https://api.openai.com/v1" or "http://localhost:11434/v1"
|
|
37
|
+
apiKey: string; // or "ollama" for local
|
|
38
|
+
model: string; // "gpt-4o" | "llama3.3" | "qwen2.5-coder:32b"
|
|
39
|
+
maxTokens?: number;
|
|
40
|
+
streaming?: boolean; // default true, false for Ollama tool-use bug
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
async chat(request: LlmRequest): Promise<LlmResponse> {
|
|
44
|
+
// POST /chat/completions
|
|
45
|
+
// Map LlmToolDef[] → OpenAI function format
|
|
46
|
+
// Map response → LlmResponse (text + tool_use blocks)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Why raw fetch instead of the OpenAI SDK:** Fewer deps, works with every
|
|
52
|
+
OpenAI-compatible endpoint, and we control retry/timeout behavior.
|
|
53
|
+
|
|
54
|
+
### 1.2 Provider Factory + Config
|
|
55
|
+
|
|
56
|
+
Decide which provider to instantiate from config alone.
|
|
57
|
+
|
|
58
|
+
**Files:**
|
|
59
|
+
|
|
60
|
+
| File | Action |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `src/config/schema.ts` | New `providers` + `activeModel` fields |
|
|
63
|
+
| `src/llm/factory.ts` | **New.** `createProvider(config) → LlmProvider` |
|
|
64
|
+
| `src/start.ts` | Use factory instead of hardcoded `new ClaudeProvider()` |
|
|
65
|
+
| `src/setup.ts` | Ask which provider during setup |
|
|
66
|
+
|
|
67
|
+
**Config shape:**
|
|
68
|
+
|
|
69
|
+
```jsonc
|
|
70
|
+
{
|
|
71
|
+
// ... existing fields ...
|
|
72
|
+
|
|
73
|
+
"providers": {
|
|
74
|
+
"anthropic": {
|
|
75
|
+
"apiKey": "sk-ant-...",
|
|
76
|
+
"model": "claude-sonnet-4-5-20250929"
|
|
77
|
+
},
|
|
78
|
+
"openai": {
|
|
79
|
+
"apiKey": "sk-...",
|
|
80
|
+
"baseUrl": "https://api.openai.com/v1",
|
|
81
|
+
"model": "gpt-4o"
|
|
82
|
+
},
|
|
83
|
+
"ollama": {
|
|
84
|
+
"baseUrl": "http://localhost:11434/v1",
|
|
85
|
+
"apiKey": "ollama",
|
|
86
|
+
"model": "qwen2.5-coder:32b",
|
|
87
|
+
"streaming": false
|
|
88
|
+
},
|
|
89
|
+
"groq": {
|
|
90
|
+
"apiKey": "gsk_...",
|
|
91
|
+
"baseUrl": "https://api.groq.com/openai/v1",
|
|
92
|
+
"model": "llama-3.3-70b-versatile"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
"activeProvider": "anthropic",
|
|
97
|
+
|
|
98
|
+
"failover": ["openai", "ollama"] // optional fallback chain
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**`src/llm/factory.ts` logic:**
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
1. Look up config.providers[config.activeProvider]
|
|
106
|
+
2. If provider name is "anthropic" → new ClaudeProvider(...)
|
|
107
|
+
3. Anything else → new OpenAICompatProvider({ name, baseUrl, apiKey, model })
|
|
108
|
+
4. Wrap in FailoverProvider if config.failover exists
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 1.3 Failover Wrapper
|
|
112
|
+
|
|
113
|
+
**File:** `src/llm/failover.ts` (new)
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
export class FailoverProvider implements LlmProvider {
|
|
117
|
+
constructor(
|
|
118
|
+
private primary: LlmProvider,
|
|
119
|
+
private fallbacks: LlmProvider[],
|
|
120
|
+
) {}
|
|
121
|
+
|
|
122
|
+
async chat(request: LlmRequest): Promise<LlmResponse> {
|
|
123
|
+
try {
|
|
124
|
+
return await this.primary.chat(request);
|
|
125
|
+
} catch (err) {
|
|
126
|
+
logger.warn(`Primary provider failed, trying fallback`, { error: err.message });
|
|
127
|
+
for (const fb of this.fallbacks) {
|
|
128
|
+
try { return await fb.chat(request); } catch {}
|
|
129
|
+
}
|
|
130
|
+
throw err; // all failed
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 1.4 Ollama Auto-Discovery (optional, nice-to-have)
|
|
137
|
+
|
|
138
|
+
**File:** `src/llm/ollama-discover.ts` (new)
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
GET http://localhost:11434/api/tags → list models
|
|
142
|
+
GET http://localhost:11434/api/show { name } → check tool support
|
|
143
|
+
Auto-populate config.providers.ollama.model with best available
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Run during `bun run setup` if user picks Ollama — show available models and let
|
|
147
|
+
them choose.
|
|
148
|
+
|
|
149
|
+
### 1.5 `bun run model` CLI command
|
|
150
|
+
|
|
151
|
+
Quick model switching without editing config.json:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
bun run model # show current model
|
|
155
|
+
bun run model ollama/llama3.3 # switch active provider+model
|
|
156
|
+
bun run model --list # list configured providers
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**File:** `src/model.ts` (new) + wire in `index.ts`
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Phase 2 — More Channels
|
|
164
|
+
|
|
165
|
+
**Goal:** Same agent on WhatsApp, Discord, and a local web UI. One memory,
|
|
166
|
+
one personality, many surfaces.
|
|
167
|
+
|
|
168
|
+
### 2.1 Channel Architecture Refinement
|
|
169
|
+
|
|
170
|
+
Current `ChannelAdapter` interface is already clean. We add:
|
|
171
|
+
|
|
172
|
+
**Files:**
|
|
173
|
+
|
|
174
|
+
| File | Action |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `src/channels/adapter.ts` | Add `channelName`, `isGroup` to InboundMessage |
|
|
177
|
+
| `src/config/schema.ts` | Per-channel config section |
|
|
178
|
+
|
|
179
|
+
### 2.2 Discord Channel
|
|
180
|
+
|
|
181
|
+
**Dep:** `discord.js` or lighter `@discordjs/rest` + gateway
|
|
182
|
+
|
|
183
|
+
**File:** `src/channels/discord.ts` (new)
|
|
184
|
+
|
|
185
|
+
- Bot token from config
|
|
186
|
+
- Listen for mentions + DMs
|
|
187
|
+
- Group mode: only respond when @mentioned
|
|
188
|
+
- Message splitting for 2000-char limit
|
|
189
|
+
|
|
190
|
+
### 2.3 WhatsApp via Baileys
|
|
191
|
+
|
|
192
|
+
**Dep:** `@whiskeysockets/baileys` (no official API needed)
|
|
193
|
+
|
|
194
|
+
**File:** `src/channels/whatsapp.ts` (new)
|
|
195
|
+
|
|
196
|
+
- QR code pairing during setup
|
|
197
|
+
- Store auth state in `~/.zubo/channels/whatsapp/`
|
|
198
|
+
- Handle text messages, ignore media for now
|
|
199
|
+
|
|
200
|
+
### 2.4 WebChat (local HTTP UI)
|
|
201
|
+
|
|
202
|
+
**No deps.** Bun's built-in HTTP server + a single HTML file.
|
|
203
|
+
|
|
204
|
+
**Files:**
|
|
205
|
+
- `src/channels/webchat.ts` — HTTP server + SSE for streaming
|
|
206
|
+
- `src/channels/webchat.html` — Minimal chat UI (inline, no build step)
|
|
207
|
+
|
|
208
|
+
Serves on `http://localhost:3000`. Good for testing without Telegram.
|
|
209
|
+
|
|
210
|
+
### 2.5 Channel Router Improvements
|
|
211
|
+
|
|
212
|
+
**File:** `src/channels/router.ts`
|
|
213
|
+
|
|
214
|
+
- Register multiple adapters (not just one)
|
|
215
|
+
- Route replies to correct channel by `sessionKey` prefix
|
|
216
|
+
- Cross-channel session access (read Telegram history from WebChat)
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Phase 3 — Skills / Plugin System
|
|
221
|
+
|
|
222
|
+
**Goal:** Let users drop a folder into `~/.zubo/workspace/skills/` and the agent
|
|
223
|
+
gains new abilities. No code changes, no restart.
|
|
224
|
+
|
|
225
|
+
### 3.1 Skill Format
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
~/.zubo/workspace/skills/
|
|
229
|
+
web-search/
|
|
230
|
+
SKILL.md # Description, when to use, tool schema
|
|
231
|
+
handler.ts # Bun-loadable module exporting tool handler
|
|
232
|
+
weather/
|
|
233
|
+
SKILL.md
|
|
234
|
+
handler.ts
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**SKILL.md example:**
|
|
238
|
+
|
|
239
|
+
```markdown
|
|
240
|
+
# Web Search
|
|
241
|
+
|
|
242
|
+
Search the web for current information.
|
|
243
|
+
|
|
244
|
+
## Tool: web_search
|
|
245
|
+
- query (string, required): Search query
|
|
246
|
+
|
|
247
|
+
## When to use
|
|
248
|
+
When the user asks about current events, prices, news, or anything
|
|
249
|
+
that requires up-to-date information beyond your training data.
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**handler.ts contract:**
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
export default async function(input: Record<string, unknown>): Promise<string> {
|
|
256
|
+
const { query } = input as { query: string };
|
|
257
|
+
// ... do the thing ...
|
|
258
|
+
return JSON.stringify(results);
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### 3.2 Skill Loader
|
|
263
|
+
|
|
264
|
+
**File:** `src/tools/skill-loader.ts` (new)
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
1. Scan ~/.zubo/workspace/skills/*/
|
|
268
|
+
2. Parse each SKILL.md for tool name + schema + description
|
|
269
|
+
3. Dynamic import() each handler.ts
|
|
270
|
+
4. Register via existing registerTool()
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Called at startup. Hot-reload on file change is a future nice-to-have.
|
|
274
|
+
|
|
275
|
+
### 3.3 Built-in Skills to Ship
|
|
276
|
+
|
|
277
|
+
| Skill | What it does |
|
|
278
|
+
|---|---|
|
|
279
|
+
| `web-search` | DuckDuckGo/Brave Search API |
|
|
280
|
+
| `url-fetch` | Fetch URL, convert to markdown, summarize |
|
|
281
|
+
| `shell` | Run shell command (with confirmation) |
|
|
282
|
+
| `file-read` | Read file from disk |
|
|
283
|
+
| `file-write` | Write file to disk |
|
|
284
|
+
| `http-request` | Generic HTTP request (GET/POST) |
|
|
285
|
+
|
|
286
|
+
These live in `src/tools/builtin/` but follow the same SKILL.md pattern
|
|
287
|
+
so users can override them.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Phase 4 — Agent Improvements
|
|
292
|
+
|
|
293
|
+
**Goal:** Smarter agent loop — thinking, streaming, multi-agent delegation.
|
|
294
|
+
|
|
295
|
+
### 4.1 Streaming Responses
|
|
296
|
+
|
|
297
|
+
Stream tokens to the channel as they arrive instead of waiting for completion.
|
|
298
|
+
|
|
299
|
+
**Files:**
|
|
300
|
+
- `src/llm/provider.ts` — Add `chatStream()` returning `AsyncIterable<LlmChunk>`
|
|
301
|
+
- `src/llm/claude.ts` — Implement streaming via Anthropic SDK
|
|
302
|
+
- `src/llm/openai-compat.ts` — Implement SSE parsing
|
|
303
|
+
- `src/agent/loop.ts` — Stream-aware loop
|
|
304
|
+
- `src/channels/telegram.ts` — Edit message in-place as tokens arrive
|
|
305
|
+
|
|
306
|
+
### 4.2 Extended Thinking / Reasoning
|
|
307
|
+
|
|
308
|
+
For models that support it (Claude with extended thinking, DeepSeek-R1, QwQ):
|
|
309
|
+
|
|
310
|
+
- Detect `thinking` blocks in response
|
|
311
|
+
- Don't send thinking to user (unless asked)
|
|
312
|
+
- Use thinking for better tool-use decisions
|
|
313
|
+
- Config toggle: `thinking: true/false` per provider
|
|
314
|
+
|
|
315
|
+
### 4.3 Cost + Token Tracking
|
|
316
|
+
|
|
317
|
+
**File:** `src/agent/usage.ts` (new)
|
|
318
|
+
|
|
319
|
+
- Track per-message input/output tokens
|
|
320
|
+
- Track per-session cumulative cost
|
|
321
|
+
- Store in DB (new `usage` table)
|
|
322
|
+
- Surface in `bun run status`
|
|
323
|
+
|
|
324
|
+
```sql
|
|
325
|
+
CREATE TABLE usage (
|
|
326
|
+
id INTEGER PRIMARY KEY,
|
|
327
|
+
session_key TEXT,
|
|
328
|
+
provider TEXT,
|
|
329
|
+
model TEXT,
|
|
330
|
+
input_tokens INTEGER,
|
|
331
|
+
output_tokens INTEGER,
|
|
332
|
+
cost_usd REAL,
|
|
333
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
334
|
+
);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 4.4 Context Window Awareness
|
|
338
|
+
|
|
339
|
+
Different models have different context windows. Compaction should respect this.
|
|
340
|
+
|
|
341
|
+
**File:** `src/agent/compaction.ts`
|
|
342
|
+
|
|
343
|
+
- Provider reports `contextWindow` size
|
|
344
|
+
- Compaction targets 66% of that (not hardcoded 100k)
|
|
345
|
+
- Small local models (8k context) get aggressive compaction
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Phase 5 — Proactive Agent + Automation
|
|
350
|
+
|
|
351
|
+
**Goal:** Zubo doesn't just respond — it acts on its own.
|
|
352
|
+
|
|
353
|
+
### 5.1 Webhook Inbound
|
|
354
|
+
|
|
355
|
+
**File:** `src/scheduler/webhooks.ts` (new)
|
|
356
|
+
|
|
357
|
+
- Bun HTTP server on configurable port
|
|
358
|
+
- Routes like `POST /webhook/:name` → trigger agent with payload
|
|
359
|
+
- Use case: GitHub push → Zubo summarizes commit
|
|
360
|
+
- Use case: IFTTT/Zapier integration
|
|
361
|
+
|
|
362
|
+
### 5.2 Agent-Managed Cron
|
|
363
|
+
|
|
364
|
+
Let the agent create/edit/delete cron jobs via tools (not just DB):
|
|
365
|
+
|
|
366
|
+
**New tools:**
|
|
367
|
+
- `cron_create` — Create a scheduled task
|
|
368
|
+
- `cron_list` — List all cron jobs
|
|
369
|
+
- `cron_delete` — Remove a job
|
|
370
|
+
|
|
371
|
+
Now the user can say "remind me every Monday at 9am to review PRs" and the
|
|
372
|
+
agent handles it end-to-end.
|
|
373
|
+
|
|
374
|
+
### 5.3 Daily Digest
|
|
375
|
+
|
|
376
|
+
A built-in cron job (opt-in) that:
|
|
377
|
+
|
|
378
|
+
1. Reads recent memories from the past 24h
|
|
379
|
+
2. Checks calendar/weather (if skills installed)
|
|
380
|
+
3. Composes a morning briefing
|
|
381
|
+
4. Sends to user's primary channel
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Phase 6 — Security + Permissions
|
|
386
|
+
|
|
387
|
+
### 6.1 Tool Approval
|
|
388
|
+
|
|
389
|
+
Some tools are dangerous (shell, file-write). Before executing:
|
|
390
|
+
|
|
391
|
+
```
|
|
392
|
+
Agent wants to run: shell("rm -rf /tmp/old-data")
|
|
393
|
+
[Approve] [Deny] [Always allow shell]
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**File:** `src/tools/permissions.ts` (new)
|
|
397
|
+
|
|
398
|
+
- Permission levels: `auto` (memory_search), `confirm` (shell), `deny`
|
|
399
|
+
- Per-tool config in `~/.zubo/workspace/PERMISSIONS.md` or config.json
|
|
400
|
+
- Channel adapters render approval buttons (Telegram inline keyboard)
|
|
401
|
+
|
|
402
|
+
### 6.2 Message Pairing / Auth
|
|
403
|
+
|
|
404
|
+
For channels where anyone can message the bot:
|
|
405
|
+
|
|
406
|
+
- First message from unknown user → pairing code
|
|
407
|
+
- User must confirm in a trusted channel (or CLI)
|
|
408
|
+
- Prevents prompt injection from strangers
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Phase 7 — Companion Interfaces
|
|
413
|
+
|
|
414
|
+
### 7.1 TUI (Terminal UI)
|
|
415
|
+
|
|
416
|
+
**File:** `src/channels/tui.ts` (new)
|
|
417
|
+
|
|
418
|
+
Interactive terminal chat using Bun's readline or `ink`:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
bun run chat
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
Full chat experience without any external service. Best for testing and
|
|
425
|
+
local-only use. Essential for Ollama-only setups where you don't need Telegram.
|
|
426
|
+
|
|
427
|
+
### 7.2 Web Dashboard
|
|
428
|
+
|
|
429
|
+
**Files:**
|
|
430
|
+
- `src/dashboard/server.ts` — Bun HTTP server
|
|
431
|
+
- `src/dashboard/index.html` — Single-page app
|
|
432
|
+
|
|
433
|
+
Shows:
|
|
434
|
+
- Live conversation view
|
|
435
|
+
- Memory browser (search + edit)
|
|
436
|
+
- Cron job management
|
|
437
|
+
- Provider/model status
|
|
438
|
+
- Usage/cost charts
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Implementation Priority
|
|
443
|
+
|
|
444
|
+
What to build first, based on impact vs. effort:
|
|
445
|
+
|
|
446
|
+
```
|
|
447
|
+
HIGH IMPACT, LOW EFFORT (do first)
|
|
448
|
+
├── Phase 1.1 OpenAI-compatible provider ★★★★★
|
|
449
|
+
├── Phase 1.2 Provider factory + config ★★★★★
|
|
450
|
+
├── Phase 1.5 `bun run model` command ★★★★
|
|
451
|
+
├── Phase 7.1 TUI / `bun run chat` ★★★★
|
|
452
|
+
├── Phase 4.3 Cost + token tracking ★★★★
|
|
453
|
+
└── Phase 5.2 Agent-managed cron tools ★★★★
|
|
454
|
+
|
|
455
|
+
HIGH IMPACT, MEDIUM EFFORT (do second)
|
|
456
|
+
├── Phase 1.3 Failover wrapper ★★★★
|
|
457
|
+
├── Phase 3.1 Skill format + loader ★★★★
|
|
458
|
+
├── Phase 3.3 web-search + url-fetch skills ★★★★
|
|
459
|
+
├── Phase 2.4 WebChat (local HTTP UI) ★★★★
|
|
460
|
+
├── Phase 4.1 Streaming responses ★★★
|
|
461
|
+
└── Phase 4.4 Context window awareness ★★★
|
|
462
|
+
|
|
463
|
+
MEDIUM IMPACT, MEDIUM EFFORT (do third)
|
|
464
|
+
├── Phase 2.2 Discord channel ★★★
|
|
465
|
+
├── Phase 2.3 WhatsApp channel ★★★
|
|
466
|
+
├── Phase 5.1 Webhook inbound ★★★
|
|
467
|
+
├── Phase 6.1 Tool approval / permissions ★★★
|
|
468
|
+
└── Phase 5.3 Daily digest ★★★
|
|
469
|
+
|
|
470
|
+
NICE TO HAVE (do when stable)
|
|
471
|
+
├── Phase 1.4 Ollama auto-discovery ★★
|
|
472
|
+
├── Phase 4.2 Extended thinking ★★
|
|
473
|
+
├── Phase 6.2 Message pairing / auth ★★
|
|
474
|
+
└── Phase 7.2 Web dashboard ★★
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Next Concrete Step
|
|
480
|
+
|
|
481
|
+
**Phase 1.1 + 1.2**: Multi-LLM support. One session of work:
|
|
482
|
+
|
|
483
|
+
1. Create `src/llm/openai-compat.ts` — OpenAI-compatible provider
|
|
484
|
+
2. Create `src/llm/factory.ts` — Provider factory
|
|
485
|
+
3. Update `src/config/schema.ts` — New provider config fields
|
|
486
|
+
4. Update `src/start.ts` — Use factory
|
|
487
|
+
5. Update `src/setup.ts` — Provider selection in wizard
|
|
488
|
+
6. Test with Ollama locally
|
|
489
|
+
|
|
490
|
+
This single change makes Zubo usable with any model, which unlocks everything else.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
channel TEXT NOT NULL,
|
|
4
|
+
user_id TEXT NOT NULL,
|
|
5
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
6
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS memory_chunks (
|
|
2
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
source_file TEXT NOT NULL,
|
|
4
|
+
chunk_index INTEGER NOT NULL,
|
|
5
|
+
content TEXT NOT NULL,
|
|
6
|
+
embedding BLOB,
|
|
7
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
8
|
+
UNIQUE(source_file, chunk_index)
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
|
|
12
|
+
content,
|
|
13
|
+
source_file,
|
|
14
|
+
content='memory_chunks',
|
|
15
|
+
content_rowid='id'
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
CREATE TRIGGER IF NOT EXISTS memory_chunks_ai AFTER INSERT ON memory_chunks BEGIN
|
|
19
|
+
INSERT INTO memory_fts(rowid, content, source_file)
|
|
20
|
+
VALUES (new.id, new.content, new.source_file);
|
|
21
|
+
END;
|
|
22
|
+
|
|
23
|
+
CREATE TRIGGER IF NOT EXISTS memory_chunks_ad AFTER DELETE ON memory_chunks BEGIN
|
|
24
|
+
INSERT INTO memory_fts(memory_fts, rowid, content, source_file)
|
|
25
|
+
VALUES ('delete', old.id, old.content, old.source_file);
|
|
26
|
+
END;
|
|
27
|
+
|
|
28
|
+
CREATE TRIGGER IF NOT EXISTS memory_chunks_au AFTER UPDATE ON memory_chunks BEGIN
|
|
29
|
+
INSERT INTO memory_fts(memory_fts, rowid, content, source_file)
|
|
30
|
+
VALUES ('delete', old.id, old.content, old.source_file);
|
|
31
|
+
INSERT INTO memory_fts(rowid, content, source_file)
|
|
32
|
+
VALUES (new.id, new.content, new.source_file);
|
|
33
|
+
END;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS cron_jobs (
|
|
2
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
name TEXT NOT NULL UNIQUE,
|
|
4
|
+
schedule TEXT NOT NULL,
|
|
5
|
+
task TEXT NOT NULL,
|
|
6
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
7
|
+
last_run TEXT,
|
|
8
|
+
next_run TEXT,
|
|
9
|
+
retry_count INTEGER NOT NULL DEFAULT 0,
|
|
10
|
+
max_retries INTEGER NOT NULL DEFAULT 3,
|
|
11
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS cron_logs (
|
|
15
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
|
+
job_id INTEGER NOT NULL REFERENCES cron_jobs(id),
|
|
17
|
+
status TEXT NOT NULL,
|
|
18
|
+
output TEXT,
|
|
19
|
+
error TEXT,
|
|
20
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
21
|
+
finished_at TEXT
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_cron_logs_job ON cron_logs(job_id);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS usage (
|
|
2
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
session_id TEXT,
|
|
4
|
+
provider TEXT NOT NULL,
|
|
5
|
+
model TEXT NOT NULL,
|
|
6
|
+
input_tokens INTEGER NOT NULL DEFAULT 0,
|
|
7
|
+
output_tokens INTEGER NOT NULL DEFAULT 0,
|
|
8
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
CREATE INDEX IF NOT EXISTS idx_usage_provider ON usage(provider);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_usage_created ON usage(created_at);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ALTER TABLE cron_jobs ADD COLUMN agent TEXT;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS workflow_executions (
|
|
2
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
workflow_name TEXT NOT NULL,
|
|
4
|
+
input TEXT,
|
|
5
|
+
status TEXT NOT NULL DEFAULT 'running',
|
|
6
|
+
result TEXT,
|
|
7
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
8
|
+
completed_at TEXT
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
CREATE TABLE IF NOT EXISTS workflow_step_logs (
|
|
12
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
13
|
+
execution_id INTEGER NOT NULL REFERENCES workflow_executions(id),
|
|
14
|
+
step_name TEXT NOT NULL,
|
|
15
|
+
agent_name TEXT NOT NULL,
|
|
16
|
+
task TEXT NOT NULL,
|
|
17
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
18
|
+
output TEXT,
|
|
19
|
+
started_at TEXT,
|
|
20
|
+
completed_at TEXT,
|
|
21
|
+
duration_ms INTEGER
|
|
22
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS memory_triggers (
|
|
2
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
pattern TEXT NOT NULL,
|
|
4
|
+
action TEXT NOT NULL,
|
|
5
|
+
schedule TEXT NOT NULL DEFAULT 'once',
|
|
6
|
+
last_fired TEXT,
|
|
7
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
8
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
CREATE TABLE IF NOT EXISTS user_preferences (
|
|
12
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
13
|
+
key TEXT NOT NULL UNIQUE,
|
|
14
|
+
value TEXT NOT NULL,
|
|
15
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
CREATE TABLE IF NOT EXISTS proactive_log (
|
|
19
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
20
|
+
type TEXT NOT NULL,
|
|
21
|
+
message TEXT NOT NULL,
|
|
22
|
+
channel TEXT,
|
|
23
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
24
|
+
);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS uploads (
|
|
2
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
3
|
+
filename TEXT NOT NULL,
|
|
4
|
+
original_name TEXT NOT NULL,
|
|
5
|
+
mime_type TEXT NOT NULL,
|
|
6
|
+
size_bytes INTEGER NOT NULL,
|
|
7
|
+
chunk_count INTEGER NOT NULL DEFAULT 0,
|
|
8
|
+
uploaded_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
9
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-- Enhance usage table with response time and cost
|
|
2
|
+
ALTER TABLE usage ADD COLUMN response_time_ms INTEGER;
|
|
3
|
+
ALTER TABLE usage ADD COLUMN cost_usd REAL;
|
|
4
|
+
|
|
5
|
+
-- Tool execution metrics
|
|
6
|
+
CREATE TABLE IF NOT EXISTS tool_metrics (
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
+
tool_name TEXT NOT NULL,
|
|
9
|
+
session_id TEXT,
|
|
10
|
+
duration_ms INTEGER NOT NULL,
|
|
11
|
+
success INTEGER NOT NULL DEFAULT 1,
|
|
12
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
-- Performance snapshots
|
|
16
|
+
CREATE TABLE IF NOT EXISTS perf_snapshots (
|
|
17
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
18
|
+
rss_mb REAL,
|
|
19
|
+
heap_mb REAL,
|
|
20
|
+
db_size_mb REAL,
|
|
21
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
22
|
+
);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
-- Performance indexes for dashboard analytics queries
|
|
2
|
+
CREATE INDEX IF NOT EXISTS idx_usage_provider_model ON usage(provider, model);
|
|
3
|
+
CREATE INDEX IF NOT EXISTS idx_tool_metrics_name ON tool_metrics(tool_name);
|
|
4
|
+
CREATE INDEX IF NOT EXISTS idx_tool_metrics_created ON tool_metrics(created_at);
|
|
5
|
+
CREATE INDEX IF NOT EXISTS idx_memory_chunks_source ON memory_chunks(source_file);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- Budget configuration
|
|
2
|
+
CREATE TABLE IF NOT EXISTS budget_config (
|
|
3
|
+
id INTEGER PRIMARY KEY CHECK (id = 1), -- singleton row
|
|
4
|
+
daily_limit_usd REAL,
|
|
5
|
+
monthly_limit_usd REAL,
|
|
6
|
+
alert_threshold REAL DEFAULT 0.8, -- alert at 80% of budget
|
|
7
|
+
paused INTEGER NOT NULL DEFAULT 0, -- 1 = budget exceeded, agent paused
|
|
8
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
INSERT OR IGNORE INTO budget_config (id) VALUES (1);
|