@tetrixdev/ai-bridge 0.1.0 → 0.1.1
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/dist/cli.js +68 -38
- package/dist/cli.js.map +1 -1
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import WebSocket from "ws";
|
|
|
11
11
|
|
|
12
12
|
// src/protocol/version.ts
|
|
13
13
|
var PROTOCOL_VERSION = "0.1";
|
|
14
|
-
var BRIDGE_VERSION = "0.1.
|
|
14
|
+
var BRIDGE_VERSION = "0.1.1";
|
|
15
15
|
|
|
16
16
|
// src/tools/manager.ts
|
|
17
17
|
import fs from "fs";
|
|
@@ -276,26 +276,29 @@ var ToolManager = class {
|
|
|
276
276
|
|
|
277
277
|
set -euo pipefail
|
|
278
278
|
|
|
279
|
-
# Read
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
# Read the JSON payload from the first CLI argument when present; otherwise
|
|
280
|
+
# fall back to stdin (some AI CLIs pass tool args one way, some the other).
|
|
281
|
+
PAYLOAD_DATA=""
|
|
282
|
+
if [ "$#" -ge 1 ] && [ -n "\${1:-}" ]; then
|
|
283
|
+
PAYLOAD_DATA="$1"
|
|
284
|
+
elif [ ! -t 0 ]; then
|
|
285
|
+
PAYLOAD_DATA=$(cat)
|
|
283
286
|
fi
|
|
284
287
|
|
|
285
288
|
# Single Node.js invocation for input parsing, payload building, HTTP call,
|
|
286
289
|
# and output extraction.
|
|
287
290
|
node -e '
|
|
288
291
|
const http = require("http");
|
|
289
|
-
const
|
|
292
|
+
const payloadData = process.argv[1];
|
|
290
293
|
const toolName = process.argv[2];
|
|
291
294
|
const toolCallId = process.argv[3];
|
|
292
295
|
const requestId = process.argv[4];
|
|
293
296
|
const secret = process.argv[5];
|
|
294
297
|
|
|
295
|
-
// Parse
|
|
298
|
+
// Parse the payload as JSON, fall back to wrapping as {input: ...}
|
|
296
299
|
let args = {};
|
|
297
|
-
if (
|
|
298
|
-
try { args = JSON.parse(
|
|
300
|
+
if (payloadData) {
|
|
301
|
+
try { args = JSON.parse(payloadData); } catch { args = { input: payloadData }; }
|
|
299
302
|
}
|
|
300
303
|
|
|
301
304
|
const payload = JSON.stringify({
|
|
@@ -327,7 +330,7 @@ req.write(payload);
|
|
|
327
330
|
req.end();
|
|
328
331
|
// The $RANDOM-based ID here is discarded \u2014 the callback server overrides it
|
|
329
332
|
// with a cryptographically strong UUID before use.
|
|
330
|
-
' "$
|
|
333
|
+
' "$PAYLOAD_DATA" "${tool.name}" "tc_\${RANDOM}\${RANDOM}" "\${AI_BRIDGE_REQUEST_ID:-}" "${secretArg}"
|
|
331
334
|
`;
|
|
332
335
|
}
|
|
333
336
|
};
|
|
@@ -1662,14 +1665,47 @@ function createFinalizer(opts) {
|
|
|
1662
1665
|
var ProviderAdapter = class {
|
|
1663
1666
|
};
|
|
1664
1667
|
|
|
1668
|
+
// src/tools/prompt.ts
|
|
1669
|
+
function buildToolInstructions(tools, toolScriptDir) {
|
|
1670
|
+
if (tools.length === 0) return "";
|
|
1671
|
+
const cmd = (name) => toolScriptDir ? `${toolScriptDir}/${name}` : name;
|
|
1672
|
+
const sections = [
|
|
1673
|
+
"# Available Tools",
|
|
1674
|
+
"",
|
|
1675
|
+
'You have access to the following tools. Each tool is an executable script. Call a tool by running it as a shell command with a single argument: a JSON object containing the parameters. The command prints its result to stdout. Run each tool using the exact path shown in its "Call it like" example. Use these tools whenever they help fulfill the request.'
|
|
1676
|
+
];
|
|
1677
|
+
for (const tool of tools) {
|
|
1678
|
+
sections.push("", `## ${tool.name}`, "", tool.description);
|
|
1679
|
+
const parameters = tool.parameters ?? {};
|
|
1680
|
+
const properties = parameters["properties"] ?? {};
|
|
1681
|
+
const required = Array.isArray(parameters["required"]) ? parameters["required"].map((r) => String(r)) : [];
|
|
1682
|
+
const propNames = Object.keys(properties);
|
|
1683
|
+
if (propNames.length === 0) {
|
|
1684
|
+
sections.push("", "Parameters: No parameters");
|
|
1685
|
+
sections.push("", `Call it like: ${cmd(tool.name)} '{}'`);
|
|
1686
|
+
continue;
|
|
1687
|
+
}
|
|
1688
|
+
sections.push("", "Parameters:");
|
|
1689
|
+
for (const pname of propNames) {
|
|
1690
|
+
const raw = properties[pname];
|
|
1691
|
+
const prop = raw && typeof raw === "object" ? raw : {};
|
|
1692
|
+
const type = typeof prop.type === "string" ? prop.type : "any";
|
|
1693
|
+
const requiredLabel = required.includes(pname) ? "required" : "optional";
|
|
1694
|
+
const description = typeof prop.description === "string" && prop.description.length > 0 ? prop.description : "No description";
|
|
1695
|
+
sections.push(`- ${pname} (${type}, ${requiredLabel}): ${description}`);
|
|
1696
|
+
}
|
|
1697
|
+
const exampleParam = propNames[0];
|
|
1698
|
+
sections.push(
|
|
1699
|
+
"",
|
|
1700
|
+
`Call it like: ${cmd(tool.name)} '{"${exampleParam}":"<value>"}'`
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
return sections.join("\n");
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1665
1706
|
// src/providers/codex.ts
|
|
1666
1707
|
var log7 = createLogger("CodexAdapter");
|
|
1667
1708
|
var DEFAULT_MODEL = "gpt-5.3-codex";
|
|
1668
|
-
function buildToolPromptNote(tools) {
|
|
1669
|
-
if (tools.length === 0) return "";
|
|
1670
|
-
const lines = tools.map((t) => `- \`${t.name}\`: ${t.description}`);
|
|
1671
|
-
return "\n\n---\nThe following bridge tools are available to you as shell commands. Run a tool by executing its command name in the shell (passing any arguments it documents); the command performs the action and prints the result. Use them when they help answer the request:\n" + lines.join("\n");
|
|
1672
|
-
}
|
|
1673
1709
|
var CodexAdapter = class extends ProviderAdapter {
|
|
1674
1710
|
providerName = "codex";
|
|
1675
1711
|
async execute(context, onEvent) {
|
|
@@ -1704,14 +1740,12 @@ var CodexAdapter = class extends ProviderAdapter {
|
|
|
1704
1740
|
if (hasTools) {
|
|
1705
1741
|
args.push(
|
|
1706
1742
|
"-s",
|
|
1707
|
-
"
|
|
1708
|
-
"-c",
|
|
1709
|
-
"sandbox_workspace_write.network_access=true",
|
|
1743
|
+
"danger-full-access",
|
|
1710
1744
|
"-c",
|
|
1711
1745
|
"approval_policy=never"
|
|
1712
1746
|
);
|
|
1713
1747
|
}
|
|
1714
|
-
const toolNote = hasTools ?
|
|
1748
|
+
const toolNote = hasTools ? "\n\n" + buildToolInstructions(context.tools, context.toolScriptDir) : "";
|
|
1715
1749
|
if (!cliSessionId && request.system_prompt) {
|
|
1716
1750
|
args.push("--", buildCombinedPrompt(request.system_prompt, userMessage) + toolNote);
|
|
1717
1751
|
} else if (toolNote) {
|
|
@@ -1963,9 +1997,13 @@ var ClaudeAdapter = class extends ProviderAdapter {
|
|
|
1963
1997
|
args.push("--max-tokens", String(request.options.max_tokens));
|
|
1964
1998
|
}
|
|
1965
1999
|
if (context.tools.length > 0 && context.toolScriptDir) {
|
|
1966
|
-
args.push("--
|
|
2000
|
+
args.push("--permission-mode", "bypassPermissions");
|
|
1967
2001
|
}
|
|
1968
|
-
|
|
2002
|
+
let promptArg = userMessage;
|
|
2003
|
+
if (context.tools.length > 0) {
|
|
2004
|
+
promptArg += "\n\n" + buildToolInstructions(context.tools, context.toolScriptDir);
|
|
2005
|
+
}
|
|
2006
|
+
args.push(promptArg);
|
|
1969
2007
|
if (isDebugEnabled()) {
|
|
1970
2008
|
log8.debug("Spawning claude", { args: args.map((a) => a.length > 50 ? a.substring(0, 50) + "..." : a) });
|
|
1971
2009
|
}
|
|
@@ -2126,13 +2164,8 @@ var ClaudeAdapter = class extends ProviderAdapter {
|
|
|
2126
2164
|
return;
|
|
2127
2165
|
}
|
|
2128
2166
|
if (type === "rate_limit_event") {
|
|
2129
|
-
log8.
|
|
2130
|
-
|
|
2131
|
-
event: "error",
|
|
2132
|
-
data: {
|
|
2133
|
-
code: "rate_limited",
|
|
2134
|
-
message: "Claude is currently rate-limited. The request may retry automatically, or you may need to try again in a moment."
|
|
2135
|
-
}
|
|
2167
|
+
log8.debug("Claude rate limit event (informational)", {
|
|
2168
|
+
status: parsed["rate_limit_info"]?.["status"]
|
|
2136
2169
|
});
|
|
2137
2170
|
return;
|
|
2138
2171
|
}
|
|
@@ -2191,6 +2224,10 @@ var GeminiAdapter = class extends ProviderAdapter {
|
|
|
2191
2224
|
if (request.system_prompt && !cliSessionId) {
|
|
2192
2225
|
prompt = buildCombinedPrompt(request.system_prompt, userMessage);
|
|
2193
2226
|
}
|
|
2227
|
+
const hasTools = context.tools.length > 0;
|
|
2228
|
+
if (hasTools) {
|
|
2229
|
+
prompt += "\n\n" + buildToolInstructions(context.tools, context.toolScriptDir);
|
|
2230
|
+
}
|
|
2194
2231
|
const args = [
|
|
2195
2232
|
"--prompt",
|
|
2196
2233
|
prompt,
|
|
@@ -2201,6 +2238,9 @@ var GeminiAdapter = class extends ProviderAdapter {
|
|
|
2201
2238
|
"--skip-trust"
|
|
2202
2239
|
// Required for headless/non-interactive mode
|
|
2203
2240
|
];
|
|
2241
|
+
if (hasTools) {
|
|
2242
|
+
args.push("--yolo");
|
|
2243
|
+
}
|
|
2204
2244
|
if (cliSessionId) {
|
|
2205
2245
|
args.push("--resume", cliSessionId);
|
|
2206
2246
|
log9.debug("Resuming session", { cliSessionId });
|
|
@@ -2384,16 +2424,6 @@ var GeminiAdapter = class extends ProviderAdapter {
|
|
|
2384
2424
|
});
|
|
2385
2425
|
onEvent({ event: "done", data: {} });
|
|
2386
2426
|
settled = true;
|
|
2387
|
-
} else if (severity === "warning") {
|
|
2388
|
-
const lowerMsg = (message ?? "").toLowerCase();
|
|
2389
|
-
const isRateLimit = lowerMsg.includes("rate limit") || lowerMsg.includes("ratelimit") || lowerMsg.includes("quota") || lowerMsg.includes("429") || lowerMsg.includes("too many requests");
|
|
2390
|
-
onEvent({
|
|
2391
|
-
event: "error",
|
|
2392
|
-
data: {
|
|
2393
|
-
code: isRateLimit ? "rate_limited" : "provider_warning",
|
|
2394
|
-
message: message ?? "Gemini warning"
|
|
2395
|
-
}
|
|
2396
|
-
});
|
|
2397
2427
|
}
|
|
2398
2428
|
return;
|
|
2399
2429
|
}
|