@mono-agent/agent-runtime 0.5.1 → 0.6.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/package.json +1 -1
- package/src/agent/tools/pi-bridge.js +14 -6
- package/src/ai/providers/claude-cli.js +6 -3
- package/src/ai/providers/claude-sdk.js +6 -2
- package/src/ai/providers/claude-subagents.js +21 -0
- package/src/ai/providers/codex-app.js +1 -2
- package/src/ai/providers/pi-native/turn-runner.js +4 -2
- package/types/agent/tools/pi-bridge.d.ts +3 -2
- package/types/ai/providers/claude-subagents.d.ts +16 -0
package/package.json
CHANGED
|
@@ -309,7 +309,7 @@ function createBuiltinTool(name, label, description, parameters, execute, { cwd,
|
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
/**
|
|
312
|
-
* Progressive skill disclosure: exposes a `
|
|
312
|
+
* Progressive skill disclosure: exposes a `ReadSkill` tool so the agent can pull
|
|
313
313
|
* a named skill's FULL body on demand (skills are otherwise injected index-only).
|
|
314
314
|
*
|
|
315
315
|
* Two input shapes are accepted, matching what hosts pass:
|
|
@@ -318,7 +318,7 @@ function createBuiltinTool(name, label, description, parameters, execute, { cwd,
|
|
|
318
318
|
* back-compat `dataDir` (skills under `<dataDir>/skills`). This path is UNCHANGED.
|
|
319
319
|
* - pi's neutral `Skill` shape (`{name, description, content, filePath, ...}`,
|
|
320
320
|
* what worklab passes): each skill carries an absolute `filePath`. When NO shared
|
|
321
|
-
* `skillsRoot`/`dataDir` is configured,
|
|
321
|
+
* `skillsRoot`/`dataDir` is configured, ReadSkill derives each skill's root from
|
|
322
322
|
* its own `filePath` — pi has no lazy-body equivalent, so the body is still read
|
|
323
323
|
* from disk on demand rather than injected up front.
|
|
324
324
|
*
|
|
@@ -361,7 +361,7 @@ function readSkillTool(skillNames = [], { skillsRoot, dataDir, skills = [] } = {
|
|
|
361
361
|
if (!enumNames.length) return null;
|
|
362
362
|
|
|
363
363
|
return {
|
|
364
|
-
name: "
|
|
364
|
+
name: "ReadSkill",
|
|
365
365
|
label: "Read Skill",
|
|
366
366
|
description: "Load the full instructions for a named skill.",
|
|
367
367
|
parameters: objectSchema({ name: { type: "string", enum: enumNames } }, ["name"]),
|
|
@@ -408,9 +408,10 @@ export function createStructuredOutputTool(outputSchema, onStructuredOutput) {
|
|
|
408
408
|
|
|
409
409
|
/**
|
|
410
410
|
* @param {any} allowedTools
|
|
411
|
-
* @param {{skillNames?: any[], skills?: any[], skillsRoot?: any, dataDir?: any, cwd?: any, onEvent?: (event: any) => void, toolLimits?: any, persistArtifact?: any, onTruncate?: any, toolPayloadMaxBytes?: number, imageInlineMaxBytes?: any, toolPolicy?: any, sandboxPolicy?: any, sandboxEngine?: any, approvalManager?: any, approvalModel?: any, ctx?: any}} [options]
|
|
411
|
+
* @param {{disallowedTools?: any[], skillNames?: any[], skills?: any[], skillsRoot?: any, dataDir?: any, cwd?: any, onEvent?: (event: any) => void, toolLimits?: any, persistArtifact?: any, onTruncate?: any, toolPayloadMaxBytes?: number, imageInlineMaxBytes?: any, toolPolicy?: any, sandboxPolicy?: any, sandboxEngine?: any, approvalManager?: any, approvalModel?: any, ctx?: any}} [options]
|
|
412
412
|
*/
|
|
413
413
|
export function getPiBuiltinTools(allowedTools, {
|
|
414
|
+
disallowedTools = [],
|
|
414
415
|
skillNames = [],
|
|
415
416
|
skills = [],
|
|
416
417
|
skillsRoot,
|
|
@@ -495,10 +496,17 @@ export function getPiBuiltinTools(allowedTools, {
|
|
|
495
496
|
limit: { type: "integer" },
|
|
496
497
|
}, ["query"]), webSearchToolImpl, toolContext),
|
|
497
498
|
};
|
|
498
|
-
|
|
499
|
+
// allowedTools honors the `"*"` allow-all sentinel (and undefined) as "every
|
|
500
|
+
// built-in"; disallowedTools is the deny-wins filter applied to the final set.
|
|
501
|
+
const allowAll = !Array.isArray(allowedTools) || allowedTools.includes("*");
|
|
502
|
+
const selected = allowAll ? Object.keys(all) : allowedTools;
|
|
503
|
+
const denied = new Set(Array.isArray(disallowedTools) ? disallowedTools : []);
|
|
504
|
+
const names = selected.filter((name) => !denied.has(name));
|
|
499
505
|
const tools = names.map((name) => all[name]).filter(Boolean);
|
|
500
506
|
const skillTool = readSkillTool(skillNames, { skillsRoot, dataDir, skills });
|
|
501
|
-
|
|
507
|
+
// Deny-check the canonical PascalCase name AND the legacy snake_case alias so
|
|
508
|
+
// an old denylist keeps disabling the tool after the rename.
|
|
509
|
+
if (skillTool && !denied.has("ReadSkill") && !denied.has("read_skill" /* legacy alias */)) tools.push(skillTool);
|
|
502
510
|
const gated = approvalManager
|
|
503
511
|
? wrapToolsWithApprovalGate(tools, approvalManager, { model: approvalModel })
|
|
504
512
|
: tools;
|
|
@@ -13,7 +13,7 @@ import { readRuntimeBrand } from "../../agent/tools/shared/runtime-context.js";
|
|
|
13
13
|
import { buildCapabilitiesUsed } from "../runtime/capabilities-used.js";
|
|
14
14
|
import {
|
|
15
15
|
claudeNativeAgentDefinitions,
|
|
16
|
-
|
|
16
|
+
resolveClaudeAllowedTools,
|
|
17
17
|
} from "./claude-subagents.js";
|
|
18
18
|
|
|
19
19
|
const DORMANT_CLI_CAPABILITIES = {
|
|
@@ -377,7 +377,10 @@ export function buildCliCommand({
|
|
|
377
377
|
const normalizedEffort = typeof effort === "string" && effort.trim() ? effort : null;
|
|
378
378
|
if (sdk === "claude-code") {
|
|
379
379
|
const nativeAgents = claudeNativeAgentDefinitions(nativeSubagents);
|
|
380
|
-
|
|
380
|
+
// `"*"` allow-all → defer to Claude Code's full default toolset (omit
|
|
381
|
+
// --tools); `cliAllowedTools` is the "*"-stripped explicit list so a bare
|
|
382
|
+
// "*" never reaches a flag value.
|
|
383
|
+
const { allowAll: cliAllowAll, tools: cliAllowedTools } = resolveClaudeAllowedTools(allowedTools, nativeSubagents);
|
|
381
384
|
// intelligence-ramp Phase 5.1: when the coordinator hands us a parent
|
|
382
385
|
// session id (recovery continuation, R12), pass --resume so the host
|
|
383
386
|
// CLI can keep its own conversation cache warm. Otherwise stay
|
|
@@ -402,7 +405,7 @@ export function buildCliCommand({
|
|
|
402
405
|
args.push("--add-dir", ...skillDirs);
|
|
403
406
|
}
|
|
404
407
|
if (nativeAgents) args.push("--agents", JSON.stringify(nativeAgents));
|
|
405
|
-
if (Array.isArray(cliAllowedTools) && cliAllowedTools.length) {
|
|
408
|
+
if (!cliAllowAll && Array.isArray(cliAllowedTools) && cliAllowedTools.length) {
|
|
406
409
|
args.push("--tools", cliAllowedTools.join(","));
|
|
407
410
|
}
|
|
408
411
|
const autoAllowed = [
|
|
@@ -20,7 +20,7 @@ import { readRuntimeBrand } from "../../agent/tools/shared/runtime-context.js";
|
|
|
20
20
|
import { createApprovalManager } from "../../agent/approval.js";
|
|
21
21
|
import {
|
|
22
22
|
claudeNativeAgentDefinitions,
|
|
23
|
-
|
|
23
|
+
resolveClaudeAllowedTools,
|
|
24
24
|
} from "./claude-subagents.js";
|
|
25
25
|
|
|
26
26
|
function thinkingForEffort(effort) {
|
|
@@ -588,6 +588,10 @@ export async function generateClaudeResponse(systemPrompt, options) {
|
|
|
588
588
|
? "default"
|
|
589
589
|
: permissionMode;
|
|
590
590
|
const nativeAgents = claudeNativeAgentDefinitions(options.nativeSubagents);
|
|
591
|
+
// `"*"` allow-all → pass `allowedTools: undefined` so the SDK uses its default
|
|
592
|
+
// toolset (every tool, incl. Task — not double-added). disallowedTools still
|
|
593
|
+
// flows through, so deny-wins holds under allow-all.
|
|
594
|
+
const { allowAll: allowAllTools, tools: resolvedAllowedTools } = resolveClaudeAllowedTools(allowedTools, options.nativeSubagents);
|
|
591
595
|
// Assembled incrementally, then handed across the SDK `query` boundary
|
|
592
596
|
// (outputFormat/resume/maxTurns are attached conditionally below).
|
|
593
597
|
/** @type {any} */
|
|
@@ -597,7 +601,7 @@ export async function generateClaudeResponse(systemPrompt, options) {
|
|
|
597
601
|
cwd,
|
|
598
602
|
permissionMode: effectivePermissionMode,
|
|
599
603
|
...(effectivePermissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
|
|
600
|
-
allowedTools:
|
|
604
|
+
allowedTools: allowAllTools ? undefined : resolvedAllowedTools,
|
|
601
605
|
disallowedTools,
|
|
602
606
|
mcpServers,
|
|
603
607
|
...(approvalManager ? { canUseTool: createClaudeCanUseTool(approvalManager, model.model) } : {}),
|
|
@@ -65,3 +65,24 @@ export function claudeToolsWithNativeSubagents(allowedTools, nativeSubagents) {
|
|
|
65
65
|
? withTaskTool(allowedTools)
|
|
66
66
|
: allowedTools;
|
|
67
67
|
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Resolve the effective allowed-tools list for the Claude bridges, honoring the
|
|
71
|
+
* `"*"` allow-all sentinel. Returns `{ allowAll, tools }` where `tools` is the
|
|
72
|
+
* native-subagent-composed list with any bare `"*"` stripped, so a literal `"*"`
|
|
73
|
+
* never reaches a CLI flag value or the SDK `query()`. When `allowAll` is true
|
|
74
|
+
* the caller MUST defer to Claude's default toolset (omit `--tools` / pass
|
|
75
|
+
* `allowedTools: undefined`) rather than pass `tools` as the tool set — the
|
|
76
|
+
* default already carries every tool, incl. `Task`, so it is not double-added.
|
|
77
|
+
* @param {any} allowedTools
|
|
78
|
+
* @param {any} nativeSubagents
|
|
79
|
+
* @returns {{allowAll: boolean, tools: any}}
|
|
80
|
+
*/
|
|
81
|
+
export function resolveClaudeAllowedTools(allowedTools, nativeSubagents) {
|
|
82
|
+
const composed = claudeToolsWithNativeSubagents(allowedTools, nativeSubagents);
|
|
83
|
+
const allowAll = Array.isArray(composed) && composed.includes("*");
|
|
84
|
+
const tools = Array.isArray(composed)
|
|
85
|
+
? composed.filter((tool) => tool !== "*")
|
|
86
|
+
: composed;
|
|
87
|
+
return { allowAll, tools };
|
|
88
|
+
}
|
|
@@ -116,8 +116,7 @@ function sandboxForPermissionMode(permissionMode) {
|
|
|
116
116
|
|
|
117
117
|
function approvalPolicyForPermissionMode(permissionMode) {
|
|
118
118
|
if (permissionMode === "bypassPermissions") return "never";
|
|
119
|
-
|
|
120
|
-
return "on-failure";
|
|
119
|
+
return "on-request";
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
function codexMcpConfig(mcpServers = {}) {
|
|
@@ -72,13 +72,15 @@ export async function buildTurnTools(runState, {
|
|
|
72
72
|
const builtIns = capabilities.tool_use === false
|
|
73
73
|
? []
|
|
74
74
|
: getPiBuiltinTools(options.allowedTools, /** @type {any} */ ({
|
|
75
|
+
// deny-wins filter applied over the built-ins + ReadSkill inside pi-bridge.
|
|
76
|
+
disallowedTools: options.disallowedTools,
|
|
75
77
|
skillNames: (options.skills || []).map((/** @type {{name: string}} */ skill) => skill.name),
|
|
76
|
-
// Full skill objects so
|
|
78
|
+
// Full skill objects so ReadSkill can honor pi's neutral Skill shape
|
|
77
79
|
// ({name, filePath, ...}) and derive each skill's root from its own
|
|
78
80
|
// filePath when no shared skillsRoot is threaded.
|
|
79
81
|
skills: options.skills || [],
|
|
80
82
|
// Progressive skill disclosure: when the harness threads the skills root
|
|
81
|
-
// (the directory holding `<name>/SKILL.md`) the
|
|
83
|
+
// (the directory holding `<name>/SKILL.md`) the ReadSkill tool resolves
|
|
82
84
|
// bodies directly from there. `dataDir` (skills under `<dataDir>/skills`)
|
|
83
85
|
// remains the back-compat fallback; a per-skill filePath is the third path.
|
|
84
86
|
skillsRoot: options.skillsRoot,
|
|
@@ -35,9 +35,10 @@ export function createStructuredOutputTool(outputSchema: any, onStructuredOutput
|
|
|
35
35
|
};
|
|
36
36
|
/**
|
|
37
37
|
* @param {any} allowedTools
|
|
38
|
-
* @param {{skillNames?: any[], skills?: any[], skillsRoot?: any, dataDir?: any, cwd?: any, onEvent?: (event: any) => void, toolLimits?: any, persistArtifact?: any, onTruncate?: any, toolPayloadMaxBytes?: number, imageInlineMaxBytes?: any, toolPolicy?: any, sandboxPolicy?: any, sandboxEngine?: any, approvalManager?: any, approvalModel?: any, ctx?: any}} [options]
|
|
38
|
+
* @param {{disallowedTools?: any[], skillNames?: any[], skills?: any[], skillsRoot?: any, dataDir?: any, cwd?: any, onEvent?: (event: any) => void, toolLimits?: any, persistArtifact?: any, onTruncate?: any, toolPayloadMaxBytes?: number, imageInlineMaxBytes?: any, toolPolicy?: any, sandboxPolicy?: any, sandboxEngine?: any, approvalManager?: any, approvalModel?: any, ctx?: any}} [options]
|
|
39
39
|
*/
|
|
40
|
-
export function getPiBuiltinTools(allowedTools: any, { skillNames, skills, skillsRoot, dataDir, cwd, onEvent, toolLimits, persistArtifact, onTruncate, toolPayloadMaxBytes, imageInlineMaxBytes, toolPolicy, sandboxPolicy, sandboxEngine, approvalManager, approvalModel, ctx, }?: {
|
|
40
|
+
export function getPiBuiltinTools(allowedTools: any, { disallowedTools, skillNames, skills, skillsRoot, dataDir, cwd, onEvent, toolLimits, persistArtifact, onTruncate, toolPayloadMaxBytes, imageInlineMaxBytes, toolPolicy, sandboxPolicy, sandboxEngine, approvalManager, approvalModel, ctx, }?: {
|
|
41
|
+
disallowedTools?: any[];
|
|
41
42
|
skillNames?: any[];
|
|
42
43
|
skills?: any[];
|
|
43
44
|
skillsRoot?: any;
|
|
@@ -1,2 +1,18 @@
|
|
|
1
1
|
export function claudeNativeAgentDefinitions(nativeSubagents: any): {};
|
|
2
2
|
export function claudeToolsWithNativeSubagents(allowedTools: any, nativeSubagents: any): any;
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the effective allowed-tools list for the Claude bridges, honoring the
|
|
5
|
+
* `"*"` allow-all sentinel. Returns `{ allowAll, tools }` where `tools` is the
|
|
6
|
+
* native-subagent-composed list with any bare `"*"` stripped, so a literal `"*"`
|
|
7
|
+
* never reaches a CLI flag value or the SDK `query()`. When `allowAll` is true
|
|
8
|
+
* the caller MUST defer to Claude's default toolset (omit `--tools` / pass
|
|
9
|
+
* `allowedTools: undefined`) rather than pass `tools` as the tool set — the
|
|
10
|
+
* default already carries every tool, incl. `Task`, so it is not double-added.
|
|
11
|
+
* @param {any} allowedTools
|
|
12
|
+
* @param {any} nativeSubagents
|
|
13
|
+
* @returns {{allowAll: boolean, tools: any}}
|
|
14
|
+
*/
|
|
15
|
+
export function resolveClaudeAllowedTools(allowedTools: any, nativeSubagents: any): {
|
|
16
|
+
allowAll: boolean;
|
|
17
|
+
tools: any;
|
|
18
|
+
};
|