praxis-agent 0.50.0 → 0.52.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 +7 -1
- package/dist/mcp/claude-mcp-tools.js +27 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,7 +215,13 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
215
215
|
disconnect recovery that never replays an already-dispatched call. Default
|
|
216
216
|
tool selection defers `mcp__*` schemas behind a turn-scoped `ToolSearch`;
|
|
217
217
|
each query activates at most eight deterministic matches for the next model
|
|
218
|
-
request
|
|
218
|
+
request, and published MCP tool descriptions are capped at 2,048 Unicode
|
|
219
|
+
code points. Text-only MCP results above 100,000 UTF-8 bytes are redacted
|
|
220
|
+
into mode-`0600` `.txt` files under the session-scoped `tool-results`
|
|
221
|
+
directory; providers and transcripts receive only a bounded instruction with
|
|
222
|
+
the absolute file path. Results at or below the limit remain inline, while
|
|
223
|
+
structured, mixed-media, and binary-resource handling is unchanged. Explicit
|
|
224
|
+
concrete `--tools` selections load selected tools directly, while
|
|
219
225
|
`--disallowedTools ToolSearch` restores the complete tool list.
|
|
220
226
|
- **Provider-neutral models** — native Provider Registry/Vault routing, API
|
|
221
227
|
adapters, an experimental Codex OAuth adapter, explicit capability checks,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { mkdir, mkdtemp, open, rm } from 'node:fs/promises';
|
|
3
3
|
import { homedir, tmpdir } from 'node:os';
|
|
4
|
-
import { join } from 'node:path';
|
|
4
|
+
import { join, resolve as resolvePath } from 'node:path';
|
|
5
5
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
6
6
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
7
7
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
@@ -21,7 +21,12 @@ function sanitizeMcpUnicode(value) {
|
|
|
21
21
|
.replace(/[\p{Cf}\p{Co}\p{Cn}]/gu, '')
|
|
22
22
|
.replace(/[\u200B-\u200F\u202A-\u202E\u2066-\u2069\uFEFF\uE000-\uF8FF]/gu, '');
|
|
23
23
|
}
|
|
24
|
+
const MAX_MCP_TOOL_DESCRIPTION_CODE_POINTS = 2_048;
|
|
25
|
+
function capMcpToolDescription(value) {
|
|
26
|
+
return [...value].slice(0, MAX_MCP_TOOL_DESCRIPTION_CODE_POINTS).join('');
|
|
27
|
+
}
|
|
24
28
|
const MAX_RESOURCE_BYTES = 25 * 1024 * 1024;
|
|
29
|
+
const MAX_INLINE_MCP_TEXT_RESULT_BYTES = 100_000;
|
|
25
30
|
const NO_MCP_RESOURCES = 'No resources found. MCP servers may still provide tools even if they have no resources.';
|
|
26
31
|
const MCP_RESOURCE_TOOL_DEFINITIONS = [
|
|
27
32
|
{
|
|
@@ -454,11 +459,21 @@ async function mcpBinaryText(options, sensitiveValues, createdFiles) {
|
|
|
454
459
|
: `Resource from ${options.serverName} at ${options.uri}`;
|
|
455
460
|
return mcpTextBlock(`[${origin}] Binary content (${options.mimeType}, ${options.bytes.length} bytes) saved to ${filePath}`, sensitiveValues);
|
|
456
461
|
}
|
|
462
|
+
async function externalizeMcpTextResult(serverName, content, context, sensitiveValues, createdFiles) {
|
|
463
|
+
if (!context.toolResultDirectory) {
|
|
464
|
+
throw new Error('MCP large text tool result output directory is unavailable');
|
|
465
|
+
}
|
|
466
|
+
const bytes = Buffer.from(content, 'utf8');
|
|
467
|
+
const filePath = await writeToolBlob(resolvePath(context.cwd, context.toolResultDirectory), serverName, bytes, '.txt');
|
|
468
|
+
createdFiles.push(filePath);
|
|
469
|
+
return mcpTextBlock(`[MCP tool result from ${serverName}] Text content (${bytes.length} bytes) saved to ${filePath}`, sensitiveValues);
|
|
470
|
+
}
|
|
457
471
|
async function mcpToolResultUnchecked(serverName, result, context, sensitiveValues, createdFiles) {
|
|
458
472
|
if (!Array.isArray(result.content)) {
|
|
459
473
|
throw new Error('MCP tool result content must be an array');
|
|
460
474
|
}
|
|
461
475
|
const blocks = [];
|
|
476
|
+
let textOnly = result.structuredContent === undefined;
|
|
462
477
|
let resultBytes = 0;
|
|
463
478
|
const consumeBytes = (bytes) => {
|
|
464
479
|
resultBytes += bytes;
|
|
@@ -483,6 +498,7 @@ async function mcpToolResultUnchecked(serverName, result, context, sensitiveValu
|
|
|
483
498
|
}
|
|
484
499
|
continue;
|
|
485
500
|
}
|
|
501
|
+
textOnly = false;
|
|
486
502
|
if (item.type === 'image') {
|
|
487
503
|
if (typeof item.mimeType !== 'string' ||
|
|
488
504
|
!MCP_IMAGE_MEDIA_TYPES.has(item.mimeType) ||
|
|
@@ -569,6 +585,15 @@ async function mcpToolResultUnchecked(serverName, result, context, sensitiveValu
|
|
|
569
585
|
if (Buffer.byteLength(content) > MAX_RESOURCE_BYTES) {
|
|
570
586
|
throw new Error(`MCP tool result exceeded ${MAX_RESOURCE_BYTES} bytes`);
|
|
571
587
|
}
|
|
588
|
+
if (textOnly &&
|
|
589
|
+
Buffer.byteLength(content) > MAX_INLINE_MCP_TEXT_RESULT_BYTES) {
|
|
590
|
+
const pointerBlock = await externalizeMcpTextResult(serverName, content, context, sensitiveValues, createdFiles);
|
|
591
|
+
return {
|
|
592
|
+
content: pointerBlock.text,
|
|
593
|
+
contentBlocks: [pointerBlock],
|
|
594
|
+
isError: result.isError === true,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
572
597
|
const images = blocks.filter((block) => block.type === 'image');
|
|
573
598
|
return {
|
|
574
599
|
content,
|
|
@@ -1250,7 +1275,7 @@ export class ClaudeMcpToolRegistry {
|
|
|
1250
1275
|
sensitiveValues,
|
|
1251
1276
|
definition: {
|
|
1252
1277
|
name,
|
|
1253
|
-
description: redactSensitiveText(tool.description ?? `MCP tool ${tool.name} from ${serverName}`, sensitiveValues),
|
|
1278
|
+
description: capMcpToolDescription(redactSensitiveText(tool.description ?? `MCP tool ${tool.name} from ${serverName}`, sensitiveValues)),
|
|
1254
1279
|
inputSchema: redactSensitiveValue(tool.inputSchema, sensitiveValues),
|
|
1255
1280
|
},
|
|
1256
1281
|
};
|