@agent-smith/server 0.0.8 → 0.0.9
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 +349 -0
- package/dist/callbacks.d.ts +4 -0
- package/dist/callbacks.js +182 -0
- package/dist/routes/agent_settings.d.ts +4 -0
- package/dist/routes/agent_settings.js +20 -0
- package/dist/routes/agents.js +24 -4
- package/dist/routes/apps.js +3 -3
- package/dist/routes/backends.js +2 -2
- package/dist/routes/conf.js +3 -3
- package/dist/routes/folders.js +3 -4
- package/dist/routes/index.js +6 -4
- package/dist/routes/models.d.ts +5 -2
- package/dist/routes/models.js +64 -27
- package/dist/routes/plugins.js +6 -6
- package/dist/routes/settings.d.ts +3 -0
- package/dist/routes/settings.js +20 -0
- package/dist/routes/state.js +3 -3
- package/dist/routes/templates.d.ts +3 -0
- package/dist/routes/templates.js +18 -0
- package/dist/routes/tools.js +3 -3
- package/dist/routes/workflows.js +1 -1
- package/dist/routes/workspace.d.ts +5 -0
- package/dist/routes/workspace.js +50 -0
- package/dist/server/router.d.ts +4 -1
- package/dist/server/router.js +6 -4
- package/dist/server/server.js +49 -204
- package/dist/utils.d.ts +7 -1
- package/dist/utils.js +17 -3
- package/package.json +3 -4
- package/dist/routes/task_settings.d.ts +0 -4
- package/dist/routes/task_settings.js +0 -21
- package/dist/routes/tasks.d.ts +0 -4
- package/dist/routes/tasks.js +0 -24
package/README.md
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# @agent-smith/server
|
|
2
|
+
|
|
3
|
+
A Koa v3 backend server that exposes the Agent Smith runtime via REST API (`/api/*`) and WebSocket (`/ws`), enabling remote AI agent execution with real-time token streaming. Part of the [Agent Smith toolkit](https://github.com/lynxai-team/agent-smith).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🌐 **REST API** — Full CRUD for agents, workflows, backends, models, settings, and configurations
|
|
8
|
+
- 🔌 **WebSocket Execution** — Real-time bidirectional communication for agent inference with streaming tokens
|
|
9
|
+
- ⚒️ **Tool Call Confirmation** — Async confirmation pattern for user-approved tool executions
|
|
10
|
+
- 📡 **Streaming Events** — Token, thinking, tool call, and turn events streamed over WebSocket
|
|
11
|
+
- 🔧 **Plugin Support** — Install npm plugins and add feature search folders via API
|
|
12
|
+
- 🏗️ **Programmatic API** — Use `runServer()` to embed the server in your own applications
|
|
13
|
+
- 🌍 **CORS Enabled** — Cross-origin requests supported with credentials
|
|
14
|
+
|
|
15
|
+
## Documentation
|
|
16
|
+
|
|
17
|
+
### For AI Agents
|
|
18
|
+
|
|
19
|
+
- [Codebase Summary](.agents/documentation/codebase-summary.md) — Architecture, key files, and patterns for the server package
|
|
20
|
+
- [API Reference](https://raw.githubusercontent.com/lynxai-team/agent-smith/refs/heads/main/docsite/public/doc/server/2.api.md) — Complete REST endpoints and WebSocket protocol
|
|
21
|
+
- [Client Usage](https://raw.githubusercontent.com/lynxai-team/agent-smith/refs/heads/main/docsite/public/doc/server/3.client-usage.md) — Integration patterns with wscli and HTTP clients
|
|
22
|
+
- [Deployment](https://raw.githubusercontent.com/lynxai-team/agent-smith/refs/heads/main/docsite/public/doc/server/4.deployment.md) — Production deployment considerations
|
|
23
|
+
|
|
24
|
+
### For Humans
|
|
25
|
+
|
|
26
|
+
- [Get Started](https://lynxai-team.github.io/agent-smith/server/get-started) — Installation and basic usage
|
|
27
|
+
- [API Reference](https://lynxai-team.github.io/agent-smith/server/api) — Complete REST endpoints and WebSocket protocol
|
|
28
|
+
- [Client Usage](https://lynxai-team.github.io/agent-smith/server/client-usage) — Integration patterns with wscli and HTTP clients
|
|
29
|
+
- [Deployment](https://lynxai-team.github.io/agent-smith/server/deployment) — Production deployment considerations
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install @agent-smith/server
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or build from source:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
cd agent-smith/server
|
|
41
|
+
npm install
|
|
42
|
+
npm run build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
### Running the Server
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Development mode with hot-reload
|
|
51
|
+
npm run devserver
|
|
52
|
+
|
|
53
|
+
# Production mode
|
|
54
|
+
npm run server
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The server listens on port **5184** by default. Verify it's running:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
curl http://localhost:5184/ping
|
|
61
|
+
# Response: { "ok": true }
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Executing an Agent via WebSocket
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { useWsServer } from "@agent-smith/wscli";
|
|
68
|
+
|
|
69
|
+
const ws = useWsServer({
|
|
70
|
+
url: "ws://localhost:5184/ws",
|
|
71
|
+
onToken: (token) => process.stdout.write(token),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
ws.executeAgent("my-agent", { prompt: "Hello, world!" });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Usage
|
|
78
|
+
|
|
79
|
+
### Programmatic Server Startup
|
|
80
|
+
|
|
81
|
+
Use `runServer()` to embed the server in your application:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { runServer } from "@agent-smith/server";
|
|
85
|
+
|
|
86
|
+
// Start with default routes and no static directory
|
|
87
|
+
runServer();
|
|
88
|
+
|
|
89
|
+
// Or with custom routes and static file serving
|
|
90
|
+
runServer(
|
|
91
|
+
undefined, // Custom route functions (optional)
|
|
92
|
+
"/path/to/static" // Static file directory (optional)
|
|
93
|
+
);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### REST API Examples
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// List all agents
|
|
100
|
+
const agentsRes = await fetch("http://localhost:5184/api/agents");
|
|
101
|
+
const agents = await agentsRes.json();
|
|
102
|
+
|
|
103
|
+
// Get a specific agent
|
|
104
|
+
const agentRes = await fetch("http://localhost:5184/api/agent/my-agent");
|
|
105
|
+
const agent = await agentRes.json();
|
|
106
|
+
|
|
107
|
+
// List inference backends
|
|
108
|
+
const backendsRes = await fetch("http://localhost:5184/api/backends");
|
|
109
|
+
const backends = await backendsRes.json();
|
|
110
|
+
|
|
111
|
+
// Get available models for a backend
|
|
112
|
+
const modelsRes = await fetch("http://localhost:5184/api/models/openai");
|
|
113
|
+
const models = await modelsRes.json();
|
|
114
|
+
|
|
115
|
+
// Update agent settings
|
|
116
|
+
const settingsRes = await fetch("http://localhost:5184/api/agentSettings", {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: { "Content-Type": "application/json" },
|
|
119
|
+
body: JSON.stringify({ name: "my-agent", settings: { temperature: 0.5 } }),
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### WebSocket Agent Execution
|
|
124
|
+
|
|
125
|
+
Connect directly to the WebSocket endpoint for real-time streaming:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const ws = new WebSocket('ws://localhost:5184/ws');
|
|
129
|
+
|
|
130
|
+
ws.onmessage = (event) => {
|
|
131
|
+
const msg = JSON.parse(event.data);
|
|
132
|
+
switch (msg.type) {
|
|
133
|
+
case 'token':
|
|
134
|
+
process.stdout.write(msg.msg);
|
|
135
|
+
break;
|
|
136
|
+
case 'thinkingtoken':
|
|
137
|
+
console.log(`\x1b[2m${msg.msg}\x1b[0m`);
|
|
138
|
+
break;
|
|
139
|
+
case 'toolcall':
|
|
140
|
+
const payload = JSON.parse(msg.msg);
|
|
141
|
+
console.log(`Tool call: ${payload.tc.name}`);
|
|
142
|
+
break;
|
|
143
|
+
case 'endemit':
|
|
144
|
+
const result = JSON.parse(msg.msg);
|
|
145
|
+
console.log('\nDone:', result);
|
|
146
|
+
ws.close();
|
|
147
|
+
break;
|
|
148
|
+
case 'error':
|
|
149
|
+
console.error('Error:', msg.msg);
|
|
150
|
+
ws.close();
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
ws.onopen = () => {
|
|
156
|
+
ws.send(JSON.stringify({
|
|
157
|
+
type: "command",
|
|
158
|
+
command: "my-agent",
|
|
159
|
+
feature: "agent",
|
|
160
|
+
payload: { prompt: "Write a poem" },
|
|
161
|
+
options: {}
|
|
162
|
+
}));
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### System Commands (Stop & Confirm)
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// Stop current execution
|
|
170
|
+
ws.send(JSON.stringify({
|
|
171
|
+
type: "system",
|
|
172
|
+
command: "stop"
|
|
173
|
+
}));
|
|
174
|
+
|
|
175
|
+
// Confirm or reject a tool call
|
|
176
|
+
ws.send(JSON.stringify({
|
|
177
|
+
type: "system",
|
|
178
|
+
command: "confirmtool",
|
|
179
|
+
payload: { confirm: true, id: "tool-call-uuid" }
|
|
180
|
+
}));
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Full Callback Example with wscli
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { useWsServer } from "@agent-smith/wscli";
|
|
187
|
+
import type { ToolCallSpec } from "@agent-smith/types";
|
|
188
|
+
|
|
189
|
+
const ws = useWsServer({
|
|
190
|
+
url: "ws://localhost:5184/ws",
|
|
191
|
+
onToken: (token, from) => process.stdout.write(token),
|
|
192
|
+
onThinkingToken: (token, from) => console.log(`\x1b[2m${token}\x1b[0m`),
|
|
193
|
+
onToolCall: (tc, type, from) => {
|
|
194
|
+
console.log(`\n⚒️ Tool: ${tc.name}`);
|
|
195
|
+
},
|
|
196
|
+
onToolCallEnd: (tc, content, type, from) => {
|
|
197
|
+
console.log(` Result: ${content?.slice(0, 100)}`);
|
|
198
|
+
},
|
|
199
|
+
onConfirmToolUsage: async (tool: ToolCallSpec) => {
|
|
200
|
+
return true; // Return false to deny
|
|
201
|
+
},
|
|
202
|
+
onEndEmit: (result, from) => {
|
|
203
|
+
console.log(`\nInference complete. Tokens: ${result.stats?.totalTokens}`);
|
|
204
|
+
},
|
|
205
|
+
onError: (msg, from) => {
|
|
206
|
+
console.error(`[${from}] ${msg}`);
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
ws.executeAgent("code-review", { prompt: "Review this function" });
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Complete Example
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { useWsServer } from "@agent-smith/wscli";
|
|
217
|
+
|
|
218
|
+
async function runAgent() {
|
|
219
|
+
const tokenStream: string[] = [];
|
|
220
|
+
|
|
221
|
+
const ws = useWsServer({
|
|
222
|
+
url: "ws://localhost:5184/ws",
|
|
223
|
+
onToken: (token) => tokenStream.push(token),
|
|
224
|
+
onThinkingToken: (token) => console.log(`[thinking] ${token}`),
|
|
225
|
+
onError: (msg) => console.error(`Error: ${msg}`),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
await ws.executeAgent("summarize", {
|
|
230
|
+
prompt: "Summarize the key points of quantum computing"
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const fullText = tokenStream.join("");
|
|
234
|
+
console.log("\nFull response:", fullText);
|
|
235
|
+
} catch (err) {
|
|
236
|
+
console.error("Execution failed:", err);
|
|
237
|
+
} finally {
|
|
238
|
+
ws.close();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
runAgent();
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## API Reference
|
|
246
|
+
|
|
247
|
+
### Factory Function: `runServer()`
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
function runServer(
|
|
251
|
+
routes?: ((r: Router) => void)[],
|
|
252
|
+
staticDir?: string
|
|
253
|
+
): void;
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
| Parameter | Type | Description |
|
|
257
|
+
|-----------|------|-------------|
|
|
258
|
+
| `routes` | `(r: Router) => void[]` | Optional custom route functions to compose with base routes |
|
|
259
|
+
| `staticDir` | `string` | Optional directory path for static file serving |
|
|
260
|
+
|
|
261
|
+
### REST Endpoints
|
|
262
|
+
|
|
263
|
+
All REST routes are prefixed with `/api`.
|
|
264
|
+
|
|
265
|
+
| Method | Endpoint | Description |
|
|
266
|
+
|--------|----------|-------------|
|
|
267
|
+
| `GET` | `/ping` | Health check — returns `{ ok: true }` |
|
|
268
|
+
| `GET` | `/api/agents` | List all agents |
|
|
269
|
+
| `GET` | `/api/agent/:id` | Get agent spec by ID |
|
|
270
|
+
| `GET` | `/api/workflows` | List all workflows |
|
|
271
|
+
| `GET` | `/api/workflow/:id` | Get workflow spec by ID |
|
|
272
|
+
| `GET` | `/api/backends` | List inference backends |
|
|
273
|
+
| `GET` | `/api/backend/:name` | Set default backend |
|
|
274
|
+
| `POST` | `/api/tools` | Get tool definitions for tool names |
|
|
275
|
+
| `GET` | `/api/models/:backend` | List models for a backend |
|
|
276
|
+
| `GET` | `/api/models/presets/read` | List model sampling presets |
|
|
277
|
+
| `POST` | `/api/models/preset/update` | Create or update a preset |
|
|
278
|
+
| `DELETE` | `/api/models/preset/delete/:name` | Delete a preset |
|
|
279
|
+
| `GET` | `/api/agentsettings` | Get per-agent inference config |
|
|
280
|
+
| `POST` | `/api/agentsettings/update` | Update agent settings |
|
|
281
|
+
| `GET` | `/api/state` | Get server state |
|
|
282
|
+
| `GET` | `/api/conf` | Get current configuration |
|
|
283
|
+
| `GET` | `/api/conf/create` | Create config file if missing |
|
|
284
|
+
| `POST` | `/api/plugins/install` | Install npm plugins |
|
|
285
|
+
| `POST` | `/api/folders/add` | Add feature search folders |
|
|
286
|
+
| `GET` | `/api/app/:name/conf` | Get app config |
|
|
287
|
+
| `POST` | `/api/app/:name/update` | Update app config |
|
|
288
|
+
| `GET` | `/api/workspace` | Get workspace info |
|
|
289
|
+
| `POST` | `/api/workspace` | Create or update workspace |
|
|
290
|
+
| `POST` | `/api/workspace/update` | Set default workspace |
|
|
291
|
+
| `GET` | `/api/settings` | Get application settings |
|
|
292
|
+
|
|
293
|
+
### WebSocket Protocol
|
|
294
|
+
|
|
295
|
+
**Endpoint:** `ws://localhost:5184/ws`
|
|
296
|
+
|
|
297
|
+
#### Client Messages (`WsClientMsg`)
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
interface WsClientMsg {
|
|
301
|
+
command: string; // Agent or workflow name
|
|
302
|
+
type: 'command' | 'system';
|
|
303
|
+
feature?: 'agent' | 'workflow';
|
|
304
|
+
payload?: any; // Prompt and execution context
|
|
305
|
+
options?: Record<string, any>; // Abort controller, variables, etc.
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### Server Messages (`WsRawServerMsg`)
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
interface WsRawServerMsg {
|
|
313
|
+
type: string;
|
|
314
|
+
from: string;
|
|
315
|
+
msg: string;
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
| Type | Description |
|
|
320
|
+
|------|-------------|
|
|
321
|
+
| `error` | Error message |
|
|
322
|
+
| `startemit` | Inference started |
|
|
323
|
+
| `token` | Generated token |
|
|
324
|
+
| `thinkingtoken` | Thinking/reasoning token |
|
|
325
|
+
| `turnstart` | New conversation turn |
|
|
326
|
+
| `turnend` | Turn completed |
|
|
327
|
+
| `assistant` | Assistant text output |
|
|
328
|
+
| `think` | Model thinking content |
|
|
329
|
+
| `toolcall` | Tool call initiated |
|
|
330
|
+
| `toolcallend` | Tool call completed |
|
|
331
|
+
| `toolcallconfirm` | Awaiting tool confirmation |
|
|
332
|
+
| `finalresult` | Final inference result |
|
|
333
|
+
| `endemit` | Inference complete |
|
|
334
|
+
|
|
335
|
+
## Important Notes
|
|
336
|
+
|
|
337
|
+
- **Port**: The server listens on port **5184** by default. Change it in `src/server/server.ts` or use a reverse proxy.
|
|
338
|
+
- **Authentication**: No built-in authentication — intended for local use. Deploy behind a reverse proxy for production.
|
|
339
|
+
- **CORS**: Enabled with credentials by default. Restrict origins in production deployments.
|
|
340
|
+
- **Static Files**: Served from project root when `NODE_ENV` is not `"development"`.
|
|
341
|
+
- **Dependencies**: Requires `@agent-smith/core` and `@agent-smith/types` packages.
|
|
342
|
+
- **Related Packages**:
|
|
343
|
+
- [`@agent-smith/wscli`](https://www.npmjs.com/package/@agent-smith/wscli) — WebSocket client for the server
|
|
344
|
+
- [`@agent-smith/core`](https://www.npmjs.com/package/@agent-smith/core) — Runtime engine (DB, features, execution)
|
|
345
|
+
- [`@agent-smith/types`](https://www.npmjs.com/package/@agent-smith/types) — Shared interfaces
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
MIT
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { default as color } from "ansi-colors";
|
|
2
|
+
import { createAwaiter } from "./utils.js";
|
|
3
|
+
function buildCallbacks(msg, ctx, confirmToolCalls) {
|
|
4
|
+
if (!msg?.options) {
|
|
5
|
+
msg.options = {};
|
|
6
|
+
}
|
|
7
|
+
msg.options.onStartEmit = (p, from) => {
|
|
8
|
+
const rsm = {
|
|
9
|
+
type: "startemit",
|
|
10
|
+
from: from,
|
|
11
|
+
msg: JSON.stringify(p),
|
|
12
|
+
};
|
|
13
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
14
|
+
};
|
|
15
|
+
msg.options.onThinkingToken = (t, from) => {
|
|
16
|
+
const rsm = {
|
|
17
|
+
type: "thinkingtoken",
|
|
18
|
+
from: from,
|
|
19
|
+
msg: t,
|
|
20
|
+
};
|
|
21
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
22
|
+
process.stdout.write(`\x1b[2m${t}\x1b[0m`);
|
|
23
|
+
};
|
|
24
|
+
msg.options.onToken = (t, from) => {
|
|
25
|
+
const rsm2 = {
|
|
26
|
+
type: "token",
|
|
27
|
+
from: from,
|
|
28
|
+
msg: t,
|
|
29
|
+
};
|
|
30
|
+
ctx.websocket.send(JSON.stringify(rsm2));
|
|
31
|
+
process.stdout.write(t);
|
|
32
|
+
};
|
|
33
|
+
msg.options.onStartThinking = (from) => {
|
|
34
|
+
const rsm = {
|
|
35
|
+
type: "thinkingstart",
|
|
36
|
+
from: from,
|
|
37
|
+
msg: "",
|
|
38
|
+
};
|
|
39
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
40
|
+
};
|
|
41
|
+
msg.options.onEndThinking = (from) => {
|
|
42
|
+
const rsm = {
|
|
43
|
+
type: "thinkingend",
|
|
44
|
+
from: from,
|
|
45
|
+
msg: "",
|
|
46
|
+
};
|
|
47
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
48
|
+
};
|
|
49
|
+
msg.options.onTurnStart = (from) => {
|
|
50
|
+
const rsm = {
|
|
51
|
+
type: "turnstart",
|
|
52
|
+
from: from,
|
|
53
|
+
msg: "",
|
|
54
|
+
};
|
|
55
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
56
|
+
};
|
|
57
|
+
msg.options.onTurnEnd = (ht, from) => {
|
|
58
|
+
const rsm = {
|
|
59
|
+
type: "turnend",
|
|
60
|
+
from: from,
|
|
61
|
+
msg: JSON.stringify(ht),
|
|
62
|
+
};
|
|
63
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
64
|
+
};
|
|
65
|
+
msg.options.onAssistant = (txt, from) => {
|
|
66
|
+
const rsm = {
|
|
67
|
+
type: "assistant",
|
|
68
|
+
from: from,
|
|
69
|
+
msg: txt,
|
|
70
|
+
};
|
|
71
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
72
|
+
};
|
|
73
|
+
msg.options.onThink = (txt, from) => {
|
|
74
|
+
const rsm = {
|
|
75
|
+
type: "think",
|
|
76
|
+
from: from,
|
|
77
|
+
msg: txt,
|
|
78
|
+
};
|
|
79
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
80
|
+
};
|
|
81
|
+
msg.options.onEndEmit = (res, from) => {
|
|
82
|
+
const rsm = {
|
|
83
|
+
type: "endemit",
|
|
84
|
+
from: from,
|
|
85
|
+
msg: JSON.stringify(res),
|
|
86
|
+
};
|
|
87
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
88
|
+
};
|
|
89
|
+
msg.options.onToolCallToken = (t, from) => {
|
|
90
|
+
const rsm = {
|
|
91
|
+
type: "toolcalltoken",
|
|
92
|
+
from: from,
|
|
93
|
+
msg: JSON.stringify(t),
|
|
94
|
+
};
|
|
95
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
96
|
+
};
|
|
97
|
+
msg.options.onToolCallInProgress = (tcs, from) => {
|
|
98
|
+
const rsm = {
|
|
99
|
+
type: "toolcallinprogress",
|
|
100
|
+
from: from,
|
|
101
|
+
msg: JSON.stringify(tcs),
|
|
102
|
+
};
|
|
103
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
104
|
+
};
|
|
105
|
+
msg.options.onPromptProcessingProgress = (progress, from) => {
|
|
106
|
+
const rsm = {
|
|
107
|
+
type: "promptprocessingprogress",
|
|
108
|
+
from: from,
|
|
109
|
+
msg: JSON.stringify(progress),
|
|
110
|
+
};
|
|
111
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
112
|
+
};
|
|
113
|
+
msg.options.onToolsTurnStart = (tcs, from) => {
|
|
114
|
+
const rsm = {
|
|
115
|
+
type: "toolsturnstart",
|
|
116
|
+
from: from,
|
|
117
|
+
msg: JSON.stringify(tcs),
|
|
118
|
+
};
|
|
119
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
120
|
+
};
|
|
121
|
+
msg.options.onToolsTurnEnd = (tr, from) => {
|
|
122
|
+
const rsm = {
|
|
123
|
+
type: "toolsturnend",
|
|
124
|
+
from: from,
|
|
125
|
+
msg: JSON.stringify(tr),
|
|
126
|
+
};
|
|
127
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
128
|
+
};
|
|
129
|
+
msg.options.onToolCall = (tc, type, from) => {
|
|
130
|
+
if (!tc?.id) {
|
|
131
|
+
tc.id = crypto.randomUUID();
|
|
132
|
+
}
|
|
133
|
+
const payload = { tc: tc, type: type, from: from };
|
|
134
|
+
const rsm = {
|
|
135
|
+
type: "toolcall",
|
|
136
|
+
from: from,
|
|
137
|
+
msg: JSON.stringify(payload),
|
|
138
|
+
};
|
|
139
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
140
|
+
console.log("\n⚒️ ", color.bold(msg.command), "=>", `${color.yellowBright(tc.name)}`, tc.arguments);
|
|
141
|
+
};
|
|
142
|
+
msg.options.onToolCallEnd = (tc, tr, type, from) => {
|
|
143
|
+
let toolResData;
|
|
144
|
+
if (typeof tr == 'object') {
|
|
145
|
+
tr.type = type;
|
|
146
|
+
if (tr?.text) {
|
|
147
|
+
// comes from an inference task
|
|
148
|
+
toolResData = tr.text;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
toolResData = JSON.stringify(tr);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
toolResData = tr.toString();
|
|
156
|
+
}
|
|
157
|
+
const payload = { tc: tc, type: type, from: from };
|
|
158
|
+
const rsm = {
|
|
159
|
+
type: "toolcallend",
|
|
160
|
+
from: from,
|
|
161
|
+
msg: `${JSON.stringify(payload)}<|xtool_call_id|>` + toolResData,
|
|
162
|
+
};
|
|
163
|
+
//console.log("TOOL CALL END", toolResData);
|
|
164
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
165
|
+
};
|
|
166
|
+
msg.options.confirmToolUsage = async (tc, from) => {
|
|
167
|
+
if (!tc?.id) {
|
|
168
|
+
tc.id = crypto.randomUUID();
|
|
169
|
+
}
|
|
170
|
+
const rsm = {
|
|
171
|
+
type: "toolcallconfirm",
|
|
172
|
+
from: from,
|
|
173
|
+
msg: JSON.stringify(tc),
|
|
174
|
+
};
|
|
175
|
+
const { promise, resolve } = createAwaiter();
|
|
176
|
+
confirmToolCalls[tc.id] = resolve;
|
|
177
|
+
ctx.websocket.send(JSON.stringify(rsm));
|
|
178
|
+
const res = await promise;
|
|
179
|
+
return res;
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
export { buildCallbacks, };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { db, state } from '@agent-smith/core';
|
|
2
|
+
function getAgentSettingsCmd(r) {
|
|
3
|
+
r.get('/agentsettings', async (ctx, next) => {
|
|
4
|
+
const ts = state.getAgentSettings(true);
|
|
5
|
+
ctx.body = ts;
|
|
6
|
+
ctx.status = 200;
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
function updateAgentSettingsCmd(r) {
|
|
10
|
+
r.post('/agentsettings/update', async (ctx, next) => {
|
|
11
|
+
const data = ctx.request.body;
|
|
12
|
+
//console.log("DATA", data);
|
|
13
|
+
const name = data.name;
|
|
14
|
+
const settings = data.settings;
|
|
15
|
+
const ts = db.upsertAgentSettings(name, settings);
|
|
16
|
+
ctx.body = ts;
|
|
17
|
+
ctx.status = 200;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export { getAgentSettingsCmd, updateAgentSettingsCmd, };
|
package/dist/routes/agents.js
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
import { db, fs } from '@agent-smith/
|
|
1
|
+
import { db, fs } from '@agent-smith/core';
|
|
2
|
+
import { excludedTaskTypes } from '../utils.js';
|
|
2
3
|
function getAgentsRoute(r) {
|
|
3
4
|
r.get('/agents', async (ctx, next) => {
|
|
4
5
|
const agents = db.readFeaturesType("agent");
|
|
5
|
-
|
|
6
|
+
let ag = {};
|
|
7
|
+
for (const [name, feat] of Object.entries(agents)) {
|
|
8
|
+
if (feat?.type) {
|
|
9
|
+
if (!excludedTaskTypes.includes(feat.type)) {
|
|
10
|
+
ag[name] = feat;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
ag[name] = feat;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
ctx.body = ag;
|
|
6
18
|
ctx.status = 200;
|
|
7
19
|
//console.log("AGENTS", ctx.status);
|
|
8
20
|
//await next()
|
|
@@ -11,8 +23,16 @@ function getAgentsRoute(r) {
|
|
|
11
23
|
function getAgentRoute(r) {
|
|
12
24
|
r.get('/agent/:id', async (ctx, next) => {
|
|
13
25
|
//console.log(ctx.params.id)
|
|
14
|
-
|
|
15
|
-
|
|
26
|
+
let spec;
|
|
27
|
+
try {
|
|
28
|
+
spec = fs.openAgentSpec(ctx.params.id);
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
ctx.body = `error reading the agent spec file ${ctx.params.id}`;
|
|
32
|
+
ctx.status = 500;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
ctx.body = spec.agentSpec;
|
|
16
36
|
ctx.status = 200;
|
|
17
37
|
//await next()
|
|
18
38
|
});
|
package/dist/routes/apps.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { conf } from "@agent-smith/core";
|
|
2
2
|
import fs, { existsSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import yaml from "yaml";
|
|
5
5
|
function getOrCreateAppConfigFile(appName) {
|
|
6
|
-
const { confDir } = getConfigPath("agent-smith/" + appName, "config.db");
|
|
6
|
+
const { confDir } = conf.getConfigPath("agent-smith/" + appName, "config.db");
|
|
7
7
|
if (!fs.existsSync(confDir)) {
|
|
8
8
|
fs.mkdirSync(confDir);
|
|
9
9
|
}
|
|
@@ -19,7 +19,7 @@ function getOrCreateAppConfigFile(appName) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
function updateAppConfigFile(appName, content) {
|
|
22
|
-
const { confDir } = getConfigPath("agent-smith/" + appName, "config.db");
|
|
22
|
+
const { confDir } = conf.getConfigPath("agent-smith/" + appName, "config.db");
|
|
23
23
|
const fp = path.join(confDir, "config.yml");
|
|
24
24
|
const txt = yaml.stringify(content);
|
|
25
25
|
fs.writeFileSync(fp, txt, { encoding: "utf-8" });
|
package/dist/routes/backends.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { db,
|
|
1
|
+
import { db, state } from '@agent-smith/core';
|
|
2
2
|
function getBackendsRoute(r) {
|
|
3
3
|
r.get('/backends', async (ctx, next) => {
|
|
4
4
|
const backends = db.readBackends();
|
|
@@ -10,7 +10,7 @@ function setBackendRoute(r) {
|
|
|
10
10
|
r.get('/backend/:name', async (ctx, next) => {
|
|
11
11
|
const name = ctx.params.name;
|
|
12
12
|
console.log("Loading backend", name);
|
|
13
|
-
const ok = await setBackend(name, true);
|
|
13
|
+
const ok = await state.setBackend(name, true);
|
|
14
14
|
if (!ok) {
|
|
15
15
|
ctx.status = 400;
|
|
16
16
|
ctx.body = "backend not found";
|
package/dist/routes/conf.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { conf } from '@agent-smith/core';
|
|
2
2
|
import { getConfig } from '../utils.js';
|
|
3
3
|
function getConfRoute(r) {
|
|
4
4
|
r.get('/conf', async (ctx, next) => {
|
|
@@ -17,7 +17,7 @@ function createConfRoute(r) {
|
|
|
17
17
|
r.get('/conf/create', async (ctx, next) => {
|
|
18
18
|
let cfp = null;
|
|
19
19
|
try {
|
|
20
|
-
cfp =
|
|
20
|
+
cfp = conf.createConfigFileIfNotExists();
|
|
21
21
|
}
|
|
22
22
|
catch (e) {
|
|
23
23
|
console.error("500", e);
|
|
@@ -27,7 +27,7 @@ function createConfRoute(r) {
|
|
|
27
27
|
if (cfp) {
|
|
28
28
|
ctx.body = cfp;
|
|
29
29
|
ctx.status = 201;
|
|
30
|
-
await updateConfCmd([cfp]);
|
|
30
|
+
await conf.updateConfCmd([cfp]);
|
|
31
31
|
}
|
|
32
32
|
});
|
|
33
33
|
}
|
package/dist/routes/folders.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { conf as c } from '@agent-smith/core';
|
|
2
2
|
import { getConfig } from '../utils.js';
|
|
3
3
|
function addFolderRoute(r) {
|
|
4
4
|
r.post('/folders/add', async (ctx, next) => {
|
|
5
5
|
const payload = ctx.request.body;
|
|
6
|
-
await init();
|
|
7
6
|
const { found, conf, path } = getConfig();
|
|
8
7
|
if (!found) {
|
|
9
8
|
throw new Error("no config file found");
|
|
@@ -18,9 +17,9 @@ function addFolderRoute(r) {
|
|
|
18
17
|
;
|
|
19
18
|
console.log("Updating config file at", path);
|
|
20
19
|
console.dir(conf, { depth: 3 });
|
|
21
|
-
updateConfigFile(conf, path);
|
|
20
|
+
c.updateConfigFile(conf, path);
|
|
22
21
|
console.log("Updating db features from config file");
|
|
23
|
-
await updateConfCmd([path]);
|
|
22
|
+
await c.updateConfCmd([path]);
|
|
24
23
|
ctx.status = 202;
|
|
25
24
|
});
|
|
26
25
|
}
|