create-theokit 1.4.0 → 1.5.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/package.json +1 -1
- package/templates/default/agents/chat.ts +11 -16
- package/templates/default/agents/prompts/instructions.ts +10 -0
- package/templates/default/agents/skills/getting-started.md +8 -7
- package/templates/default/agents/{_tools → tools}/weather.ts +2 -2
- package/templates/default/docs/ARCHITECTURE.md +21 -18
- package/templates/default/docs/CUSTOMIZATION.md +5 -5
- package/templates/default/package.json.tmpl +1 -1
- package/templates/default/agents/_lib/instructions.ts +0 -15
package/package.json
CHANGED
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
import { agent } from '@theokit/agents'
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
|
|
4
|
-
import { BASE_INSTRUCTIONS } from './
|
|
5
|
-
import { weatherTool } from './
|
|
4
|
+
import { BASE_INSTRUCTIONS } from './prompts/instructions.js'
|
|
5
|
+
import { weatherTool } from './tools/weather.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* The `chat` agent — served at `POST /api/agents/chat` and bound by `useAgent('chat')`. This file IS the
|
|
9
|
+
* agent; it composes its neighbours under `agents/`: the persona in `prompts/`, capabilities in `tools/`,
|
|
10
|
+
* procedures in `skills/`. Those folders are that concern, NOT extra routes — the framework's scanner
|
|
11
|
+
* treats `prompts/ tools/ skills/ lib/ …` as semantic folders, so `agents/tools/weather.ts` never becomes
|
|
12
|
+
* a `/api/agents/tools/weather` endpoint. Add a second agent as another `agents/<name>.ts`. See
|
|
13
|
+
* `docs/ARCHITECTURE.md`.
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* session (the SDK owns storage).
|
|
14
|
-
*
|
|
15
|
-
* Provider: resolved from the environment — OPENROUTER_API_KEY (preferred — gateway to many
|
|
16
|
-
* models) OR ANTHROPIC_API_KEY / OPENAI_API_KEY. The `model` id is prefixed with the provider
|
|
17
|
-
* namespace so OpenRouter routes it upstream (see https://openrouter.ai/models).
|
|
18
|
-
*
|
|
19
|
-
* The agent is composed from its neighbours (see `docs/ARCHITECTURE.md`): the persona lives in
|
|
20
|
-
* `agents/_lib/instructions.ts` and tools in `agents/_tools/` (both underscore-prefixed so the
|
|
21
|
-
* route scanner skips them). Add a tool with `tool('name')…build()` and chain it via `.tool(...)`;
|
|
22
|
-
* add a skill as `agents/skills/<name>.md`.
|
|
15
|
+
* `@theokit/sdk` runs the agent; conversation turns auto-persist per session. Provider is resolved from
|
|
16
|
+
* the environment — OPENROUTER_API_KEY (preferred) OR ANTHROPIC_API_KEY / OPENAI_API_KEY; the model id is
|
|
17
|
+
* provider-prefixed so OpenRouter routes it upstream (https://openrouter.ai/models).
|
|
23
18
|
*/
|
|
24
19
|
export default agent()
|
|
25
20
|
.input(z.object({ message: z.string() }))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `chat` agent's system prompt (persona + rules). Lives in `prompts/` — a semantic sub-folder the
|
|
3
|
+
* framework's agent scanner skips, so it never becomes a route. Grow the persona here instead of inlining
|
|
4
|
+
* a long string in `index.ts`.
|
|
5
|
+
*/
|
|
6
|
+
export const BASE_INSTRUCTIONS = `You are a helpful assistant living inside a TheoKit app.
|
|
7
|
+
|
|
8
|
+
- Answer clearly and concisely.
|
|
9
|
+
- When the user asks about current weather, call the \`weather\` tool instead of guessing.
|
|
10
|
+
- If you are unsure, say so rather than inventing an answer.`
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
# Getting started
|
|
2
2
|
|
|
3
3
|
A **skill** is a Markdown file that documents a repeatable task for your agent — a recipe it (and you) can
|
|
4
|
-
follow. Skills live in `
|
|
5
|
-
|
|
4
|
+
follow. Skills live in the agent's `skills/` folder and are plain `.md`; reference them from your prompt or
|
|
5
|
+
load them into context as your app grows.
|
|
6
6
|
|
|
7
|
-
This example
|
|
7
|
+
This example documents the scaffold itself:
|
|
8
8
|
|
|
9
9
|
## Answer a question
|
|
10
10
|
|
|
11
11
|
1. Read the user's message.
|
|
12
|
-
2. If it needs live weather, call the `weather` tool (see
|
|
12
|
+
2. If it needs live weather, call the `weather` tool (see `../tools/weather.ts`).
|
|
13
13
|
3. Otherwise answer directly, concisely.
|
|
14
14
|
|
|
15
|
-
## Add a capability
|
|
15
|
+
## Add a capability to this agent
|
|
16
16
|
|
|
17
|
-
- **A tool** (an action the agent can take) → `agents/
|
|
17
|
+
- **A tool** (an action the agent can take) → `agents/tools/<name>.ts`, then `.tool(<name>Tool)` in
|
|
18
18
|
`agents/chat.ts`.
|
|
19
19
|
- **A skill** (a documented procedure) → a new `agents/skills/<name>.md` like this one.
|
|
20
|
-
- **The persona / rules** → edit `agents/
|
|
20
|
+
- **The persona / rules** → edit `agents/prompts/instructions.ts`.
|
|
21
|
+
- **A whole new agent** → a new folder `agents/<name>/index.ts` → served at `/api/agents/<name>`.
|
|
@@ -5,8 +5,8 @@ import { z } from 'zod'
|
|
|
5
5
|
* An example agent tool — current weather for a place, via the keyless open-meteo API.
|
|
6
6
|
*
|
|
7
7
|
* A tool is PURE metadata + a handler: it describes a capability and runs local/HTTP work; it NEVER calls
|
|
8
|
-
* an LLM (the agent decides when to invoke it). Lives in `
|
|
9
|
-
*
|
|
8
|
+
* an LLM (the agent decides when to invoke it). Lives in `tools/` — a semantic sub-folder the agent
|
|
9
|
+
* scanner skips — and is imported into `chat.ts` and chained with `.tool(weatherTool)`.
|
|
10
10
|
*
|
|
11
11
|
* Add your own the same way: `tool('name').describe(...).input(z.object({...})).execute(async (input) => …).build()`.
|
|
12
12
|
*/
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
# Architecture
|
|
2
2
|
|
|
3
|
-
How this TheoKit app is organized. The layout puts the **agent at the center
|
|
4
|
-
|
|
3
|
+
How this TheoKit app is organized. The layout puts the **agent at the center**: the agent file and the
|
|
4
|
+
folders it composes (prompts, tools, skills) live together under `agents/`, with clean names — the
|
|
5
|
+
"file = identity" convention agent frameworks like [Eve](https://eve.dev) use.
|
|
5
6
|
|
|
6
7
|
## Project structure
|
|
7
8
|
|
|
8
9
|
```
|
|
9
10
|
.
|
|
10
|
-
├── agents/ # The agent
|
|
11
|
-
│ ├── chat.ts # the agent
|
|
12
|
-
│ ├──
|
|
13
|
-
│ │ └── instructions.ts
|
|
14
|
-
│ ├──
|
|
15
|
-
│ │ └── weather.ts #
|
|
11
|
+
├── agents/ # The agent, and what composes it
|
|
12
|
+
│ ├── chat.ts # the agent → POST /api/agents/chat, useAgent('chat')
|
|
13
|
+
│ ├── prompts/ # system prompts / personas
|
|
14
|
+
│ │ └── instructions.ts
|
|
15
|
+
│ ├── tools/ # tools the agent can call
|
|
16
|
+
│ │ └── weather.ts # tool('weather')…build()
|
|
16
17
|
│ └── skills/ # Markdown procedures the agent (and you) can follow
|
|
17
18
|
│ └── getting-started.md
|
|
18
19
|
├── app/ # Frontend (web surface). tui → tui/, desktop → frontend/
|
|
@@ -24,13 +25,14 @@ between the agent, the backend, the frontend, and cross-layer code.
|
|
|
24
25
|
└── theo.config.ts # App config (name, dirs, plugins)
|
|
25
26
|
```
|
|
26
27
|
|
|
27
|
-
##
|
|
28
|
+
## Clean names, no phantom routes
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
An agent is a file: `agents/<name>.ts` → `POST /api/agents/<name>`. But the framework's scanner is
|
|
31
|
+
**folder-semantic** — the conventional sub-folders under `agents/` (`prompts/`, `tools/`, `skills/`,
|
|
32
|
+
`lib/`, `hooks/`, `channels/`, `connections/`, `subagents/`, `schedules/`) are **that concern, not routes**.
|
|
33
|
+
So the names stay clean (`tools/`, not `_tools/`) and `agents/tools/weather.ts` never becomes a phantom
|
|
34
|
+
`/api/agents/tools/weather` endpoint. Markdown (`skills/*.md`) is never scanned either way. The
|
|
35
|
+
prompts/tools/skills are **shared** across every agent in `agents/`.
|
|
34
36
|
|
|
35
37
|
## Composition
|
|
36
38
|
|
|
@@ -40,13 +42,14 @@ folders). `skills/` needs no underscore because Markdown is never scanned.
|
|
|
40
42
|
export default agent()
|
|
41
43
|
.input(z.object({ message: z.string() }))
|
|
42
44
|
.model('openai/gpt-4o-mini')
|
|
43
|
-
.system(BASE_INSTRUCTIONS) // agents/
|
|
44
|
-
.tool(weatherTool) // agents/
|
|
45
|
+
.system(BASE_INSTRUCTIONS) // agents/prompts/instructions.ts
|
|
46
|
+
.tool(weatherTool) // agents/tools/weather.ts
|
|
45
47
|
.build()
|
|
46
48
|
```
|
|
47
49
|
|
|
48
|
-
Grow the agent by editing its neighbours, not by inflating `chat.ts`: persona → `
|
|
49
|
-
a new capability → `
|
|
50
|
+
Grow the agent by editing its neighbours, not by inflating `chat.ts`: persona → `prompts/instructions.ts`,
|
|
51
|
+
a new capability → `tools/<name>.ts` (then `.tool(<name>Tool)`), a documented procedure →
|
|
52
|
+
`skills/<name>.md`. Add a **second agent** as another `agents/<name>.ts`.
|
|
50
53
|
|
|
51
54
|
## Surfaces
|
|
52
55
|
|
|
@@ -5,18 +5,18 @@ Common changes, and where they go. See [ARCHITECTURE](./ARCHITECTURE.md) for the
|
|
|
5
5
|
| I want to… | Edit |
|
|
6
6
|
|------------|------|
|
|
7
7
|
| Change the model | `agents/chat.ts` (`.model(...)`) + the label in `shared/agent.ts` |
|
|
8
|
-
| Change the persona / rules | `agents/
|
|
9
|
-
| Add a tool (an action the agent can take) | new `agents/
|
|
8
|
+
| Change the persona / rules | `agents/prompts/instructions.ts` |
|
|
9
|
+
| Add a tool (an action the agent can take) | new `agents/tools/<name>.ts`, then `.tool(<name>Tool)` in `agents/chat.ts` |
|
|
10
10
|
| Add a skill (a documented procedure) | new `agents/skills/<name>.md` |
|
|
11
|
-
| Change the greeting / app name | `shared/agent.ts` |
|
|
12
11
|
| Add a second agent | new `agents/<name>.ts` → auto-served at `/api/agents/<name>`, bind with `useAgent('<name>')` |
|
|
12
|
+
| Change the greeting / app name | `shared/agent.ts` |
|
|
13
13
|
| Add a backend route | `server/routes/<name>.ts` |
|
|
14
14
|
| Change the provider key | `.env` — `OPENROUTER_API_KEY` (or `ANTHROPIC_API_KEY` / `OPENAI_API_KEY`). See [ENVIRONMENT](./ENVIRONMENT.md) |
|
|
15
15
|
|
|
16
16
|
## Adding a tool
|
|
17
17
|
|
|
18
18
|
```ts
|
|
19
|
-
// agents/
|
|
19
|
+
// agents/tools/echo.ts
|
|
20
20
|
import { tool } from 'theokit/server'
|
|
21
21
|
import { z } from 'zod'
|
|
22
22
|
|
|
@@ -29,7 +29,7 @@ export const echoTool = tool('echo')
|
|
|
29
29
|
|
|
30
30
|
```ts
|
|
31
31
|
// agents/chat.ts
|
|
32
|
-
import { echoTool } from './
|
|
32
|
+
import { echoTool } from './tools/echo.js'
|
|
33
33
|
// …
|
|
34
34
|
.tool(weatherTool)
|
|
35
35
|
.tool(echoTool) // chain as many as you need
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The agent's base system prompt.
|
|
3
|
-
*
|
|
4
|
-
* Kept in `agents/_lib/` (an underscore-prefixed folder) so the framework's `agents/*` route scanner
|
|
5
|
-
* skips it — only real agents like `agents/chat.ts` become `POST /api/agents/<name>` endpoints. Import
|
|
6
|
-
* this into an agent's `.system(...)`; grow it here (persona, guardrails, tool guidance) instead of
|
|
7
|
-
* inlining a long string in the agent file.
|
|
8
|
-
*/
|
|
9
|
-
import { AGENT } from '../../shared/agent.js'
|
|
10
|
-
|
|
11
|
-
export const BASE_INSTRUCTIONS = `You are ${AGENT.name}, a helpful assistant living inside a TheoKit app.
|
|
12
|
-
|
|
13
|
-
- Answer clearly and concisely.
|
|
14
|
-
- When the user asks about current weather, call the \`weather\` tool instead of guessing.
|
|
15
|
-
- If you are unsure, say so rather than inventing an answer.`
|