@hachej/boring-agent 0.1.41 → 0.1.43
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 +31 -252
- package/dist/{DebugDrawer-2PUDZ2RL.js → DebugDrawer-RYEBQ6CO.js} +1 -1
- package/dist/{agentPluginEvents-CKrZLW3g.d.ts → agentPluginEvents-DP-vLNCs.d.ts} +36 -3
- package/dist/{session-BRovhe0D.d.ts → chatSubmitPayload-gC61O4Ni.d.ts} +20 -1
- package/dist/{chunk-IUJ22EFB.js → chunk-BOIV2I3N.js} +2 -10
- package/dist/{chunk-VQ7VSSSX.js → chunk-YUDMSYAO.js} +6 -1
- package/dist/front/index.d.ts +22 -5
- package/dist/front/index.js +155 -103
- package/dist/front/styles.css +0 -6
- package/dist/piChatEvent-DR9a-FVz.d.ts +306 -0
- package/dist/server/index.d.ts +363 -94
- package/dist/server/index.js +1611 -414
- package/dist/shared/index.d.ts +29 -23
- package/dist/shared/index.js +1 -1
- package/docs/ACCESSIBILITY.md +11 -13
- package/docs/API.md +86 -59
- package/docs/CSP.md +10 -9
- package/docs/ERROR_CODES.md +5 -1
- package/docs/KNOWN_LIMITATIONS.md +3 -3
- package/docs/MIGRATION.md +16 -16
- package/docs/PERFORMANCE.md +1 -1
- package/docs/PLUGINS.md +42 -12
- package/docs/README.md +89 -12
- package/docs/RISKS-MULTI-TAB.md +1 -1
- package/docs/STYLING.md +6 -4
- package/docs/UI-SHADCN.md +7 -7
- package/docs/runtime-provisioning.md +7 -3
- package/docs/runtime.md +68 -13
- package/docs/tools.md +37 -14
- package/package.json +2 -2
- package/dist/piChatEvent-Ck1BAE_m.d.ts +0 -323
- /package/docs/plans/{AGENT_EVAL_FRAMEWORK.md → archive/AGENT_EVAL_FRAMEWORK.md} +0 -0
- /package/docs/plans/{agent-package-spec.md → archive/agent-package-spec.md} +0 -0
- /package/docs/plans/{harness-followup-capabilities.md → archive/harness-followup-capabilities.md} +0 -0
- /package/docs/plans/{harness-tool-ui-capabilities.md → archive/harness-tool-ui-capabilities.md} +0 -0
- /package/docs/plans/{pi-followup-history-projection.md → archive/pi-followup-history-projection.md} +0 -0
- /package/docs/plans/{pi-tools-migration.md → archive/pi-tools-migration.md} +0 -0
- /package/docs/plans/{reviews → archive/reviews}/pi-followup-history-codex-review.md +0 -0
- /package/docs/plans/{reviews → archive/reviews}/pi-followup-history-gpt-review.md +0 -0
- /package/docs/plans/{reviews → archive/reviews}/pi-followup-history-opus-review.md +0 -0
- /package/docs/plans/{reviews → archive/reviews}/pi-followup-history-xai-review.md +0 -0
- /package/docs/plans/{vercel-base-snapshot-template-plan.md → archive/vercel-base-snapshot-template-plan.md} +0 -0
- /package/docs/plans/{vercel-persistent-sandbox-adapter.md → archive/vercel-persistent-sandbox-adapter.md} +0 -0
package/README.md
CHANGED
|
@@ -7,291 +7,70 @@
|
|
|
7
7
|
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
|
-
A pane-embeddable coding agent
|
|
10
|
+
A pane-embeddable coding agent: an LLM agent loop, a tool catalog, and a chat UI
|
|
11
|
+
behind one interface, with three swappable execution modes. The same agent,
|
|
12
|
+
tools, and UI run in `direct` (host process), `local` (bwrap sandbox), or
|
|
13
|
+
`vercel-sandbox` (Firecracker microVM) mode.
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
npx @hachej/boring-agent
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## TL;DR
|
|
19
|
-
|
|
20
|
-
**The Problem**: You want a coding agent in the browser — but also as a CLI — and you need it to run your code somewhere safe (or not). Existing solutions force you into one deployment model and one UI.
|
|
21
|
-
|
|
22
|
-
**The Solution**: One package that ships a full LLM agent loop, tool catalog, and chat UI — with swappable execution backends. Same agent, same tools, same UI. Three modes. Zero config to start.
|
|
23
|
-
|
|
24
|
-
### Why Use @hachej/boring-agent?
|
|
25
|
-
|
|
26
|
-
| Feature | What It Does |
|
|
27
|
-
|---------|--------------|
|
|
28
|
-
| **Three execution modes** | `direct` (no isolation, macOS dev) / `local` (bwrap sandbox) / `vercel-sandbox` (Firecracker microVM) |
|
|
29
|
-
| **CLI + embeddable** | `npx @hachej/boring-agent` works standalone; `<ChatPanel />` composes into any layout |
|
|
30
|
-
| **7 standard tools** | `bash`, `read`, `write`, `edit`, `find`, `grep`, `ls` — ported from pi-coding-agent |
|
|
31
|
-
| **Workspace-local runtime provisioning** | Generates `.boring-agent` inside the selected workspace for mirrored skills, SDKs, CLIs, and templates |
|
|
32
|
-
| **Workspace-agnostic FS** | `Workspace` interface — agent tools and HTTP routes share the same filesystem view |
|
|
33
|
-
| **Session management** | List, create, switch, delete sessions with streamed history hydration |
|
|
34
|
-
| **UI bridge** | Agent opens files, panels, and surfaces in the workbench via typed commands |
|
|
35
|
-
| **Model picker + thinking toggle** | Inline in the composer — switch models and reasoning depth per message |
|
|
36
|
-
|
|
37
|
-
### Quick Example
|
|
15
|
+
## Install
|
|
38
16
|
|
|
39
17
|
```bash
|
|
40
|
-
# Start the agent in your current directory — zero setup
|
|
41
|
-
npx @hachej/boring-agent
|
|
42
|
-
|
|
43
|
-
# Or run with a specific workspace root
|
|
44
|
-
BORING_AGENT_WORKSPACE_ROOT=/path/to/project npx @hachej/boring-agent
|
|
45
|
-
|
|
46
|
-
# Set the API key
|
|
47
|
-
ANTHROPIC_API_KEY=sk-ant-... npx @hachej/boring-agent
|
|
48
|
-
|
|
49
|
-
# Run in local sandbox mode (Linux + bubblewrap)
|
|
50
|
-
BORING_AGENT_MODE=local npx @hachej/boring-agent
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
In the browser chat, try:
|
|
54
|
-
```
|
|
55
|
-
read the README and summarize it
|
|
56
|
-
find all TypeScript files that import "react"
|
|
57
|
-
write a test for src/utils.ts
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## Workspace-local runtime provisioning
|
|
63
|
-
|
|
64
|
-
Boring UI keeps generated runtime state in the selected workspace at
|
|
65
|
-
`$BORING_AGENT_WORKSPACE_ROOT/.boring-agent`. Plugin skills are mirrored to
|
|
66
|
-
`.boring-agent/skills`, runtime CLIs live under `.boring-agent/node` or
|
|
67
|
-
`.boring-agent/venv`, and templates seed only missing workspace files. The
|
|
68
|
-
folder is generated/disposable and should not be hand-edited or committed.
|
|
69
|
-
|
|
70
|
-
See [docs/runtime-provisioning.md](docs/runtime-provisioning.md) for the full
|
|
71
|
-
user and plugin-author contract, including package metadata shape,
|
|
72
|
-
`provisionWorkspace: false`, `/api/v1/agent/reload`, and direct/local/Vercel
|
|
73
|
-
mode behavior.
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## Architecture
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
┌─────────────────────────────────────┐
|
|
81
|
-
│ Chat UI (browser) │
|
|
82
|
-
│ Composer · Messages · SessionBar │
|
|
83
|
-
└──────────────────┬──────────────────┘
|
|
84
|
-
│ UIMessage stream (SSE)
|
|
85
|
-
┌──────────────────▼──────────────────┐
|
|
86
|
-
│ Agent Harness │
|
|
87
|
-
│ (pi-coding-agent loop) │
|
|
88
|
-
└──────────────────┬──────────────────┘
|
|
89
|
-
│ AgentTool[]
|
|
90
|
-
┌──────────────────▼──────────────────┐
|
|
91
|
-
│ Tool Catalog │
|
|
92
|
-
│ bash · read · write · edit │
|
|
93
|
-
│ find · grep · ls │
|
|
94
|
-
└──────┬──────────────┬───────────────┘
|
|
95
|
-
│ │
|
|
96
|
-
┌──────▼─────┐ ┌──────▼─────┐
|
|
97
|
-
│ Workspace │ │ Sandbox │
|
|
98
|
-
│ (fs ops) │ │ (exec) │
|
|
99
|
-
│ read/write │ │ bwrap │
|
|
100
|
-
│ readdir │ │ vercel │
|
|
101
|
-
└────────────┘ └────────────┘
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**Two layers, clear boundary:**
|
|
105
|
-
|
|
106
|
-
- **Layer 1 (Core runtime):** `AgentHarness` · `Catalog` · `Workspace` · `Sandbox` — interfaces locked; adapters swap per mode.
|
|
107
|
-
- **Layer 2 (Integration):** `SessionStore` · `UiBridge` · `Provisioning` — replaceable plumbing, independent evolution.
|
|
108
|
-
|
|
109
|
-
### Execution Modes
|
|
110
|
-
|
|
111
|
-
| Mode | Workspace | Sandbox | Isolation | Use Case |
|
|
112
|
-
|------|-----------|---------|-----------|----------|
|
|
113
|
-
| `direct` | `NodeWorkspace` | `DirectSandbox` | None | macOS/Windows dev, quick tests |
|
|
114
|
-
| `local` | `NodeWorkspace` | `BwrapSandbox` | bwrap process jail | Linux deployments, safer default |
|
|
115
|
-
| `vercel-sandbox` | `VercelSandboxWorkspace` | `VercelSandboxExec` | Firecracker microVM | Multi-tenant, remote execution |
|
|
116
|
-
|
|
117
|
-
**Pairing invariant:** Workspace + Sandbox must target the same filesystem substrate. The adapter factory enforces this at construction — mismatched pairs are impossible.
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## Installation
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
# npm
|
|
125
|
-
npm install @hachej/boring-agent
|
|
126
|
-
|
|
127
|
-
# pnpm
|
|
128
18
|
pnpm add @hachej/boring-agent
|
|
129
|
-
|
|
130
|
-
# standalone (no install needed)
|
|
131
|
-
npx @hachej/boring-agent
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### From Source
|
|
135
|
-
|
|
136
|
-
```bash
|
|
137
|
-
git clone https://github.com/hachej/boring-ui.git
|
|
138
|
-
cd boring-ui
|
|
139
|
-
pnpm install
|
|
140
|
-
pnpm --filter @hachej/boring-agent build
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## Quick Start
|
|
146
|
-
|
|
147
|
-
### 1. As a CLI
|
|
148
|
-
|
|
149
|
-
```bash
|
|
150
|
-
# Set your API key
|
|
151
|
-
export ANTHROPIC_API_KEY=sk-ant-...
|
|
152
|
-
|
|
153
|
-
# Run in your project directory
|
|
154
|
-
cd /path/to/project
|
|
155
|
-
npx @hachej/boring-agent
|
|
19
|
+
# or: npm install @hachej/boring-agent
|
|
156
20
|
```
|
|
157
21
|
|
|
158
|
-
|
|
22
|
+
Peer deps (optional): `react`, `react-dom`, `tailwindcss`.
|
|
159
23
|
|
|
160
|
-
|
|
24
|
+
## Usage
|
|
161
25
|
|
|
162
|
-
**Server
|
|
26
|
+
**Server** — standalone Fastify app:
|
|
163
27
|
|
|
164
28
|
```ts
|
|
165
29
|
import { createAgentApp } from "@hachej/boring-agent/server"
|
|
166
30
|
|
|
167
31
|
const app = await createAgentApp({
|
|
168
|
-
mode: "local",
|
|
32
|
+
mode: "local", // "direct" | "local" | "vercel-sandbox"
|
|
169
33
|
workspaceRoot: process.cwd(),
|
|
170
|
-
apiBaseUrl: "http://localhost:3000",
|
|
171
34
|
})
|
|
172
35
|
await app.listen({ port: 3001 })
|
|
173
36
|
```
|
|
174
37
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
import { ChatPanel, useAgentChat } from "@hachej/boring-agent"
|
|
179
|
-
import "@hachej/boring-agent/front/styles.css"
|
|
180
|
-
|
|
181
|
-
function App() {
|
|
182
|
-
return <ChatPanel apiBaseUrl="http://localhost:3000" />
|
|
183
|
-
}
|
|
184
|
-
```
|
|
38
|
+
To embed routes into an existing Fastify instance, use `registerAgentRoutes`
|
|
39
|
+
instead. The full IDE shell (file tree, panes, UI-bridge tools) lives in
|
|
40
|
+
`@hachej/boring-workspace`, which mounts this agent.
|
|
185
41
|
|
|
186
|
-
|
|
42
|
+
**Frontend** — the chat panel:
|
|
187
43
|
|
|
188
44
|
```tsx
|
|
189
|
-
import { WorkspaceProvider, IdeLayout } from "@hachej/boring-workspace"
|
|
190
45
|
import { ChatPanel } from "@hachej/boring-agent"
|
|
46
|
+
import "@hachej/boring-agent/front/styles.css"
|
|
191
47
|
|
|
192
48
|
function App() {
|
|
193
|
-
return
|
|
194
|
-
<WorkspaceProvider chatPanel={ChatPanel} workspaceId="proj-1">
|
|
195
|
-
<IdeLayout />
|
|
196
|
-
</WorkspaceProvider>
|
|
197
|
-
)
|
|
49
|
+
return <ChatPanel apiBaseUrl="http://localhost:3001" />
|
|
198
50
|
}
|
|
199
51
|
```
|
|
200
52
|
|
|
201
|
-
---
|
|
202
|
-
|
|
203
|
-
## Package Surfaces
|
|
204
|
-
|
|
205
|
-
| Import | Environment | What You Get |
|
|
206
|
-
|--------|-------------|--------------|
|
|
207
|
-
| `@hachej/boring-agent` | Browser | `ChatPanel`, `SessionToolbar`, primitives, hooks, `theme.css` |
|
|
208
|
-
| `@hachej/boring-agent/server` | Node | `createAgentApp`, routes, harness, sandbox, workspace adapters |
|
|
209
|
-
| `@hachej/boring-agent/front` | Browser | Frontend-specific (same as top-level, explicit subpath) |
|
|
210
|
-
| `@hachej/boring-agent/shared` | Any | `AgentHarness`, `Workspace`, `Sandbox`, `AgentTool`, `SessionStore` interfaces |
|
|
211
|
-
| `@hachej/boring-agent/front/styles.css` | Browser | CSS custom properties for theming |
|
|
212
|
-
| `@hachej/boring-agent/eval` | Node | Evaluation toolkit for agent behavior |
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
53
|
## Configuration
|
|
217
54
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
| `BORING_AGENT_MODE` | No | `direct` | `direct`, `local`, or `vercel-sandbox` |
|
|
224
|
-
| `BORING_AGENT_WORKSPACE_ROOT` | No | `.` | Root directory for workspace |
|
|
225
|
-
| `BORING_AGENT_DEFAULT_MODEL_PROVIDER` | No | `anthropic` | Default model provider |
|
|
226
|
-
| `BORING_AGENT_DEFAULT_MODEL_ID` | No | `claude-sonnet-4-6` | Default model ID |
|
|
227
|
-
| `VERCEL_OIDC_TOKEN` | Remote only | — | Required for `vercel-sandbox` mode |
|
|
228
|
-
| `PORT` | No | `5200` | Server port |
|
|
229
|
-
| `HOST` | No | `localhost` | Server host |
|
|
230
|
-
|
|
231
|
-
### Config File
|
|
232
|
-
|
|
233
|
-
`boring.app.toml` (optional, for embedded mode):
|
|
234
|
-
|
|
235
|
-
```toml
|
|
236
|
-
[runtime]
|
|
237
|
-
mode = "local" # direct | local | vercel-sandbox
|
|
238
|
-
|
|
239
|
-
[model]
|
|
240
|
-
default_provider = "anthropic"
|
|
241
|
-
default_id = "claude-sonnet-4-6"
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
---
|
|
245
|
-
|
|
246
|
-
## Troubleshooting
|
|
247
|
-
|
|
248
|
-
| Error | Cause | Fix |
|
|
249
|
-
|-------|-------|-----|
|
|
250
|
-
| `ANTHROPIC_API_KEY not set` | Missing API key | `export ANTHROPIC_API_KEY=sk-ant-...` |
|
|
251
|
-
| `bwrap not found` (local mode) | bubblewrap not installed | `sudo apt install bubblewrap` (Debian/Ubuntu) |
|
|
252
|
-
| `port already in use` | Port 5200 occupied | `PORT=5201 npx @hachej/boring-agent` |
|
|
253
|
-
| `workspace root not found` | Invalid `BORING_AGENT_WORKSPACE_ROOT` | Point to an existing directory |
|
|
254
|
-
| `Vercel sandbox auth failed` (remote mode) | Missing/invalid OIDC token | Set `VERCEL_OIDC_TOKEN` |
|
|
255
|
-
| `model provider not supported` | Unknown provider in config | Use `anthropic` (only supported provider in v1) |
|
|
256
|
-
|
|
257
|
-
---
|
|
258
|
-
|
|
259
|
-
## Limitations
|
|
260
|
-
|
|
261
|
-
- **Single model provider**: Only Anthropic (Claude) is supported in v1. The harness interface is designed to accept others, but only `anthropic` is wired.
|
|
262
|
-
- **No multi-user auth**: The agent is single-workspace-per-instance. Multi-user auth, billing, and workspace CRUD belong to `@hachej/boring-core`.
|
|
263
|
-
- **No git UI**: The agent runs git via `bash`, but there's no status bar, diff pane, or branch picker. When git UI lands, thin routes will be added.
|
|
264
|
-
- **Plugin loading is local-only**: Pi plugins load in the backend Node process. They're disabled in `vercel-sandbox` mode for security.
|
|
265
|
-
- **No browser-agent mode yet**: The `AgentHarness` interface has a `placement: "browser"` option, but no browser harness is implemented.
|
|
266
|
-
- **No MCP tool integration**: Not in scope for v1.
|
|
267
|
-
|
|
268
|
-
---
|
|
269
|
-
|
|
270
|
-
## FAQ
|
|
271
|
-
|
|
272
|
-
**Q: What's the difference between `direct` and `local` mode?**
|
|
273
|
-
A: `direct` runs bash commands with no sandbox — the agent has full access to your machine. `local` wraps commands in bubblewrap (`bwrap`), which provides filesystem and process isolation on Linux. Use `direct` for macOS dev; use `local` on Linux servers.
|
|
274
|
-
|
|
275
|
-
**Q: Can I use OpenAI or other model providers?**
|
|
276
|
-
A: Not in v1. Only Anthropic's Claude is wired up. The harness interface is provider-agnostic — community PRs for other providers are welcome.
|
|
277
|
-
|
|
278
|
-
**Q: How do sessions persist?**
|
|
279
|
-
A: Via pi-coding-agent's JSONL session files under `${workdir}/.pi/sessions/`. The `PiSessionStore` reads and manages lifecycle. SQLite and IndexedDB implementations are planned.
|
|
280
|
-
|
|
281
|
-
**Q: Can I add custom tools to the agent?**
|
|
282
|
-
A: Yes. Use the `CatalogDeps` pattern to build tools that bind to `Workspace` and `Sandbox`. For pi-native tools, register them via pi's extension system (`pi.extensions` in config). In `vercel-sandbox` mode, extensions are disabled.
|
|
283
|
-
|
|
284
|
-
**Q: What's the UI bridge for?**
|
|
285
|
-
A: It lets the agent programmatically open files, panels, and surfaces in the workbench. The agent calls `exec_ui({ kind: "openFile", params: { path: "src/index.ts" } })` and the panel opens. It's a typed pubsub bus between backend and frontend.
|
|
55
|
+
Set an API key for the model provider (e.g. `ANTHROPIC_API_KEY`). Common env
|
|
56
|
+
vars: `BORING_AGENT_MODE` (default `direct`), `BORING_AGENT_WORKSPACE_ROOT`
|
|
57
|
+
(default cwd), `BORING_AGENT_PORT`, and the `BORING_AGENT_DEFAULT_MODEL*` /
|
|
58
|
+
`BORING_AGENT_CUSTOM_MODEL*` / `BORING_AGENT_INFOMANIAK*` provider settings. See
|
|
59
|
+
[docs/runtime.md](./docs/runtime.md) and [docs/API.md](./docs/API.md).
|
|
286
60
|
|
|
287
|
-
|
|
288
|
-
A: The server wraps the harness's event stream in a per-turn ring buffer. Disconnected clients reconnect via `GET /api/v1/agent/pi-chat/:sessionId/events?from=<seq>`; the replay buffer serves missed events.
|
|
61
|
+
## Documentation
|
|
289
62
|
|
|
290
|
-
|
|
63
|
+
See [docs/README.md](./docs/README.md) for the full doc index — architecture,
|
|
64
|
+
the export surfaces (`/front`, `/server`, `/shared`, `/eval`), runtime modes and
|
|
65
|
+
provisioning, theming, plugins, error codes, and risk/cost notes.
|
|
291
66
|
|
|
292
|
-
|
|
67
|
+
## Contributions
|
|
293
68
|
|
|
294
|
-
|
|
69
|
+
I do not accept outside contributions for my projects: I don't have the
|
|
70
|
+
bandwidth to review them, and it's my name on the result. Issues and bug reports
|
|
71
|
+
are welcome; PRs may be used to illustrate a fix, but I won't merge them
|
|
72
|
+
directly — I'll have Claude or Codex review submissions via `gh` and
|
|
73
|
+
independently decide whether and how to address them.
|
|
295
74
|
|
|
296
75
|
## License
|
|
297
76
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as SessionStore } from './chatSubmitPayload-gC61O4Ni.js';
|
|
2
2
|
|
|
3
3
|
interface TelemetrySink {
|
|
4
4
|
capture(event: TelemetryEvent): void | Promise<void>;
|
|
@@ -215,6 +215,32 @@ interface WorkspaceChangeEvent {
|
|
|
215
215
|
oldPath?: string;
|
|
216
216
|
mtimeMs?: number;
|
|
217
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Result of a watcher's readiness probe. `ok: false` means the
|
|
220
|
+
* implementation decided it cannot observe this workspace (e.g. the
|
|
221
|
+
* tree is too large to watch without harming the host process) —
|
|
222
|
+
* hosts should tell clients to fall back rather than wait for events
|
|
223
|
+
* that will never come.
|
|
224
|
+
*/
|
|
225
|
+
type WorkspaceWatcherReadiness = {
|
|
226
|
+
ok: true;
|
|
227
|
+
} | {
|
|
228
|
+
ok: false;
|
|
229
|
+
reason: string;
|
|
230
|
+
message?: string;
|
|
231
|
+
};
|
|
232
|
+
interface WorkspaceWatchControlEvent {
|
|
233
|
+
type: 'resync-required';
|
|
234
|
+
reason: string;
|
|
235
|
+
}
|
|
236
|
+
interface WorkspaceWatchSubscribeOptions {
|
|
237
|
+
/**
|
|
238
|
+
* Called when the watcher detects a gap where changes may have been
|
|
239
|
+
* missed. Consumers should drop caches/refetch instead of trusting
|
|
240
|
+
* incremental events alone.
|
|
241
|
+
*/
|
|
242
|
+
onControlEvent?: (event: WorkspaceWatchControlEvent) => void;
|
|
243
|
+
}
|
|
218
244
|
interface WorkspaceWatcher {
|
|
219
245
|
/**
|
|
220
246
|
* Add a listener for change events. Returns an unsubscribe fn —
|
|
@@ -222,7 +248,14 @@ interface WorkspaceWatcher {
|
|
|
222
248
|
* itself is disposed, so unsubscribing one listener is cheap and
|
|
223
249
|
* does NOT tear down the watcher.
|
|
224
250
|
*/
|
|
225
|
-
subscribe(listener: (event: WorkspaceChangeEvent) => void): () => void;
|
|
251
|
+
subscribe(listener: (event: WorkspaceChangeEvent) => void, options?: WorkspaceWatchSubscribeOptions): () => void;
|
|
252
|
+
/**
|
|
253
|
+
* Optional readiness probe. Implementations with a startup guard
|
|
254
|
+
* (workspace-size check, native module availability, …) resolve it
|
|
255
|
+
* once the underlying source is observing — or with `ok: false`
|
|
256
|
+
* when observation was refused. Absent → assume always ready.
|
|
257
|
+
*/
|
|
258
|
+
whenReady?(): Promise<WorkspaceWatcherReadiness>;
|
|
226
259
|
/**
|
|
227
260
|
* Tear down the underlying observation source (chokidar instance,
|
|
228
261
|
* sandbox emitter binding, …). Idempotent. Subscribers added after
|
|
@@ -444,4 +477,4 @@ interface CommandNotifyPayload {
|
|
|
444
477
|
command?: string;
|
|
445
478
|
}
|
|
446
479
|
|
|
447
|
-
export { type AgentTool as A, type CommandNotifyPayload as C, type Entry as E, type FileSearch as F, type IsolatedCodeInput as I, type JSONSchema as J, type PluginRestartWarning as P, type RunContext as R, type Sandbox as S, type TelemetryEvent as T, type Workspace as W, type AgentHarness as a, type ExecOptions as b, type ExecResult as c, type IsolatedCodeOutput as d, type SandboxCapability as e, type SandboxHandleRecord as f, type SandboxHandleStore as g, type SendMessageInput as h, type Stat as i, type TelemetrySink as j, type ToolExecContext as k, type ToolResult as l, WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT as m, WORKSPACE_COMMAND_NOTIFY_EVENT as n, type WorkspaceRuntimeContext as o, noopTelemetry as p, type
|
|
480
|
+
export { type AgentTool as A, type CommandNotifyPayload as C, type Entry as E, type FileSearch as F, type IsolatedCodeInput as I, type JSONSchema as J, type PluginRestartWarning as P, type RunContext as R, type Sandbox as S, type TelemetryEvent as T, type Workspace as W, type AgentHarness as a, type ExecOptions as b, type ExecResult as c, type IsolatedCodeOutput as d, type SandboxCapability as e, type SandboxHandleRecord as f, type SandboxHandleStore as g, type SendMessageInput as h, type Stat as i, type TelemetrySink as j, type ToolExecContext as k, type ToolResult as l, WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT as m, WORKSPACE_COMMAND_NOTIFY_EVENT as n, type WorkspaceRuntimeContext as o, noopTelemetry as p, type WorkspaceChangeEvent as q, type AgentHarnessFactory as r, safeCapture as s, type AgentHarnessFactoryInput as t };
|
|
@@ -24,4 +24,23 @@ interface SessionSummary {
|
|
|
24
24
|
}
|
|
25
25
|
type SessionDetail = SessionSummary;
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
type ThinkingLevel = 'off' | 'low' | 'medium' | 'high';
|
|
28
|
+
interface ChatModelSelection {
|
|
29
|
+
provider: string;
|
|
30
|
+
id: string;
|
|
31
|
+
}
|
|
32
|
+
interface ChatAttachmentPayload {
|
|
33
|
+
filename?: string;
|
|
34
|
+
mediaType?: string;
|
|
35
|
+
url: string;
|
|
36
|
+
}
|
|
37
|
+
interface ChatSubmitPayload {
|
|
38
|
+
message: string;
|
|
39
|
+
displayMessage?: string;
|
|
40
|
+
clientNonce: string;
|
|
41
|
+
model?: ChatModelSelection;
|
|
42
|
+
thinkingLevel?: ThinkingLevel;
|
|
43
|
+
attachments?: ChatAttachmentPayload[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type { ChatAttachmentPayload as C, SessionCtx as S, ThinkingLevel as T, ChatModelSelection as a, ChatSubmitPayload as b, SessionDetail as c, SessionStore as d, SessionSummary as e };
|
|
@@ -81,17 +81,9 @@ function DebugValue({ label, value }) {
|
|
|
81
81
|
] });
|
|
82
82
|
}
|
|
83
83
|
function SessionTab({ sessionId }) {
|
|
84
|
-
const resumeCommand = `pi --session ${sessionId}`;
|
|
85
84
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 overflow-auto p-3 text-[11px] text-muted-foreground dark:text-zinc-300", children: [
|
|
86
|
-
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground dark:text-zinc-300", children: "This web chat is backed by a
|
|
87
|
-
/* @__PURE__ */ jsx(DebugValue, { label: "
|
|
88
|
-
/* @__PURE__ */ jsx(DebugValue, { label: "Resume command", value: resumeCommand }),
|
|
89
|
-
/* @__PURE__ */ jsxs("p", { className: "rounded-md border border-border/30 bg-muted/10 p-2 text-[10px] leading-relaxed text-muted-foreground dark:text-zinc-300", children: [
|
|
90
|
-
"Tip: ",
|
|
91
|
-
/* @__PURE__ */ jsx("code", { className: "font-mono text-foreground/80", children: "pi --continue" }),
|
|
92
|
-
" ",
|
|
93
|
-
"opens the most recent session for the current working directory. The explicit command above targets this session directly."
|
|
94
|
-
] })
|
|
85
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground dark:text-zinc-300", children: "This web chat is backed by a runtime session. Use the id below for support or debugging." }),
|
|
86
|
+
/* @__PURE__ */ jsx(DebugValue, { label: "Runtime session id", value: sessionId })
|
|
95
87
|
] });
|
|
96
88
|
}
|
|
97
89
|
var RETRY_DELAY_MS = 2500;
|
|
@@ -29,6 +29,7 @@ function extractToolUiMetadata(output) {
|
|
|
29
29
|
import { z } from "zod";
|
|
30
30
|
var ErrorCode = z.enum([
|
|
31
31
|
// Auth / config
|
|
32
|
+
"UNAUTHORIZED",
|
|
32
33
|
"MISSING_API_KEY",
|
|
33
34
|
"INVALID_API_KEY",
|
|
34
35
|
"OIDC_REFRESH_FAILED",
|
|
@@ -54,8 +55,12 @@ var ErrorCode = z.enum([
|
|
|
54
55
|
"SANDBOX_NOT_READY",
|
|
55
56
|
"SANDBOX_EXPIRED",
|
|
56
57
|
"VERCEL_API_ERROR",
|
|
58
|
+
"REMOTE_WORKER_TIMEOUT",
|
|
59
|
+
"REMOTE_WORKER_STREAM_CLOSED",
|
|
57
60
|
"CIRCUIT_OPEN",
|
|
58
61
|
"ABORTED",
|
|
62
|
+
// Billing / metering
|
|
63
|
+
"PAYMENT_REQUIRED",
|
|
59
64
|
// Session / bridge
|
|
60
65
|
"SESSION_NOT_FOUND",
|
|
61
66
|
"SESSION_LOCKED",
|
|
@@ -208,7 +213,7 @@ var PiChatSnapshotSchema = z2.object({
|
|
|
208
213
|
var baseEvent = z2.object({ seq: seqNumber });
|
|
209
214
|
var PiChatEventSchema = z2.discriminatedUnion("type", [
|
|
210
215
|
baseEvent.extend({ type: z2.literal("agent-start"), turnId: nonEmptyString }),
|
|
211
|
-
baseEvent.extend({ type: z2.literal("agent-end"), turnId: nonEmptyString, status: z2.enum(["ok", "aborted", "error"]) }),
|
|
216
|
+
baseEvent.extend({ type: z2.literal("agent-end"), turnId: nonEmptyString, status: z2.enum(["ok", "aborted", "error"]), willRetry: z2.boolean().optional() }),
|
|
212
217
|
baseEvent.extend({
|
|
213
218
|
type: z2.literal("message-start"),
|
|
214
219
|
messageId: nonEmptyString,
|
package/dist/front/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { FileUIPart, UIMessage, ChatStatus } from 'ai';
|
|
3
2
|
import * as react from 'react';
|
|
4
3
|
import { ComponentType, ReactNode, HTMLAttributes, ComponentProps, FormEvent } from 'react';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { FileUIPart, UIMessage, ChatStatus } from 'ai';
|
|
5
|
+
import { T as ToolUiMetadata, B as BoringChatPart, d as BoringChatMessage, m as PiChatStatus, r as QueuedUserMessage, C as ChatError, P as PiChatEvent, o as PromptPayload, p as PromptReceipt, F as FollowUpPayload, i as FollowUpReceipt, Q as QueueClearPayload, q as QueueClearReceipt, I as InterruptPayload, e as CommandReceipt, S as StopPayload, s as StopReceipt } from '../piChatEvent-DR9a-FVz.js';
|
|
6
|
+
import { e as SessionSummary } from '../chatSubmitPayload-gC61O4Ni.js';
|
|
7
7
|
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger, InputGroupAddon, InputGroupButton, InputGroupTextarea } from '@hachej/boring-ui-kit';
|
|
8
8
|
import { Streamdown } from 'streamdown';
|
|
9
9
|
import { StickToBottom } from 'use-stick-to-bottom';
|
|
@@ -238,6 +238,10 @@ interface PiChatRuntimeNotice {
|
|
|
238
238
|
level: 'info' | 'warning' | 'error';
|
|
239
239
|
text: string;
|
|
240
240
|
dismissible?: boolean;
|
|
241
|
+
/** Stable, canonical server error code (a shared ErrorCode enum member) when this
|
|
242
|
+
* notice came from a rejected run. Lets a host render a recovery action for a specific
|
|
243
|
+
* code without the agent knowing what the code means. */
|
|
244
|
+
errorCode?: string;
|
|
241
245
|
}
|
|
242
246
|
interface PiChatRetryNotice {
|
|
243
247
|
attempt: number;
|
|
@@ -501,6 +505,8 @@ interface ChatPanelEmptyState {
|
|
|
501
505
|
eyebrow?: string;
|
|
502
506
|
title?: string;
|
|
503
507
|
description?: string;
|
|
508
|
+
/** Optional content rendered below the suggestion grid (e.g. a footer link). */
|
|
509
|
+
footer?: ReactNode;
|
|
504
510
|
}
|
|
505
511
|
interface PiChatPanelProps {
|
|
506
512
|
/** Optional externally selected Pi session id. When provided, session navigation is owned by the host. */
|
|
@@ -530,6 +536,9 @@ interface PiChatPanelProps {
|
|
|
530
536
|
model?: ModelSelection | null;
|
|
531
537
|
defaultModel?: ModelSelection;
|
|
532
538
|
availableModels?: AvailableModel[];
|
|
539
|
+
hideDefaultModelOption?: boolean;
|
|
540
|
+
hideComposerSettings?: boolean;
|
|
541
|
+
suppressPreSubmitCancelledWarning?: boolean;
|
|
533
542
|
thinkingLevel?: ThinkingLevel;
|
|
534
543
|
thinkingControl?: boolean;
|
|
535
544
|
serverResourcesEnabled?: boolean;
|
|
@@ -553,8 +562,16 @@ interface PiChatPanelProps {
|
|
|
553
562
|
composerBlockers?: ComposerBlocker[];
|
|
554
563
|
onComposerStop?: () => void;
|
|
555
564
|
onComposerBlockerAction?: (blocker: ComposerBlocker, action: string) => void;
|
|
556
|
-
|
|
557
|
-
|
|
565
|
+
/** Fired once each time a run settles (busy → idle). Hosts use it to refresh
|
|
566
|
+
* out-of-band state after a turn (e.g. a usage/quota indicator). The agent stays
|
|
567
|
+
* agnostic about what the host does with it. */
|
|
568
|
+
onTurnComplete?: () => void;
|
|
569
|
+
/** Host-supplied action node for a runtime notice, keyed off notice.errorCode.
|
|
570
|
+
* Lets a host attach a recovery action for a specific error code without the agent
|
|
571
|
+
* knowing what the code means or what the action does. */
|
|
572
|
+
renderNoticeAction?: (notice: PiChatRuntimeNotice) => ReactNode;
|
|
573
|
+
}
|
|
574
|
+
declare function PiChatPanel({ sessionId, extraCommands, apiBaseUrl, workspaceId, storageScope, requestHeaders, storage, fetch, className, chrome, debug, showSessions, hotReloadEnabled, suggestions, emptyState, emptyPlacement, composerPlaceholder, initialDraft, autoSubmitInitialDraft, onDraftRestored, onAutoSubmitInitialDraftAccepted, onAutoSubmitInitialDraftSettled, model, defaultModel, availableModels, hideDefaultModelOption, hideComposerSettings, suppressPreSubmitCancelledWarning, thinkingLevel, thinkingControl, serverResourcesEnabled, mentionedFiles, commands, excludeBuiltinCommands, toolRenderers, createRemoteSession, remoteSessionOptions, hydrateMessages, workspaceWarmupStatus, onSessionReset, onBeforeSubmit, onReloadAgentPlugins, onCommandResult, onComposerWarning, onMentionedFilesConsumed, onData, onOpenArtifact, composerBlockers, onComposerStop, onComposerBlockerAction, onTurnComplete, renderNoticeAction, }: PiChatPanelProps): react_jsx_runtime.JSX.Element;
|
|
558
575
|
|
|
559
576
|
interface DebugDrawerProps {
|
|
560
577
|
apiBaseUrl?: string;
|