@contextableai/clawg-ui 0.3.2 → 0.4.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/README.md +23 -2
- package/dist/index.js +6 -1
- package/dist/src/http-handler.d.ts +1 -0
- package/dist/src/http-handler.js +42 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -133,15 +133,36 @@ function App() {
|
|
|
133
133
|
}
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
## Agent discovery (`/info`)
|
|
137
|
+
|
|
138
|
+
The plugin registers a `/v1/clawg-ui/info` endpoint that CopilotKit and other AG-UI clients use to discover available agents. Accepts GET or POST.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
curl http://localhost:18789/v1/clawg-ui/info \
|
|
142
|
+
-H "Authorization: Bearer <device-token>"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Response:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"agents": {
|
|
150
|
+
"main": { "name": "main", "description": "Default agent" }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The response reflects the agents configured in OpenClaw's `agents.list` config. If no agents are configured, a default `"main"` agent is returned.
|
|
156
|
+
|
|
136
157
|
## Request format
|
|
137
158
|
|
|
138
|
-
The endpoint accepts a POST with a JSON body matching the AG-UI `RunAgentInput` schema:
|
|
159
|
+
The run endpoint accepts a POST with a JSON body matching the AG-UI `RunAgentInput` schema:
|
|
139
160
|
|
|
140
161
|
| Field | Type | Required | Description |
|
|
141
162
|
|---|---|---|---|
|
|
142
163
|
| `threadId` | string | no | Conversation thread ID. Auto-generated if omitted. |
|
|
143
164
|
| `runId` | string | no | Unique run ID. Auto-generated if omitted. |
|
|
144
|
-
| `messages` | Message[] | yes | Array of messages.
|
|
165
|
+
| `messages` | Message[] | yes | Array of messages. May be empty (returns an empty run). For agent execution, at least one `user` or `tool` message should be present. |
|
|
145
166
|
| `tools` | Tool[] | no | Client-side tool definitions. The agent can invoke these; see [Tool call events](#tool-call-events). |
|
|
146
167
|
| `state` | object | no | Client state (reserved for future use). |
|
|
147
168
|
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { EventType } from "@ag-ui/core";
|
|
4
4
|
import { aguiChannelPlugin } from "./src/channel.js";
|
|
5
|
-
import { createAguiHttpHandler } from "./src/http-handler.js";
|
|
5
|
+
import { createAguiHttpHandler, createAguiInfoHandler } from "./src/http-handler.js";
|
|
6
6
|
import { clawgUiToolFactory } from "./src/client-tools.js";
|
|
7
7
|
import { getWriter, getMessageId, pushToolCallId, popToolCallId, isClientTool, setClientToolCalled, setToolFiredInRun, } from "./src/tool-store.js";
|
|
8
8
|
/**
|
|
@@ -97,6 +97,11 @@ const plugin = {
|
|
|
97
97
|
auth: "plugin",
|
|
98
98
|
handler: createAguiHttpHandler(api),
|
|
99
99
|
});
|
|
100
|
+
api.registerHttpRoute({
|
|
101
|
+
path: "/v1/clawg-ui/info",
|
|
102
|
+
auth: "plugin",
|
|
103
|
+
handler: createAguiInfoHandler(api),
|
|
104
|
+
});
|
|
100
105
|
api.on("before_tool_call", handleBeforeToolCall);
|
|
101
106
|
api.on("tool_result_persist", handleToolResultPersist);
|
|
102
107
|
// CLI commands for device management
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
3
3
|
export declare function createAguiHttpHandler(api: OpenClawPluginApi): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
4
|
+
export declare function createAguiInfoHandler(api: OpenClawPluginApi): (_req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
package/dist/src/http-handler.js
CHANGED
|
@@ -12,8 +12,8 @@ function sendJson(res, status, body) {
|
|
|
12
12
|
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
13
13
|
res.end(JSON.stringify(body));
|
|
14
14
|
}
|
|
15
|
-
function sendMethodNotAllowed(res) {
|
|
16
|
-
res.setHeader("Allow",
|
|
15
|
+
function sendMethodNotAllowed(res, allow = "POST") {
|
|
16
|
+
res.setHeader("Allow", allow);
|
|
17
17
|
res.statusCode = 405;
|
|
18
18
|
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
19
19
|
res.end("Method Not Allowed");
|
|
@@ -264,13 +264,21 @@ export function createAguiHttpHandler(api) {
|
|
|
264
264
|
const hasUserMessage = messages.some((m) => m.role === "user");
|
|
265
265
|
const hasToolMessage = messages.some((m) => m.role === "tool");
|
|
266
266
|
if (!hasUserMessage && !hasToolMessage) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
267
|
+
// AG-UI protocol allows empty messages (used for session init/sync).
|
|
268
|
+
// Return a valid empty run instead of 400.
|
|
269
|
+
const accept = typeof req.headers.accept === "string"
|
|
270
|
+
? req.headers.accept
|
|
271
|
+
: "text/event-stream";
|
|
272
|
+
const encoder = new EventEncoder({ accept });
|
|
273
|
+
res.statusCode = 200;
|
|
274
|
+
res.setHeader("Content-Type", encoder.getContentType());
|
|
275
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
276
|
+
res.setHeader("Connection", "keep-alive");
|
|
277
|
+
res.setHeader("X-Accel-Buffering", "no");
|
|
278
|
+
res.flushHeaders?.();
|
|
279
|
+
res.write(encoder.encode({ type: EventType.RUN_STARTED, threadId, runId }));
|
|
280
|
+
res.write(encoder.encode({ type: EventType.RUN_FINISHED, threadId, runId }));
|
|
281
|
+
res.end();
|
|
274
282
|
return;
|
|
275
283
|
}
|
|
276
284
|
// Build body from messages
|
|
@@ -543,3 +551,28 @@ export function createAguiHttpHandler(api) {
|
|
|
543
551
|
}
|
|
544
552
|
};
|
|
545
553
|
}
|
|
554
|
+
// ---------------------------------------------------------------------------
|
|
555
|
+
// /info handler — agent discovery for CopilotKit
|
|
556
|
+
// ---------------------------------------------------------------------------
|
|
557
|
+
export function createAguiInfoHandler(api) {
|
|
558
|
+
const runtime = api.runtime;
|
|
559
|
+
return async function handleAguiInfo(_req, res) {
|
|
560
|
+
if (_req.method !== "GET" && _req.method !== "POST") {
|
|
561
|
+
sendMethodNotAllowed(res, "GET, POST");
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const cfg = runtime.config.loadConfig();
|
|
565
|
+
const agentList = cfg
|
|
566
|
+
.agents?.list ?? [];
|
|
567
|
+
const agents = {};
|
|
568
|
+
for (const agent of agentList) {
|
|
569
|
+
const name = agent.name ?? agent.id;
|
|
570
|
+
agents[agent.id] = { name, description: name };
|
|
571
|
+
}
|
|
572
|
+
// If no agents configured, expose a default "main" agent
|
|
573
|
+
if (Object.keys(agents).length === 0) {
|
|
574
|
+
agents["main"] = { name: "main", description: "Default agent" };
|
|
575
|
+
}
|
|
576
|
+
sendJson(res, 200, { agents });
|
|
577
|
+
};
|
|
578
|
+
}
|
package/package.json
CHANGED