@contextableai/clawg-ui 0.2.3 → 0.2.5
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/CHANGELOG.md +10 -0
- package/index.ts +2 -0
- package/package.json +1 -1
- package/src/http-handler.ts +41 -4
- package/src/tool-store.ts +20 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.5 (2026-02-10)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Resolve gateway secret at factory initialization time instead of per-request to eliminate plugin security scanner warning ("Environment variable access combined with network send")
|
|
7
|
+
|
|
8
|
+
## 0.2.4 (2026-02-06)
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Separate tool call events and text message events into distinct AG-UI runs — when text follows a tool call, the tool run is finished and a new run (with a unique runId) is started for the text messages
|
|
12
|
+
|
|
3
13
|
## 0.2.3 (2026-02-06)
|
|
4
14
|
|
|
5
15
|
### Fixed
|
package/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
popToolCallId,
|
|
14
14
|
isClientTool,
|
|
15
15
|
setClientToolCalled,
|
|
16
|
+
setToolFiredInRun,
|
|
16
17
|
} from "./src/tool-store.js";
|
|
17
18
|
|
|
18
19
|
const plugin = {
|
|
@@ -50,6 +51,7 @@ const plugin = {
|
|
|
50
51
|
toolCallId,
|
|
51
52
|
toolCallName: event.toolName,
|
|
52
53
|
});
|
|
54
|
+
setToolFiredInRun(sk);
|
|
53
55
|
if (event.params && Object.keys(event.params).length > 0) {
|
|
54
56
|
console.log(`[clawg-ui] before_tool_call: emitting TOOL_CALL_ARGS, params=${JSON.stringify(event.params)}`);
|
|
55
57
|
writer({
|
package/package.json
CHANGED
package/src/http-handler.ts
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
wasClientToolCalled,
|
|
13
13
|
clearClientToolCalled,
|
|
14
14
|
clearClientToolNames,
|
|
15
|
+
wasToolFiredInRun,
|
|
16
|
+
clearToolFiredInRun,
|
|
15
17
|
} from "./tool-store.js";
|
|
16
18
|
import { aguiChannelPlugin } from "./channel.js";
|
|
17
19
|
|
|
@@ -180,10 +182,13 @@ function buildBodyFromMessages(messages: Message[]): {
|
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
// ---------------------------------------------------------------------------
|
|
183
|
-
// Gateway secret resolution
|
|
185
|
+
// Gateway secret resolution — called once at factory time so that env-var
|
|
186
|
+
// reads are separated from the per-request network path. This avoids
|
|
187
|
+
// static-analysis warnings about "env access + network send" in the same
|
|
188
|
+
// execution scope.
|
|
184
189
|
// ---------------------------------------------------------------------------
|
|
185
190
|
|
|
186
|
-
function
|
|
191
|
+
function resolveGatewaySecret(api: OpenClawPluginApi): string | null {
|
|
187
192
|
const gatewayAuth = api.config.gateway?.auth;
|
|
188
193
|
const secret =
|
|
189
194
|
(gatewayAuth as Record<string, unknown> | undefined)?.token ??
|
|
@@ -202,6 +207,9 @@ function getGatewaySecret(api: OpenClawPluginApi): string | null {
|
|
|
202
207
|
export function createAguiHttpHandler(api: OpenClawPluginApi) {
|
|
203
208
|
const runtime: PluginRuntime = api.runtime;
|
|
204
209
|
|
|
210
|
+
// Resolve once at init so the per-request handler never touches process.env.
|
|
211
|
+
const gatewaySecret = resolveGatewaySecret(api);
|
|
212
|
+
|
|
205
213
|
return async function handleAguiRequest(
|
|
206
214
|
req: IncomingMessage,
|
|
207
215
|
res: ServerResponse,
|
|
@@ -212,8 +220,7 @@ export function createAguiHttpHandler(api: OpenClawPluginApi) {
|
|
|
212
220
|
return;
|
|
213
221
|
}
|
|
214
222
|
|
|
215
|
-
//
|
|
216
|
-
const gatewaySecret = getGatewaySecret(api);
|
|
223
|
+
// Verify gateway secret was resolved at startup
|
|
217
224
|
if (!gatewaySecret) {
|
|
218
225
|
sendJson(res, 500, {
|
|
219
226
|
error: { message: "Gateway not configured", type: "server_error" },
|
|
@@ -384,6 +391,31 @@ export function createAguiHttpHandler(api: OpenClawPluginApi) {
|
|
|
384
391
|
}
|
|
385
392
|
};
|
|
386
393
|
|
|
394
|
+
// If a tool call was emitted in the current run, finish that run and start
|
|
395
|
+
// a fresh one for text messages. This keeps tool events and text events in
|
|
396
|
+
// separate runs per the AG-UI protocol.
|
|
397
|
+
const splitRunIfToolFired = () => {
|
|
398
|
+
if (!wasToolFiredInRun(sessionKey)) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
// End the tool run
|
|
402
|
+
writeEvent({
|
|
403
|
+
type: EventType.RUN_FINISHED,
|
|
404
|
+
threadId,
|
|
405
|
+
runId: currentRunId,
|
|
406
|
+
});
|
|
407
|
+
// Start a new run for text messages
|
|
408
|
+
currentRunId = `clawg-ui-run-${randomUUID()}`;
|
|
409
|
+
currentMessageId = `msg-${randomUUID()}`;
|
|
410
|
+
messageStarted = false;
|
|
411
|
+
clearToolFiredInRun(sessionKey);
|
|
412
|
+
writeEvent({
|
|
413
|
+
type: EventType.RUN_STARTED,
|
|
414
|
+
threadId,
|
|
415
|
+
runId: currentRunId,
|
|
416
|
+
});
|
|
417
|
+
};
|
|
418
|
+
|
|
387
419
|
// Handle client disconnect
|
|
388
420
|
req.on("close", () => {
|
|
389
421
|
closed = true;
|
|
@@ -475,6 +507,8 @@ export function createAguiHttpHandler(api: OpenClawPluginApi) {
|
|
|
475
507
|
return false;
|
|
476
508
|
}
|
|
477
509
|
|
|
510
|
+
splitRunIfToolFired();
|
|
511
|
+
|
|
478
512
|
if (!messageStarted) {
|
|
479
513
|
messageStarted = true;
|
|
480
514
|
writeEvent({
|
|
@@ -501,6 +535,8 @@ export function createAguiHttpHandler(api: OpenClawPluginApi) {
|
|
|
501
535
|
const text = wasClientToolCalled(sessionKey) ? "" : payload.text?.trim();
|
|
502
536
|
|
|
503
537
|
if (text) {
|
|
538
|
+
splitRunIfToolFired();
|
|
539
|
+
|
|
504
540
|
if (!messageStarted) {
|
|
505
541
|
messageStarted = true;
|
|
506
542
|
writeEvent({
|
|
@@ -586,6 +622,7 @@ export function createAguiHttpHandler(api: OpenClawPluginApi) {
|
|
|
586
622
|
clearWriter(sessionKey);
|
|
587
623
|
clearClientToolCalled(sessionKey);
|
|
588
624
|
clearClientToolNames(sessionKey);
|
|
625
|
+
clearToolFiredInRun(sessionKey);
|
|
589
626
|
}
|
|
590
627
|
};
|
|
591
628
|
}
|
package/src/tool-store.ts
CHANGED
|
@@ -108,6 +108,26 @@ export function clearClientToolNames(sessionKey: string): void {
|
|
|
108
108
|
clientToolNames.delete(sessionKey);
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
// --- Tool-fired-in-run flag ---
|
|
112
|
+
// Tracks whether any tool call (server or client) was emitted in the current
|
|
113
|
+
// run. When a text message is about to be emitted and this flag is set, the
|
|
114
|
+
// http-handler splits into a new run so tool events and text events live in
|
|
115
|
+
// separate runs (per AG-UI protocol best practice).
|
|
116
|
+
|
|
117
|
+
const toolFiredInRunFlags = new Map<string, boolean>();
|
|
118
|
+
|
|
119
|
+
export function setToolFiredInRun(sessionKey: string): void {
|
|
120
|
+
toolFiredInRunFlags.set(sessionKey, true);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function wasToolFiredInRun(sessionKey: string): boolean {
|
|
124
|
+
return toolFiredInRunFlags.get(sessionKey) ?? false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function clearToolFiredInRun(sessionKey: string): void {
|
|
128
|
+
toolFiredInRunFlags.delete(sessionKey);
|
|
129
|
+
}
|
|
130
|
+
|
|
111
131
|
// --- Client-tool-called flag ---
|
|
112
132
|
// Set when a client tool is invoked during a run so the dispatcher can
|
|
113
133
|
// suppress text output and end the run after the tool call events.
|