@theokit/sdk 1.7.0 → 1.8.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/CHANGELOG.md +6 -0
- package/bin/init-claude.mjs +34 -0
- package/claude-template/AGENTS.md +139 -0
- package/claude-template/CLAUDE.md +51 -0
- package/claude-template/dot-claude/rules/theokit-conventions.md +33 -0
- package/claude-template/dot-claude/settings.json +16 -0
- package/claude-template/dot-claude/skills/theokit-agent-core/SKILL.md +209 -0
- package/claude-template/dot-claude/skills/theokit-budget/SKILL.md +176 -0
- package/claude-template/dot-claude/skills/theokit-config/SKILL.md +139 -0
- package/claude-template/dot-claude/skills/theokit-cron/SKILL.md +148 -0
- package/claude-template/dot-claude/skills/theokit-di/SKILL.md +233 -0
- package/claude-template/dot-claude/skills/theokit-di-agent/SKILL.md +294 -0
- package/claude-template/dot-claude/skills/theokit-errors/SKILL.md +172 -0
- package/claude-template/dot-claude/skills/theokit-eval/SKILL.md +144 -0
- package/claude-template/dot-claude/skills/theokit-gateways/SKILL.md +209 -0
- package/claude-template/dot-claude/skills/theokit-memory/SKILL.md +176 -0
- package/claude-template/dot-claude/skills/theokit-rag/SKILL.md +226 -0
- package/claude-template/dot-claude/skills/theokit-streaming/SKILL.md +156 -0
- package/claude-template/dot-claude/skills/theokit-subscriptions/SKILL.md +148 -0
- package/claude-template/dot-claude/skills/theokit-tools/SKILL.md +170 -0
- package/claude-template/dot-claude/skills/theokit-workflows/SKILL.md +218 -0
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.8.0] - 2026-06-12
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `.claude/` consumer template with 15 domain-specific passive skills, convention rules, AGENTS.md (cross-agent), and CLAUDE.md for AI coding tool integration. Scaffold via `npx theokit-init-claude`. Skills auto-inject TheoKit API knowledge when editing files matching each domain (Agent Core, Tools, Memory, DI, DI-Agent, Gateways, RAG, Workflows, Eval, Cron, Subscriptions, Errors, Config, Streaming, Budget). 33 tests.
|
|
10
|
+
|
|
5
11
|
## [1.7.0] - 2026-06-11
|
|
6
12
|
|
|
7
13
|
### Changed
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cpSync, existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
// EC-1: Node version guard (matches SDK engines.node)
|
|
6
|
+
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
7
|
+
if (major < 22 || (major === 22 && minor < 12)) {
|
|
8
|
+
console.error(`@theokit/sdk requires Node >= 22.12.0. Current: ${process.version}`);
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const templateDir = join(import.meta.dirname, "../claude-template");
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
const targetDir = join(cwd, ".claude");
|
|
15
|
+
const force = process.argv.includes("--force");
|
|
16
|
+
|
|
17
|
+
// EC-4: Check .claude/, AGENTS.md, CLAUDE.md independently
|
|
18
|
+
const conflicts = [];
|
|
19
|
+
if (existsSync(targetDir)) conflicts.push(".claude/");
|
|
20
|
+
if (existsSync(join(cwd, "AGENTS.md"))) conflicts.push("AGENTS.md");
|
|
21
|
+
if (existsSync(join(cwd, "CLAUDE.md"))) conflicts.push("CLAUDE.md");
|
|
22
|
+
|
|
23
|
+
if (conflicts.length > 0 && !force) {
|
|
24
|
+
console.error(`Already exists: ${conflicts.join(", ")}. Use --force to overwrite.`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
cpSync(join(templateDir, "dot-claude"), targetDir, { recursive: true });
|
|
29
|
+
cpSync(join(templateDir, "AGENTS.md"), join(cwd, "AGENTS.md"));
|
|
30
|
+
cpSync(join(templateDir, "CLAUDE.md"), join(cwd, "CLAUDE.md"));
|
|
31
|
+
|
|
32
|
+
console.log("Created .claude/ with TheoKit SDK configuration (15 domain skills).");
|
|
33
|
+
console.log("Created AGENTS.md (cross-agent) and CLAUDE.md (Claude Code).");
|
|
34
|
+
console.log("\nNext: open Claude Code and start building with TheoKit.");
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# @theokit/sdk — TypeScript SDK for AI Agents
|
|
2
|
+
|
|
3
|
+
Build AI agents that run locally or in the cloud. Same code, same API, pick your runtime.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @theokit/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Set your API key:
|
|
12
|
+
```bash
|
|
13
|
+
export THEOKIT_API_KEY="your-key"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Import Map
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Agent } from "@theokit/sdk"; // Core: Agent, Run, SDKMessage
|
|
20
|
+
import { defineTool } from "@theokit/sdk"; // Tool definitions
|
|
21
|
+
import { TheokitAgentError } from "@theokit/sdk/errors"; // Error hierarchy
|
|
22
|
+
import { Cron } from "@theokit/sdk/cron"; // Scheduled jobs
|
|
23
|
+
import { Eval } from "@theokit/sdk/eval"; // Evaluation suite
|
|
24
|
+
import { Workflow } from "@theokit/sdk/workflow"; // Multi-step workflows
|
|
25
|
+
import { defineSubscription } from "@theokit/sdk/subscription"; // SSE/WebSocket subscriptions
|
|
26
|
+
import { VectorRetriever } from "@theokit/sdk/rag"; // RAG: retrievers, rerankers, splitters
|
|
27
|
+
import { defineSubAgent } from "@theokit/sdk/a2a"; // Agent-to-agent delegation
|
|
28
|
+
import { SandboxBackend } from "@theokit/sdk/sandbox"; // Sandbox backends
|
|
29
|
+
import { defineAuth } from "@theokit/sdk/server/auth"; // Authentication
|
|
30
|
+
import { TaskStore } from "@theokit/sdk/task-store"; // Task persistence
|
|
31
|
+
import { createClient } from "@theokit/sdk/client"; // HTTP client
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const agent = await Agent.create({
|
|
38
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
39
|
+
model: { id: "google/gemini-2.0-flash-001" },
|
|
40
|
+
local: { cwd: process.cwd() },
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const run = await agent.send("Summarize this repository");
|
|
44
|
+
for await (const event of run.stream()) {
|
|
45
|
+
if (event.type === "assistant") console.log(event.content);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
agent.dispose(); // Always clean up
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Core Patterns
|
|
52
|
+
|
|
53
|
+
### Agent lifecycle
|
|
54
|
+
- `Agent.create(options)` — create an agent (local or cloud)
|
|
55
|
+
- `agent.send(prompt)` — send a message, get a Run
|
|
56
|
+
- `run.stream()` — AsyncGenerator of SDKMessage events
|
|
57
|
+
- `agent.dispose()` — clean up resources (or use `await using`)
|
|
58
|
+
- `Agent.prompt(options, prompt)` — one-shot: create, send, dispose
|
|
59
|
+
|
|
60
|
+
### Tool definition
|
|
61
|
+
```typescript
|
|
62
|
+
const searchTool = defineTool({
|
|
63
|
+
name: "search",
|
|
64
|
+
description: "Search the web",
|
|
65
|
+
inputSchema: z.object({ query: z.string() }),
|
|
66
|
+
execute: async ({ query }) => ({ results: await search(query) }),
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Streaming events (SDKMessage)
|
|
71
|
+
- `{ type: "assistant", content }` — text from the model
|
|
72
|
+
- `{ type: "tool_use", name, input }` — tool call
|
|
73
|
+
- `{ type: "tool_result", name, output }` — tool response
|
|
74
|
+
- `{ type: "status", status }` — run status change
|
|
75
|
+
- `{ type: "error", error }` — error event
|
|
76
|
+
- `{ type: "usage", tokens }` — token usage update
|
|
77
|
+
|
|
78
|
+
### Error handling
|
|
79
|
+
```typescript
|
|
80
|
+
try {
|
|
81
|
+
await agent.send("...");
|
|
82
|
+
} catch (e) {
|
|
83
|
+
if (e instanceof TheokitAgentError) {
|
|
84
|
+
console.error(e.code, e.message); // typed error with code
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### DI decorators (`@theokit/di` + `@theokit/di-agent`)
|
|
90
|
+
```typescript
|
|
91
|
+
import { Injectable, Container } from "@theokit/di";
|
|
92
|
+
import { Tool, Workflow, Cron, InjectAgent } from "@theokit/di-agent";
|
|
93
|
+
|
|
94
|
+
@Injectable()
|
|
95
|
+
class MyService {
|
|
96
|
+
@Tool({ name: "search", description: "Search" })
|
|
97
|
+
searchTool!: ToolOptions;
|
|
98
|
+
|
|
99
|
+
@Cron({ schedule: "*/5 * * * *" })
|
|
100
|
+
cleanup() { /* runs every 5 min */ }
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Gateways
|
|
105
|
+
```typescript
|
|
106
|
+
import { defineGateway } from "@theokit/gateway-telegram"; // or -slack, -discord, etc.
|
|
107
|
+
const gateway = defineGateway({ token: process.env.BOT_TOKEN });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Available: telegram, slack, discord, whatsapp, teams, email, sms, mattermost, line, matrix.
|
|
111
|
+
|
|
112
|
+
## Anti-patterns
|
|
113
|
+
|
|
114
|
+
- NEVER import from `@theokit/sdk/internal/...` — internal paths are not public API
|
|
115
|
+
- NEVER import from `@theokit/sdk/dist/...` — use the exports map above
|
|
116
|
+
- NEVER forget `agent.dispose()` — causes resource leaks
|
|
117
|
+
- NEVER use `new Agent()` — always use `Agent.create()`
|
|
118
|
+
- NEVER use `any` for tool input schemas — use Zod schemas
|
|
119
|
+
|
|
120
|
+
## Packages
|
|
121
|
+
|
|
122
|
+
| Package | Purpose |
|
|
123
|
+
|---------|---------|
|
|
124
|
+
| `@theokit/sdk` | Core SDK (Agent, Run, Tools, Memory, Streaming) |
|
|
125
|
+
| `@theokit/di` | Dependency injection container |
|
|
126
|
+
| `@theokit/di-agent` | 15 agentic decorators for DI |
|
|
127
|
+
| `@theokit/gateway-*` | Platform gateways (Telegram, Slack, etc.) |
|
|
128
|
+
| `@theokit/react` | React hooks for agent UIs |
|
|
129
|
+
|
|
130
|
+
## Configuration
|
|
131
|
+
|
|
132
|
+
Project config lives in `.theokit/`:
|
|
133
|
+
- `.theokit/mcp.json` — MCP server configuration
|
|
134
|
+
- `.theokit/hooks.json` — lifecycle hooks
|
|
135
|
+
- `.theokit/agents/*.md` — agent instruction files
|
|
136
|
+
|
|
137
|
+
Environment variables:
|
|
138
|
+
- `THEOKIT_API_KEY` — API key (required)
|
|
139
|
+
- `THEOKIT_MODEL_ID` — default model override
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
@AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Claude Code — TheoKit SDK Extensions
|
|
4
|
+
|
|
5
|
+
This project uses `@theokit/sdk`. The AGENTS.md above contains the full API reference. Below are Claude Code-specific extensions.
|
|
6
|
+
|
|
7
|
+
### Available Skills (auto-loaded by domain)
|
|
8
|
+
|
|
9
|
+
These skills inject TheoKit knowledge automatically when you edit files matching their domain:
|
|
10
|
+
|
|
11
|
+
| Skill | Triggers on files matching |
|
|
12
|
+
|-------|---------------------------|
|
|
13
|
+
| `theokit-agent-core` | `*agent*`, `*Agent*`, `sdk.*` |
|
|
14
|
+
| `theokit-tools` | `*tool*`, `*Tool*` |
|
|
15
|
+
| `theokit-memory` | `*memory*`, `*Memory*`, `*embed*` |
|
|
16
|
+
| `theokit-di` | `*container*`, `*inject*`, `*provider*`, `*module*` |
|
|
17
|
+
| `theokit-di-agent` | `*decorator*`, `*Decorator*`, `di-agent*` |
|
|
18
|
+
| `theokit-gateways` | `*gateway*`, `*telegram*`, `*slack*`, `*discord*` |
|
|
19
|
+
| `theokit-rag` | `*retriev*`, `*rerank*`, `*splitter*`, `*rag*` |
|
|
20
|
+
| `theokit-workflows` | `*workflow*`, `*Workflow*`, `*step*` |
|
|
21
|
+
| `theokit-eval` | `*eval*`, `*Eval*`, `*scorer*` |
|
|
22
|
+
| `theokit-cron` | `*cron*`, `*Cron*`, `*job*`, `*schedule*` |
|
|
23
|
+
| `theokit-subscriptions` | `*subscri*`, `*sse*`, `*websocket*`, `*ws.*` |
|
|
24
|
+
| `theokit-errors` | `*error*`, `*Error*`, `*exception*` |
|
|
25
|
+
| `theokit-config` | `.theokit/**`, `config.*`, `theo.config.*` |
|
|
26
|
+
| `theokit-streaming` | `*stream*`, `*Stream*`, `*SDKMessage*` |
|
|
27
|
+
| `theokit-budget` | `*budget*`, `*Budget*`, `*cost*`, `*token*` |
|
|
28
|
+
|
|
29
|
+
### Settings
|
|
30
|
+
|
|
31
|
+
`.claude/settings.json` is pre-configured with safe defaults:
|
|
32
|
+
- Allows: `npm run *`, `pnpm *`, `git status`, `git diff`, reading `src/` and `docs/`
|
|
33
|
+
- Denies: `.env*` file reads, `sudo`, `rm -rf`
|
|
34
|
+
- Override locally: create `.claude/settings.local.json` (add to `.gitignore`)
|
|
35
|
+
|
|
36
|
+
### Customization
|
|
37
|
+
|
|
38
|
+
Add your project-specific instructions below this line. The SDK knowledge above stays current with your installed `@theokit/sdk` version.
|
|
39
|
+
|
|
40
|
+
```markdown
|
|
41
|
+
## My Project
|
|
42
|
+
|
|
43
|
+
Build: `npm run build`
|
|
44
|
+
Test: `npm test`
|
|
45
|
+
Lint: `npm run lint`
|
|
46
|
+
|
|
47
|
+
## Architecture
|
|
48
|
+
- `src/agents/` — agent definitions
|
|
49
|
+
- `src/tools/` — tool implementations
|
|
50
|
+
- `src/services/` — business logic
|
|
51
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# TheoKit SDK Conventions
|
|
2
|
+
|
|
3
|
+
## Agent lifecycle
|
|
4
|
+
- Always use `Agent.create()` to create agents — NEVER `new Agent()`
|
|
5
|
+
- Always call `agent.dispose()` or use `await using` when done
|
|
6
|
+
- Use `Agent.prompt()` for one-shot operations (auto-disposes)
|
|
7
|
+
|
|
8
|
+
## Imports
|
|
9
|
+
- Use `@theokit/sdk` for core (Agent, defineTool, Memory)
|
|
10
|
+
- Use `@theokit/sdk/errors` for error types
|
|
11
|
+
- Use `@theokit/sdk/subscription` for SSE/WebSocket
|
|
12
|
+
- Use `@theokit/sdk/rag` for retrievers, rerankers, splitters
|
|
13
|
+
- Use `@theokit/sdk/cron` for scheduled jobs
|
|
14
|
+
- Use `@theokit/sdk/eval` for evaluation
|
|
15
|
+
- Use `@theokit/sdk/workflow` for workflows
|
|
16
|
+
- NEVER import from `@theokit/sdk/internal/...`
|
|
17
|
+
- NEVER import from `@theokit/sdk/dist/...`
|
|
18
|
+
|
|
19
|
+
## Tools
|
|
20
|
+
- Tool `inputSchema` MUST use Zod schemas — NEVER `any` or untyped objects
|
|
21
|
+
- Tool `execute` MUST return a serializable value
|
|
22
|
+
|
|
23
|
+
## DI
|
|
24
|
+
- Use `@Injectable()` + `@Inject()` from `@theokit/di`
|
|
25
|
+
- NEVER manually `new` a service — let the container resolve it
|
|
26
|
+
|
|
27
|
+
## Error handling
|
|
28
|
+
- Catch `TheokitAgentError` (base class) and check `error.code`
|
|
29
|
+
- NEVER silently swallow errors — log with context or rethrow
|
|
30
|
+
|
|
31
|
+
## Gateways
|
|
32
|
+
- One gateway per agent instance
|
|
33
|
+
- Configure via `defineGateway()` from the specific gateway package
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm run *)",
|
|
5
|
+
"Bash(pnpm *)",
|
|
6
|
+
"Bash(npx *)",
|
|
7
|
+
"Read(./src/**)",
|
|
8
|
+
"Read(./docs/**)",
|
|
9
|
+
"Read(./tests/**)",
|
|
10
|
+
"Bash(git status)",
|
|
11
|
+
"Bash(git diff)",
|
|
12
|
+
"Bash(git log *)"
|
|
13
|
+
],
|
|
14
|
+
"deny": ["Read(.env*)", "Read(**/.env*)", "Bash(sudo *)", "Bash(rm -rf *)"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
description: Agent lifecycle, sending messages, streaming, and disposal patterns for @theokit/sdk.
|
|
4
|
+
paths:
|
|
5
|
+
- "**/*agent*"
|
|
6
|
+
- "**/*Agent*"
|
|
7
|
+
- "**/sdk.*"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TheoKit SDK -- Agent Core
|
|
11
|
+
|
|
12
|
+
Quick reference for Agent lifecycle, Run streaming, and disposal.
|
|
13
|
+
|
|
14
|
+
## Agent.create
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Agent } from "@theokit/sdk";
|
|
18
|
+
|
|
19
|
+
const agent = await Agent.create({
|
|
20
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
21
|
+
model: { id: "google/gemini-2.0-flash-001" },
|
|
22
|
+
local: { cwd: process.cwd() },
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Returns an `SDKAgent`. Local agents get `agent-<uuid>` IDs; cloud agents get `bc-<uuid>`.
|
|
27
|
+
|
|
28
|
+
### AgentOptions (key fields)
|
|
29
|
+
|
|
30
|
+
| Property | Type | Notes |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `model` | `ModelSelection` | Required for local; `{ id, params? }`. |
|
|
33
|
+
| `apiKey` | `string` | Falls back to `THEOKIT_API_KEY` env. |
|
|
34
|
+
| `local` | `{ cwd, settingSources?, sandboxOptions? }` | Local runtime config. |
|
|
35
|
+
| `cloud` | `CloudOptions` | Cloud runtime config (repos, autoCreatePR, envVars). |
|
|
36
|
+
| `systemPrompt` | `string \| (ctx: SystemPromptContext) => string` | Static string or async resolver. |
|
|
37
|
+
| `mcpServers` | `Record<string, McpServerConfig>` | Inline MCP server definitions. |
|
|
38
|
+
| `agents` | `Record<string, AgentDefinition>` | Subagent definitions. |
|
|
39
|
+
| `tools` | `CustomTool[]` | Inline custom tools (local only). |
|
|
40
|
+
| `memory` | `MemoryOptions` | Durable memory config. |
|
|
41
|
+
| `handoffs` | `Array<SDKAgent \| Handoff>` | Peer-to-peer agent handoffs. |
|
|
42
|
+
| `conversationStorage` | `ConversationStorageAdapter` | Pluggable persistence. |
|
|
43
|
+
|
|
44
|
+
## Agent.prompt (one-shot)
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
const result = await Agent.prompt("What does the auth middleware do?", {
|
|
48
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
49
|
+
model: { id: "google/gemini-2.0-flash-001" },
|
|
50
|
+
local: { cwd: process.cwd() },
|
|
51
|
+
});
|
|
52
|
+
// result: { id, status, result?, model?, durationMs?, git? }
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Pass `throwOnError: true` to reject with `AgentRunError` instead of resolving with `status: 'error'`.
|
|
56
|
+
|
|
57
|
+
## agent.send and Run
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const run = await agent.send("Find the bug in src/auth.ts");
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Run interface
|
|
64
|
+
|
|
65
|
+
| Member | Type | Description |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `id` | `string` | Run identifier. |
|
|
68
|
+
| `status` | `RunStatus` | `"running" \| "finished" \| "error" \| "cancelled"` |
|
|
69
|
+
| `stream()` | `AsyncGenerator<SDKMessage>` | Normalized event stream. |
|
|
70
|
+
| `wait()` | `Promise<RunResult>` | Block until finished. |
|
|
71
|
+
| `cancel()` | `Promise<void>` | Cancel the run. |
|
|
72
|
+
| `conversation()` | `Promise<ConversationTurn[]>` | Structured turn history. |
|
|
73
|
+
| `onDidChangeStatus(fn)` | `() => void` | Status change listener; returns unsubscribe. |
|
|
74
|
+
|
|
75
|
+
### Streaming SDKMessage types
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
for await (const event of run.stream()) {
|
|
79
|
+
switch (event.type) {
|
|
80
|
+
case "assistant": /* event.message.content: (TextBlock | ToolUseBlock)[] */ break;
|
|
81
|
+
case "thinking": /* event.text, event.thinking_duration_ms? */ break;
|
|
82
|
+
case "tool_call": /* event.name, event.status, event.args?, event.result? */ break;
|
|
83
|
+
case "status": /* event.status: cloud lifecycle transitions */ break;
|
|
84
|
+
case "task": /* event.text: task milestones */ break;
|
|
85
|
+
case "request": /* event.request_id: awaiting user input */ break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Per-send options
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
await agent.send("Plan the refactor", {
|
|
94
|
+
model: { id: "claude-sonnet-4-6", params: [{ id: "thinking", value: "high" }] },
|
|
95
|
+
systemPrompt: "Focus on performance.",
|
|
96
|
+
signal: abortController.signal,
|
|
97
|
+
onDelta: ({ update }) => { /* InteractionUpdate */ },
|
|
98
|
+
onStep: ({ step }) => { /* ConversationStep */ },
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Agent.resume
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const agent = await Agent.resume("bc-abc123", {
|
|
106
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Runtime auto-detected from ID prefix. Inline `mcpServers` and `tools` are NOT persisted -- re-pass on resume.
|
|
111
|
+
|
|
112
|
+
## Agent.getOrCreate
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const agent = await Agent.getOrCreate(`tg-user-${userId}`, {
|
|
116
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
117
|
+
model: { id: "claude-sonnet-4-6" },
|
|
118
|
+
local: { cwd: process.cwd() },
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Tries resume first; on `UnknownAgentError` falls through to create.
|
|
123
|
+
|
|
124
|
+
## Agent.get / Agent.list / Agent.listRuns
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const info = await Agent.get(agentId);
|
|
128
|
+
const { items, nextCursor } = await Agent.list({ runtime: "local", cwd: process.cwd() });
|
|
129
|
+
const { items: runs } = await Agent.listRuns(agentId);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## createAgentFactory
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { createAgentFactory } from "@theokit/sdk";
|
|
136
|
+
|
|
137
|
+
const factory = createAgentFactory({
|
|
138
|
+
apiKey: process.env.THEOKIT_API_KEY!,
|
|
139
|
+
model: { id: "claude-sonnet-4-6" },
|
|
140
|
+
local: { cwd: process.cwd() },
|
|
141
|
+
systemPrompt: "You are a helpful assistant.",
|
|
142
|
+
});
|
|
143
|
+
const agent = await factory.getOrCreate(`user-${userId}`);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Agent.builder (fluent API)
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const agent = await Agent.builder()
|
|
150
|
+
.apiKey(process.env.THEOKIT_API_KEY!)
|
|
151
|
+
.model({ id: "claude-sonnet-4-6" })
|
|
152
|
+
.local({ cwd: process.cwd() })
|
|
153
|
+
.tools([myTool])
|
|
154
|
+
.getOrCreate(`user-${userId}`);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Agent.generateObject / Agent.streamObject
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { z } from "zod";
|
|
161
|
+
|
|
162
|
+
const { object } = await Agent.generateObject({
|
|
163
|
+
schema: z.object({ title: z.string(), year: z.number().nullable() }),
|
|
164
|
+
prompt: "Fact card about jazz.",
|
|
165
|
+
model: { id: "google/gemini-2.0-flash-001" },
|
|
166
|
+
local: { cwd: process.cwd() },
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
for await (const evt of Agent.streamObject({ schema, prompt, model, local })) {
|
|
170
|
+
if (evt.type === "partial") render(evt.partial);
|
|
171
|
+
if (evt.type === "complete") finalize(evt.object);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Disposal patterns
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Preferred: await using (auto-dispose on block exit)
|
|
179
|
+
await using agent = await Agent.create({ /* ... */ });
|
|
180
|
+
|
|
181
|
+
// Explicit dispose
|
|
182
|
+
await agent[Symbol.asyncDispose]();
|
|
183
|
+
|
|
184
|
+
// Fire-and-forget close
|
|
185
|
+
agent.close();
|
|
186
|
+
|
|
187
|
+
// Reload config without disposing
|
|
188
|
+
await agent.reload();
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Agent.registry (production)
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
Agent.registry.configure({ maxAgents: 1000, idleTimeoutMs: 15 * 60 * 1000 });
|
|
195
|
+
Agent.registry.size();
|
|
196
|
+
Agent.registry.evict("agent-42");
|
|
197
|
+
await Agent.registry.evictAll(); // graceful shutdown
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Cancellation
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
const run = await agent.send(message, { signal: request.signal });
|
|
204
|
+
// On abort: AgentRunError with code "aborted"
|
|
205
|
+
|
|
206
|
+
// Compose with timeout:
|
|
207
|
+
const composed = AbortSignal.any([request.signal, AbortSignal.timeout(30_000)]);
|
|
208
|
+
await agent.send(message, { signal: composed });
|
|
209
|
+
```
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*budget*"
|
|
5
|
+
- "**/*Budget*"
|
|
6
|
+
- "**/*cost*"
|
|
7
|
+
- "**/*token*"
|
|
8
|
+
description: TheoKit SDK Budget API reference — cost tracking, token budget enforcement, usage reporting
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# TheoKit Budget
|
|
12
|
+
|
|
13
|
+
Token cost enforcement primitive. Track, warn, and block LLM spend at the
|
|
14
|
+
process level with stacked USD limits and configurable enforcement modes.
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Budget } from "@theokit/sdk";
|
|
20
|
+
|
|
21
|
+
const handle = Budget.create({
|
|
22
|
+
name: "my-bot",
|
|
23
|
+
scope: "process",
|
|
24
|
+
mode: "warn",
|
|
25
|
+
limits: [
|
|
26
|
+
{ window: "1h", limitUsd: 5.0 },
|
|
27
|
+
{ window: "1d", limitUsd: 50.0 },
|
|
28
|
+
],
|
|
29
|
+
onThreshold: (event) => {
|
|
30
|
+
console.warn(`Budget ${event.budgetName}: ${event.threshold * 100}% of ${event.window} limit`);
|
|
31
|
+
},
|
|
32
|
+
onExceed: (event) => {
|
|
33
|
+
console.error(`Budget ${event.budgetName}: exceeded ${event.window} limit`);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Enforcement modes
|
|
39
|
+
|
|
40
|
+
| Mode | Behavior |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `"audit"` | Log only. Never throws, never blocks. |
|
|
43
|
+
| `"warn"` | Callbacks fire at 80%, 95%, and 100% thresholds. No throw. Default. |
|
|
44
|
+
| `"block"` | Preflight throw (`BudgetExceededError`) BEFORE the LLM call when would-exceed. |
|
|
45
|
+
|
|
46
|
+
## Stacked limits
|
|
47
|
+
|
|
48
|
+
Pass multiple limits. ANY exceeded limit triggers enforcement:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
Budget.create({
|
|
52
|
+
name: "emergency-stop",
|
|
53
|
+
scope: "process",
|
|
54
|
+
mode: "block",
|
|
55
|
+
limits: [
|
|
56
|
+
{ window: "1h", limitUsd: 2.0 },
|
|
57
|
+
{ window: "1d", limitUsd: 10.0 },
|
|
58
|
+
{ window: "30d", limitUsd: 100.0 },
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Empty `limits[]` is valid: pure tracking with no threshold/exceed callbacks.
|
|
64
|
+
|
|
65
|
+
## Time windows
|
|
66
|
+
|
|
67
|
+
| Window | Alignment |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `"1h"` | Relative (last 60 minutes) |
|
|
70
|
+
| `"1d"` | UTC midnight boundary |
|
|
71
|
+
| `"1w"` | Monday 00:00 UTC |
|
|
72
|
+
| `"30d"` | 1st of month 00:00 UTC |
|
|
73
|
+
| `"365d"` | Jan 1 00:00 UTC |
|
|
74
|
+
|
|
75
|
+
## Managing budgets
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// Retrieve a budget handle
|
|
79
|
+
const handle = Budget.get("my-bot");
|
|
80
|
+
|
|
81
|
+
// Check spend and remaining
|
|
82
|
+
handle?.spentIn("1d"); // USD spent in current day window
|
|
83
|
+
handle?.remainingIn("1d"); // USD remaining before limit
|
|
84
|
+
|
|
85
|
+
// List all active budgets
|
|
86
|
+
const budgets = Budget.list();
|
|
87
|
+
|
|
88
|
+
// Snapshot all windows for all budgets
|
|
89
|
+
const snapshots = Budget.snapshot();
|
|
90
|
+
// [{ name, window, spentUsd, limitUsd, ratio }, ...]
|
|
91
|
+
|
|
92
|
+
// Delete a budget
|
|
93
|
+
Budget.delete("my-bot");
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Type reference
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
type BudgetScope = "agent" | "call" | "process";
|
|
100
|
+
type BudgetWindow = "1h" | "1d" | "1w" | "30d" | "365d";
|
|
101
|
+
type BudgetMode = "audit" | "warn" | "block";
|
|
102
|
+
|
|
103
|
+
interface BudgetLimit {
|
|
104
|
+
readonly window: BudgetWindow;
|
|
105
|
+
readonly limitUsd: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface BudgetOptions {
|
|
109
|
+
readonly name: string; // must match ^[a-z0-9][a-z0-9_-]*$
|
|
110
|
+
readonly scope: BudgetScope;
|
|
111
|
+
readonly limits: ReadonlyArray<BudgetLimit>;
|
|
112
|
+
readonly mode?: BudgetMode; // default "warn"
|
|
113
|
+
readonly onThreshold?: (event: BudgetThresholdEvent) => void | Promise<void>;
|
|
114
|
+
readonly onExceed?: (event: BudgetExceedEvent) => void | Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
interface BudgetHandle {
|
|
118
|
+
readonly name: string;
|
|
119
|
+
readonly mode: BudgetMode;
|
|
120
|
+
readonly scope: BudgetScope;
|
|
121
|
+
readonly limits: ReadonlyArray<BudgetLimit>;
|
|
122
|
+
spentIn(window: BudgetWindow): number;
|
|
123
|
+
remainingIn(window: BudgetWindow): number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface BudgetSnapshot {
|
|
127
|
+
readonly name: string;
|
|
128
|
+
readonly window: BudgetWindow;
|
|
129
|
+
readonly spentUsd: number;
|
|
130
|
+
readonly limitUsd: number;
|
|
131
|
+
readonly ratio: number;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface BudgetThresholdEvent {
|
|
135
|
+
readonly budgetName: string;
|
|
136
|
+
readonly window: BudgetWindow;
|
|
137
|
+
readonly threshold: 0.8 | 0.95;
|
|
138
|
+
readonly spentUsd: number;
|
|
139
|
+
readonly limitUsd: number;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface BudgetExceedEvent {
|
|
143
|
+
readonly budgetName: string;
|
|
144
|
+
readonly window: BudgetWindow;
|
|
145
|
+
readonly spentUsd: number;
|
|
146
|
+
readonly limitUsd: number;
|
|
147
|
+
readonly mode: BudgetMode;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Wiring with agents
|
|
152
|
+
|
|
153
|
+
Budget enforcement integrates with `agent.send()`. When a budget is active
|
|
154
|
+
and mode is `"block"`, a preflight check runs before the LLM call. If the
|
|
155
|
+
estimated cost would exceed a limit, `BudgetExceededError` is thrown.
|
|
156
|
+
|
|
157
|
+
The `turn-ended` InteractionUpdate carries token usage that feeds the budget
|
|
158
|
+
ledger automatically:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
{ inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens }
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Errors
|
|
165
|
+
|
|
166
|
+
| Error | When |
|
|
167
|
+
|---|---|
|
|
168
|
+
| `ConfigurationError` | Invalid `name` (grammar violation) or duplicate `name` |
|
|
169
|
+
| `BudgetExceededError` | `mode: "block"` and spend would exceed a limit |
|
|
170
|
+
|
|
171
|
+
## Known limitations
|
|
172
|
+
|
|
173
|
+
- v1 supports `scope: "process"` only. `"agent"` and `"call"` scopes are
|
|
174
|
+
reserved for future multi-tenant scenarios.
|
|
175
|
+
- In-flight `agent.send` calls referencing a deleted budget treat subsequent
|
|
176
|
+
charges as a silent no-op with a stderr warning.
|