wolli 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -24
- package/built-in/plugins/discord/discord-chat.ts +47 -84
- package/built-in/plugins/discord/index.ts +139 -97
- package/built-in/plugins/discord/package.json +2 -2
- package/built-in/plugins/scheduler/cron.ts +131 -0
- package/built-in/plugins/scheduler/index.ts +147 -151
- package/built-in/plugins/scheduler/package.json +3 -2
- package/built-in/plugins/scheduler/scheduler-due.ts +22 -0
- package/built-in/plugins/telegram/README.md +3 -3
- package/built-in/plugins/telegram/index.ts +177 -139
- package/built-in/plugins/telegram/package.json +2 -2
- package/built-in/plugins/telegram/telegram-chat.ts +79 -155
- package/dist/cli.js +5696 -5841
- package/docs/hooks.md +103 -0
- package/docs/index.md +10 -8
- package/docs/integrations.md +78 -663
- package/docs/introduction.md +95 -0
- package/docs/plugins.md +43 -36
- package/docs/providers.md +63 -0
- package/docs/sdk.md +42 -47
- package/docs/tools.md +81 -0
- package/docs/workflows.md +170 -0
- package/package.json +1 -1
- package/built-in/plugins/scheduler/scheduler-chat.ts +0 -164
- package/docs/extensions.md +0 -2331
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Introduction
|
|
2
|
+
|
|
3
|
+
How a wolli agent is laid out as files, what runs when a message arrives, and the capabilities you add as it grows.
|
|
4
|
+
|
|
5
|
+
wolli runs durable personal agents as always-on daemons; each agent is a home directory of ordinary files that you and the agent both edit.
|
|
6
|
+
|
|
7
|
+
Instead of one large configuration object, each capability gets a clear home. Identity lives in one file, workflows in one folder, integrations in another. wolli discovers that structure and turns it into an agent that remembers across sessions, reacts to events, and keeps working while your machine is on. Clients (the CLI, the TUI) attach to the daemon over HTTP.
|
|
8
|
+
|
|
9
|
+
## An agent home at a glance
|
|
10
|
+
|
|
11
|
+
Every agent lives under `~/.wolli/agents/<name>/`:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
~/.wolli/agents/<name>/
|
|
15
|
+
├── SOUL.md
|
|
16
|
+
├── MEMORY.md
|
|
17
|
+
├── agent.json
|
|
18
|
+
├── integrations/
|
|
19
|
+
│ └── telegram.ts
|
|
20
|
+
├── workflows/
|
|
21
|
+
│ └── telegram-chat.ts
|
|
22
|
+
├── hooks/
|
|
23
|
+
├── tools/
|
|
24
|
+
├── providers/
|
|
25
|
+
├── skills/
|
|
26
|
+
├── prompts/
|
|
27
|
+
├── themes/
|
|
28
|
+
└── sessions/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
You can read most of an agent from that tree:
|
|
32
|
+
|
|
33
|
+
- `SOUL.md` and `MEMORY.md` hold identity and durable notes; the agent maintains both.
|
|
34
|
+
- `agent.json` holds runtime configuration.
|
|
35
|
+
- [integrations/](./integrations.md) connect external services (Telegram, a scheduler); transport only.
|
|
36
|
+
- [workflows/](./workflows.md) route events into sessions and automate everything else.
|
|
37
|
+
- [hooks/](./hooks.md) intercept engine events: block tool calls, rewrite input.
|
|
38
|
+
- [tools/](./tools.md) hold typed functions loaded into session tooling.
|
|
39
|
+
- [providers/](./providers.md) add model providers.
|
|
40
|
+
- [skills/](./skills.md) hold procedures the model loads when they apply.
|
|
41
|
+
- `prompts/` holds `/name` text macros, and `themes/` holds TUI color schemes.
|
|
42
|
+
- `sessions/` is the agent's lifetime conversation record.
|
|
43
|
+
|
|
44
|
+
A new agent needs none of the capability folders. wolli writes `SOUL.md` with you in the first conversation; add the rest when the agent needs them.
|
|
45
|
+
|
|
46
|
+
## The files are the interface
|
|
47
|
+
|
|
48
|
+
Identity comes from the path. A workflow's name is its export binding — a `default` export takes the filename — and a file may hold several. This file defines a workflow named `inbound`:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// ~/.wolli/agents/assistant/workflows/telegram-chat.ts
|
|
52
|
+
import telegram from "../integrations/telegram";
|
|
53
|
+
|
|
54
|
+
// msg is typed from the event schema
|
|
55
|
+
export const inbound = telegram.on("message", async (msg, ctx) => {
|
|
56
|
+
const [match] = await ctx.agent.findSessions({ "telegram:chat": String(msg.chatId) });
|
|
57
|
+
const session = await ctx.agent.openSession(match.id); // create-if-missing elided
|
|
58
|
+
await session.sendUserMessage(msg.text, { deliverAs: "followUp" });
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
There is no registry to keep in sync. Add the file and wolli discovers it; run `/reload` to apply the change without restarting the daemon. See [Workflows](./workflows.md) for the complete API.
|
|
63
|
+
|
|
64
|
+
## What happens when a message arrives
|
|
65
|
+
|
|
66
|
+
A Telegram message lands in the integration's transport loop, which emits a typed `message` event. A workflow bound to that event finds the chat's session by tag, or creates one, and sends the text in. The agent runs the turn, calling tools as it works. When the turn ends, a second workflow fires on `agent_end`, reads the chat tag off the session, and delivers the reply through the integration.
|
|
67
|
+
|
|
68
|
+
The session does not know which platform asked. Replies ride the session's tags, so a turn the scheduler triggers in a Telegram-tagged session still returns to that chat.
|
|
69
|
+
|
|
70
|
+
## Sessions are durable
|
|
71
|
+
|
|
72
|
+
A session is an append-only JSONL tree, the lifetime record of one conversation. Nothing is rewritten; wolli reconstructs context deterministically from the log, and the latest leaf resumes by default. The daemon restarts, the machine reboots, and every conversation survives.
|
|
73
|
+
|
|
74
|
+
Workflow activity is recorded the same way. Each trigger firing creates a run, and everything the handler does through its context lands in that run as a step, so you can inspect what fired and what it did.
|
|
75
|
+
|
|
76
|
+
## Grow the agent by adding capabilities
|
|
77
|
+
|
|
78
|
+
As the agent grows, each concern keeps a predictable home:
|
|
79
|
+
|
|
80
|
+
| Path | Add it when you need... |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| [providers/](./providers.md) | A model provider wolli does not ship |
|
|
83
|
+
| [skills/](./skills.md) | Procedures the model loads on demand |
|
|
84
|
+
| `prompts/` | Reusable `/name` text macros |
|
|
85
|
+
| `themes/` | A custom TUI color scheme |
|
|
86
|
+
| `store/` | Durable key-value state an integration owns |
|
|
87
|
+
|
|
88
|
+
The home is plain files, so the agent can author them itself; an agent that needs a new workflow writes one into its own folder. The directory stays readable before it runs.
|
|
89
|
+
|
|
90
|
+
## What to read next
|
|
91
|
+
|
|
92
|
+
- [Workflows](./workflows.md): triggers, routing, and the run and step record.
|
|
93
|
+
- [Integrations](./integrations.md): transports, typed events, and actions.
|
|
94
|
+
- [Tools](./tools.md): typed functions the model calls.
|
|
95
|
+
- [Plugins](./plugins.md): package and install capabilities.
|
package/docs/plugins.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Plugins
|
|
2
2
|
|
|
3
|
-
A plugin is an npm-style package whose `package.json` carries a `"wolli"` manifest declaring the resources it contributes
|
|
3
|
+
A plugin is an npm-style package whose `package.json` carries a `"wolli"` manifest declaring the resources it contributes: integrations, workflows, hooks, tools, providers, skills, prompt templates, and/or themes. One install adds all of them to an agent at once, resolved in place from the single package. Plugins are how you share a channel (an [integration](./integrations.md) plus the [workflows](./workflows.md) that route it), a set of [tools](./tools.md), or any mix of resource types between agents and across machines.
|
|
4
4
|
|
|
5
5
|
> **Per-agent, not global.** Wolli has no project scope. A plugin is installed for one agent and lands in that agent's own home (`~/.wolli/agents/<name>/`). The agent name precedes every verb: `wolli <agent> plugins install <source>`.
|
|
6
6
|
|
|
7
|
-
> **Security:** Plugins run with full host access.
|
|
7
|
+
> **Security:** Plugins run with full host access. Integrations, workflows, hooks, tools, and providers execute arbitrary code inside the agent process, and skills can instruct the model to take any action. Review a plugin's source before installing a third-party package.
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
10
10
|
|
|
@@ -23,13 +23,16 @@ A plugin is an npm-style package whose `package.json` carries a `"wolli"` manife
|
|
|
23
23
|
|
|
24
24
|
A plugin is a directory (or published package) with a `package.json` whose `"wolli"` field names the contribution files. Each listed path is a normal source module loaded by the agent's resource loader at launch:
|
|
25
25
|
|
|
26
|
-
- **integrations** — transport modules
|
|
27
|
-
- **
|
|
26
|
+
- **integrations** — transport modules default-exporting `defineIntegration` (see [integrations.md](./integrations.md)).
|
|
27
|
+
- **workflows** — routing and automation modules default-exporting `defineWorkflow` (see [workflows.md](./workflows.md)).
|
|
28
|
+
- **hooks** — interception modules default-exporting `defineHook` (see [hooks.md](./hooks.md)).
|
|
29
|
+
- **tools** — tool modules default-exporting `defineTool` (see [tools.md](./tools.md)).
|
|
30
|
+
- **providers** — model provider modules default-exporting `defineProvider` (see [providers.md](./providers.md)).
|
|
28
31
|
- **skills** — `SKILL.md` (or top-level `.md`) instruction files (see [skills.md](./skills.md)).
|
|
29
32
|
- **prompts** — `.md` prompt templates (see [prompt-templates.md](./prompt-templates.md)).
|
|
30
33
|
- **themes** — `.json` theme files (see [themes.md](./themes.md)).
|
|
31
34
|
|
|
32
|
-
A plugin may declare any subset. The common case is a
|
|
35
|
+
A plugin may declare any subset. The common case is a channel plugin that bundles a transport under `"integrations"` with its routing files under `"workflows"`, so they install and version as one unit; for a single agent you can instead place the files directly in its `integrations/` and `workflows/` folders without a plugin. In a plugin, everything resolves from the one install — nothing is copied into the agent's folders; the files load in place from the package (see [How Resolution Works](#how-resolution-works)).
|
|
33
36
|
|
|
34
37
|
## Where Plugins Install
|
|
35
38
|
|
|
@@ -50,7 +53,7 @@ A plugin may declare any subset. The common case is a single plugin that bundles
|
|
|
50
53
|
- `git:` sources are cloned to `<store>/git/<host>/<user>/<repo>`; if the clone has a `package.json`, dependencies are installed there.
|
|
51
54
|
- Local sources are copied (not symlinked) to `<store>/local/<basename-slug>-<sha256-prefix>`, so the install travels even if the origin moves; dependencies install in the copy.
|
|
52
55
|
|
|
53
|
-
The agent's discovery dirs (`~/.wolli/agents/<name>/
|
|
56
|
+
The agent's discovery dirs (`~/.wolli/agents/<name>/integrations/`, `workflows/`, `tools/`, etc.) are for hand-placed local resources. Installed plugins are **not** unpacked into those dirs — they stay in `.plugins/` and are resolved from there.
|
|
54
57
|
|
|
55
58
|
## The package.json `wolli` Manifest
|
|
56
59
|
|
|
@@ -59,7 +62,10 @@ The plugin manager reads `package.json` and parses exactly the `"wolli"` object.
|
|
|
59
62
|
| Key | Loaded as | File pattern |
|
|
60
63
|
|----------------|-----------------|-------------------------------|
|
|
61
64
|
| `integrations` | integration modules | `.ts` / `.js` |
|
|
62
|
-
| `
|
|
65
|
+
| `workflows` | workflow modules | `.ts` / `.js` |
|
|
66
|
+
| `hooks` | hook modules | `.ts` / `.js` |
|
|
67
|
+
| `tools` | tool modules | `.ts` / `.js` |
|
|
68
|
+
| `providers` | provider modules | `.ts` / `.js` |
|
|
63
69
|
| `skills` | skills | `SKILL.md` / `.md` |
|
|
64
70
|
| `prompts` | prompt templates | `.md` |
|
|
65
71
|
| `themes` | themes | `.json` |
|
|
@@ -74,14 +80,14 @@ Example manifest (modeled on the shipped Telegram plugin; see the [worked exampl
|
|
|
74
80
|
"type": "module",
|
|
75
81
|
"wolli": {
|
|
76
82
|
"integrations": ["./index.ts"],
|
|
77
|
-
"
|
|
83
|
+
"workflows": ["./telegram-chat.ts"]
|
|
78
84
|
},
|
|
79
85
|
"dependencies": {
|
|
80
86
|
"grammy": "1.44.0",
|
|
81
87
|
"@grammyjs/runner": "2.0.3"
|
|
82
88
|
},
|
|
83
89
|
"peerDependencies": {
|
|
84
|
-
"
|
|
90
|
+
"wolli": "*"
|
|
85
91
|
}
|
|
86
92
|
}
|
|
87
93
|
```
|
|
@@ -92,7 +98,7 @@ The simplest manifest lists one plain single-file path per key — a flat packag
|
|
|
92
98
|
{
|
|
93
99
|
"wolli": {
|
|
94
100
|
"integrations": ["./index.ts"],
|
|
95
|
-
"
|
|
101
|
+
"workflows": ["./x.ts"]
|
|
96
102
|
}
|
|
97
103
|
}
|
|
98
104
|
```
|
|
@@ -102,39 +108,40 @@ Plain single-file path entries are **first-class**; globs and override prefixes
|
|
|
102
108
|
**Notes:**
|
|
103
109
|
|
|
104
110
|
- Paths are relative to the package root and resolved against it. An entry is one of three things:
|
|
105
|
-
- a **plain path** — a single file (`./index.ts`) loaded as-is, or a **directory**, which is then collected for that resource type. Directories collect by the type's file pattern (`.md` for skills/prompts, `.json` for themes); for `integrations
|
|
106
|
-
- a **glob** (contains `*` or `?`, e.g. `
|
|
111
|
+
- a **plain path** — a single file (`./index.ts`) loaded as-is, or a **directory**, which is then collected for that resource type. Directories collect by the type's file pattern (`.md` for skills/prompts, `.json` for themes); for the module types (`integrations`, `workflows`, `hooks`, `tools`, `providers`) the directory is collected with the same package-style discovery as a convention dir (an `index.ts`/`index.js` or nested `package.json` manifest per subdir, **not** a flat sweep of every `.ts`).
|
|
112
|
+
- a **glob** (contains `*` or `?`, e.g. `workflows/*.ts`) — expanded against the package root, then each match collected as above.
|
|
107
113
|
- an **override prefix** (`!exclude`, `+force-include`, `-force-exclude`) — not a source itself; it layers on top of the paths the plain/glob entries already produced. `!` removes matches, `+` adds an exact path back even if excluded, `-` removes an exact path even if force-included.
|
|
108
114
|
When an entry resolves to a directory (or a glob matches one), only files matching the resource type's pattern are picked up; a plain entry pointing straight at a single file is taken as-is, so list each file under its correct key.
|
|
109
|
-
- If no `"wolli"` manifest is present, the manager falls back to convention directories — `
|
|
110
|
-
- Third-party runtime deps (here `grammy`; `croner` in the scheduler plugin) go in `dependencies` and are installed automatically when the plugin is fetched. `"dependencies"` is **optional** and may be omitted entirely when the transport relies only on Node globals — a transport that talks to a plain HTTP endpoint can call `fetch` directly with no bundled client
|
|
115
|
+
- If no `"wolli"` manifest is present, the manager falls back to convention directories — `integrations/`, `workflows/`, `hooks/`, `tools/`, `providers/`, `skills/`, `prompts/`, `themes/` — and auto-discovers files there.
|
|
116
|
+
- Third-party runtime deps (here `grammy`; `croner` in the scheduler plugin) go in `dependencies` and are installed automatically when the plugin is fetched. `"dependencies"` is **optional** and may be omitted entirely when the transport relies only on Node globals — a transport that talks to a plain HTTP endpoint can call `fetch` directly with no bundled client. Bundling a client library is only needed for richer protocols.
|
|
111
117
|
|
|
112
|
-
### Why peerDependencies on
|
|
118
|
+
### Why peerDependencies on `wolli`
|
|
113
119
|
|
|
114
|
-
Contribution modules import host
|
|
120
|
+
Contribution modules import the host's definer helpers from `wolli` (`defineIntegration`, `defineWorkflow`, `defineHook`, `defineTool`, `defineProvider`). The host process *provides* that package at runtime, so the plugin must not bundle its own copy. Declare it as a peer with a `"*"` range:
|
|
115
121
|
|
|
116
122
|
```json
|
|
117
|
-
{ "peerDependencies": { "
|
|
123
|
+
{ "peerDependencies": { "wolli": "*" } }
|
|
118
124
|
```
|
|
119
125
|
|
|
120
126
|
Managed installs are run with peer resolution disabled (`--legacy-peer-deps` and equivalents), so the package manager does not try to install or solve this host-provided peer. The agent resolves it from the host at load time instead.
|
|
121
127
|
|
|
122
128
|
## Authoring a Plugin
|
|
123
129
|
|
|
124
|
-
Lay the package out as a normal npm package. A
|
|
130
|
+
Lay the package out as a normal npm package. A channel plugin looks like:
|
|
125
131
|
|
|
126
132
|
```
|
|
127
133
|
my-plugin/
|
|
128
134
|
├── package.json # name, type: "module", "wolli" manifest, deps, peerDependencies
|
|
129
135
|
├── index.ts # the integration transport (listed under "integrations")
|
|
130
|
-
├── my-
|
|
136
|
+
├── my-inbound.ts # routing workflow (listed under "workflows")
|
|
137
|
+
├── my-reply.ts # reply workflow (listed under "workflows")
|
|
131
138
|
└── README.md
|
|
132
139
|
```
|
|
133
140
|
|
|
134
|
-
1. **Write the contribution files.** Author the transport
|
|
141
|
+
1. **Write the contribution files.** Author the transport per [integrations.md](./integrations.md) and the routing per [workflows.md](./workflows.md). This doc does not duplicate their authoring guidance; it only packages them.
|
|
135
142
|
2. **Declare them in the manifest.** List each file under the matching `"wolli"` key (above).
|
|
136
143
|
3. **Set `"type": "module"`** so `.ts`/`.js` modules load as ESM.
|
|
137
|
-
4. **Put runtime deps in `dependencies`** and
|
|
144
|
+
4. **Put runtime deps in `dependencies`** and **`wolli` in `peerDependencies`** with `"*"`.
|
|
138
145
|
|
|
139
146
|
That is the whole contract. There is no build step or registration call beyond the manifest — the agent's resource loader imports the listed files at launch.
|
|
140
147
|
|
|
@@ -227,7 +234,7 @@ A plugin entry in settings can be a bare string (load everything) or an object t
|
|
|
227
234
|
"npm:wolli-integration-scheduler",
|
|
228
235
|
{
|
|
229
236
|
"source": "git:github.com/user/repo",
|
|
230
|
-
"
|
|
237
|
+
"workflows": ["*.ts", "!legacy.ts"],
|
|
231
238
|
"skills": []
|
|
232
239
|
}
|
|
233
240
|
]
|
|
@@ -242,13 +249,13 @@ At each launch the resource loader calls the plugin manager's `resolve()`, which
|
|
|
242
249
|
|
|
243
250
|
1. reads the agent's `"plugins"[]` from settings,
|
|
244
251
|
2. for each source, self-heals a missing install (re-fetches if the store entry is gone but the origin still exists),
|
|
245
|
-
3. resolves the contributions **in place** from the install — manifest paths first, then convention dirs,
|
|
252
|
+
3. resolves the contributions **in place** from the install — manifest paths first, then convention dirs,
|
|
246
253
|
4. applies any per-entry filter and name-collision precedence,
|
|
247
|
-
5. hands the enabled paths to the
|
|
254
|
+
5. hands the enabled paths to the per-type resource loaders.
|
|
248
255
|
|
|
249
|
-
Crucially, a
|
|
256
|
+
Crucially, a channel package's integration and its workflows all resolve from the *same* install directory in `.plugins/`. Nothing is copied into the agent's folders. The integration arm loads first so its event descriptors exist before workflows bind them.
|
|
250
257
|
|
|
251
|
-
Because `install`/`remove`/`update` go through the daemon (the single writer), the running agent reloads itself after the change — installed contributions become active without a manual restart. Onboarding-gated
|
|
258
|
+
Because `install`/`remove`/`update` go through the daemon (the single writer), the running agent reloads itself after the change — installed contributions become active without a manual restart. Onboarding-gated services activate once their account is configured.
|
|
252
259
|
|
|
253
260
|
## Worked Example: Packaging the Telegram Integration
|
|
254
261
|
|
|
@@ -256,14 +263,14 @@ The shipped Telegram plugin (`packages/wolli/plugins/telegram/`) is the canonica
|
|
|
256
263
|
|
|
257
264
|
```
|
|
258
265
|
telegram/
|
|
259
|
-
├── package.json
|
|
260
|
-
├── index.ts
|
|
261
|
-
│
|
|
262
|
-
└── telegram-chat.ts
|
|
263
|
-
|
|
266
|
+
├── package.json # "wolli": { integrations: ["./index.ts"], workflows: ["./telegram-chat.ts"] }
|
|
267
|
+
├── index.ts # transport: long-polls grammY, holds the bot token, emits a `message` event,
|
|
268
|
+
│ # exposes sendMessage / startTyping / stopTyping, declares onboard
|
|
269
|
+
└── telegram-chat.ts # workflows: inbound routes each message into a per-chat session by tag
|
|
270
|
+
# (and /commands); typing on agent_start; reply on agent_end
|
|
264
271
|
```
|
|
265
272
|
|
|
266
|
-
Its manifest
|
|
273
|
+
Its manifest:
|
|
267
274
|
|
|
268
275
|
```json
|
|
269
276
|
{
|
|
@@ -273,14 +280,14 @@ Its manifest (verbatim):
|
|
|
273
280
|
"type": "module",
|
|
274
281
|
"wolli": {
|
|
275
282
|
"integrations": ["./index.ts"],
|
|
276
|
-
"
|
|
283
|
+
"workflows": ["./telegram-chat.ts"]
|
|
277
284
|
},
|
|
278
285
|
"dependencies": {
|
|
279
286
|
"grammy": "1.44.0",
|
|
280
287
|
"@grammyjs/runner": "2.0.3"
|
|
281
288
|
},
|
|
282
289
|
"peerDependencies": {
|
|
283
|
-
"
|
|
290
|
+
"wolli": "*"
|
|
284
291
|
}
|
|
285
292
|
}
|
|
286
293
|
```
|
|
@@ -294,6 +301,6 @@ wolli my-agent plugins install ./packages/wolli/plugins/telegram
|
|
|
294
301
|
# -> runs onboard: prompts for the bot token, writes the account to integrations.json
|
|
295
302
|
```
|
|
296
303
|
|
|
297
|
-
|
|
304
|
+
The transport and both workflows resolve from that one copy. The transport starts; once the account is configured, the workflows bind its events and bidirectional chat is live. To package it for others, publish the same directory to npm (`wolli-integration-telegram`) or a git repo and have them install with `npm:` / `git:` instead of the local path.
|
|
298
305
|
|
|
299
|
-
The shipped scheduler plugin
|
|
306
|
+
The shipped scheduler plugin has the same shape with one addition — a transport under `"integrations"`, its `due` routing under `"workflows"`, the agent-facing `cron` tool under `"tools"`, one runtime dep (`croner`), and the same `wolli` peer — confirming the channel pattern is the convention, not Telegram-specific. The only differences are the package name, the dependency, the workflow/tool filenames, and that a scheduler ships a tool the model calls rather than typing indicators.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Providers
|
|
2
|
+
|
|
3
|
+
Add model providers the agent can run on: a proxy, a self-hosted endpoint, or an API wolli does not ship.
|
|
4
|
+
|
|
5
|
+
A provider registers models the agent can run on, beyond the built-in catalog. Use one when the models you want live behind a proxy, a self-hosted endpoint, or a provider wolli does not ship; built-in models need no provider file. Each provider is one file under `providers/` in the agent home, default-exporting `defineProvider`. The provider name comes from the filename. wolli loads providers once at startup; there is no dynamic registration.
|
|
6
|
+
|
|
7
|
+
## Defining a provider
|
|
8
|
+
|
|
9
|
+
A proxy that fronts the Anthropic API and serves one model:
|
|
10
|
+
|
|
11
|
+
`~/.wolli/agents/assistant/providers/my-proxy.ts`
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { defineProvider } from "wolli";
|
|
15
|
+
|
|
16
|
+
export default defineProvider({
|
|
17
|
+
baseUrl: "https://proxy.example.com",
|
|
18
|
+
apiKey: "$PROXY_API_KEY",
|
|
19
|
+
api: "anthropic-messages",
|
|
20
|
+
models: [
|
|
21
|
+
{
|
|
22
|
+
id: "claude-sonnet-4-20250514",
|
|
23
|
+
name: "Claude 4 Sonnet (proxy)",
|
|
24
|
+
reasoning: false,
|
|
25
|
+
input: ["text", "image"],
|
|
26
|
+
// Per-token cost, used for usage tracking; 0 is fine for a proxy.
|
|
27
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
28
|
+
contextWindow: 200000,
|
|
29
|
+
maxTokens: 16384,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
When `models` is set, it replaces any existing models for that provider name, and `baseUrl`, `apiKey`, and `api` become required (`api` at the provider or model level). Each model carries its own `contextWindow` and `maxTokens`, so wolli sizes context and output correctly even when the endpoint is yours.
|
|
36
|
+
|
|
37
|
+
## Credentials
|
|
38
|
+
|
|
39
|
+
`apiKey` accepts three forms. `$PROXY_API_KEY` or `${PROXY_API_KEY}` reads an environment variable, a leading `!` runs a shell command and uses its output (`"!op read op://vault/proxy-key"`), and any other string passes through as a literal key. Do not put raw keys in provider files; reference the environment or a secret manager command instead.
|
|
40
|
+
|
|
41
|
+
For endpoints that expect extra request headers, set `headers`; `authHeader: true` adds an `Authorization: Bearer` header carrying the resolved key.
|
|
42
|
+
|
|
43
|
+
## Overriding an existing provider
|
|
44
|
+
|
|
45
|
+
A file that sets only `baseUrl` redirects an existing provider instead of defining a new one. The filename names the target: `providers/anthropic.ts` overrides the `anthropic` provider, and its built-in models keep their ids, costs, and limits while requests go to the new endpoint. Use this to route traffic through a gateway or a regional mirror.
|
|
46
|
+
|
|
47
|
+
`~/.wolli/agents/assistant/providers/anthropic.ts`
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { defineProvider } from "wolli";
|
|
51
|
+
|
|
52
|
+
export default defineProvider({ baseUrl: "https://proxy.example.com" });
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## OAuth providers
|
|
56
|
+
|
|
57
|
+
A provider with an `oauth` block authenticates through a login flow instead of a static key, which is what lets you sign in to a corporate gateway with SSO rather than pasting a token. The block gives the provider a display name for the login UI and three functions: `login` runs the flow and returns credentials to persist, `refreshToken` renews them when they expire, and `getApiKey` converts the stored credentials into the key sent on each request. When `oauth` is present, `apiKey` is optional.
|
|
58
|
+
|
|
59
|
+
## What to read next
|
|
60
|
+
|
|
61
|
+
- [Introduction](./introduction.md): the agent home and how capability folders load.
|
|
62
|
+
- [Workflows](./workflows.md): route events into sessions and automate the agent.
|
|
63
|
+
- [Tools](./tools.md): author tools the agent calls during a turn.
|