@modelprofile.com/flexharness 10.12.0 → 10.13.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.
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Renders JSON Schema as TypeScript declarations for the tool catalog. The output depends only on
3
+ * the schema, so the same schema always renders to the same bytes.
4
+ */
5
+ const identifierPattern = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
6
+ const maxRenderDepth = 32;
7
+ const maxInlineObjectCharacters = 100;
8
+ const maxSafeInteger = Number.MAX_SAFE_INTEGER;
9
+ export const isSchemaRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
10
+ export const isIdentifier = (value) => identifierPattern.test(value);
11
+ const literal = (value) => {
12
+ if (typeof value === 'string')
13
+ return JSON.stringify(value);
14
+ if (typeof value === 'number' && Number.isFinite(value))
15
+ return String(value);
16
+ if (typeof value === 'boolean' || value === null)
17
+ return String(value);
18
+ return 'unknown';
19
+ };
20
+ /**
21
+ * Reports whether `character` occurs outside brackets, braces, parentheses, string literals and
22
+ * comments.
23
+ */
24
+ const hasTopLevel = (text, character) => {
25
+ let depth = 0;
26
+ let quote;
27
+ for (let index = 0; index < text.length; index++) {
28
+ const current = text[index];
29
+ if (quote) {
30
+ if (current === '\\')
31
+ index++;
32
+ else if (current === quote)
33
+ quote = undefined;
34
+ continue;
35
+ }
36
+ if (current === '/' && text[index + 1] === '*') {
37
+ const end = text.indexOf('*/', index + 2);
38
+ if (end === -1)
39
+ return false;
40
+ index = end + 1;
41
+ continue;
42
+ }
43
+ if (current === '"' || current === "'")
44
+ quote = current;
45
+ else if (current === '{' || current === '[' || current === '(' || current === '<')
46
+ depth++;
47
+ else if (current === '}' || current === ']' || current === ')' || current === '>')
48
+ depth--;
49
+ else if (depth === 0 && current === character)
50
+ return true;
51
+ }
52
+ return false;
53
+ };
54
+ const union = (parts) => {
55
+ const unique = [...new Set(parts)];
56
+ if (unique.includes('unknown'))
57
+ return 'unknown';
58
+ const withoutNever = unique.length > 1 ? unique.filter((part) => part !== 'never') : unique;
59
+ return withoutNever.join(' | ');
60
+ };
61
+ const intersection = (parts) => {
62
+ const unique = [...new Set(parts)].filter((part) => part !== 'unknown');
63
+ if (unique.length === 0)
64
+ return 'unknown';
65
+ return unique.map((part) => hasTopLevel(part, '|') ? `(${part})` : part).join(' & ');
66
+ };
67
+ const arrayOf = (element) => hasTopLevel(element, '|') || hasTopLevel(element, '&') ? `(${element})[]` : `${element}[]`;
68
+ const propertyKey = (name) => isIdentifier(name) ? name : JSON.stringify(name);
69
+ /** A JSDoc block at `indent`; a short single line stays on one line. */
70
+ export const docBlock = (text, indent) => {
71
+ const lines = text.replace(/\*\//g, '*\\/').split('\n').map((line) => line.trimEnd());
72
+ if (lines.length === 1 && indent.length + lines[0].length <= 100)
73
+ return `${indent}/** ${lines[0]} */\n`;
74
+ return `${indent}/**\n${lines.map((line) => line ? `${indent} * ${line}` : `${indent} *`).join('\n')}\n${indent} */\n`;
75
+ };
76
+ export const countOf = (count, unit) => `${count} ${unit}${count === 1 ? '' : 's'}`;
77
+ /** Constraints a TypeScript type cannot state, in a short readable form. */
78
+ const constraintsOf = (schema) => {
79
+ const constraints = [];
80
+ const types = Array.isArray(schema.type) ? schema.type : [schema.type];
81
+ if (types.includes('integer'))
82
+ constraints.push('integer');
83
+ if (typeof schema.format === 'string')
84
+ constraints.push(`format ${schema.format}`);
85
+ const bound = (value) => typeof value === 'number' && Number.isFinite(value) && Math.abs(value) !== maxSafeInteger;
86
+ if (bound(schema.exclusiveMinimum))
87
+ constraints.push(`> ${schema.exclusiveMinimum}`);
88
+ else if (bound(schema.minimum))
89
+ constraints.push(`${schema.exclusiveMinimum === true ? '>' : '>='} ${schema.minimum}`);
90
+ if (bound(schema.exclusiveMaximum))
91
+ constraints.push(`< ${schema.exclusiveMaximum}`);
92
+ else if (bound(schema.maximum))
93
+ constraints.push(`${schema.exclusiveMaximum === true ? '<' : '<='} ${schema.maximum}`);
94
+ if (bound(schema.multipleOf))
95
+ constraints.push(`multiple of ${schema.multipleOf}`);
96
+ const range = (min, max, unit) => {
97
+ const hasMin = bound(min) && min > 0;
98
+ const hasMax = bound(max);
99
+ if (hasMin && hasMax)
100
+ constraints.push(min === max ? countOf(min, unit) : `${min}-${countOf(max, unit)}`);
101
+ else if (hasMin)
102
+ constraints.push(`at least ${countOf(min, unit)}`);
103
+ else if (hasMax)
104
+ constraints.push(`at most ${countOf(max, unit)}`);
105
+ };
106
+ range(schema.minLength, schema.maxLength, 'character');
107
+ range(schema.minItems, schema.maxItems, 'item');
108
+ if (schema.uniqueItems === true)
109
+ constraints.push('unique items');
110
+ if (typeof schema.pattern === 'string')
111
+ constraints.push(`pattern /${schema.pattern}/`);
112
+ if (schema.default !== undefined) {
113
+ const value = JSON.stringify(schema.default);
114
+ if (value !== undefined && value.length <= 60)
115
+ constraints.push(`default ${value}`);
116
+ }
117
+ if (schema.deprecated === true)
118
+ constraints.push('deprecated');
119
+ return constraints;
120
+ };
121
+ /** The documentation of a property: its description and the constraints its type cannot state. */
122
+ export const schemaDoc = (schema, description) => {
123
+ if (!isSchemaRecord(schema))
124
+ return description?.trim() || undefined;
125
+ const text = (description ?? (typeof schema.description === 'string' ? schema.description : '')).trim();
126
+ const constraints = constraintsOf(schema);
127
+ if (constraints.length === 0)
128
+ return text || undefined;
129
+ return text ? `${text} (${constraints.join(', ')})` : constraints.join(', ');
130
+ };
131
+ export class SchemaDeclarationWriter {
132
+ context;
133
+ used = new Set();
134
+ inlining = new Set();
135
+ constructor(context) {
136
+ this.context = context;
137
+ }
138
+ get usedTypes() {
139
+ return [...this.used].sort();
140
+ }
141
+ /** The TypeScript type of `schema`, with continuation lines indented relative to `indent`. */
142
+ type(schema, indent = '', depth = 0, omitMemberDocs = false) {
143
+ if (depth > maxRenderDepth)
144
+ return 'unknown';
145
+ if (schema === true)
146
+ return 'unknown';
147
+ if (schema === false)
148
+ return 'never';
149
+ if (!isSchemaRecord(schema))
150
+ return 'unknown';
151
+ const base = this.baseType(schema, indent, depth, omitMemberDocs);
152
+ return schema.nullable === true ? union([base, 'null']) : base;
153
+ }
154
+ /** The members of an object schema; undefined when the schema is not a plain object type. */
155
+ objectMembers(schema) {
156
+ if (!isSchemaRecord(schema) || !this.isPlainObject(schema))
157
+ return undefined;
158
+ const properties = isSchemaRecord(schema.properties) ? schema.properties : {};
159
+ return Object.entries(properties).map(([name, property]) => {
160
+ const doc = schemaDoc(property);
161
+ return { name, ...(doc === undefined ? {} : { doc }) };
162
+ });
163
+ }
164
+ /** Whether an object schema requires none of its properties. */
165
+ hasNoRequiredProperties(schema) {
166
+ return isSchemaRecord(schema)
167
+ && this.isPlainObject(schema)
168
+ && !(Array.isArray(schema.required) && schema.required.length > 0);
169
+ }
170
+ /** `interface Name { … }` for a plain object schema, otherwise `type Name = …;`. */
171
+ namedDeclaration(name, schema, description) {
172
+ const doc = isSchemaRecord(schema)
173
+ ? (description ?? (typeof schema.description === 'string' ? schema.description : undefined))?.trim()
174
+ : description?.trim();
175
+ const prefix = doc ? docBlock(doc, '') : '';
176
+ if (isSchemaRecord(schema) && this.isPlainObject(schema) && schema.nullable !== true) {
177
+ return `${prefix}interface ${name} ${this.objectType(schema, '', 0, false)}`;
178
+ }
179
+ return `${prefix}type ${name} = ${this.type(schema, '', 0)};`;
180
+ }
181
+ isPlainObject(schema) {
182
+ if (schema.$ref !== undefined || 'const' in schema || schema.enum !== undefined)
183
+ return false;
184
+ if (schema.anyOf !== undefined || schema.oneOf !== undefined || schema.allOf !== undefined)
185
+ return false;
186
+ if (schema.type === 'object')
187
+ return true;
188
+ return schema.type === undefined && isSchemaRecord(schema.properties);
189
+ }
190
+ baseType(schema, indent, depth, omitMemberDocs) {
191
+ if (typeof schema.$ref === 'string')
192
+ return this.reference(schema.$ref, indent, depth);
193
+ if ('const' in schema)
194
+ return literal(schema.const);
195
+ if (Array.isArray(schema.enum))
196
+ return schema.enum.length ? union(schema.enum.map(literal)) : 'never';
197
+ const alternatives = Array.isArray(schema.anyOf) ? schema.anyOf : Array.isArray(schema.oneOf) ? schema.oneOf : undefined;
198
+ if (alternatives?.length) {
199
+ return union(alternatives.map((alternative) => this.type(alternative, indent, depth + 1)));
200
+ }
201
+ if (Array.isArray(schema.allOf) && schema.allOf.length) {
202
+ const own = { ...schema };
203
+ delete own.allOf;
204
+ const hasOwnShape = own.type !== undefined || own.properties !== undefined;
205
+ return intersection([
206
+ ...schema.allOf.map((part) => this.type(part, indent, depth + 1)),
207
+ ...(hasOwnShape ? [this.type(own, indent, depth + 1)] : []),
208
+ ]);
209
+ }
210
+ const types = Array.isArray(schema.type)
211
+ ? schema.type.filter((type) => typeof type === 'string')
212
+ : typeof schema.type === 'string'
213
+ ? [schema.type]
214
+ : this.inferredTypes(schema);
215
+ if (types.length === 0)
216
+ return 'unknown';
217
+ return union(types.map((type) => {
218
+ switch (type) {
219
+ case 'string': return 'string';
220
+ case 'number':
221
+ case 'integer': return 'number';
222
+ case 'boolean': return 'boolean';
223
+ case 'null': return 'null';
224
+ case 'array': return this.arrayType(schema, indent, depth);
225
+ case 'object': return this.objectType(schema, indent, depth, omitMemberDocs);
226
+ default: return 'unknown';
227
+ }
228
+ }));
229
+ }
230
+ inferredTypes(schema) {
231
+ if (schema.properties !== undefined
232
+ || schema.additionalProperties !== undefined
233
+ || schema.patternProperties !== undefined
234
+ || schema.required !== undefined)
235
+ return ['object'];
236
+ if (schema.items !== undefined || schema.prefixItems !== undefined)
237
+ return ['array'];
238
+ return [];
239
+ }
240
+ reference(ref, indent, depth) {
241
+ const name = this.context.namedType(ref);
242
+ if (name) {
243
+ this.used.add(name);
244
+ return name;
245
+ }
246
+ const target = this.context.resolve(ref);
247
+ if (target === undefined || this.inlining.has(ref))
248
+ return 'unknown';
249
+ this.inlining.add(ref);
250
+ try {
251
+ return this.type(target, indent, depth + 1);
252
+ }
253
+ finally {
254
+ this.inlining.delete(ref);
255
+ }
256
+ }
257
+ arrayType(schema, indent, depth) {
258
+ const tuple = Array.isArray(schema.prefixItems)
259
+ ? schema.prefixItems
260
+ : Array.isArray(schema.items) ? schema.items : undefined;
261
+ if (tuple) {
262
+ const rest = Array.isArray(schema.prefixItems) ? schema.items : schema.additionalItems;
263
+ const members = tuple.map((item) => this.type(item, indent, depth + 1));
264
+ if (rest !== undefined && rest !== false) {
265
+ members.push(`...${arrayOf(this.type(rest, indent, depth + 1))}`);
266
+ }
267
+ return `[${members.join(', ')}]`;
268
+ }
269
+ if (schema.items === undefined)
270
+ return 'unknown[]';
271
+ return arrayOf(this.type(schema.items, indent, depth + 1));
272
+ }
273
+ objectType(schema, indent, depth, omitMemberDocs) {
274
+ const memberIndent = `${indent} `;
275
+ const properties = isSchemaRecord(schema.properties) ? schema.properties : {};
276
+ const required = new Set(Array.isArray(schema.required)
277
+ ? schema.required.filter((name) => typeof name === 'string')
278
+ : []);
279
+ const members = [];
280
+ for (const [name, property] of Object.entries(properties)) {
281
+ const type = this.type(property, memberIndent, depth + 1);
282
+ const doc = omitMemberDocs ? undefined : schemaDoc(property);
283
+ members.push({
284
+ ...(doc === undefined ? {} : { doc }),
285
+ text: `${propertyKey(name)}${required.has(name) ? '' : '?'}: ${type}`,
286
+ });
287
+ }
288
+ const indexTypes = [];
289
+ if (isSchemaRecord(schema.patternProperties)) {
290
+ for (const property of Object.values(schema.patternProperties)) {
291
+ indexTypes.push(this.type(property, memberIndent, depth + 1));
292
+ }
293
+ }
294
+ if (isSchemaRecord(schema.additionalProperties)) {
295
+ indexTypes.push(this.type(schema.additionalProperties, memberIndent, depth + 1));
296
+ }
297
+ else if (schema.additionalProperties === true && members.length > 0) {
298
+ indexTypes.push('unknown');
299
+ }
300
+ if (indexTypes.length)
301
+ members.push({ text: `[key: string]: ${union(indexTypes)}` });
302
+ if (members.length === 0)
303
+ return schema.additionalProperties === false ? '{}' : 'Record<string, unknown>';
304
+ if (members.every((member) => member.doc === undefined && !member.text.includes('\n'))) {
305
+ const inline = `{ ${members.map((member) => member.text).join('; ')} }`;
306
+ if (inline.length <= maxInlineObjectCharacters)
307
+ return inline;
308
+ }
309
+ const lines = members.map((member) => `${member.doc === undefined ? '' : docBlock(member.doc, memberIndent)}${memberIndent}${member.text};`);
310
+ return `{\n${lines.join('\n')}\n${indent}}`;
311
+ }
312
+ }
313
+ /** Indents every non-empty line of `text`. */
314
+ export const indentLines = (text, indent) => text.split('\n').map((line) => line ? `${indent}${line}` : line).join('\n');
315
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuc2NoZW1hZGVjbGFyYXRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdXRpbHMuc2NoZW1hZGVjbGFyYXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQWlCSCxNQUFNLGlCQUFpQixHQUFHLDRCQUE0QixDQUFDO0FBQ3ZELE1BQU0sY0FBYyxHQUFHLEVBQUUsQ0FBQztBQUMxQixNQUFNLHlCQUF5QixHQUFHLEdBQUcsQ0FBQztBQUN0QyxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7QUFFL0MsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsS0FBYyxFQUF1QyxFQUFFLENBQ3BGLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV2RSxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsQ0FBQyxLQUFhLEVBQVcsRUFBRSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUV0RixNQUFNLE9BQU8sR0FBRyxDQUFDLEtBQWMsRUFBVSxFQUFFO0lBQ3pDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtRQUFFLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM1RCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlFLElBQUksT0FBTyxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssS0FBSyxJQUFJO1FBQUUsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkUsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyxDQUFDO0FBRUY7OztHQUdHO0FBQ0gsTUFBTSxXQUFXLEdBQUcs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
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Task Venture Capital GmbH",
3
3
  "license": "MIT",
4
4
  "name": "@modelprofile.com/flexharness",
5
- "version": "10.12.0",
5
+ "version": "10.13.0",
6
6
  "type": "module",
7
7
  "description": "Managed agent sessions with tools, MCP, chat, OCR, documents and browser control through focused subpath imports.",
8
8
  "main": "./dist_ts/index.js",
@@ -74,8 +74,9 @@
74
74
  }
75
75
  },
76
76
  "dependencies": {
77
- "@modelprofile.com/flexharness-agent": "10.12.0",
78
- "@modelprofile.com/flexharness-models": "10.12.0",
77
+ "@cfworker/json-schema": "^4.1.1",
78
+ "@modelprofile.com/flexharness-agent": "10.13.0",
79
+ "@modelprofile.com/flexharness-models": "10.13.0",
79
80
  "@push.rocks/smartrequest": "^5.5.1",
80
81
  "ai": "^7.0.111",
81
82
  "zod": "^4.6.5"
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@modelprofile.com/flexharness',
6
- version: '10.12.0',
6
+ version: '10.13.0',
7
7
  description: 'The FlexHarness toolbox source repository and shared dependency catalog.'
8
8
  }
@@ -29,7 +29,13 @@ import {
29
29
  FLEX_REVERSION_WORKSPACE_ID_MAX_BYTES,
30
30
  FLEX_REVERSION_WORKSPACE_LABEL_MAX_BYTES,
31
31
  FLEX_SESSION_IMPORT_MAX_DEPTH,
32
+ FLEX_TOOL_CATALOG_TOOL_NAMES,
32
33
  } from './interfaces.js';
34
+ import {
35
+ FlexToolCatalog,
36
+ assertNoCatalogCollisions,
37
+ catalogToolInputSchema,
38
+ } from './classes.toolcatalog.js';
33
39
  import type {
34
40
  IFlexAgentContextCompactionOptions,
35
41
  IFlexAgentContextInvocation,
@@ -112,6 +118,9 @@ import type {
112
118
  IFlexSubagentDefinition,
113
119
  IFlexSubagentProvenance,
114
120
  IFlexTerminalProjection,
121
+ IFlexCatalogDescribeInput,
122
+ IFlexCatalogSearchInput,
123
+ IFlexToolCatalogOptions,
115
124
  IFlexToolHandle,
116
125
  IFlexToolMessagePart,
117
126
  IFlexToolProviderContext,
@@ -168,6 +177,7 @@ import {
168
177
  normalizeAgentSessionPolicy,
169
178
  normalizeBuiltInTools,
170
179
  normalizeSlashCommands,
180
+ normalizeToolCatalogOptions,
171
181
  normalizeSubagents,
172
182
  requireHarnessStores,
173
183
  resolveBoundedPositiveInteger,
@@ -431,6 +441,10 @@ interface IActiveRun {
431
441
  reservedUserMessage?: IFlexMessage;
432
442
  reservedAssistantMessage?: IFlexMessage;
433
443
  modelResolution?: IFlexResolvedModel;
444
+ /** The tool-provider context of the run, passed to catalog methods. */
445
+ toolProviderContext?: Readonly<IFlexToolProviderContext<unknown>>;
446
+ /** The catalog methods the run offers through search_tools, describe_tools and execute. */
447
+ toolCatalog?: FlexToolCatalog<unknown>;
434
448
  subagents: ReadonlyMap<string, Readonly<IFlexSubagentDefinition>>;
435
449
  allowedTools?: readonly string[];
436
450
  agentAllowedTools?: readonly string[];
@@ -851,6 +865,7 @@ export class FlexHarness<TScope = unknown> {
851
865
  private readonly externalErrorProjector?: TFlexExternalErrorProjector;
852
866
  private readonly subagents: ReadonlyMap<string, Readonly<IFlexSubagentDefinition>>;
853
867
  private readonly builtInTools: INormalizedBuiltInTools;
868
+ private readonly toolCatalogOptions: Readonly<Required<IFlexToolCatalogOptions>>;
854
869
  private readonly slashCommands: ReadonlyMap<string, TRegisteredSlashCommand<TScope>>;
855
870
  private readonly maxSubagentDepth: number;
856
871
  private readonly maxSubagentCallsPerRun: number;
@@ -937,6 +952,7 @@ export class FlexHarness<TScope = unknown> {
937
952
  this.externalErrorProjector = options.externalErrorProjector;
938
953
  this.subagents = normalizeSubagents(options.subagents);
939
954
  this.builtInTools = normalizeBuiltInTools(options.builtInTools);
955
+ this.toolCatalogOptions = normalizeToolCatalogOptions(options.toolCatalog);
940
956
  this.slashCommands = normalizeSlashCommands(options.slashCommands);
941
957
  this.maxSubagentDepth = resolveBoundedPositiveInteger(
942
958
  options.maxSubagentDepth,
@@ -5823,18 +5839,37 @@ export class FlexHarness<TScope = unknown> {
5823
5839
  }
5824
5840
  signal.throwIfAborted();
5825
5841
  run.modelResolution = model!;
5842
+ run.toolProviderContext = toolProviderContext as Readonly<IFlexToolProviderContext<unknown>>;
5843
+ let catalog: FlexToolCatalog<unknown> | undefined;
5844
+ if (toolHandle?.catalog) {
5845
+ try {
5846
+ catalog = await FlexToolCatalog.create(toolHandle.catalog, this.toolCatalogOptions);
5847
+ } catch (error) {
5848
+ throw this.projectExternalError(run, error, 'toolProvider');
5849
+ }
5850
+ signal.throwIfAborted();
5851
+ }
5826
5852
  let tools: TFlexAgentToolSet | undefined;
5827
5853
  try {
5828
5854
  const providedTools = toolHandle?.tools;
5829
5855
  const combinedTools: Record<string, unknown> = { ...(providedTools ?? {}) };
5830
5856
  Object.assign(combinedTools, this.createBuiltInTools(run));
5857
+ if (catalog) assertNoCatalogCollisions(catalog, combinedTools);
5831
5858
  const globalNames = run.allowedTools === undefined ? undefined : new Set(run.allowedTools);
5832
5859
  const agentNames = run.agentAllowedTools === undefined ? undefined : new Set(run.agentAllowedTools);
5860
+ const admitted = (name: string): boolean =>
5861
+ (globalNames === undefined || globalNames.has(name))
5862
+ && (agentNames === undefined || agentNames.has(name));
5833
5863
  const admittedTools = globalNames === undefined && agentNames === undefined
5834
5864
  ? combinedTools
5835
- : Object.fromEntries(Object.entries(combinedTools).filter(([name]) =>
5836
- (globalNames === undefined || globalNames.has(name))
5837
- && (agentNames === undefined || agentNames.has(name))));
5865
+ : Object.fromEntries(Object.entries(combinedTools).filter(([name]) => admitted(name)));
5866
+ const admittedCatalog = catalog && (globalNames === undefined && agentNames === undefined
5867
+ ? catalog
5868
+ : catalog.restrict(catalog.methods.filter(admitted)));
5869
+ if (admittedCatalog && admittedCatalog.methods.length > 0) {
5870
+ run.toolCatalog = admittedCatalog;
5871
+ Object.assign(admittedTools, this.createCatalogTools(run, admittedCatalog));
5872
+ }
5838
5873
  tools = Object.keys(admittedTools).length > 0
5839
5874
  ? wrapToolSet(
5840
5875
  admittedTools as TFlexAgentToolSet,
@@ -5913,6 +5948,59 @@ export class FlexHarness<TScope = unknown> {
5913
5948
  }
5914
5949
  }
5915
5950
 
5951
+ /**
5952
+ * search_tools, describe_tools and execute. `execute` validates the call and runs the method
5953
+ * inside this tool call, so the tool wrapper bounds its output and projects its errors, and the
5954
+ * call's part, events and permission requests carry the method's path.
5955
+ */
5956
+ private createCatalogTools(run: IActiveRun, catalog: FlexToolCatalog<unknown>): Record<string, unknown> {
5957
+ const names = FLEX_TOOL_CATALOG_TOOL_NAMES;
5958
+ const definitions = catalog.toolDefinitions();
5959
+ const describeBytes = Math.max(1024, this.toolOutputLimits.maxBytes - 1024);
5960
+ return {
5961
+ [names.search]: plugins.tool({
5962
+ description: definitions[names.search].description,
5963
+ strict: false,
5964
+ inputSchema: catalogToolInputSchema<IFlexCatalogSearchInput>(definitions[names.search]),
5965
+ execute: async (input: IFlexCatalogSearchInput) => catalog.search(input),
5966
+ }),
5967
+ [names.describe]: plugins.tool({
5968
+ description: definitions[names.describe].description,
5969
+ strict: false,
5970
+ inputSchema: catalogToolInputSchema<IFlexCatalogDescribeInput>(definitions[names.describe]),
5971
+ execute: async (input: IFlexCatalogDescribeInput, options?: { messages?: plugins.ModelMessage[] }) =>
5972
+ catalog.describe(input, {
5973
+ declaredTypes: catalog.declaredTypesIn(options?.messages),
5974
+ maxBytes: describeBytes,
5975
+ }).output,
5976
+ }),
5977
+ [names.execute]: plugins.tool({
5978
+ description: definitions[names.execute].description,
5979
+ strict: false,
5980
+ inputSchema: catalogToolInputSchema<{ method: string; params?: Record<string, unknown> }>(
5981
+ definitions[names.execute],
5982
+ ),
5983
+ execute: async (
5984
+ input: { method: string; params?: Record<string, unknown> },
5985
+ options?: { toolCallId?: string; abortSignal?: AbortSignal },
5986
+ ) => {
5987
+ const call = await catalog.prepareCall(input.method, input.params);
5988
+ if (!call.success) {
5989
+ const error = this.trustInternalError(new FlexHarnessValidationError(JSON.stringify(call.error)));
5990
+ if (options?.toolCallId) run.trustedToolExecutionErrors.set(options.toolCallId, error);
5991
+ throw error;
5992
+ }
5993
+ return call.run({
5994
+ method: call.method,
5995
+ toolCallId: options?.toolCallId ?? '',
5996
+ abortSignal: options?.abortSignal ?? run.controller.signal,
5997
+ provider: run.toolProviderContext!,
5998
+ });
5999
+ },
6000
+ }),
6001
+ };
6002
+ }
6003
+
5916
6004
  private createBuiltInTools(run: IActiveRun): Record<string, unknown> {
5917
6005
  const tools: Record<string, unknown> = {};
5918
6006
  if (run.subagents.size > 0 && (run.stored.session.depth ?? 0) < this.maxSubagentDepth) {
@@ -8422,13 +8510,17 @@ export class FlexHarness<TScope = unknown> {
8422
8510
  const run = this.callbackRun(state, sessionId);
8423
8511
  if (!run || run.toolPartIds.has(event.toolCallId)) return;
8424
8512
  try {
8425
- const input = normalizeJsonValue(event.input, this.toolOutputLimits);
8513
+ // An execute call is the call of the catalog method it names.
8514
+ const target = event.toolName === FLEX_TOOL_CATALOG_TOOL_NAMES.execute
8515
+ ? run.toolCatalog?.callTarget(event.input)
8516
+ : undefined;
8517
+ const input = normalizeJsonValue(target ? target.params : event.input, this.toolOutputLimits);
8426
8518
  if (!this.reserveCallbackCapacity(run, 1, jsonBytes(input), 1)) return;
8427
8519
  const part: IFlexToolMessagePart = {
8428
8520
  partId: plugins.crypto.randomUUID(),
8429
8521
  type: 'tool',
8430
8522
  toolCallId: this.boundedIdentifier(event.toolCallId, 'toolCallId'),
8431
- toolName: this.boundedIdentifier(event.toolName, 'toolName'),
8523
+ toolName: this.boundedIdentifier(target ? target.method : event.toolName, 'toolName'),
8432
8524
  status: 'running',
8433
8525
  input,
8434
8526
  startedAt: new Date().toISOString(),
@@ -9129,9 +9221,14 @@ export class FlexHarness<TScope = unknown> {
9129
9221
  }
9130
9222
  const tools = handle.tools;
9131
9223
  this.assertNoBuiltInToolCollisions(run, tools);
9224
+ const catalog = handle.catalog;
9225
+ if (catalog !== undefined && (typeof catalog !== 'object' || catalog === null)) {
9226
+ throw new FlexHarnessValidationError('Tool handle catalog must be an object.');
9227
+ }
9132
9228
  const closeHandle = close;
9133
9229
  return {
9134
9230
  tools,
9231
+ ...(catalog === undefined ? {} : { catalog }),
9135
9232
  ...(closeHandle ? { close: () => closeHandle.call(handle) } : {}),
9136
9233
  };
9137
9234
  } catch (error) {
@@ -9218,6 +9315,9 @@ export class FlexHarness<TScope = unknown> {
9218
9315
  );
9219
9316
  if (!handle) continue;
9220
9317
  owned.push({ handle, closed: false });
9318
+ if (handle.catalog !== undefined) {
9319
+ throw new FlexHarnessValidationError('Resource tool providers cannot supply a tool catalog.');
9320
+ }
9221
9321
  for (const [toolName, tool] of Object.entries(handle.tools)) {
9222
9322
  const exposedName = createFlexResourceToolName(namespace, toolName);
9223
9323
  if (Object.prototype.hasOwnProperty.call(tools, exposedName)) {
@@ -9229,6 +9329,7 @@ export class FlexHarness<TScope = unknown> {
9229
9329
  if (owned.length === 0 && Object.keys(tools).length === 0) return undefined;
9230
9330
  return {
9231
9331
  tools: tools as TFlexAgentToolSet,
9332
+ ...(applicationHandle?.catalog === undefined ? {} : { catalog: applicationHandle.catalog }),
9232
9333
  ...(owned.some((entry) => entry.handle.close) ? { close: closeOwned } : {}),
9233
9334
  };
9234
9335
  } catch (error) {