@clawdreyhepburn/carapace 0.3.2 → 0.3.3
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 +21 -0
- package/README.md +36 -1
- package/dist/cedar-engine-cedarling.d.ts +81 -0
- package/dist/cedar-engine-cedarling.js +651 -0
- package/dist/cedar-engine-cedarling.js.map +1 -0
- package/dist/cedar-engine.d.ts +77 -0
- package/dist/cedar-engine.js +374 -0
- package/dist/cedar-engine.js.map +1 -0
- package/dist/gui/html.d.ts +5 -0
- package/dist/gui/html.js +930 -0
- package/dist/gui/html.js.map +1 -0
- package/dist/gui/server.d.ts +28 -0
- package/dist/gui/server.js +159 -0
- package/dist/gui/server.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +584 -0
- package/dist/index.js.map +1 -0
- package/dist/llm-proxy.d.ts +75 -0
- package/dist/llm-proxy.js +565 -0
- package/dist/llm-proxy.js.map +1 -0
- package/dist/mcp-aggregator.d.ts +29 -0
- package/dist/mcp-aggregator.js +144 -0
- package/dist/mcp-aggregator.js.map +1 -0
- package/dist/policy-source.d.ts +26 -0
- package/dist/policy-source.js +28 -0
- package/dist/policy-source.js.map +1 -0
- package/dist/types.d.ts +135 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/docs/carapace_proxy_tool_filter_flow_v3.svg +96 -0
- package/docs/ungated_ai_agent_capabilities.svg +143 -0
- package/package.json +1 -1
- package/src/gui/html.ts +14 -0
- package/src/gui/server.ts +7 -1
- package/src/index.ts +12 -0
- package/src/policy-source.ts +44 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Proxy — Sits between OpenClaw and the LLM provider.
|
|
3
|
+
*
|
|
4
|
+
* Intercepts tool_use blocks in LLM responses and evaluates them
|
|
5
|
+
* against Cedar policies before OpenClaw can execute them.
|
|
6
|
+
*
|
|
7
|
+
* The agent never gets the real API key. Carapace holds it.
|
|
8
|
+
* Denied tool calls are replaced with text blocks explaining why.
|
|
9
|
+
*
|
|
10
|
+
* Supports:
|
|
11
|
+
* - Anthropic Messages API (/v1/messages)
|
|
12
|
+
* - OpenAI Chat Completions API (/v1/chat/completions)
|
|
13
|
+
* - Both streaming and non-streaming (streaming is buffered, filtered, re-streamed)
|
|
14
|
+
*/
|
|
15
|
+
import type { Logger } from "./types.js";
|
|
16
|
+
interface CedarAuthorizer {
|
|
17
|
+
authorize(request: {
|
|
18
|
+
principal: string;
|
|
19
|
+
action: string;
|
|
20
|
+
resource: string;
|
|
21
|
+
context?: Record<string, unknown>;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
decision: "allow" | "deny";
|
|
24
|
+
reasons: string[];
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export interface LlmProxyOpts {
|
|
28
|
+
port: number;
|
|
29
|
+
upstream: {
|
|
30
|
+
anthropic?: {
|
|
31
|
+
url: string;
|
|
32
|
+
apiKey: string;
|
|
33
|
+
};
|
|
34
|
+
openai?: {
|
|
35
|
+
url: string;
|
|
36
|
+
apiKey: string;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
cedar: CedarAuthorizer;
|
|
40
|
+
logger: Logger;
|
|
41
|
+
}
|
|
42
|
+
export declare class LlmProxy {
|
|
43
|
+
private server;
|
|
44
|
+
private port;
|
|
45
|
+
private upstream;
|
|
46
|
+
private cedar;
|
|
47
|
+
private logger;
|
|
48
|
+
private stats;
|
|
49
|
+
private auditLog;
|
|
50
|
+
constructor(opts: LlmProxyOpts);
|
|
51
|
+
getAuditLog(): {
|
|
52
|
+
timestamp: number;
|
|
53
|
+
tool: string;
|
|
54
|
+
decision: "allow" | "deny";
|
|
55
|
+
reasons: string[];
|
|
56
|
+
}[];
|
|
57
|
+
start(): Promise<void>;
|
|
58
|
+
stop(): Promise<void>;
|
|
59
|
+
getStats(): {
|
|
60
|
+
requests: number;
|
|
61
|
+
toolCallsEvaluated: number;
|
|
62
|
+
toolCallsDenied: number;
|
|
63
|
+
};
|
|
64
|
+
private handleRequest;
|
|
65
|
+
private proxyAnthropic;
|
|
66
|
+
private forwardToAnthropic;
|
|
67
|
+
private handleAnthropicNonStreaming;
|
|
68
|
+
private handleAnthropicStreaming;
|
|
69
|
+
private proxyOpenAI;
|
|
70
|
+
private passthrough;
|
|
71
|
+
private evaluateToolCall;
|
|
72
|
+
private filterContentBlocks;
|
|
73
|
+
private readBody;
|
|
74
|
+
}
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Proxy — Sits between OpenClaw and the LLM provider.
|
|
3
|
+
*
|
|
4
|
+
* Intercepts tool_use blocks in LLM responses and evaluates them
|
|
5
|
+
* against Cedar policies before OpenClaw can execute them.
|
|
6
|
+
*
|
|
7
|
+
* The agent never gets the real API key. Carapace holds it.
|
|
8
|
+
* Denied tool calls are replaced with text blocks explaining why.
|
|
9
|
+
*
|
|
10
|
+
* Supports:
|
|
11
|
+
* - Anthropic Messages API (/v1/messages)
|
|
12
|
+
* - OpenAI Chat Completions API (/v1/chat/completions)
|
|
13
|
+
* - Both streaming and non-streaming (streaming is buffered, filtered, re-streamed)
|
|
14
|
+
*/
|
|
15
|
+
import { createServer } from "node:http";
|
|
16
|
+
export class LlmProxy {
|
|
17
|
+
server = null;
|
|
18
|
+
port;
|
|
19
|
+
upstream;
|
|
20
|
+
cedar;
|
|
21
|
+
logger;
|
|
22
|
+
// Stats
|
|
23
|
+
stats = {
|
|
24
|
+
requests: 0,
|
|
25
|
+
toolCallsEvaluated: 0,
|
|
26
|
+
toolCallsDenied: 0,
|
|
27
|
+
};
|
|
28
|
+
// Audit log for GUI display
|
|
29
|
+
auditLog = [];
|
|
30
|
+
constructor(opts) {
|
|
31
|
+
this.port = opts.port;
|
|
32
|
+
this.upstream = opts.upstream;
|
|
33
|
+
this.cedar = opts.cedar;
|
|
34
|
+
this.logger = opts.logger;
|
|
35
|
+
}
|
|
36
|
+
getAuditLog() {
|
|
37
|
+
return this.auditLog.slice(-100); // last 100 entries
|
|
38
|
+
}
|
|
39
|
+
async start() {
|
|
40
|
+
this.server = createServer(async (req, res) => {
|
|
41
|
+
try {
|
|
42
|
+
await this.handleRequest(req, res);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
this.logger.error(`LLM Proxy error: ${err.message}`);
|
|
46
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
47
|
+
res.end(JSON.stringify({ error: { message: `Carapace proxy error: ${err.message}` } }));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
this.server.listen(this.port, "127.0.0.1", () => {
|
|
52
|
+
this.logger.info(`LLM Proxy listening on http://127.0.0.1:${this.port}`);
|
|
53
|
+
resolve();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async stop() {
|
|
58
|
+
if (!this.server)
|
|
59
|
+
return;
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
this.server.close(() => resolve());
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
getStats() {
|
|
65
|
+
return { ...this.stats };
|
|
66
|
+
}
|
|
67
|
+
// ── Request handling ──
|
|
68
|
+
async handleRequest(req, res) {
|
|
69
|
+
this.stats.requests++;
|
|
70
|
+
const path = req.url ?? "/";
|
|
71
|
+
// Health check
|
|
72
|
+
if (path === "/health" || path === "/carapace/status") {
|
|
73
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
74
|
+
res.end(JSON.stringify({ ok: true, stats: this.stats }));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Detect provider from path
|
|
78
|
+
if (path.startsWith("/v1/messages")) {
|
|
79
|
+
await this.proxyAnthropic(req, res);
|
|
80
|
+
}
|
|
81
|
+
else if (path.startsWith("/v1/chat/completions")) {
|
|
82
|
+
await this.proxyOpenAI(req, res);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Pass through unknown paths (models list, etc.)
|
|
86
|
+
await this.passthrough(req, res, path);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// ── Anthropic Messages API ──
|
|
90
|
+
async proxyAnthropic(req, res) {
|
|
91
|
+
const upstream = this.upstream.anthropic;
|
|
92
|
+
if (!upstream) {
|
|
93
|
+
res.writeHead(501, { "Content-Type": "application/json" });
|
|
94
|
+
res.end(JSON.stringify({ error: { message: "Anthropic upstream not configured" } }));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const body = await this.readBody(req);
|
|
98
|
+
let parsed;
|
|
99
|
+
try {
|
|
100
|
+
parsed = JSON.parse(body);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
104
|
+
res.end(JSON.stringify({ error: { message: "Invalid JSON body" } }));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const isStreaming = parsed.stream === true;
|
|
108
|
+
// Forward to Anthropic (always non-streaming for filtering)
|
|
109
|
+
const upstreamResponse = await this.forwardToAnthropic(upstream, body, req, isStreaming);
|
|
110
|
+
if (!upstreamResponse.ok) {
|
|
111
|
+
// Forward error as-is
|
|
112
|
+
const errorBody = await upstreamResponse.text();
|
|
113
|
+
res.writeHead(upstreamResponse.status, {
|
|
114
|
+
"Content-Type": upstreamResponse.headers.get("content-type") ?? "application/json",
|
|
115
|
+
});
|
|
116
|
+
res.end(errorBody);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (isStreaming) {
|
|
120
|
+
await this.handleAnthropicStreaming(upstreamResponse, res);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
await this.handleAnthropicNonStreaming(upstreamResponse, res);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async forwardToAnthropic(upstream, body, req, isStreaming) {
|
|
127
|
+
// Build headers, replacing auth
|
|
128
|
+
const headers = {
|
|
129
|
+
"Content-Type": "application/json",
|
|
130
|
+
"x-api-key": upstream.apiKey,
|
|
131
|
+
"anthropic-version": req.headers["anthropic-version"] ?? "2023-06-01",
|
|
132
|
+
};
|
|
133
|
+
// Forward anthropic-beta if present
|
|
134
|
+
const beta = req.headers["anthropic-beta"];
|
|
135
|
+
if (beta)
|
|
136
|
+
headers["anthropic-beta"] = beta;
|
|
137
|
+
return fetch(`${upstream.url}/v1/messages`, {
|
|
138
|
+
method: "POST",
|
|
139
|
+
headers,
|
|
140
|
+
body,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async handleAnthropicNonStreaming(upstreamResponse, res) {
|
|
144
|
+
const responseBody = await upstreamResponse.text();
|
|
145
|
+
let parsed;
|
|
146
|
+
try {
|
|
147
|
+
parsed = JSON.parse(responseBody);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
151
|
+
res.end(responseBody);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Filter tool_use blocks
|
|
155
|
+
if (parsed.content && Array.isArray(parsed.content)) {
|
|
156
|
+
parsed.content = await this.filterContentBlocks(parsed.content);
|
|
157
|
+
// Update stop_reason if all tool_use blocks were denied
|
|
158
|
+
const hasToolUse = parsed.content.some((b) => b.type === "tool_use");
|
|
159
|
+
if (!hasToolUse && parsed.stop_reason === "tool_use") {
|
|
160
|
+
parsed.stop_reason = "end_turn";
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const filtered = JSON.stringify(parsed);
|
|
164
|
+
res.writeHead(200, {
|
|
165
|
+
"Content-Type": "application/json",
|
|
166
|
+
});
|
|
167
|
+
res.end(filtered);
|
|
168
|
+
}
|
|
169
|
+
async handleAnthropicStreaming(upstreamResponse, res) {
|
|
170
|
+
// Buffer the full streaming response, then filter and re-stream
|
|
171
|
+
const reader = upstreamResponse.body?.getReader();
|
|
172
|
+
if (!reader) {
|
|
173
|
+
res.writeHead(502);
|
|
174
|
+
res.end();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
// Collect all SSE events
|
|
178
|
+
const decoder = new TextDecoder();
|
|
179
|
+
let buffer = "";
|
|
180
|
+
const events = [];
|
|
181
|
+
while (true) {
|
|
182
|
+
const { done, value } = await reader.read();
|
|
183
|
+
if (done)
|
|
184
|
+
break;
|
|
185
|
+
buffer += decoder.decode(value, { stream: true });
|
|
186
|
+
// Parse SSE events from buffer
|
|
187
|
+
const lines = buffer.split("\n");
|
|
188
|
+
buffer = lines.pop() ?? ""; // Keep incomplete line
|
|
189
|
+
let currentEvent = "";
|
|
190
|
+
for (const line of lines) {
|
|
191
|
+
if (line.startsWith("event: ")) {
|
|
192
|
+
currentEvent = line.slice(7).trim();
|
|
193
|
+
}
|
|
194
|
+
else if (line.startsWith("data: ")) {
|
|
195
|
+
events.push({ event: currentEvent, data: line.slice(6) });
|
|
196
|
+
currentEvent = "";
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Find tool_use content blocks and evaluate them
|
|
201
|
+
const toolBlocks = new Map();
|
|
202
|
+
const deniedIndices = new Set();
|
|
203
|
+
let currentBlockIndex = -1;
|
|
204
|
+
for (const ev of events) {
|
|
205
|
+
if (ev.event === "content_block_start") {
|
|
206
|
+
try {
|
|
207
|
+
const d = JSON.parse(ev.data);
|
|
208
|
+
currentBlockIndex = d.index ?? -1;
|
|
209
|
+
if (d.content_block?.type === "tool_use") {
|
|
210
|
+
toolBlocks.set(currentBlockIndex, {
|
|
211
|
+
name: d.content_block.name,
|
|
212
|
+
id: d.content_block.id,
|
|
213
|
+
inputJson: "",
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch { }
|
|
218
|
+
}
|
|
219
|
+
else if (ev.event === "content_block_delta") {
|
|
220
|
+
try {
|
|
221
|
+
const d = JSON.parse(ev.data);
|
|
222
|
+
const idx = d.index ?? currentBlockIndex;
|
|
223
|
+
const block = toolBlocks.get(idx);
|
|
224
|
+
if (block && d.delta?.type === "input_json_delta") {
|
|
225
|
+
block.inputJson += d.delta.partial_json ?? "";
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch { }
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Evaluate each tool call against Cedar
|
|
232
|
+
for (const [idx, block] of toolBlocks) {
|
|
233
|
+
const decision = await this.evaluateToolCall(block.name, block.inputJson);
|
|
234
|
+
if (decision === "deny") {
|
|
235
|
+
deniedIndices.add(idx);
|
|
236
|
+
this.logger.info(`LLM Proxy DENIED tool call: ${block.name} (block ${idx})`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
if (deniedIndices.size === 0) {
|
|
240
|
+
// No denials — forward everything as-is
|
|
241
|
+
res.writeHead(200, {
|
|
242
|
+
"Content-Type": "text/event-stream",
|
|
243
|
+
"Cache-Control": "no-cache",
|
|
244
|
+
"Connection": "keep-alive",
|
|
245
|
+
});
|
|
246
|
+
for (const ev of events) {
|
|
247
|
+
if (ev.event)
|
|
248
|
+
res.write(`event: ${ev.event}\n`);
|
|
249
|
+
res.write(`data: ${ev.data}\n\n`);
|
|
250
|
+
}
|
|
251
|
+
res.end();
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
// Rewrite stream: replace denied tool blocks with text blocks
|
|
255
|
+
res.writeHead(200, {
|
|
256
|
+
"Content-Type": "text/event-stream",
|
|
257
|
+
"Cache-Control": "no-cache",
|
|
258
|
+
"Connection": "keep-alive",
|
|
259
|
+
});
|
|
260
|
+
let skipBlock = false;
|
|
261
|
+
let skipBlockIndex = -1;
|
|
262
|
+
for (const ev of events) {
|
|
263
|
+
if (ev.event === "content_block_start") {
|
|
264
|
+
try {
|
|
265
|
+
const d = JSON.parse(ev.data);
|
|
266
|
+
const idx = d.index ?? -1;
|
|
267
|
+
if (deniedIndices.has(idx)) {
|
|
268
|
+
skipBlock = true;
|
|
269
|
+
skipBlockIndex = idx;
|
|
270
|
+
const block = toolBlocks.get(idx);
|
|
271
|
+
// Emit a text block instead
|
|
272
|
+
const replacement = {
|
|
273
|
+
index: idx,
|
|
274
|
+
content_block: {
|
|
275
|
+
type: "text",
|
|
276
|
+
text: "",
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
res.write(`event: content_block_start\ndata: ${JSON.stringify(replacement)}\n\n`);
|
|
280
|
+
// Emit the denial text as a delta
|
|
281
|
+
const denialText = `\n🚫 DENIED by Cedar policy: ${block.name}\n`;
|
|
282
|
+
const delta = {
|
|
283
|
+
index: idx,
|
|
284
|
+
delta: { type: "text_delta", text: denialText },
|
|
285
|
+
};
|
|
286
|
+
res.write(`event: content_block_delta\ndata: ${JSON.stringify(delta)}\n\n`);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
catch { }
|
|
291
|
+
skipBlock = false;
|
|
292
|
+
}
|
|
293
|
+
if (ev.event === "content_block_delta") {
|
|
294
|
+
try {
|
|
295
|
+
const d = JSON.parse(ev.data);
|
|
296
|
+
if (deniedIndices.has(d.index ?? skipBlockIndex))
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
catch { }
|
|
300
|
+
}
|
|
301
|
+
if (ev.event === "content_block_stop") {
|
|
302
|
+
try {
|
|
303
|
+
const d = JSON.parse(ev.data);
|
|
304
|
+
if (deniedIndices.has(d.index ?? skipBlockIndex)) {
|
|
305
|
+
// Emit the stop for our replacement text block
|
|
306
|
+
res.write(`event: content_block_stop\ndata: ${ev.data}\n\n`);
|
|
307
|
+
skipBlock = false;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch { }
|
|
312
|
+
}
|
|
313
|
+
if (skipBlock)
|
|
314
|
+
continue;
|
|
315
|
+
// Fix message_delta stop_reason if all tools were denied
|
|
316
|
+
if (ev.event === "message_delta") {
|
|
317
|
+
try {
|
|
318
|
+
const d = JSON.parse(ev.data);
|
|
319
|
+
const remainingTools = [...toolBlocks.keys()].filter((i) => !deniedIndices.has(i));
|
|
320
|
+
if (remainingTools.length === 0 && d.delta?.stop_reason === "tool_use") {
|
|
321
|
+
d.delta.stop_reason = "end_turn";
|
|
322
|
+
res.write(`event: message_delta\ndata: ${JSON.stringify(d)}\n\n`);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
catch { }
|
|
327
|
+
}
|
|
328
|
+
// Forward event as-is
|
|
329
|
+
if (ev.event)
|
|
330
|
+
res.write(`event: ${ev.event}\n`);
|
|
331
|
+
res.write(`data: ${ev.data}\n\n`);
|
|
332
|
+
}
|
|
333
|
+
res.end();
|
|
334
|
+
}
|
|
335
|
+
// ── OpenAI Chat Completions API ──
|
|
336
|
+
async proxyOpenAI(req, res) {
|
|
337
|
+
const upstream = this.upstream.openai;
|
|
338
|
+
if (!upstream) {
|
|
339
|
+
res.writeHead(501, { "Content-Type": "application/json" });
|
|
340
|
+
res.end(JSON.stringify({ error: { message: "OpenAI upstream not configured" } }));
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const body = await this.readBody(req);
|
|
344
|
+
let parsed;
|
|
345
|
+
try {
|
|
346
|
+
parsed = JSON.parse(body);
|
|
347
|
+
}
|
|
348
|
+
catch {
|
|
349
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
350
|
+
res.end(JSON.stringify({ error: { message: "Invalid JSON body" } }));
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
const isStreaming = parsed.stream === true;
|
|
354
|
+
// For streaming: force non-streaming, filter, then re-stream
|
|
355
|
+
const forwardBody = isStreaming ? JSON.stringify({ ...parsed, stream: false }) : body;
|
|
356
|
+
const headers = {
|
|
357
|
+
"Content-Type": "application/json",
|
|
358
|
+
"Authorization": `Bearer ${upstream.apiKey}`,
|
|
359
|
+
};
|
|
360
|
+
const upstreamResponse = await fetch(`${upstream.url}/v1/chat/completions`, {
|
|
361
|
+
method: "POST",
|
|
362
|
+
headers,
|
|
363
|
+
body: forwardBody,
|
|
364
|
+
});
|
|
365
|
+
if (!upstreamResponse.ok) {
|
|
366
|
+
const errorBody = await upstreamResponse.text();
|
|
367
|
+
res.writeHead(upstreamResponse.status, { "Content-Type": "application/json" });
|
|
368
|
+
res.end(errorBody);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const responseBody = await upstreamResponse.text();
|
|
372
|
+
let response;
|
|
373
|
+
try {
|
|
374
|
+
response = JSON.parse(responseBody);
|
|
375
|
+
}
|
|
376
|
+
catch {
|
|
377
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
378
|
+
res.end(responseBody);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
// Filter tool_calls from choices
|
|
382
|
+
if (response.choices) {
|
|
383
|
+
for (const choice of response.choices) {
|
|
384
|
+
if (choice.message?.tool_calls) {
|
|
385
|
+
const filtered = [];
|
|
386
|
+
const denials = [];
|
|
387
|
+
for (const tc of choice.message.tool_calls) {
|
|
388
|
+
const decision = await this.evaluateToolCall(tc.function?.name ?? tc.name, typeof tc.function?.arguments === "string"
|
|
389
|
+
? tc.function.arguments
|
|
390
|
+
: JSON.stringify(tc.function?.arguments ?? {}));
|
|
391
|
+
if (decision === "allow") {
|
|
392
|
+
filtered.push(tc);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
denials.push(`🚫 DENIED by Cedar policy: ${tc.function?.name ?? tc.name}`);
|
|
396
|
+
this.logger.info(`LLM Proxy DENIED tool call: ${tc.function?.name}`);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
choice.message.tool_calls = filtered.length > 0 ? filtered : undefined;
|
|
400
|
+
// Add denial messages to content
|
|
401
|
+
if (denials.length > 0) {
|
|
402
|
+
const existing = choice.message.content ?? "";
|
|
403
|
+
choice.message.content = (existing + "\n" + denials.join("\n")).trim();
|
|
404
|
+
}
|
|
405
|
+
// Fix finish_reason if all tool calls were denied
|
|
406
|
+
if (filtered.length === 0 && choice.finish_reason === "tool_calls") {
|
|
407
|
+
choice.finish_reason = "stop";
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
if (isStreaming) {
|
|
413
|
+
// Re-stream as SSE (single chunk since we forced non-streaming)
|
|
414
|
+
res.writeHead(200, {
|
|
415
|
+
"Content-Type": "text/event-stream",
|
|
416
|
+
"Cache-Control": "no-cache",
|
|
417
|
+
});
|
|
418
|
+
// Convert to streaming format
|
|
419
|
+
const chunk = { ...response, object: "chat.completion.chunk" };
|
|
420
|
+
for (const choice of chunk.choices ?? []) {
|
|
421
|
+
choice.delta = choice.message;
|
|
422
|
+
delete choice.message;
|
|
423
|
+
}
|
|
424
|
+
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
|
425
|
+
res.write("data: [DONE]\n\n");
|
|
426
|
+
res.end();
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
430
|
+
res.end(JSON.stringify(response));
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
// ── Passthrough for non-chat endpoints ──
|
|
434
|
+
async passthrough(req, res, path) {
|
|
435
|
+
// Try Anthropic first, then OpenAI
|
|
436
|
+
const upstream = this.upstream.anthropic ?? this.upstream.openai;
|
|
437
|
+
if (!upstream) {
|
|
438
|
+
res.writeHead(501);
|
|
439
|
+
res.end();
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const body = req.method !== "GET" ? await this.readBody(req) : undefined;
|
|
443
|
+
const headers = { "Content-Type": "application/json" };
|
|
444
|
+
if (this.upstream.anthropic) {
|
|
445
|
+
headers["x-api-key"] = upstream.apiKey;
|
|
446
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
headers["Authorization"] = `Bearer ${upstream.apiKey}`;
|
|
450
|
+
}
|
|
451
|
+
const response = await fetch(`${upstream.url}${path}`, {
|
|
452
|
+
method: req.method ?? "GET",
|
|
453
|
+
headers,
|
|
454
|
+
body,
|
|
455
|
+
});
|
|
456
|
+
const responseBody = await response.text();
|
|
457
|
+
res.writeHead(response.status, {
|
|
458
|
+
"Content-Type": response.headers.get("content-type") ?? "application/json",
|
|
459
|
+
});
|
|
460
|
+
res.end(responseBody);
|
|
461
|
+
}
|
|
462
|
+
// ── Cedar evaluation ──
|
|
463
|
+
async evaluateToolCall(toolName, inputJson) {
|
|
464
|
+
this.stats.toolCallsEvaluated++;
|
|
465
|
+
let parsedInput = {};
|
|
466
|
+
try {
|
|
467
|
+
parsedInput = JSON.parse(inputJson || "{}");
|
|
468
|
+
}
|
|
469
|
+
catch { }
|
|
470
|
+
// Determine resource type based on tool name
|
|
471
|
+
let resourceType = "Tool";
|
|
472
|
+
let action = "call_tool";
|
|
473
|
+
let resourceId = toolName;
|
|
474
|
+
let context = {};
|
|
475
|
+
// Map known OpenClaw built-in tools to resource types
|
|
476
|
+
if (toolName === "exec" || toolName === "process") {
|
|
477
|
+
resourceType = "Shell";
|
|
478
|
+
action = "exec_command";
|
|
479
|
+
// Extract binary name from the command argument
|
|
480
|
+
const cmd = parsedInput.command ?? "";
|
|
481
|
+
resourceId = cmd.trim().split(/\s+/)[0]?.replace(/^.*\//, "") || toolName;
|
|
482
|
+
// Map to schema-known context attributes
|
|
483
|
+
context = {
|
|
484
|
+
args: cmd,
|
|
485
|
+
workdir: parsedInput.workdir ?? "",
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
else if (toolName === "web_fetch" || toolName === "web_search") {
|
|
489
|
+
resourceType = "API";
|
|
490
|
+
action = "call_api";
|
|
491
|
+
// Extract domain from URL
|
|
492
|
+
const url = parsedInput.url ?? parsedInput.query ?? "";
|
|
493
|
+
try {
|
|
494
|
+
if (url.startsWith("http")) {
|
|
495
|
+
resourceId = new URL(url).hostname;
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
resourceId = toolName;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
resourceId = toolName;
|
|
503
|
+
}
|
|
504
|
+
// Map to schema-known context attributes
|
|
505
|
+
context = {
|
|
506
|
+
url,
|
|
507
|
+
method: parsedInput.method ?? "GET",
|
|
508
|
+
body: parsedInput.body ?? "",
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
const decision = await this.cedar.authorize({
|
|
512
|
+
principal: `Agent::"openclaw"`,
|
|
513
|
+
action: `Action::"${action}"`,
|
|
514
|
+
resource: `${resourceType}::"${resourceId}"`,
|
|
515
|
+
context,
|
|
516
|
+
});
|
|
517
|
+
// Audit log entry
|
|
518
|
+
this.auditLog.push({
|
|
519
|
+
timestamp: Date.now(),
|
|
520
|
+
tool: toolName,
|
|
521
|
+
decision: decision.decision,
|
|
522
|
+
reasons: decision.reasons,
|
|
523
|
+
});
|
|
524
|
+
if (this.auditLog.length > 500)
|
|
525
|
+
this.auditLog.splice(0, this.auditLog.length - 100);
|
|
526
|
+
if (decision.decision === "deny") {
|
|
527
|
+
this.stats.toolCallsDenied++;
|
|
528
|
+
}
|
|
529
|
+
return decision.decision;
|
|
530
|
+
}
|
|
531
|
+
// ── Content block filtering (Anthropic non-streaming) ──
|
|
532
|
+
async filterContentBlocks(blocks) {
|
|
533
|
+
const result = [];
|
|
534
|
+
for (const block of blocks) {
|
|
535
|
+
if (block.type !== "tool_use") {
|
|
536
|
+
result.push(block);
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
const toolBlock = block;
|
|
540
|
+
const decision = await this.evaluateToolCall(toolBlock.name, JSON.stringify(toolBlock.input));
|
|
541
|
+
if (decision === "allow") {
|
|
542
|
+
result.push(block);
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
// Replace with denial text
|
|
546
|
+
result.push({
|
|
547
|
+
type: "text",
|
|
548
|
+
text: `\n🚫 DENIED by Cedar policy: ${toolBlock.name}\n`,
|
|
549
|
+
});
|
|
550
|
+
this.logger.info(`LLM Proxy DENIED tool call: ${toolBlock.name}`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return result;
|
|
554
|
+
}
|
|
555
|
+
// ── Utilities ──
|
|
556
|
+
readBody(req) {
|
|
557
|
+
return new Promise((resolve, reject) => {
|
|
558
|
+
const chunks = [];
|
|
559
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
560
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString()));
|
|
561
|
+
req.on("error", reject);
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
//# sourceMappingURL=llm-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-proxy.js","sourceRoot":"","sources":["../src/llm-proxy.ts"],"names":[],"mappings":"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"}
|