@theokit/sdk 4.2.6 → 4.2.8
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 +12 -0
- package/claude-template/AGENTS.md +73 -55
- package/claude-template/CLAUDE.md +16 -1
- package/claude-template/dot-claude/rules/theokit-conventions.md +2 -3
- package/claude-template/dot-claude/skills/theokit-agent-core/SKILL.md +3 -3
- package/claude-template/dot-claude/skills/theokit-auth/SKILL.md +102 -0
- package/claude-template/dot-claude/skills/theokit-client/SKILL.md +58 -0
- package/claude-template/dot-claude/skills/theokit-compaction/SKILL.md +102 -0
- package/claude-template/dot-claude/skills/theokit-concurrency/SKILL.md +68 -0
- package/claude-template/dot-claude/skills/theokit-filesystem/SKILL.md +74 -0
- package/claude-template/dot-claude/skills/theokit-messages/SKILL.md +58 -0
- package/claude-template/dot-claude/skills/theokit-models/SKILL.md +79 -0
- package/claude-template/dot-claude/skills/theokit-path-safety/SKILL.md +60 -0
- package/claude-template/dot-claude/skills/theokit-persistence/SKILL.md +85 -0
- package/claude-template/dot-claude/skills/theokit-project/SKILL.md +55 -0
- package/claude-template/dot-claude/skills/theokit-retry/SKILL.md +50 -0
- package/claude-template/dot-claude/skills/theokit-sandbox/SKILL.md +93 -0
- package/claude-template/dot-claude/skills/theokit-sanitize/SKILL.md +66 -0
- package/claude-template/dot-claude/skills/theokit-skills/SKILL.md +68 -0
- package/claude-template/dot-claude/skills/theokit-subagents/SKILL.md +109 -0
- package/claude-template/dot-claude/skills/theokit-subscriptions/SKILL.md +6 -6
- package/claude-template/dot-claude/skills/theokit-task-store/SKILL.md +75 -0
- package/claude-template/dot-claude/skills/theokit-tools/SKILL.md +9 -9
- package/package.json +1 -1
- package/claude-template/dot-claude/skills/theokit-rag/SKILL.md +0 -226
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.2.8
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat(init-claude): the scaffolded `.claude/` template now covers **every public `@theokit/sdk` subpath**. Added 16 per-module skills — models, subagents (`/a2a` + tool-scope), retry, task-store, sandbox, compaction, messages, auth (`/server/auth` + errors-envelope), sanitize, skills, path-safety, concurrency, persistence, client, filesystem, project — each authored against the shipped type declarations (verified signatures: `Retry.create` executor, `Semaphore.create`, `SubAgent.create`, `Auth.create`, `sanitizeToolInput`, …). The `claude-template-no-drift` gate covers the expanded set.
|
|
8
|
+
|
|
9
|
+
## 4.2.7
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- fix(init-claude): the scaffolded `.claude/` template (`npx theokit-init-claude`) now teaches the current `X.create()` API instead of the pre-3.0 surface removed by SE36 (#139). `AGENTS.md` + the affected skills/rules were corrected: `defineTool`→`Tool.create`, `defineSubscription`→`Subscription.create`, `createAgentFactory`→`AgentFactory.create`; the tool spec field is `handler` (not `execute`); streaming events are `system`/`user`/`assistant`/`thinking`/`tool_call`/`status`/`task`/`request` (there is no `tool_use`/`tool_result`/`usage`/`error`); assistant text is `event.message.content`; `Agent.prompt(prompt, options)` (prompt first); built-in coding tools import from `@theokit/sdk-tools` (not a `@theokit/sdk/tools` subpath). The phantom `theokit-rag` skill and the non-existent `@theokit/sdk/rag` import were removed. A `tests/lint/claude-template-no-drift.test.ts` gate now fails CI if the scaffold teaches a removed factory, phantom subpath, or non-existent stream event.
|
|
14
|
+
|
|
3
15
|
## 4.2.6
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @theokit/sdk — TypeScript SDK for AI Agents
|
|
2
2
|
|
|
3
|
-
Build AI agents that run locally or in the cloud. Same code, same API, pick your runtime.
|
|
3
|
+
Build AI agents that run locally or in the cloud. Same code, same API, pick your runtime. The exported types are the canonical contract.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
@@ -13,24 +13,23 @@ Set your API key:
|
|
|
13
13
|
export THEOKIT_API_KEY="your-key"
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Node 22.12+ required.
|
|
17
|
+
|
|
18
|
+
## Import Map (verified subpaths)
|
|
17
19
|
|
|
18
20
|
```typescript
|
|
19
|
-
import { Agent } from "@theokit/sdk";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
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
|
|
21
|
+
import { Agent, Cron, Tool } from "@theokit/sdk"; // core: Agent, Run, Cron, Tool, SDKMessage
|
|
22
|
+
import { TheokitAgentError } from "@theokit/sdk/errors"; // error hierarchy
|
|
23
|
+
import { Workflow } from "@theokit/sdk/workflow"; // multi-step workflows
|
|
24
|
+
import { Eval } from "@theokit/sdk/eval"; // evaluation suite
|
|
25
|
+
import { Subscription } from "@theokit/sdk/subscription"; // SSE / WebSocket subscriptions
|
|
26
|
+
import { SubAgent } from "@theokit/sdk/a2a"; // agent-to-agent delegation
|
|
27
|
+
import { Auth } from "@theokit/sdk/server/auth"; // authentication
|
|
28
|
+
import { TaskStore } from "@theokit/sdk/task-store"; // task persistence
|
|
32
29
|
```
|
|
33
30
|
|
|
31
|
+
Other public subpaths: `/messages`, `/models`, `/skills`, `/project`, `/subagents`, `/sandbox`, `/client`, `/persistence`, `/retry`, `/concurrency`, `/sanitize`. There is **no** `@theokit/sdk/rag` subpath. Never import from `@theokit/sdk/internal/*` or `@theokit/sdk/dist/*`.
|
|
32
|
+
|
|
34
33
|
## Quick Start
|
|
35
34
|
|
|
36
35
|
```typescript
|
|
@@ -42,90 +41,109 @@ const agent = await Agent.create({
|
|
|
42
41
|
|
|
43
42
|
const run = await agent.send("Summarize this repository");
|
|
44
43
|
for await (const event of run.stream()) {
|
|
45
|
-
if (event.type === "assistant")
|
|
44
|
+
if (event.type === "assistant") {
|
|
45
|
+
for (const block of event.message.content) {
|
|
46
|
+
if (block.type === "text") process.stdout.write(block.text);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
agent.
|
|
51
|
+
await agent[Symbol.asyncDispose](); // or: await using agent = await Agent.create(...)
|
|
49
52
|
```
|
|
50
53
|
|
|
51
54
|
## Core Patterns
|
|
52
55
|
|
|
53
56
|
### 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
|
-
- `
|
|
58
|
-
- `Agent.prompt(
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
- `Agent.create(options)` — create an agent (local or cloud); returns immediately, `agent.agentId` is `agent-<uuid>` (local) or `bc-<uuid>` (cloud).
|
|
58
|
+
- `agent.send(prompt)` — send a message, get a `Run` (context is retained across sends).
|
|
59
|
+
- `run.stream()` — `AsyncGenerator` of `SDKMessage` events.
|
|
60
|
+
- `run.wait()` — resolve to `{ status, result, model, durationMs, git? }` after the run ends.
|
|
61
|
+
- `Agent.prompt(prompt, options)` — one-shot (create + send + dispose). **Prompt is the first argument.**
|
|
62
|
+
- `Agent.resume(agentId, { apiKey })` — reattach; runtime auto-detected from the ID prefix.
|
|
63
|
+
- Dispose with `await using`, `await agent[Symbol.asyncDispose]()`, or `agent.close()` (fire-and-forget).
|
|
64
|
+
|
|
65
|
+
### Tool definition — `Tool.create` with a Zod schema
|
|
61
66
|
```typescript
|
|
62
|
-
|
|
67
|
+
import { z } from "zod";
|
|
68
|
+
import { Tool } from "@theokit/sdk";
|
|
69
|
+
|
|
70
|
+
const searchTool = Tool.create({
|
|
63
71
|
name: "search",
|
|
64
72
|
description: "Search the web",
|
|
65
73
|
inputSchema: z.object({ query: z.string() }),
|
|
66
|
-
|
|
74
|
+
handler: async ({ query }) => JSON.stringify({ results: await search(query) }),
|
|
67
75
|
});
|
|
68
76
|
```
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
- `{ type: "
|
|
78
|
+
The tool spec field is `handler` (returns a string, or a typed value when you set `outputSchema`). Built-in coding tools (`createReadFileTool`, …) live in the separate `@theokit/sdk-tools` package, not a `@theokit/sdk/tools` subpath.
|
|
79
|
+
|
|
80
|
+
`Tool.create` is the canonical factory (uniform `X.create()` API since v3.0). Every public factory follows it: `Provider.create`, `Plugin.create`, `Subscription.create`, `Auth.create`, `SubAgent.create`, `Squad.create`, `Retry.create`. There is **no** `defineTool` / `define*` export — those were removed at v3.0.
|
|
81
|
+
|
|
82
|
+
### Streaming events (`SDKMessage`)
|
|
83
|
+
Discriminate on `type`. All events carry `agent_id` and `run_id`.
|
|
84
|
+
- `{ type: "system" }` — init metadata, once at start (`model?`, `tools?`)
|
|
85
|
+
- `{ type: "user", message: { content } }` — echo of the prompt
|
|
86
|
+
- `{ type: "assistant", message: { content } }` — model output; `content` is a `(TextBlock | ToolUseBlock)[]`
|
|
87
|
+
- `{ type: "thinking", text }` — reasoning content
|
|
88
|
+
- `{ type: "tool_call", call_id, name, status, args?, result? }` — tool lifecycle
|
|
89
|
+
- `{ type: "status", status }` — cloud run lifecycle
|
|
90
|
+
- `{ type: "task" }` / `{ type: "request", request_id }` — task milestones / awaiting input
|
|
91
|
+
|
|
92
|
+
There is no `tool_use` / `tool_result` / `usage` / `error` event. Read assistant text from `event.message.content` (a block array), not `event.content`. Treat `tool_call` `args`/`result` as `unknown`.
|
|
77
93
|
|
|
78
94
|
### Error handling
|
|
79
95
|
```typescript
|
|
96
|
+
import { TheokitAgentError } from "@theokit/sdk/errors";
|
|
97
|
+
|
|
80
98
|
try {
|
|
81
99
|
await agent.send("...");
|
|
82
100
|
} catch (e) {
|
|
83
|
-
if (e instanceof TheokitAgentError)
|
|
84
|
-
console.error(e.code, e.message); // typed error with code
|
|
85
|
-
}
|
|
101
|
+
if (e instanceof TheokitAgentError) console.error(e.code, e.isRetryable, e.message);
|
|
86
102
|
}
|
|
87
103
|
```
|
|
104
|
+
Subclasses: `AuthenticationError`, `RateLimitError`, `ConfigurationError`, `IntegrationNotConnectedError`, `NetworkError`, `UnknownAgentError`, `UnsupportedRunOperationError`.
|
|
88
105
|
|
|
89
|
-
### DI decorators (`@theokit/di` + `@theokit/di-agent`)
|
|
106
|
+
### Optional: DI decorators (`@theokit/di` + `@theokit/di-agent`)
|
|
107
|
+
Decorators are an **optional** convenience layer in separate packages — the factory API above is canonical and never requires them.
|
|
90
108
|
```typescript
|
|
91
|
-
import { Injectable
|
|
92
|
-
import { Tool
|
|
109
|
+
import { Injectable } from "@theokit/di";
|
|
110
|
+
import { Tool as ToolDecorator, Cron as CronDecorator } from "@theokit/di-agent";
|
|
93
111
|
|
|
94
112
|
@Injectable()
|
|
95
113
|
class MyService {
|
|
96
|
-
@
|
|
97
|
-
searchTool!:
|
|
114
|
+
@ToolDecorator({ name: "search", description: "Search" })
|
|
115
|
+
searchTool!: unknown;
|
|
98
116
|
|
|
99
|
-
@
|
|
117
|
+
@CronDecorator({ schedule: "*/5 * * * *" })
|
|
100
118
|
cleanup() { /* runs every 5 min */ }
|
|
101
119
|
}
|
|
102
120
|
```
|
|
103
121
|
|
|
104
|
-
### Gateways
|
|
122
|
+
### Optional: Gateways
|
|
105
123
|
```typescript
|
|
106
124
|
import { defineGateway } from "@theokit/gateway-telegram"; // or -slack, -discord, etc.
|
|
107
125
|
const gateway = defineGateway({ token: process.env.BOT_TOKEN });
|
|
108
126
|
```
|
|
109
127
|
|
|
110
|
-
Available: telegram, slack, discord, whatsapp, teams, email, sms, mattermost, line, matrix.
|
|
111
|
-
|
|
112
128
|
## Anti-patterns
|
|
113
129
|
|
|
114
|
-
- NEVER
|
|
115
|
-
- NEVER
|
|
116
|
-
- NEVER
|
|
117
|
-
- NEVER
|
|
118
|
-
- NEVER
|
|
130
|
+
- NEVER `new Agent()` — always `await Agent.create()`.
|
|
131
|
+
- NEVER author `defineTool` / `defineSubscription` / `defineAuth` / `defineSubAgent` — use `Tool.create` / `Subscription.create` / `Auth.create` / `SubAgent.create`.
|
|
132
|
+
- NEVER switch on `tool_use` / `tool_result` / `usage` / `error` stream events — they don't exist; use `tool_call` / `assistant` / `thinking` / `status`.
|
|
133
|
+
- NEVER read assistant text as `event.content` — it's `event.message.content`.
|
|
134
|
+
- NEVER import from `@theokit/sdk/internal/*`, `@theokit/sdk/dist/*`, or `@theokit/sdk/rag` (no such subpath).
|
|
135
|
+
- NEVER forget disposal (`await using` / `Symbol.asyncDispose` / `close()`) — it leaks the runtime.
|
|
136
|
+
- NEVER use `any` for tool input schemas — use Zod schemas.
|
|
119
137
|
|
|
120
138
|
## Packages
|
|
121
139
|
|
|
122
140
|
| Package | Purpose |
|
|
123
141
|
|---------|---------|
|
|
124
|
-
| `@theokit/sdk` | Core SDK (Agent, Run,
|
|
125
|
-
| `@theokit/di` | Dependency injection container |
|
|
126
|
-
| `@theokit/di-agent` |
|
|
127
|
-
| `@theokit/gateway-*` | Platform gateways
|
|
128
|
-
| `@theokit/react` | React hooks for agent UIs |
|
|
142
|
+
| `@theokit/sdk` | Core SDK (Agent, Run, Tool, Cron, streaming, memory, workflows, eval, subscriptions) |
|
|
143
|
+
| `@theokit/di` | Dependency injection container (optional) |
|
|
144
|
+
| `@theokit/di-agent` | Agentic decorators for DI (optional) |
|
|
145
|
+
| `@theokit/gateway-*` | Platform gateways — telegram, slack, discord, etc. (optional) |
|
|
146
|
+
| `@theokit/react` | React hooks for agent UIs (optional) |
|
|
129
147
|
|
|
130
148
|
## Configuration
|
|
131
149
|
|
|
@@ -16,7 +16,6 @@ These skills inject TheoKit knowledge automatically when you edit files matching
|
|
|
16
16
|
| `theokit-di` | `*container*`, `*inject*`, `*provider*`, `*module*` |
|
|
17
17
|
| `theokit-di-agent` | `*decorator*`, `*Decorator*`, `di-agent*` |
|
|
18
18
|
| `theokit-gateways` | `*gateway*`, `*telegram*`, `*slack*`, `*discord*` |
|
|
19
|
-
| `theokit-rag` | `*retriev*`, `*rerank*`, `*splitter*`, `*rag*` |
|
|
20
19
|
| `theokit-workflows` | `*workflow*`, `*Workflow*`, `*step*` |
|
|
21
20
|
| `theokit-eval` | `*eval*`, `*Eval*`, `*scorer*` |
|
|
22
21
|
| `theokit-cron` | `*cron*`, `*Cron*`, `*job*`, `*schedule*` |
|
|
@@ -25,6 +24,22 @@ These skills inject TheoKit knowledge automatically when you edit files matching
|
|
|
25
24
|
| `theokit-config` | `.theokit/**`, `config.*`, `theo.config.*` |
|
|
26
25
|
| `theokit-streaming` | `*stream*`, `*Stream*`, `*SDKMessage*` |
|
|
27
26
|
| `theokit-budget` | `*budget*`, `*Budget*`, `*cost*`, `*token*` |
|
|
27
|
+
| `theokit-models` | `*model*`, `*Model*` |
|
|
28
|
+
| `theokit-subagents` | `*subagent*`, `*a2a*`, `*delegat*` |
|
|
29
|
+
| `theokit-retry` | `*retry*`, `*Retry*` |
|
|
30
|
+
| `theokit-task-store` | `*task-store*`, `*taskstore*`, `*TaskStore*` |
|
|
31
|
+
| `theokit-sandbox` | `*sandbox*`, `*Sandbox*` |
|
|
32
|
+
| `theokit-compaction` | `*compact*`, `*Compact*` |
|
|
33
|
+
| `theokit-messages` | `*message*`, `*Message*` |
|
|
34
|
+
| `theokit-auth` | `*auth*`, `*Auth*`, `*envelope*` |
|
|
35
|
+
| `theokit-sanitize` | `*sanitize*`, `*Sanitize*` |
|
|
36
|
+
| `theokit-skills` | `*skill*`, `*Skill*` |
|
|
37
|
+
| `theokit-path-safety` | `*path-safety*`, `*pathsafety*` |
|
|
38
|
+
| `theokit-concurrency` | `*concurren*`, `*semaphore*`, `*Semaphore*` |
|
|
39
|
+
| `theokit-persistence` | `*persist*`, `*Persist*` |
|
|
40
|
+
| `theokit-client` | `*client*`, `*Client*` |
|
|
41
|
+
| `theokit-filesystem` | `*filesystem*`, `*Filesystem*` |
|
|
42
|
+
| `theokit-project` | `*project*`, `*Project*` |
|
|
28
43
|
|
|
29
44
|
### Settings
|
|
30
45
|
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
- Use `Agent.prompt()` for one-shot operations (auto-disposes)
|
|
7
7
|
|
|
8
8
|
## Imports
|
|
9
|
-
- Use `@theokit/sdk` for core (Agent,
|
|
9
|
+
- Use `@theokit/sdk` for core (Agent, Tool, Cron, Memory)
|
|
10
10
|
- Use `@theokit/sdk/errors` for error types
|
|
11
11
|
- Use `@theokit/sdk/subscription` for SSE/WebSocket
|
|
12
|
-
- Use `@theokit/sdk/rag` for retrievers, rerankers, splitters
|
|
13
12
|
- Use `@theokit/sdk/cron` for scheduled jobs
|
|
14
13
|
- Use `@theokit/sdk/eval` for evaluation
|
|
15
14
|
- Use `@theokit/sdk/workflow` for workflows
|
|
@@ -18,7 +17,7 @@
|
|
|
18
17
|
|
|
19
18
|
## Tools
|
|
20
19
|
- Tool `inputSchema` MUST use Zod schemas — NEVER `any` or untyped objects
|
|
21
|
-
- Tool `
|
|
20
|
+
- Tool `handler` MUST return a string (or a value matching `outputSchema` when set)
|
|
22
21
|
|
|
23
22
|
## DI
|
|
24
23
|
- Use `@Injectable()` + `@Inject()` from `@theokit/di`
|
|
@@ -129,12 +129,12 @@ const { items, nextCursor } = await Agent.list({ runtime: "local", cwd: process.
|
|
|
129
129
|
const { items: runs } = await Agent.listRuns(agentId);
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
##
|
|
132
|
+
## AgentFactory.create
|
|
133
133
|
|
|
134
134
|
```typescript
|
|
135
|
-
import {
|
|
135
|
+
import { AgentFactory } from "@theokit/sdk";
|
|
136
136
|
|
|
137
|
-
const factory =
|
|
137
|
+
const factory = AgentFactory.create({
|
|
138
138
|
apiKey: process.env.THEOKIT_API_KEY!,
|
|
139
139
|
model: { id: "claude-sonnet-4-6" },
|
|
140
140
|
local: { cwd: process.cwd() },
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*auth*"
|
|
5
|
+
- "**/*Auth*"
|
|
6
|
+
- "**/*envelope*"
|
|
7
|
+
description: TheoKit SDK server auth — Auth.create orchestrator, validateReturnTo, and the cross-layer error envelope
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TheoKit Server Auth
|
|
11
|
+
|
|
12
|
+
Server-side auth orchestrator and the cross-layer error envelope. These live
|
|
13
|
+
under the `@theokit/sdk/server/*` sub-paths (not the main barrel). Concrete
|
|
14
|
+
OAuth/email providers ship in opt-in `@theokit/auth-*` packages — the SDK only
|
|
15
|
+
defines the orchestrator contract.
|
|
16
|
+
|
|
17
|
+
## `Auth.create` — session + provider orchestrator
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import {
|
|
21
|
+
Auth,
|
|
22
|
+
validateReturnTo,
|
|
23
|
+
AuthConfigError,
|
|
24
|
+
AuthProviderNotFoundError,
|
|
25
|
+
AuthCallbackError,
|
|
26
|
+
AuthCancelledError,
|
|
27
|
+
AuthSecretTooShortError,
|
|
28
|
+
} from "@theokit/sdk/server/auth";
|
|
29
|
+
import type {
|
|
30
|
+
AuthProvider,
|
|
31
|
+
SessionManager,
|
|
32
|
+
AuthOrchestrator,
|
|
33
|
+
} from "@theokit/sdk/server/auth";
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`Auth.create(opts)` returns an `AuthOrchestrator<TSession>` with 5 methods.
|
|
37
|
+
`providers` is optional — an empty list is the manual-`signIn`-only escape hatch.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
const auth: AuthOrchestrator<Session> = Auth.create<Session>({
|
|
41
|
+
session, // your SessionManager<Session> implementation
|
|
42
|
+
providers: [githubProvider], // AuthProvider<Profile>[] from a @theokit/auth-* package
|
|
43
|
+
onSignIn: async ({ profile, provider }) => {
|
|
44
|
+
return toSession(profile, provider); // returns the TSession to persist
|
|
45
|
+
},
|
|
46
|
+
onSignOut: async (session) => {
|
|
47
|
+
/* revoke, audit, etc. */
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// OAuth flow (node:http req/res):
|
|
52
|
+
const redirect = await auth.startSignIn("github", req, { returnTo: "/dashboard" });
|
|
53
|
+
const { session, returnTo } = await auth.finishSignIn("github", req, res); // rotates session id (OWASP A07)
|
|
54
|
+
const current = await auth.getSession(req);
|
|
55
|
+
await auth.signOut(res);
|
|
56
|
+
|
|
57
|
+
// Escape hatch — persist a session directly, skipping the OAuth flow:
|
|
58
|
+
const s = await auth.signIn(externalProfile, "github", req, res);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## `validateReturnTo` — open-redirect guard (OWASP A01)
|
|
62
|
+
|
|
63
|
+
Returns a safe same-origin path. Cross-origin, protocol-relative (`//evil.com`),
|
|
64
|
+
empty, and defensive cases all collapse to `"/"`.
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const safe = validateReturnTo(returnTo, new URL("https://app.example.com"));
|
|
68
|
+
// "/dashboard" -> kept; "https://evil.com" -> "/"; undefined -> "/"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Typed errors: `AuthConfigError`, `AuthProviderNotFoundError`, `AuthCallbackError`,
|
|
72
|
+
`AuthCancelledError`, `AuthSecretTooShortError`.
|
|
73
|
+
|
|
74
|
+
## Error envelope — cross-layer boundary translation
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import {
|
|
78
|
+
toEnvelope,
|
|
79
|
+
fromEnvelope,
|
|
80
|
+
MemoryAdapterError,
|
|
81
|
+
} from "@theokit/sdk/server/errors-envelope";
|
|
82
|
+
import type {
|
|
83
|
+
TheokitErrorEnvelope,
|
|
84
|
+
TheokitErrorCode,
|
|
85
|
+
} from "@theokit/sdk/server/errors-envelope";
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`toEnvelope` translates any SDK error (or arbitrary thrown value) into the wire
|
|
89
|
+
envelope at egress; `fromEnvelope` reconstructs SDK class identity at ingress so
|
|
90
|
+
`instanceof` checks keep working across an IPC/serialization boundary.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
try {
|
|
94
|
+
await agent.send(prompt);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
const envelope: TheokitErrorEnvelope = toEnvelope(err); // { code, message, meta?, ext? }
|
|
97
|
+
send(envelope); // code is a TheokitErrorCode, e.g. "RATE_LIMITED"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Inbound edge (e.g. worker receiving the envelope):
|
|
101
|
+
const restored = fromEnvelope(envelope); // a TheokitAgentError subclass
|
|
102
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*client*"
|
|
5
|
+
- "**/*Client*"
|
|
6
|
+
description: TheoKit SDK low-level HTTP client — TheoKitClient (DEPRECATED; prefer the Agent façade)
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# TheoKit Client
|
|
10
|
+
|
|
11
|
+
`TheoKitClient` is a browser-safe, zero-Node-dependency HTTP client (native
|
|
12
|
+
`fetch` + manual SSE parsing) for a legacy server-adapter contract.
|
|
13
|
+
|
|
14
|
+
> DEPRECATED since 2.x — the `@theokit/sdk/client` sub-path consumes a legacy
|
|
15
|
+
> server-adapter HTTP contract (`POST /agent/send`, `GET /agent/stream`) that the
|
|
16
|
+
> ecosystem no longer produces, and will be removed in the next major. For
|
|
17
|
+
> in-process runs use the `Agent` façade (`@theokit/sdk`); for HTTP, use the
|
|
18
|
+
> framework's typed `POST /api/agents/<name>` client. Reach for this only when
|
|
19
|
+
> maintaining an existing integration against the old contract.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { TheoKitClient } from "@theokit/sdk/client";
|
|
23
|
+
import type { ClientOptions, SendResponse, StreamEvent } from "@theokit/sdk/client";
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Construct
|
|
27
|
+
|
|
28
|
+
The constructor takes `ClientOptions` — `baseUrl` (required), optional `basePath`
|
|
29
|
+
and `headers`.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
const client = new TheoKitClient({
|
|
33
|
+
baseUrl: "https://adapter.example.com",
|
|
34
|
+
basePath: "/agent", // optional
|
|
35
|
+
headers: { authorization: "Bearer …" }, // optional
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Send (one-shot)
|
|
40
|
+
|
|
41
|
+
`send(input)` POSTs and resolves a `SendResponse` (`{ status, output?, error? }`).
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const res: SendResponse = await client.send("summarize the repo");
|
|
45
|
+
if (res.error) throw new Error(res.error);
|
|
46
|
+
console.log(res.status, res.output);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Stream (SSE)
|
|
50
|
+
|
|
51
|
+
`stream(input)` returns an `AsyncGenerator<StreamEvent>`; each `StreamEvent` has a
|
|
52
|
+
`type` and an optional `text` (plus arbitrary extra fields).
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
for await (const event of client.stream("build the changelog")) {
|
|
56
|
+
if (event.type === "text" && event.text) process.stdout.write(event.text);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*compact*"
|
|
5
|
+
- "**/*Compact*"
|
|
6
|
+
description: TheoKit SDK compaction reference — compactTranscript, shouldCompact, checkpoints, context-overflow
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# TheoKit Compaction
|
|
10
|
+
|
|
11
|
+
Public context-management helpers. Every function is pure and never mutates its
|
|
12
|
+
input. A `CompressibleMessage` is `{ role: "user" | "assistant" | "system"; content: string }`.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
import {
|
|
16
|
+
compactTranscript,
|
|
17
|
+
shouldCompact,
|
|
18
|
+
estimateTokens,
|
|
19
|
+
buildCheckpoint,
|
|
20
|
+
filterFromLatestCheckpoint,
|
|
21
|
+
isContextOverflowError,
|
|
22
|
+
CHECKPOINT_MARKER,
|
|
23
|
+
SUMMARY_TEMPLATE,
|
|
24
|
+
type CompactTranscriptOptions,
|
|
25
|
+
type ShouldCompactInput,
|
|
26
|
+
type CompressibleMessage,
|
|
27
|
+
} from "@theokit/sdk/compaction";
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Pre-call gate — `estimateTokens` + `shouldCompact`
|
|
31
|
+
|
|
32
|
+
`estimateTokens` is a tokenizer-free `ceil(text.length / 4)` heuristic — a cheap
|
|
33
|
+
gate, NOT exact tokenization. `shouldCompact` is pure: the caller supplies the
|
|
34
|
+
model's window.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const estimated = estimateTokens(transcript.map((m) => m.content).join("\n"));
|
|
38
|
+
|
|
39
|
+
const input: ShouldCompactInput = {
|
|
40
|
+
estimated,
|
|
41
|
+
contextWindow: 200_000,
|
|
42
|
+
buffer: 8_000, // headroom to reserve (output + safety margin)
|
|
43
|
+
maxOutput: 4_000, // optional; separate response reservation (default 0)
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (shouldCompact(input)) {
|
|
47
|
+
// compact before sending — see below
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## `compactTranscript` — summarize the older window
|
|
52
|
+
|
|
53
|
+
Default `keepRecent` mode keeps the last N turns verbatim (default 6) and
|
|
54
|
+
preserves leading system prompts. The older window is summarized via the
|
|
55
|
+
caller-supplied `summarize` callback (or dropped if omitted). With `failSafe`, a
|
|
56
|
+
thrown summarizer returns the ORIGINAL transcript instead of propagating.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const opts: CompactTranscriptOptions = {
|
|
60
|
+
keepRecent: 6, // OR keepTokens: 40_000 (token-budget mode, takes precedence)
|
|
61
|
+
failSafe: true,
|
|
62
|
+
summarize: async (older: CompressibleMessage[], template: string) => {
|
|
63
|
+
// template is SUMMARY_TEMPLATE unless overridden via summaryTemplate
|
|
64
|
+
const summary = await callYourModel(template, older);
|
|
65
|
+
return { role: "system", content: summary };
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const compacted = await compactTranscript(transcript, opts);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Checkpoints — mark and filter
|
|
73
|
+
|
|
74
|
+
`buildCheckpoint` produces a `system` turn whose content starts with
|
|
75
|
+
`CHECKPOINT_MARKER`. `filterFromLatestCheckpoint` returns turns relative to the
|
|
76
|
+
most recent marker (`include: "after"` excludes it — the default; `"from"`
|
|
77
|
+
includes it).
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const marked = [...transcript, buildCheckpoint("milestone: tests green")];
|
|
81
|
+
|
|
82
|
+
const recent = filterFromLatestCheckpoint(marked); // after (exclusive)
|
|
83
|
+
const withHead = filterFromLatestCheckpoint(marked, { include: "from" });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Context-overflow detection
|
|
87
|
+
|
|
88
|
+
`isContextOverflowError` is `true` only for a `TheokitAgentError` reporting the
|
|
89
|
+
typed `context_too_long` code — never a brittle message regex.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
try {
|
|
93
|
+
await agent.send(prompt);
|
|
94
|
+
} catch (err) {
|
|
95
|
+
if (isContextOverflowError(err)) {
|
|
96
|
+
const compacted = await compactTranscript(transcript, { keepRecent: 4 });
|
|
97
|
+
// retry with the compacted transcript
|
|
98
|
+
} else {
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
user-invocable: false
|
|
3
|
+
description: Bound in-process parallelism with Semaphore.create and mapWithConcurrency from @theokit/sdk/concurrency.
|
|
4
|
+
paths:
|
|
5
|
+
- "**/*concurren*"
|
|
6
|
+
- "**/*semaphore*"
|
|
7
|
+
- "**/*Semaphore*"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TheoKit SDK -- Concurrency
|
|
11
|
+
|
|
12
|
+
In-house concurrency helpers (no `p-limit`/`p-map` dependency). `Semaphore.create(permits)` builds an N-permit async counting gate; `mapWithConcurrency` runs an async mapper over items with bounded parallelism while preserving input order.
|
|
13
|
+
|
|
14
|
+
## Import
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Semaphore, mapWithConcurrency } from "@theokit/sdk/concurrency";
|
|
18
|
+
import type { AsyncSemaphore } from "@theokit/sdk/concurrency";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Signatures
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
class Semaphore {
|
|
25
|
+
static create(permits: number): AsyncSemaphore; // canonical factory (ADR 0015)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface AsyncSemaphore {
|
|
29
|
+
acquire(): Promise<() => void>; // returns a release fn; call it exactly once
|
|
30
|
+
inFlight(): number; // permits currently held
|
|
31
|
+
pending(): number; // in-flight + queued waiters
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function mapWithConcurrency<T, R>(
|
|
35
|
+
items: ReadonlyArray<T>,
|
|
36
|
+
concurrency: number, // positive integer; validated
|
|
37
|
+
fn: (item: T, index: number, signal: AbortSignal) => Promise<R>,
|
|
38
|
+
options?: { signal?: AbortSignal },
|
|
39
|
+
): Promise<R[]>; // ordered; fail-fast; throws ConfigurationError on bad concurrency
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Semaphore -- release in a finally
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const sem = Semaphore.create(4); // at most 4 in flight
|
|
46
|
+
|
|
47
|
+
async function guarded<T>(task: () => Promise<T>): Promise<T> {
|
|
48
|
+
const release = await sem.acquire();
|
|
49
|
+
try {
|
|
50
|
+
return await task();
|
|
51
|
+
} finally {
|
|
52
|
+
release(); // release exactly once (idempotent, but leaking it consumes a permit)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## mapWithConcurrency -- ordered bounded map
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const controller = new AbortController();
|
|
61
|
+
const results = await mapWithConcurrency(
|
|
62
|
+
["a", "b", "c"],
|
|
63
|
+
2, // max 2 concurrent fetches
|
|
64
|
+
async (url, _index, signal) => (await fetch(url, { signal })).json(),
|
|
65
|
+
{ signal: controller.signal },
|
|
66
|
+
);
|
|
67
|
+
// results align with input order; rejects on the first task error
|
|
68
|
+
```
|