@1presence/bridge 0.42.0 → 0.44.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/dist/claude.js +42 -2
- package/dist/config.js +5 -4
- package/dist/index.js +6 -0
- package/package.json +2 -2
package/dist/claude.js
CHANGED
|
@@ -82,6 +82,26 @@ function debugBlock(label, colorCode, body) {
|
|
|
82
82
|
const rule = `── ${label} `.padEnd(64, '─');
|
|
83
83
|
process.stderr.write(`\n${paint(colorCode, rule)}\n${body.trimEnd()}\n`);
|
|
84
84
|
}
|
|
85
|
+
// Strip confabulated tool-call XML out of assistant text. Real tool calls arrive
|
|
86
|
+
// as structured tool_use blocks, never as text — so when assistant text contains
|
|
87
|
+
// <function_calls>/<function_results>/<invoke>, the model is role-playing the tool
|
|
88
|
+
// protocol because it had no callable tools, and that raw XML (often invented
|
|
89
|
+
// internal-looking content) must never reach the user. Kept as a tiny local copy
|
|
90
|
+
// rather than importing @presence/shared so the published bridge stays decoupled.
|
|
91
|
+
const TOOL_CALL_XML_RE = /<function_calls\b|<function_results\b|<invoke\b/i;
|
|
92
|
+
function stripToolCallXml(text) {
|
|
93
|
+
if (!text || !TOOL_CALL_XML_RE.test(text))
|
|
94
|
+
return text;
|
|
95
|
+
let out = text
|
|
96
|
+
.replace(/<function_calls>[\s\S]*?<\/function_calls>/gi, '')
|
|
97
|
+
.replace(/<function_results>[\s\S]*?<\/function_results>/gi, '')
|
|
98
|
+
.replace(/<invoke\b[\s\S]*?<\/invoke>/gi, '');
|
|
99
|
+
// Truncated / unclosed opener: drop from the first stray opener to the end.
|
|
100
|
+
out = out.replace(/<function_calls\b[\s\S]*$/i, '')
|
|
101
|
+
.replace(/<function_results\b[\s\S]*$/i, '')
|
|
102
|
+
.replace(/<invoke\b[\s\S]*$/i, '');
|
|
103
|
+
return out.trim();
|
|
104
|
+
}
|
|
85
105
|
// Render one replayed-history content block as a single readable line for the
|
|
86
106
|
// debug transcript. Tool calls and results are inlined so a history turn shows
|
|
87
107
|
// exactly what the model received — text, the tools it ran, and what they
|
|
@@ -348,7 +368,19 @@ export function spawnClaude(params) {
|
|
|
348
368
|
}
|
|
349
369
|
}
|
|
350
370
|
else if (block['type'] === 'text') {
|
|
351
|
-
|
|
371
|
+
let blockText = block['text'];
|
|
372
|
+
// Drop confabulated tool-call XML before this event is forwarded to
|
|
373
|
+
// the gateway (onEvent forwards THIS object, so mutate it in place).
|
|
374
|
+
// Happens when a turn ran with no callable tools and the model
|
|
375
|
+
// role-played the protocol in prose. See vault/Bugs.md 2026-05-28.
|
|
376
|
+
if (blockText && TOOL_CALL_XML_RE.test(blockText)) {
|
|
377
|
+
const cleaned = stripToolCallXml(blockText);
|
|
378
|
+
if (cleaned !== blockText) {
|
|
379
|
+
process.stderr.write(paint(SECTION_COLORS.result, `[bridge] suppressed confabulated tool-call XML in assistant text`) + '\n');
|
|
380
|
+
block['text'] = cleaned;
|
|
381
|
+
blockText = cleaned;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
352
384
|
if (blockText) {
|
|
353
385
|
// The CLI/SDK can report auth/API failures as a synthetic assistant
|
|
354
386
|
// text turn whose wording varies. Detect by the structured signal
|
|
@@ -414,6 +446,11 @@ export function spawnClaude(params) {
|
|
|
414
446
|
if (!apiErrorText && typeof event['result'] === 'string') {
|
|
415
447
|
apiErrorText = event['result'].trim();
|
|
416
448
|
}
|
|
449
|
+
// Operator visibility — a result-borne error would otherwise reach the
|
|
450
|
+
// user as a chat error with NOTHING in the bridge logs (the failure
|
|
451
|
+
// mode that made the empty-content `invalid_request` regression so hard
|
|
452
|
+
// to diagnose). Mechanical log only; no product logic.
|
|
453
|
+
process.stderr.write(paint(SECTION_COLORS.result, `[bridge] result error${status ? ` (${status})` : ''}: ${apiErrorText || 'unknown'}`) + '\n');
|
|
417
454
|
}
|
|
418
455
|
}
|
|
419
456
|
return true;
|
|
@@ -440,7 +477,10 @@ export function spawnClaude(params) {
|
|
|
440
477
|
settingSources: [], // no user/project settings or memory
|
|
441
478
|
allowedTools: ['mcp__1presence__*'], // auto-approve our MCP surface (no prompt)
|
|
442
479
|
canUseTool, // hard deny anything else
|
|
443
|
-
|
|
480
|
+
tools: [], // disable ALL built-in tools; MCP tools come via mcpServers and survive.
|
|
481
|
+
// (The old `extraArgs: { tools: '' }` passed a malformed --tools "" that
|
|
482
|
+
// cleared the whole tool surface — including MCP — so the model had no
|
|
483
|
+
// callable tools and confabulated tool calls as text. See vault/Bugs.md.)
|
|
444
484
|
cwd: BRIDGE_CWD,
|
|
445
485
|
abortController: abort,
|
|
446
486
|
includePartialMessages: false, // whole messages, matching the old non-partial path
|
package/dist/config.js
CHANGED
|
@@ -78,12 +78,13 @@ function detectClaudeDefaultModel() {
|
|
|
78
78
|
// `--model` flag passed to the subprocess).
|
|
79
79
|
const MODEL_OPTIONS = [
|
|
80
80
|
{ num: 1, model: null, label: 'Use Claude Code default' },
|
|
81
|
-
{ num: 2, model: 'claude-opus-4-
|
|
82
|
-
{ num: 3, model: 'claude-
|
|
83
|
-
{ num: 4, model: 'claude-
|
|
81
|
+
{ num: 2, model: 'claude-opus-4-8', label: 'claude-opus-4-8' },
|
|
82
|
+
{ num: 3, model: 'claude-opus-4-7', label: 'claude-opus-4-7' },
|
|
83
|
+
{ num: 4, model: 'claude-sonnet-4-6', label: 'claude-sonnet-4-6' },
|
|
84
|
+
{ num: 5, model: 'claude-haiku-4-5', label: 'claude-haiku-4-5' },
|
|
84
85
|
];
|
|
85
86
|
const PROMPT_TIMEOUT_MS = 10_000;
|
|
86
|
-
const DEFAULT_OPTION_NUM =
|
|
87
|
+
const DEFAULT_OPTION_NUM = 2;
|
|
87
88
|
function promptForModel(defaultModel) {
|
|
88
89
|
return new Promise((resolve) => {
|
|
89
90
|
const initialIdx = Math.max(0, MODEL_OPTIONS.findIndex((o) => o.num === DEFAULT_OPTION_NUM));
|
package/dist/index.js
CHANGED
|
@@ -182,6 +182,12 @@ function writeMcpConfig(auth) {
|
|
|
182
182
|
type: 'sse',
|
|
183
183
|
url: `${GATEWAY_HTTP}/mcp`,
|
|
184
184
|
headers: { Authorization: `Bearer ${token}` },
|
|
185
|
+
// Force every 1Presence tool into the prompt from turn 1. Without this the
|
|
186
|
+
// SDK defers MCP tools behind tool-search, so the model sees tool *names*
|
|
187
|
+
// (from the system prompt) but has nothing callable and confabulates the
|
|
188
|
+
// call + result as text. Also blocks the turn until the MCP server connects
|
|
189
|
+
// (5s cap) — a loud failure beats a silent tool-less run. See vault/Bugs.md.
|
|
190
|
+
alwaysLoad: true,
|
|
185
191
|
},
|
|
186
192
|
},
|
|
187
193
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1presence/bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^20.0.0",
|
|
27
27
|
"@types/ws": "^8.18.1",
|
|
28
|
-
"tsx": "^4.
|
|
28
|
+
"tsx": "^4.22.3",
|
|
29
29
|
"typescript": "^5.5.0"
|
|
30
30
|
}
|
|
31
31
|
}
|