@sweny-ai/core 0.1.79 → 0.1.80
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/executor.js +6 -1
- package/dist/schema.d.ts +5 -0
- package/dist/schema.js +1 -0
- package/dist/skills/github.js +17 -0
- package/dist/skills/index.d.ts +22 -1
- package/dist/skills/index.js +91 -0
- package/dist/skills/linear.js +20 -0
- package/dist/types.d.ts +19 -0
- package/dist/verify.d.ts +5 -4
- package/dist/verify.js +14 -55
- package/package.json +1 -1
package/dist/executor.js
CHANGED
|
@@ -17,6 +17,7 @@ import { resolveSources } from "./source-resolver.js";
|
|
|
17
17
|
import { evaluateVerify } from "./verify.js";
|
|
18
18
|
import { evaluateRequires } from "./requires.js";
|
|
19
19
|
import { buildRetryPreamble } from "./retry.js";
|
|
20
|
+
import { buildToolAliases } from "./skills/index.js";
|
|
20
21
|
/**
|
|
21
22
|
* Execute a workflow from entry to completion.
|
|
22
23
|
*
|
|
@@ -37,6 +38,10 @@ export async function execute(workflow, input, options) {
|
|
|
37
38
|
const nodeRunCounts = new Map(); // node → times executed
|
|
38
39
|
const trace = { steps: [], edges: [], sources: {} };
|
|
39
40
|
validate(workflow, skills);
|
|
41
|
+
// Build a verify-time alias table from the loaded skills. Each skill owns
|
|
42
|
+
// its own mapping between skill-tool names and equivalent MCP names. Core
|
|
43
|
+
// stays vendor-neutral — this call just unions what the skills declare.
|
|
44
|
+
const toolAliases = buildToolAliases(skills.values(), logger);
|
|
40
45
|
// ── Source resolution phase ─────────────────────────────────────
|
|
41
46
|
// Resolve all Source values (node instructions + rules/context at every
|
|
42
47
|
// level) into plain text before the main execution loop. This eagerly
|
|
@@ -159,7 +164,7 @@ export async function execute(workflow, input, options) {
|
|
|
159
164
|
// Retry only triggers on verify failure — bail on tool/API errors.
|
|
160
165
|
if (result.status !== "success")
|
|
161
166
|
break;
|
|
162
|
-
const verifyError = evaluateVerify(node.verify, result);
|
|
167
|
+
const verifyError = evaluateVerify(node.verify, result, toolAliases);
|
|
163
168
|
if (!verifyError)
|
|
164
169
|
break;
|
|
165
170
|
// Apply verify failure to the result.
|
package/dist/schema.d.ts
CHANGED
|
@@ -236,6 +236,7 @@ export declare const skillZ: z.ZodEffects<z.ZodObject<{
|
|
|
236
236
|
command?: string | undefined;
|
|
237
237
|
args?: string[] | undefined;
|
|
238
238
|
}>>;
|
|
239
|
+
mcpAliases: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>>;
|
|
239
240
|
}, "strip", z.ZodTypeAny, {
|
|
240
241
|
id: string;
|
|
241
242
|
name: string;
|
|
@@ -260,6 +261,7 @@ export declare const skillZ: z.ZodEffects<z.ZodObject<{
|
|
|
260
261
|
command?: string | undefined;
|
|
261
262
|
args?: string[] | undefined;
|
|
262
263
|
} | undefined;
|
|
264
|
+
mcpAliases?: Record<string, string[]> | undefined;
|
|
263
265
|
}, {
|
|
264
266
|
id: string;
|
|
265
267
|
name: string;
|
|
@@ -284,6 +286,7 @@ export declare const skillZ: z.ZodEffects<z.ZodObject<{
|
|
|
284
286
|
description: string;
|
|
285
287
|
input_schema: Record<string, unknown>;
|
|
286
288
|
}[] | undefined;
|
|
289
|
+
mcpAliases?: Record<string, string[]> | undefined;
|
|
287
290
|
}>, {
|
|
288
291
|
id: string;
|
|
289
292
|
name: string;
|
|
@@ -308,6 +311,7 @@ export declare const skillZ: z.ZodEffects<z.ZodObject<{
|
|
|
308
311
|
command?: string | undefined;
|
|
309
312
|
args?: string[] | undefined;
|
|
310
313
|
} | undefined;
|
|
314
|
+
mcpAliases?: Record<string, string[]> | undefined;
|
|
311
315
|
}, {
|
|
312
316
|
id: string;
|
|
313
317
|
name: string;
|
|
@@ -332,6 +336,7 @@ export declare const skillZ: z.ZodEffects<z.ZodObject<{
|
|
|
332
336
|
description: string;
|
|
333
337
|
input_schema: Record<string, unknown>;
|
|
334
338
|
}[] | undefined;
|
|
339
|
+
mcpAliases?: Record<string, string[]> | undefined;
|
|
335
340
|
}>;
|
|
336
341
|
/**
|
|
337
342
|
* NodeSources: either an array of Sources (additive — inherits cascade)
|
package/dist/schema.js
CHANGED
|
@@ -61,6 +61,7 @@ export const skillZ = z
|
|
|
61
61
|
tools: z.array(toolZ).default([]),
|
|
62
62
|
instruction: z.string().optional(),
|
|
63
63
|
mcp: mcpServerConfigZ.optional(),
|
|
64
|
+
mcpAliases: z.record(z.array(z.string().min(1)).min(1)).optional(),
|
|
64
65
|
})
|
|
65
66
|
.refine((s) => s.tools.length > 0 || s.instruction || s.mcp, {
|
|
66
67
|
message: "Skill must provide at least one of: tools, instruction, or mcp",
|
package/dist/skills/github.js
CHANGED
|
@@ -183,4 +183,21 @@ export const github = {
|
|
|
183
183
|
},
|
|
184
184
|
},
|
|
185
185
|
],
|
|
186
|
+
// Equivalent tool names on GitHub's official MCP server
|
|
187
|
+
// (github.com/github/github-mcp-server). Aliases declared for every
|
|
188
|
+
// GitHub MCP name that does NOT also exist on Linear's MCP. The
|
|
189
|
+
// executor's buildToolAliases already drops any name claimed by more
|
|
190
|
+
// than one loaded skill, so these declarations are safe even if a
|
|
191
|
+
// future provider starts using the same name — declare what this
|
|
192
|
+
// skill knows, let the runtime resolve conflicts.
|
|
193
|
+
//
|
|
194
|
+
// Names that currently exist on both Linear and GitHub MCPs and are
|
|
195
|
+
// therefore intentionally NOT aliased on either side: `get_issue`,
|
|
196
|
+
// `list_issues`.
|
|
197
|
+
mcpAliases: {
|
|
198
|
+
github_create_pr: ["create_pull_request"],
|
|
199
|
+
github_add_comment: ["add_issue_comment"],
|
|
200
|
+
github_create_issue: ["create_issue"],
|
|
201
|
+
github_search_issues: ["search_issues"],
|
|
202
|
+
},
|
|
186
203
|
};
|
package/dist/skills/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Custom skill discovery (filesystem-based) lives in `./custom-loader.js`,
|
|
8
8
|
* which is Node-only and re-exported from `@sweny-ai/core` (the Node entry).
|
|
9
9
|
*/
|
|
10
|
-
import type { Skill, SkillCategory } from "../types.js";
|
|
10
|
+
import type { Logger, Skill, SkillCategory } from "../types.js";
|
|
11
11
|
import { github } from "./github.js";
|
|
12
12
|
import { linear } from "./linear.js";
|
|
13
13
|
import { slack } from "./slack.js";
|
|
@@ -86,3 +86,24 @@ export declare function validateWorkflowSkills(workflow: {
|
|
|
86
86
|
skills: string[];
|
|
87
87
|
}>;
|
|
88
88
|
}, available: Map<string, Skill>, inlineSkills?: Record<string, InlineSkillDef>): SkillValidationResult;
|
|
89
|
+
/**
|
|
90
|
+
* Build a symmetric tool-name alias table from the loaded skills.
|
|
91
|
+
*
|
|
92
|
+
* Each skill declares its own `mcpAliases` (canonical name → list of
|
|
93
|
+
* equivalent MCP tool names). This function:
|
|
94
|
+
*
|
|
95
|
+
* 1. Collects every alias pair declared by every loaded skill.
|
|
96
|
+
* 2. Flattens each pair into one equivalence group (symmetric closure).
|
|
97
|
+
* 3. Drops any MCP name claimed by more than one skill (ambiguous).
|
|
98
|
+
*
|
|
99
|
+
* Core stays vendor-neutral: nothing here knows Linear or GitHub by name.
|
|
100
|
+
* Skills own their own naming, and ambiguity is detected at map-build
|
|
101
|
+
* time so a call to one provider's `get_issue` can never spuriously
|
|
102
|
+
* satisfy another provider's `any_tool_called` verify rule.
|
|
103
|
+
*
|
|
104
|
+
* @returns a map from every participating name to the full set of names
|
|
105
|
+
* that count as equivalent to it (including itself). Names that do not
|
|
106
|
+
* participate in any alias are absent — callers should fall back to
|
|
107
|
+
* name-equality when a lookup returns `undefined`.
|
|
108
|
+
*/
|
|
109
|
+
export declare function buildToolAliases(skills: Iterable<Skill>, logger?: Logger): ReadonlyMap<string, ReadonlySet<string>>;
|
package/dist/skills/index.js
CHANGED
|
@@ -144,3 +144,94 @@ export function validateWorkflowSkills(workflow, available, inlineSkills) {
|
|
|
144
144
|
}
|
|
145
145
|
return { configured, missing, errors, warnings };
|
|
146
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Build a symmetric tool-name alias table from the loaded skills.
|
|
149
|
+
*
|
|
150
|
+
* Each skill declares its own `mcpAliases` (canonical name → list of
|
|
151
|
+
* equivalent MCP tool names). This function:
|
|
152
|
+
*
|
|
153
|
+
* 1. Collects every alias pair declared by every loaded skill.
|
|
154
|
+
* 2. Flattens each pair into one equivalence group (symmetric closure).
|
|
155
|
+
* 3. Drops any MCP name claimed by more than one skill (ambiguous).
|
|
156
|
+
*
|
|
157
|
+
* Core stays vendor-neutral: nothing here knows Linear or GitHub by name.
|
|
158
|
+
* Skills own their own naming, and ambiguity is detected at map-build
|
|
159
|
+
* time so a call to one provider's `get_issue` can never spuriously
|
|
160
|
+
* satisfy another provider's `any_tool_called` verify rule.
|
|
161
|
+
*
|
|
162
|
+
* @returns a map from every participating name to the full set of names
|
|
163
|
+
* that count as equivalent to it (including itself). Names that do not
|
|
164
|
+
* participate in any alias are absent — callers should fall back to
|
|
165
|
+
* name-equality when a lookup returns `undefined`.
|
|
166
|
+
*/
|
|
167
|
+
export function buildToolAliases(skills, logger) {
|
|
168
|
+
// First pass: record which skill(s) claim each MCP alias name.
|
|
169
|
+
const mcpClaims = new Map(); // mcp name → skill ids that declared it
|
|
170
|
+
const pairs = []; // [canonical, mcpAlias]
|
|
171
|
+
for (const skill of skills) {
|
|
172
|
+
if (!skill.mcpAliases)
|
|
173
|
+
continue;
|
|
174
|
+
for (const [canonical, aliases] of Object.entries(skill.mcpAliases)) {
|
|
175
|
+
for (const alias of aliases) {
|
|
176
|
+
if (canonical === alias)
|
|
177
|
+
continue;
|
|
178
|
+
pairs.push([canonical, alias]);
|
|
179
|
+
const claimers = mcpClaims.get(alias);
|
|
180
|
+
if (claimers) {
|
|
181
|
+
if (!claimers.includes(skill.id))
|
|
182
|
+
claimers.push(skill.id);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
mcpClaims.set(alias, [skill.id]);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Drop ambiguous MCP names (claimed by >1 skill) and log once.
|
|
191
|
+
const ambiguous = new Set();
|
|
192
|
+
for (const [name, claimers] of mcpClaims) {
|
|
193
|
+
if (claimers.length > 1) {
|
|
194
|
+
ambiguous.add(name);
|
|
195
|
+
logger?.warn(`Tool alias "${name}" is declared by multiple skills (${claimers.join(", ")}); dropping from verify alias table to avoid cross-provider false positives.`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// Second pass: union-find over the remaining pairs.
|
|
199
|
+
const parent = new Map();
|
|
200
|
+
const find = (x) => {
|
|
201
|
+
let cur = parent.get(x) ?? x;
|
|
202
|
+
while (cur !== (parent.get(cur) ?? cur))
|
|
203
|
+
cur = parent.get(cur) ?? cur;
|
|
204
|
+
parent.set(x, cur);
|
|
205
|
+
return cur;
|
|
206
|
+
};
|
|
207
|
+
const union = (a, b) => {
|
|
208
|
+
const ra = find(a);
|
|
209
|
+
const rb = find(b);
|
|
210
|
+
if (ra !== rb)
|
|
211
|
+
parent.set(ra, rb);
|
|
212
|
+
};
|
|
213
|
+
// `find` registers previously-unseen nodes via `parent.get(x) ?? x` and
|
|
214
|
+
// writes them back, so `union` handles first-contact pairs on its own.
|
|
215
|
+
for (const [canonical, alias] of pairs) {
|
|
216
|
+
if (ambiguous.has(alias))
|
|
217
|
+
continue;
|
|
218
|
+
union(canonical, alias);
|
|
219
|
+
}
|
|
220
|
+
// Build the result: each name → its full equivalence set.
|
|
221
|
+
const groups = new Map();
|
|
222
|
+
for (const name of parent.keys()) {
|
|
223
|
+
const root = find(name);
|
|
224
|
+
let group = groups.get(root);
|
|
225
|
+
if (!group) {
|
|
226
|
+
group = new Set();
|
|
227
|
+
groups.set(root, group);
|
|
228
|
+
}
|
|
229
|
+
group.add(name);
|
|
230
|
+
}
|
|
231
|
+
const result = new Map();
|
|
232
|
+
for (const group of groups.values()) {
|
|
233
|
+
for (const name of group)
|
|
234
|
+
result.set(name, group);
|
|
235
|
+
}
|
|
236
|
+
return result;
|
|
237
|
+
}
|
package/dist/skills/linear.js
CHANGED
|
@@ -144,4 +144,24 @@ export const linear = {
|
|
|
144
144
|
},
|
|
145
145
|
},
|
|
146
146
|
],
|
|
147
|
+
// Equivalent tool names on Linear's official remote MCP server (mcp.linear.app).
|
|
148
|
+
//
|
|
149
|
+
// Linear's MCP uses upsert naming: a single `save_issue` handles both
|
|
150
|
+
// create and update. The executor builds symmetric equivalence groups, so
|
|
151
|
+
// both `linear_create_issue` and `linear_update_issue` end up in one group
|
|
152
|
+
// with `save_issue`. A `save_issue` call satisfies verify rules for either
|
|
153
|
+
// canonical name — verify cannot distinguish create from update when the
|
|
154
|
+
// agent uses the remote MCP. That reflects the provider's reality, not a
|
|
155
|
+
// shortcoming of the alias layer.
|
|
156
|
+
//
|
|
157
|
+
// Names that also exist on GitHub's MCP server (`get_issue`, `list_issues`,
|
|
158
|
+
// `get_team`) are left out. `buildToolAliases` also drops any MCP name
|
|
159
|
+
// claimed by more than one loaded skill as a defensive backstop.
|
|
160
|
+
mcpAliases: {
|
|
161
|
+
linear_create_issue: ["save_issue"],
|
|
162
|
+
linear_update_issue: ["save_issue"],
|
|
163
|
+
linear_search_issues: ["list_issues"],
|
|
164
|
+
linear_add_comment: ["save_comment"],
|
|
165
|
+
linear_list_teams: ["list_teams"],
|
|
166
|
+
},
|
|
147
167
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -36,6 +36,25 @@ export interface Skill {
|
|
|
36
36
|
instruction?: string;
|
|
37
37
|
/** External MCP server definition wired for nodes referencing this skill. */
|
|
38
38
|
mcp?: McpServerConfig;
|
|
39
|
+
/**
|
|
40
|
+
* Tool-name aliases recognized by `verify`.
|
|
41
|
+
*
|
|
42
|
+
* When a workflow references `any_tool_called: [linear_create_issue]` and
|
|
43
|
+
* the agent instead calls the equivalent MCP tool exposed by this skill's
|
|
44
|
+
* MCP server (e.g. `save_issue` on Linear's remote MCP), the two names
|
|
45
|
+
* should count as equivalent. Each skill owns the mapping for its own
|
|
46
|
+
* domain — core stays vendor-neutral.
|
|
47
|
+
*
|
|
48
|
+
* Key: a canonical tool name (usually one of this skill's `tools[].name`,
|
|
49
|
+
* but any name the skill wants to equate is valid).
|
|
50
|
+
* Value: list of equivalent names, typically tool names exposed by this
|
|
51
|
+
* skill's external MCP server.
|
|
52
|
+
*
|
|
53
|
+
* Aliases are symmetric: a verify rule naming either side matches a call
|
|
54
|
+
* on either side. Omit names that are ambiguous across providers
|
|
55
|
+
* (e.g. `get_issue` is exposed by both Linear and GitHub MCP servers).
|
|
56
|
+
*/
|
|
57
|
+
mcpAliases?: Record<string, string[]>;
|
|
39
58
|
}
|
|
40
59
|
/**
|
|
41
60
|
* Per-node rules or context.
|
package/dist/verify.d.ts
CHANGED
|
@@ -9,9 +9,10 @@ export type Resolution = {
|
|
|
9
9
|
};
|
|
10
10
|
export declare function resolvePath(data: unknown, path: string): Resolution;
|
|
11
11
|
export declare function isErrorOutput(output: unknown): boolean;
|
|
12
|
-
export
|
|
13
|
-
export declare function
|
|
14
|
-
export declare function
|
|
12
|
+
export type ToolAliases = ReadonlyMap<string, ReadonlySet<string>>;
|
|
13
|
+
export declare function checkAnyToolCalled(required: string[], toolCalls: ToolCall[], aliases?: ToolAliases): string | null;
|
|
14
|
+
export declare function checkAllToolsCalled(required: string[], toolCalls: ToolCall[], aliases?: ToolAliases): string | null;
|
|
15
|
+
export declare function checkNoToolCalled(forbidden: string[], toolCalls: ToolCall[], aliases?: ToolAliases): string | null;
|
|
15
16
|
export declare function checkOutputRequired(paths: string[], data: unknown): string | null;
|
|
16
17
|
export declare function checkOutputMatches(matches: OutputMatch[], data: unknown): string | null;
|
|
17
18
|
/**
|
|
@@ -21,4 +22,4 @@ export declare function checkOutputMatches(matches: OutputMatch[], data: unknown
|
|
|
21
22
|
* Deterministic and side-effect free — the executor calls this synchronously
|
|
22
23
|
* after the LLM finishes.
|
|
23
24
|
*/
|
|
24
|
-
export declare function evaluateVerify(verify: NodeVerify | undefined, result: NodeResult): string | null;
|
|
25
|
+
export declare function evaluateVerify(verify: NodeVerify | undefined, result: NodeResult, aliases?: ToolAliases): string | null;
|
package/dist/verify.js
CHANGED
|
@@ -105,73 +105,32 @@ function succeededTools(toolCalls) {
|
|
|
105
105
|
function calledList(toolCalls) {
|
|
106
106
|
return toolCalls.map((c) => c.tool).join(", ") || "none";
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// When an external MCP server is wired for the same provider a skill covers
|
|
111
|
-
// (e.g. the Linear HTTP MCP server alongside the `linear` skill), both sets of
|
|
112
|
-
// tools are presented to the agent and the agent may pick either. The calls
|
|
113
|
-
// are functionally equivalent — same backend, same effect — but the names
|
|
114
|
-
// differ, so a verify rule that lists one will fail when the agent picked the
|
|
115
|
-
// other. These aliases let either call satisfy the rule.
|
|
116
|
-
//
|
|
117
|
-
// Only unambiguous MCP tool names are aliased. Names that collide across
|
|
118
|
-
// providers (e.g. `get_issue` exists on both Linear and GitHub MCP servers)
|
|
119
|
-
// are deliberately omitted so a call to one provider cannot spuriously
|
|
120
|
-
// satisfy a rule about the other.
|
|
121
|
-
const TOOL_ALIAS_GROUPS = [
|
|
122
|
-
// Linear (official remote MCP at mcp.linear.app — upsert naming)
|
|
123
|
-
["linear_search_issues", "list_issues"],
|
|
124
|
-
["linear_create_issue", "save_issue"],
|
|
125
|
-
["linear_update_issue", "save_issue"],
|
|
126
|
-
["linear_add_comment", "save_comment"],
|
|
127
|
-
["linear_list_teams", "list_teams"],
|
|
128
|
-
// GitHub (github.com/github/github-mcp-server)
|
|
129
|
-
["github_create_issue", "create_issue"],
|
|
130
|
-
["github_search_issues", "search_issues"],
|
|
131
|
-
["github_add_comment", "add_issue_comment"],
|
|
132
|
-
["github_create_pr", "create_pull_request"],
|
|
133
|
-
];
|
|
134
|
-
const TOOL_ALIASES = (() => {
|
|
135
|
-
const map = new Map();
|
|
136
|
-
for (const group of TOOL_ALIAS_GROUPS) {
|
|
137
|
-
for (const name of group) {
|
|
138
|
-
let set = map.get(name);
|
|
139
|
-
if (!set) {
|
|
140
|
-
set = new Set();
|
|
141
|
-
map.set(name, set);
|
|
142
|
-
}
|
|
143
|
-
for (const other of group)
|
|
144
|
-
set.add(other);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return map;
|
|
148
|
-
})();
|
|
149
|
-
function expandAliases(name) {
|
|
150
|
-
return TOOL_ALIASES.get(name) ?? new Set([name]);
|
|
108
|
+
function expandAliases(name, aliases) {
|
|
109
|
+
return aliases?.get(name) ?? new Set([name]);
|
|
151
110
|
}
|
|
152
|
-
function anyAliasIn(name, set) {
|
|
153
|
-
for (const alias of expandAliases(name)) {
|
|
111
|
+
function anyAliasIn(name, set, aliases) {
|
|
112
|
+
for (const alias of expandAliases(name, aliases)) {
|
|
154
113
|
if (set.has(alias))
|
|
155
114
|
return true;
|
|
156
115
|
}
|
|
157
116
|
return false;
|
|
158
117
|
}
|
|
159
|
-
export function checkAnyToolCalled(required, toolCalls) {
|
|
118
|
+
export function checkAnyToolCalled(required, toolCalls, aliases) {
|
|
160
119
|
const succeeded = succeededTools(toolCalls);
|
|
161
|
-
if (required.some((t) => anyAliasIn(t, succeeded)))
|
|
120
|
+
if (required.some((t) => anyAliasIn(t, succeeded, aliases)))
|
|
162
121
|
return null;
|
|
163
122
|
return `any_tool_called: required one of [${required.join(", ")}] to succeed, called: [${calledList(toolCalls)}]`;
|
|
164
123
|
}
|
|
165
|
-
export function checkAllToolsCalled(required, toolCalls) {
|
|
124
|
+
export function checkAllToolsCalled(required, toolCalls, aliases) {
|
|
166
125
|
const succeeded = succeededTools(toolCalls);
|
|
167
|
-
const missing = required.filter((t) => !anyAliasIn(t, succeeded));
|
|
126
|
+
const missing = required.filter((t) => !anyAliasIn(t, succeeded, aliases));
|
|
168
127
|
if (missing.length === 0)
|
|
169
128
|
return null;
|
|
170
129
|
return `all_tools_called: missing successful calls to [${missing.join(", ")}], called: [${calledList(toolCalls)}]`;
|
|
171
130
|
}
|
|
172
|
-
export function checkNoToolCalled(forbidden, toolCalls) {
|
|
131
|
+
export function checkNoToolCalled(forbidden, toolCalls, aliases) {
|
|
173
132
|
const calledNames = new Set(toolCalls.map((c) => c.tool));
|
|
174
|
-
const violated = forbidden.filter((t) => anyAliasIn(t, calledNames));
|
|
133
|
+
const violated = forbidden.filter((t) => anyAliasIn(t, calledNames, aliases));
|
|
175
134
|
if (violated.length === 0)
|
|
176
135
|
return null;
|
|
177
136
|
return `no_tool_called: forbidden tools were invoked: [${violated.join(", ")}], called: [${calledList(toolCalls)}]`;
|
|
@@ -363,22 +322,22 @@ function describeOperator(c) {
|
|
|
363
322
|
* Deterministic and side-effect free — the executor calls this synchronously
|
|
364
323
|
* after the LLM finishes.
|
|
365
324
|
*/
|
|
366
|
-
export function evaluateVerify(verify, result) {
|
|
325
|
+
export function evaluateVerify(verify, result, aliases) {
|
|
367
326
|
if (!verify)
|
|
368
327
|
return null;
|
|
369
328
|
const failures = [];
|
|
370
329
|
if (verify.any_tool_called && verify.any_tool_called.length > 0) {
|
|
371
|
-
const e = checkAnyToolCalled(verify.any_tool_called, result.toolCalls);
|
|
330
|
+
const e = checkAnyToolCalled(verify.any_tool_called, result.toolCalls, aliases);
|
|
372
331
|
if (e)
|
|
373
332
|
failures.push(e);
|
|
374
333
|
}
|
|
375
334
|
if (verify.all_tools_called && verify.all_tools_called.length > 0) {
|
|
376
|
-
const e = checkAllToolsCalled(verify.all_tools_called, result.toolCalls);
|
|
335
|
+
const e = checkAllToolsCalled(verify.all_tools_called, result.toolCalls, aliases);
|
|
377
336
|
if (e)
|
|
378
337
|
failures.push(e);
|
|
379
338
|
}
|
|
380
339
|
if (verify.no_tool_called && verify.no_tool_called.length > 0) {
|
|
381
|
-
const e = checkNoToolCalled(verify.no_tool_called, result.toolCalls);
|
|
340
|
+
const e = checkNoToolCalled(verify.no_tool_called, result.toolCalls, aliases);
|
|
382
341
|
if (e)
|
|
383
342
|
failures.push(e);
|
|
384
343
|
}
|