@botbotgo/agent-harness 0.0.161 → 0.0.163
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 +2 -0
- package/README.zh.md +2 -0
- package/dist/contracts/runtime.d.ts +2 -0
- package/dist/contracts/workspace.d.ts +2 -0
- package/dist/extensions.js +4 -0
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/harness/bindings.js +2 -1
- package/dist/runtime/harness/run/governance.js +58 -3
- package/dist/runtime/harness/system/policy-engine.js +69 -0
- package/dist/runtime/harness/tool-schema.d.ts +2 -0
- package/dist/runtime/harness/tool-schema.js +3 -0
- package/dist/tool-modules.d.ts +1 -0
- package/dist/tool-modules.js +1 -0
- package/dist/workspace/object-loader.js +41 -4
- package/dist/workspace/resource-compilers.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -578,6 +578,7 @@ Example workspaces:
|
|
|
578
578
|
|
|
579
579
|
Workspace-local tool modules in `resources/tools/` should be exported with `tool({...})`.
|
|
580
580
|
Any other local module shape is not supported, and unsupported shapes are rejected at load time.
|
|
581
|
+
When a local function tool declares its schema in the module, runtime governance treats that module-defined schema as the source of truth; duplicating it into YAML `inputSchema.ref` is optional rather than required for schema-bound metadata.
|
|
581
582
|
When local tools use Zod-authored schemas, keep the workspace or isolated `resources` package on `zod@^4` so raw-shape validators and runtime parsing stay on one supported major version.
|
|
582
583
|
|
|
583
584
|
Default wiring guidance:
|
|
@@ -911,3 +912,4 @@ ACP transport notes:
|
|
|
911
912
|
- `serveAcpStdio(runtime)` exposes newline-delimited JSON-RPC over stdio for local IDE, CLI, or subprocess clients.
|
|
912
913
|
- `serveAcpHttp(runtime)` exposes JSON-RPC over HTTP plus SSE runtime events so remote operator surfaces can connect without importing the runtime in-process.
|
|
913
914
|
- `exportRunPackage(...)` and `exportSessionPackage(...)` package stable runtime records, transcript, approvals, events, and artifacts for operator tooling without reaching into persistence internals.
|
|
915
|
+
- `runtime/default.governance.remoteMcp` can now deny or allow specific MCP servers, raise approval requirements by transport, and stamp transport-based risk tiers into runtime governance bundles.
|
package/README.zh.md
CHANGED
|
@@ -542,6 +542,7 @@ await stop(runtime);
|
|
|
542
542
|
|
|
543
543
|
`resources/tools/` 下的工作区本地工具模块应统一用 `tool({...})` 导出。
|
|
544
544
|
不支持历史/兼容写法,任何不带该导出形式的工具模块都会在工作区加载时被拒绝。
|
|
545
|
+
本地 function tool 如果在模块里声明了 schema,runtime governance 会直接把该模块 schema 视为事实来源;不需要为了 schema-bound 元数据再额外复制一份 YAML `inputSchema.ref`。
|
|
545
546
|
若本地工具使用 Zod schema,请让工作区或隔离的 `resources` 包统一使用 `zod@^4`,避免 raw shape validator 与 runtime 解析落在不同 major 版本上。
|
|
546
547
|
|
|
547
548
|
主要有三层配置:
|
|
@@ -870,3 +871,4 @@ ACP transport 说明:
|
|
|
870
871
|
- `serveAcpStdio(runtime)` 提供基于 stdio 的 newline-delimited JSON-RPC,适合本地 IDE、CLI 或子进程客户端。
|
|
871
872
|
- `serveAcpHttp(runtime)` 提供基于 HTTP 的 JSON-RPC 与 SSE runtime events,适合远程 operator surface 或独立控制面接入。
|
|
872
873
|
- `exportRunPackage(...)` 与 `exportSessionPackage(...)` 可把稳定 runtime 记录、transcript、approvals、events 和 artifacts 打包给 operator tooling,而不必直接访问 persistence 内部实现。
|
|
874
|
+
- `runtime/default.governance.remoteMcp` 现在可以按 MCP server 或 transport 做 allow/deny、审批升级,并把 transport 风险等级写进 runtime governance bundles。
|
|
@@ -102,6 +102,8 @@ export type RuntimeGovernanceToolPolicy = {
|
|
|
102
102
|
toolId: string;
|
|
103
103
|
toolType: string;
|
|
104
104
|
category: "local" | "backend" | "mcp" | "provider-native";
|
|
105
|
+
mcpServerRef?: string;
|
|
106
|
+
mcpTransport?: string;
|
|
105
107
|
risk: RuntimeGovernanceRiskLevel;
|
|
106
108
|
requiresApproval: boolean;
|
|
107
109
|
approvalPolicy: "explicit-hitl" | "runtime-default" | "none";
|
|
@@ -83,6 +83,7 @@ export type ParsedToolObject = {
|
|
|
83
83
|
config?: Record<string, unknown>;
|
|
84
84
|
subprocess?: boolean;
|
|
85
85
|
inputSchemaRef?: string;
|
|
86
|
+
hasModuleSchema?: boolean;
|
|
86
87
|
embeddingModelRef?: string;
|
|
87
88
|
backendOperation?: string;
|
|
88
89
|
mcpRef?: string;
|
|
@@ -132,6 +133,7 @@ export type CompiledTool = {
|
|
|
132
133
|
config?: Record<string, unknown>;
|
|
133
134
|
subprocess?: boolean;
|
|
134
135
|
inputSchemaRef?: string;
|
|
136
|
+
hasModuleSchema?: boolean;
|
|
135
137
|
embeddingModelRef?: string;
|
|
136
138
|
backendOperation?: string;
|
|
137
139
|
mcpRef?: string;
|
package/dist/extensions.js
CHANGED
|
@@ -124,6 +124,7 @@ registerToolKind({
|
|
|
124
124
|
config: tool.config,
|
|
125
125
|
subprocess: tool.subprocess,
|
|
126
126
|
inputSchemaRef: tool.inputSchemaRef,
|
|
127
|
+
hasModuleSchema: tool.hasModuleSchema,
|
|
127
128
|
embeddingModelRef: tool.embeddingModelRef,
|
|
128
129
|
bundleRefs: [],
|
|
129
130
|
hitl: tool.hitl
|
|
@@ -158,6 +159,7 @@ registerToolKind({
|
|
|
158
159
|
config: tool.config,
|
|
159
160
|
subprocess: tool.subprocess,
|
|
160
161
|
inputSchemaRef: tool.inputSchemaRef,
|
|
162
|
+
hasModuleSchema: tool.hasModuleSchema,
|
|
161
163
|
embeddingModelRef: tool.embeddingModelRef,
|
|
162
164
|
backendOperation: tool.backendOperation,
|
|
163
165
|
bundleRefs: [],
|
|
@@ -193,6 +195,7 @@ registerToolKind({
|
|
|
193
195
|
config: tool.config,
|
|
194
196
|
subprocess: tool.subprocess,
|
|
195
197
|
inputSchemaRef: tool.inputSchemaRef,
|
|
198
|
+
hasModuleSchema: tool.hasModuleSchema,
|
|
196
199
|
embeddingModelRef: tool.embeddingModelRef,
|
|
197
200
|
mcpRef: tool.mcpRef,
|
|
198
201
|
bundleRefs: [],
|
|
@@ -234,6 +237,7 @@ registerToolKind({
|
|
|
234
237
|
config: tool.config,
|
|
235
238
|
subprocess: tool.subprocess,
|
|
236
239
|
inputSchemaRef: tool.inputSchemaRef,
|
|
240
|
+
hasModuleSchema: tool.hasModuleSchema,
|
|
237
241
|
embeddingModelRef: tool.embeddingModelRef,
|
|
238
242
|
bundleRefs: [],
|
|
239
243
|
hitl: tool.hitl
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.162";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.162";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveBindingTimeout, resolveProviderRetryPolicy, resolveStreamIdleTimeout } from "../adapter/resilience.js";
|
|
2
2
|
import { toolRequiresRuntimeApproval } from "../adapter/tool/tool-hitl.js";
|
|
3
3
|
import { getBindingPrimaryTools } from "../support/compiled-binding.js";
|
|
4
|
+
import { compiledToolHasInputSchema } from "./tool-schema.js";
|
|
4
5
|
export function getWorkspaceBinding(workspace, agentId) {
|
|
5
6
|
return workspace.bindings.get(agentId);
|
|
6
7
|
}
|
|
@@ -29,7 +30,7 @@ export function projectBindingToolExecutionPolicy(binding) {
|
|
|
29
30
|
toolId: tool.id,
|
|
30
31
|
name: tool.name,
|
|
31
32
|
retryable: tool.retryable === true,
|
|
32
|
-
hasInputSchema:
|
|
33
|
+
hasInputSchema: compiledToolHasInputSchema(tool),
|
|
33
34
|
requiresApproval: toolRequiresRuntimeApproval(tool),
|
|
34
35
|
}));
|
|
35
36
|
const retryableToolCount = projectedTools.filter((tool) => tool.retryable).length;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getBindingPrimaryTools } from "../../support/compiled-binding.js";
|
|
2
2
|
import { toolRequiresRuntimeApproval } from "../../adapter/tool/tool-hitl.js";
|
|
3
|
+
import { compiledToolHasInputSchema } from "../tool-schema.js";
|
|
3
4
|
const WRITE_LIKE_PATTERN = /\b(write|edit|delete|create|update|append|insert|push|commit|publish|send|post|apply|merge|sync|upload|save)\b/i;
|
|
4
5
|
function inputHints(binding, tool) {
|
|
5
6
|
const hints = new Set();
|
|
@@ -57,6 +58,25 @@ function readRisk(value) {
|
|
|
57
58
|
function readApprovalPolicy(value) {
|
|
58
59
|
return value === "explicit-hitl" || value === "runtime-default" || value === "none" ? value : undefined;
|
|
59
60
|
}
|
|
61
|
+
function normalizeServerRef(value) {
|
|
62
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const trimmed = value.trim();
|
|
66
|
+
return trimmed.startsWith("mcp/") ? trimmed : `mcp/${trimmed}`;
|
|
67
|
+
}
|
|
68
|
+
function readRemoteMcpMetadata(tool) {
|
|
69
|
+
const config = asObject(tool.config);
|
|
70
|
+
const mcpReference = asObject(config?.mcp);
|
|
71
|
+
const inlineServer = asObject(config?.mcpServer);
|
|
72
|
+
const transport = typeof inlineServer?.transport === "string" && inlineServer.transport.trim().length > 0
|
|
73
|
+
? inlineServer.transport.trim()
|
|
74
|
+
: undefined;
|
|
75
|
+
return {
|
|
76
|
+
...(normalizeServerRef(mcpReference?.serverRef) ? { serverRef: normalizeServerRef(mcpReference?.serverRef) } : {}),
|
|
77
|
+
...(transport ? { transport } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
60
80
|
function matchesToolPolicy(rule, policy) {
|
|
61
81
|
const match = asObject(rule.match) ?? rule;
|
|
62
82
|
const toolName = typeof match.toolName === "string" ? match.toolName.trim() : undefined;
|
|
@@ -102,14 +122,49 @@ function applyGovernanceOverrides(binding, policies) {
|
|
|
102
122
|
return merged;
|
|
103
123
|
});
|
|
104
124
|
}
|
|
125
|
+
function applyRemoteMcpGovernance(binding, policies) {
|
|
126
|
+
const governance = asObject(binding.harnessRuntime.governance);
|
|
127
|
+
const remoteMcp = asObject(governance?.remoteMcp);
|
|
128
|
+
if (!remoteMcp) {
|
|
129
|
+
return policies;
|
|
130
|
+
}
|
|
131
|
+
const requireApprovalTransports = new Set(readStringArray(remoteMcp.requireApprovalTransports));
|
|
132
|
+
const riskByTransport = asObject(remoteMcp.riskByTransport);
|
|
133
|
+
const inputRiskHintsByTransport = asObject(remoteMcp.inputRiskHintsByTransport);
|
|
134
|
+
return policies.map((policy) => {
|
|
135
|
+
if (policy.category !== "mcp") {
|
|
136
|
+
return policy;
|
|
137
|
+
}
|
|
138
|
+
const merged = { ...policy };
|
|
139
|
+
const transport = merged.mcpTransport;
|
|
140
|
+
if (transport && requireApprovalTransports.has(transport)) {
|
|
141
|
+
merged.requiresApproval = true;
|
|
142
|
+
if (merged.approvalPolicy === "none") {
|
|
143
|
+
merged.approvalPolicy = "runtime-default";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const transportRisk = transport ? readRisk(riskByTransport?.[transport]) : undefined;
|
|
147
|
+
if (transportRisk) {
|
|
148
|
+
merged.risk = transportRisk;
|
|
149
|
+
}
|
|
150
|
+
const transportHints = transport ? readStringArray(inputRiskHintsByTransport?.[transport]) : [];
|
|
151
|
+
if (transportHints.length > 0) {
|
|
152
|
+
merged.inputRiskHints = Array.from(new Set([...merged.inputRiskHints, ...transportHints]));
|
|
153
|
+
}
|
|
154
|
+
return merged;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
105
157
|
export function buildRuntimeGovernanceBundles(binding) {
|
|
106
|
-
const toolPolicies = applyGovernanceOverrides(binding, getBindingPrimaryTools(binding).map((tool) => {
|
|
158
|
+
const toolPolicies = applyGovernanceOverrides(binding, applyRemoteMcpGovernance(binding, getBindingPrimaryTools(binding).map((tool) => {
|
|
107
159
|
const requiresApproval = toolRequiresRuntimeApproval(tool);
|
|
160
|
+
const remoteMcp = readRemoteMcpMetadata(tool);
|
|
108
161
|
return {
|
|
109
162
|
toolName: tool.name,
|
|
110
163
|
toolId: tool.id,
|
|
111
164
|
toolType: tool.type,
|
|
112
165
|
category: toCategory(tool.type),
|
|
166
|
+
...(remoteMcp.serverRef ? { mcpServerRef: remoteMcp.serverRef } : {}),
|
|
167
|
+
...(remoteMcp.transport ? { mcpTransport: remoteMcp.transport } : {}),
|
|
113
168
|
risk: classifyRisk({
|
|
114
169
|
toolType: tool.type,
|
|
115
170
|
requiresApproval,
|
|
@@ -119,10 +174,10 @@ export function buildRuntimeGovernanceBundles(binding) {
|
|
|
119
174
|
}),
|
|
120
175
|
requiresApproval,
|
|
121
176
|
approvalPolicy: tool.hitl?.enabled === true ? "explicit-hitl" : requiresApproval ? "runtime-default" : "none",
|
|
122
|
-
hasInputSchema:
|
|
177
|
+
hasInputSchema: compiledToolHasInputSchema(tool),
|
|
123
178
|
inputRiskHints: inputHints(binding, tool),
|
|
124
179
|
};
|
|
125
|
-
}));
|
|
180
|
+
})));
|
|
126
181
|
if (toolPolicies.length === 0) {
|
|
127
182
|
return [];
|
|
128
183
|
}
|
|
@@ -12,6 +12,9 @@ export class PolicyEngine {
|
|
|
12
12
|
const governance = typeof binding.harnessRuntime.governance === "object" && binding.harnessRuntime.governance
|
|
13
13
|
? binding.harnessRuntime.governance
|
|
14
14
|
: undefined;
|
|
15
|
+
const remoteMcp = typeof governance?.remoteMcp === "object" && governance.remoteMcp
|
|
16
|
+
? governance.remoteMcp
|
|
17
|
+
: undefined;
|
|
15
18
|
const denyConfig = typeof governance?.deny === "object" && governance.deny
|
|
16
19
|
? governance.deny
|
|
17
20
|
: undefined;
|
|
@@ -38,6 +41,72 @@ export class PolicyEngine {
|
|
|
38
41
|
reasons.push(`runtime governance denied tool access: ${blocked.map((tool) => tool.name).join(", ")}`);
|
|
39
42
|
}
|
|
40
43
|
}
|
|
44
|
+
if (remoteMcp) {
|
|
45
|
+
const normalizeServerRef = (value) => {
|
|
46
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const trimmed = value.trim();
|
|
50
|
+
return trimmed.startsWith("mcp/") ? trimmed : `mcp/${trimmed}`;
|
|
51
|
+
};
|
|
52
|
+
const allowServerRefs = new Set(Array.isArray(remoteMcp.allowServerRefs)
|
|
53
|
+
? remoteMcp.allowServerRefs
|
|
54
|
+
.map((item) => normalizeServerRef(item))
|
|
55
|
+
.filter((item) => Boolean(item))
|
|
56
|
+
: []);
|
|
57
|
+
const denyServerRefs = new Set(Array.isArray(remoteMcp.denyServerRefs)
|
|
58
|
+
? remoteMcp.denyServerRefs
|
|
59
|
+
.map((item) => normalizeServerRef(item))
|
|
60
|
+
.filter((item) => Boolean(item))
|
|
61
|
+
: []);
|
|
62
|
+
const denyTransports = new Set(Array.isArray(remoteMcp.denyTransports)
|
|
63
|
+
? remoteMcp.denyTransports.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
|
|
64
|
+
: []);
|
|
65
|
+
const tools = binding.execution?.params?.tools ?? binding.langchainAgentParams?.tools ?? binding.deepAgentParams?.tools ?? [];
|
|
66
|
+
const deniedRemoteTools = tools.flatMap((tool) => {
|
|
67
|
+
if (tool.type !== "mcp") {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const config = typeof tool.config === "object" && tool.config && !Array.isArray(tool.config)
|
|
71
|
+
? tool.config
|
|
72
|
+
: undefined;
|
|
73
|
+
const mcpRef = typeof config?.mcp === "object" && config.mcp && !Array.isArray(config.mcp)
|
|
74
|
+
? config.mcp
|
|
75
|
+
: undefined;
|
|
76
|
+
const inlineMcpServer = typeof config?.mcpServer === "object" && config.mcpServer && !Array.isArray(config.mcpServer)
|
|
77
|
+
? config.mcpServer
|
|
78
|
+
: undefined;
|
|
79
|
+
const serverRef = normalizeServerRef(mcpRef?.serverRef);
|
|
80
|
+
const transport = typeof inlineMcpServer?.transport === "string" && inlineMcpServer.transport.trim().length > 0
|
|
81
|
+
? inlineMcpServer.transport.trim()
|
|
82
|
+
: undefined;
|
|
83
|
+
const serverDenied = serverRef ? denyServerRefs.has(serverRef) || (allowServerRefs.size > 0 && !allowServerRefs.has(serverRef)) : false;
|
|
84
|
+
const transportDenied = transport ? denyTransports.has(transport) : false;
|
|
85
|
+
return serverDenied || transportDenied
|
|
86
|
+
? [{
|
|
87
|
+
toolName: tool.name,
|
|
88
|
+
...(serverRef ? { serverRef } : {}),
|
|
89
|
+
...(transport ? { transport } : {}),
|
|
90
|
+
}]
|
|
91
|
+
: [];
|
|
92
|
+
});
|
|
93
|
+
if (deniedRemoteTools.length > 0) {
|
|
94
|
+
allowed = false;
|
|
95
|
+
const details = deniedRemoteTools.map((tool) => {
|
|
96
|
+
if (tool.serverRef && tool.transport) {
|
|
97
|
+
return `${tool.toolName} (${tool.serverRef}, ${tool.transport})`;
|
|
98
|
+
}
|
|
99
|
+
if (tool.serverRef) {
|
|
100
|
+
return `${tool.toolName} (${tool.serverRef})`;
|
|
101
|
+
}
|
|
102
|
+
if (tool.transport) {
|
|
103
|
+
return `${tool.toolName} (${tool.transport})`;
|
|
104
|
+
}
|
|
105
|
+
return tool.toolName;
|
|
106
|
+
});
|
|
107
|
+
reasons.push(`runtime governance denied remote MCP access: ${details.join(", ")}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
41
110
|
for (const evaluator of getPolicyEvaluators()) {
|
|
42
111
|
const decision = evaluator.evaluate(binding);
|
|
43
112
|
if (!decision) {
|
package/dist/tool-modules.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export type LoadedToolModule = {
|
|
|
4
4
|
implementationName: string;
|
|
5
5
|
invoke: (input: unknown, context?: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
6
6
|
schema: ReturnType<typeof normalizeToolSchema>;
|
|
7
|
+
hasModuleSchema: boolean;
|
|
7
8
|
description: string;
|
|
8
9
|
retryable?: boolean;
|
|
9
10
|
memory?: {
|
package/dist/tool-modules.js
CHANGED
|
@@ -20,6 +20,7 @@ function loadToolObjectDefinition(imported, exportName) {
|
|
|
20
20
|
implementationName: definition.name?.trim() || exportName,
|
|
21
21
|
invoke: definition.invoke,
|
|
22
22
|
schema: normalizeToolSchema(definition.schema),
|
|
23
|
+
hasModuleSchema: true,
|
|
23
24
|
description: definition.description.trim(),
|
|
24
25
|
retryable: definition.retryable === true,
|
|
25
26
|
...(definition.memory ? { memory: { ...definition.memory } } : {}),
|
|
@@ -4,7 +4,7 @@ import { readdir, readFile } from "node:fs/promises";
|
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
5
|
import { resolveIsolatedResourceModulePath } from "../resource/isolation.js";
|
|
6
6
|
import { isExternalSourceLocator, resolveResourcePackageRoot } from "../resource/sources.js";
|
|
7
|
-
import { discoverToolModuleDefinitions, isSupportedToolModulePath } from "../tool-modules.js";
|
|
7
|
+
import { discoverToolModuleDefinitions, isSupportedToolModulePath, loadToolModuleDefinition } from "../tool-modules.js";
|
|
8
8
|
import { fileExists } from "../utils/fs.js";
|
|
9
9
|
import { readNamedYamlItems, readYamlItems, } from "./yaml-object-reader.js";
|
|
10
10
|
export { normalizeYamlItem, readYamlItems } from "./yaml-object-reader.js";
|
|
@@ -633,12 +633,22 @@ async function readModuleToolItems(root) {
|
|
|
633
633
|
if (inferredType === "function" && !discoveredPath) {
|
|
634
634
|
throw new Error(`Module tool ${workspaceObject.id} must define implementation.path or provide index.mjs|index.js|index.cjs`);
|
|
635
635
|
}
|
|
636
|
+
const implementationName = typeof normalizedItem.implementationName === "string" && normalizedItem.implementationName.trim().length > 0
|
|
637
|
+
? normalizedItem.implementationName.trim()
|
|
638
|
+
: typeof implementation?.export === "string" && implementation.export.trim().length > 0
|
|
639
|
+
? implementation.export.trim()
|
|
640
|
+
: workspaceObject.id;
|
|
641
|
+
const schemaMetadata = inferredType === "function" && discoveredPath
|
|
642
|
+
? await readModuleToolSchemaMetadata({
|
|
643
|
+
sourcePath: discoveredPath,
|
|
644
|
+
implementationName,
|
|
645
|
+
})
|
|
646
|
+
: { hasModuleSchema: false };
|
|
636
647
|
records.push({
|
|
637
648
|
item: {
|
|
638
649
|
...normalizedItem,
|
|
639
|
-
...(typeof implementation?.export === "string" && !normalizedItem.implementationName
|
|
640
|
-
|
|
641
|
-
: {}),
|
|
650
|
+
...(typeof implementation?.export === "string" && !normalizedItem.implementationName ? { implementationName } : {}),
|
|
651
|
+
...(schemaMetadata.hasModuleSchema ? { hasModuleSchema: true } : {}),
|
|
642
652
|
},
|
|
643
653
|
sourcePath: discoveredPath ?? sourcePath,
|
|
644
654
|
});
|
|
@@ -646,6 +656,32 @@ async function readModuleToolItems(root) {
|
|
|
646
656
|
}
|
|
647
657
|
return records;
|
|
648
658
|
}
|
|
659
|
+
function findToolPackageRoot(startPath) {
|
|
660
|
+
let current = path.dirname(startPath);
|
|
661
|
+
for (;;) {
|
|
662
|
+
const packageJsonPath = path.join(current, "package.json");
|
|
663
|
+
if (existsSync(packageJsonPath)) {
|
|
664
|
+
return current;
|
|
665
|
+
}
|
|
666
|
+
const parent = path.dirname(current);
|
|
667
|
+
if (parent === current) {
|
|
668
|
+
return path.dirname(startPath);
|
|
669
|
+
}
|
|
670
|
+
current = parent;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
async function readModuleToolSchemaMetadata(input) {
|
|
674
|
+
if (!isSupportedToolModulePath(input.sourcePath)) {
|
|
675
|
+
return { hasModuleSchema: false };
|
|
676
|
+
}
|
|
677
|
+
const packageRoot = findToolPackageRoot(input.sourcePath);
|
|
678
|
+
const isolatedSourcePath = await resolveIsolatedResourceModulePath(packageRoot, input.sourcePath);
|
|
679
|
+
const imported = await import(pathToFileURL(isolatedSourcePath).href);
|
|
680
|
+
const definition = loadToolModuleDefinition(imported, input.implementationName);
|
|
681
|
+
return {
|
|
682
|
+
hasModuleSchema: definition.hasModuleSchema,
|
|
683
|
+
};
|
|
684
|
+
}
|
|
649
685
|
async function loadModuleObjectsForRoot(root, mergedObjects) {
|
|
650
686
|
for (const { item, sourcePath } of await readModuleToolItems(root)) {
|
|
651
687
|
const workspaceObject = parseWorkspaceObject(item, sourcePath);
|
|
@@ -728,6 +764,7 @@ export async function readToolModuleItems(root) {
|
|
|
728
764
|
name: definition.implementationName,
|
|
729
765
|
description: definition.description,
|
|
730
766
|
implementationName: definition.implementationName,
|
|
767
|
+
hasModuleSchema: definition.hasModuleSchema,
|
|
731
768
|
...(definition.retryable !== undefined ? { retryable: definition.retryable } : {}),
|
|
732
769
|
...(definition.memory ? { config: { memory: definition.memory } } : {}),
|
|
733
770
|
},
|
|
@@ -269,6 +269,7 @@ export function parseToolObject(object) {
|
|
|
269
269
|
: undefined),
|
|
270
270
|
subprocess: value.subprocess === true,
|
|
271
271
|
inputSchemaRef: typeof asObject(value.inputSchema)?.ref === "string" ? String(asObject(value.inputSchema)?.ref) : undefined,
|
|
272
|
+
hasModuleSchema: value.hasModuleSchema === true,
|
|
272
273
|
embeddingModelRef: typeof value.embeddingModelRef === "string"
|
|
273
274
|
? value.embeddingModelRef
|
|
274
275
|
: typeof value.embeddingModel === "string"
|