la-machina-engine 0.13.0 → 0.15.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/dist/index.cjs +319 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +174 -2
- package/dist/index.d.ts +174 -2
- package/dist/index.js +316 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -137,23 +137,23 @@ var init_fetchData = __esm({
|
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
// src/orchestrator/types.ts
|
|
140
|
-
var
|
|
140
|
+
var import_zod27, PlanStepSchema, PlanSchema;
|
|
141
141
|
var init_types = __esm({
|
|
142
142
|
"src/orchestrator/types.ts"() {
|
|
143
143
|
"use strict";
|
|
144
144
|
init_cjs_shims();
|
|
145
|
-
|
|
146
|
-
PlanStepSchema =
|
|
147
|
-
id:
|
|
148
|
-
description:
|
|
149
|
-
action:
|
|
150
|
-
files:
|
|
151
|
-
spec:
|
|
152
|
-
dependsOn:
|
|
145
|
+
import_zod27 = require("zod");
|
|
146
|
+
PlanStepSchema = import_zod27.z.object({
|
|
147
|
+
id: import_zod27.z.string().min(1),
|
|
148
|
+
description: import_zod27.z.string().min(1),
|
|
149
|
+
action: import_zod27.z.enum(["research", "implement", "verify", "review", "custom"]),
|
|
150
|
+
files: import_zod27.z.array(import_zod27.z.string()).optional(),
|
|
151
|
+
spec: import_zod27.z.string().optional(),
|
|
152
|
+
dependsOn: import_zod27.z.array(import_zod27.z.string()).optional()
|
|
153
153
|
});
|
|
154
|
-
PlanSchema =
|
|
155
|
-
summary:
|
|
156
|
-
steps:
|
|
154
|
+
PlanSchema = import_zod27.z.object({
|
|
155
|
+
summary: import_zod27.z.string().min(1),
|
|
156
|
+
steps: import_zod27.z.array(PlanStepSchema).min(1)
|
|
157
157
|
});
|
|
158
158
|
}
|
|
159
159
|
});
|
|
@@ -889,6 +889,7 @@ __export(src_exports, {
|
|
|
889
889
|
canSpawnProcesses: () => canSpawnProcesses,
|
|
890
890
|
capabilityStub: () => capabilityStub,
|
|
891
891
|
createApiCallTool: () => createApiCallTool,
|
|
892
|
+
createDescribeServiceTool: () => createDescribeServiceTool,
|
|
892
893
|
createFetchDataTool: () => createFetchDataTool,
|
|
893
894
|
createLogger: () => createLogger,
|
|
894
895
|
createModelAdapter: () => createModelAdapter,
|
|
@@ -905,6 +906,7 @@ __export(src_exports, {
|
|
|
905
906
|
getCoordinatorBasePrompt: () => getCoordinatorBasePrompt,
|
|
906
907
|
getCoordinatorSystemPrompt: () => getCoordinatorSystemPrompt,
|
|
907
908
|
getExtractor: () => getExtractor,
|
|
909
|
+
hasDescribableEndpoints: () => hasDescribableEndpoints,
|
|
908
910
|
hasProcessLifecycle: () => hasProcessLifecycle,
|
|
909
911
|
initEngine: () => initEngine,
|
|
910
912
|
isCoordinatorMode: () => isCoordinatorMode,
|
|
@@ -1259,6 +1261,23 @@ var ApiAuthSchema = import_zod.z.discriminatedUnion("type", [
|
|
|
1259
1261
|
}).strict(),
|
|
1260
1262
|
import_zod.z.object({ type: import_zod.z.literal("custom"), id: import_zod.z.string().min(1) }).strict()
|
|
1261
1263
|
]);
|
|
1264
|
+
var ApiEndpointSchema = import_zod.z.object({
|
|
1265
|
+
method: ApiHttpMethodEnum,
|
|
1266
|
+
path: import_zod.z.string().regex(/^\//, "path must start with /"),
|
|
1267
|
+
description: import_zod.z.string().min(1),
|
|
1268
|
+
// JSON Schema 7 — passed through opaquely. Validated at author
|
|
1269
|
+
// time by higher-level tooling (nikaido's yaml compiler), not
|
|
1270
|
+
// here.
|
|
1271
|
+
inputSchema: import_zod.z.unknown().optional(),
|
|
1272
|
+
outputHint: import_zod.z.string().optional()
|
|
1273
|
+
}).strict();
|
|
1274
|
+
var HEADER_NAME_RE = /^[!#$%&'*+\-.0-9A-Z^_`a-z|~]+$/;
|
|
1275
|
+
var RESERVED_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
1276
|
+
"authorization",
|
|
1277
|
+
"cookie",
|
|
1278
|
+
"set-cookie",
|
|
1279
|
+
"proxy-authorization"
|
|
1280
|
+
]);
|
|
1262
1281
|
var ApiServiceSchema = import_zod.z.object({
|
|
1263
1282
|
name: import_zod.z.string().min(1),
|
|
1264
1283
|
description: import_zod.z.string().optional(),
|
|
@@ -1269,11 +1288,46 @@ var ApiServiceSchema = import_zod.z.object({
|
|
|
1269
1288
|
allowedPaths: import_zod.z.array(import_zod.z.union([import_zod.z.string(), import_zod.z.instanceof(RegExp)])).optional(),
|
|
1270
1289
|
allowedMethods: import_zod.z.array(ApiHttpMethodEnum).optional(),
|
|
1271
1290
|
defaultHeaders: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
|
|
1272
|
-
maxBodyBytes: import_zod.z.number().int().positive().optional()
|
|
1273
|
-
|
|
1291
|
+
maxBodyBytes: import_zod.z.number().int().positive().optional(),
|
|
1292
|
+
endpoints: import_zod.z.array(ApiEndpointSchema).optional(),
|
|
1293
|
+
secretHeaders: import_zod.z.record(import_zod.z.string(), import_zod.z.string().min(1)).optional()
|
|
1294
|
+
}).strict().superRefine((svc, ctx) => {
|
|
1295
|
+
if (svc.secretHeaders === void 0) return;
|
|
1296
|
+
const lowerDefault = /* @__PURE__ */ new Set();
|
|
1297
|
+
for (const k of Object.keys(svc.defaultHeaders ?? {})) lowerDefault.add(k.toLowerCase());
|
|
1298
|
+
for (const headerName of Object.keys(svc.secretHeaders)) {
|
|
1299
|
+
if (!HEADER_NAME_RE.test(headerName)) {
|
|
1300
|
+
ctx.addIssue({
|
|
1301
|
+
code: "custom",
|
|
1302
|
+
message: `secretHeaders key "${headerName}" is not a valid HTTP header name (RFC 7230 token charset)`,
|
|
1303
|
+
path: ["secretHeaders", headerName]
|
|
1304
|
+
});
|
|
1305
|
+
continue;
|
|
1306
|
+
}
|
|
1307
|
+
const lower = headerName.toLowerCase();
|
|
1308
|
+
if (RESERVED_HEADER_NAMES.has(lower)) {
|
|
1309
|
+
ctx.addIssue({
|
|
1310
|
+
code: "custom",
|
|
1311
|
+
message: `secretHeaders key "${headerName}" is reserved \u2014 primary \`auth\` owns ${headerName}`,
|
|
1312
|
+
path: ["secretHeaders", headerName]
|
|
1313
|
+
});
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
if (lowerDefault.has(lower)) {
|
|
1317
|
+
ctx.addIssue({
|
|
1318
|
+
code: "custom",
|
|
1319
|
+
message: `secretHeaders key "${headerName}" collides with defaultHeaders (case-insensitive). Move the secret-bearing version to secretHeaders only.`,
|
|
1320
|
+
path: ["secretHeaders", headerName]
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1325
|
+
var ApiCatalogModeEnum = import_zod.z.enum(["eager", "lazy", "auto"]);
|
|
1274
1326
|
var ApiConfigResolved = import_zod.z.object({
|
|
1275
1327
|
services: import_zod.z.array(ApiServiceSchema),
|
|
1276
|
-
maxResponseBytes: import_zod.z.number().int().positive().optional()
|
|
1328
|
+
maxResponseBytes: import_zod.z.number().int().positive().optional(),
|
|
1329
|
+
mode: ApiCatalogModeEnum.optional(),
|
|
1330
|
+
lazyTokenThreshold: import_zod.z.number().int().positive().optional()
|
|
1277
1331
|
}).strict();
|
|
1278
1332
|
var KnowledgeConfigResolved = import_zod.z.object({
|
|
1279
1333
|
enabled: import_zod.z.boolean(),
|
|
@@ -8047,6 +8101,89 @@ function getMcpSection(options) {
|
|
|
8047
8101
|
return lines.join("\n");
|
|
8048
8102
|
}
|
|
8049
8103
|
|
|
8104
|
+
// src/prompts/sections/apiServices.ts
|
|
8105
|
+
init_cjs_shims();
|
|
8106
|
+
var DEFAULT_LAZY_TOKEN_THRESHOLD = 6e3;
|
|
8107
|
+
function getApiServicesSection(opts) {
|
|
8108
|
+
if (opts.services.length === 0) return null;
|
|
8109
|
+
const threshold = opts.lazyTokenThreshold ?? DEFAULT_LAZY_TOKEN_THRESHOLD;
|
|
8110
|
+
const effective = resolveEffectiveMode(opts.services, opts.mode, threshold);
|
|
8111
|
+
const withEndpoints = [];
|
|
8112
|
+
const withoutEndpoints = [];
|
|
8113
|
+
for (const svc of opts.services) {
|
|
8114
|
+
if (svc.endpoints !== void 0 && svc.endpoints.length > 0) {
|
|
8115
|
+
withEndpoints.push(svc);
|
|
8116
|
+
} else {
|
|
8117
|
+
withoutEndpoints.push(svc);
|
|
8118
|
+
}
|
|
8119
|
+
}
|
|
8120
|
+
const lines = ["# API Services"];
|
|
8121
|
+
lines.push("");
|
|
8122
|
+
if (effective === "eager") {
|
|
8123
|
+
lines.push(
|
|
8124
|
+
"Configured external HTTP APIs. Use the `ApiCall` tool to invoke \u2014 auth is injected automatically. Do not pass credentials via headers."
|
|
8125
|
+
);
|
|
8126
|
+
lines.push("");
|
|
8127
|
+
for (const svc of withEndpoints) {
|
|
8128
|
+
lines.push(`## ${svc.name}${svc.description ? ` \u2014 ${svc.description}` : ""}`);
|
|
8129
|
+
lines.push(`baseUrl: ${svc.baseUrl}`);
|
|
8130
|
+
lines.push("");
|
|
8131
|
+
lines.push("Endpoints:");
|
|
8132
|
+
for (const ep of svc.endpoints) {
|
|
8133
|
+
lines.push(`- ${ep.method} ${ep.path} \u2014 ${ep.description}`);
|
|
8134
|
+
if (ep.outputHint !== void 0) {
|
|
8135
|
+
lines.push(` (${ep.outputHint})`);
|
|
8136
|
+
}
|
|
8137
|
+
}
|
|
8138
|
+
lines.push("");
|
|
8139
|
+
}
|
|
8140
|
+
if (withoutEndpoints.length > 0) {
|
|
8141
|
+
lines.push("## Services without a structured catalog");
|
|
8142
|
+
lines.push("Supply the endpoint path from context; `ApiCall` accepts any path.");
|
|
8143
|
+
for (const svc of withoutEndpoints) {
|
|
8144
|
+
lines.push(
|
|
8145
|
+
`- ${svc.name}${svc.description ? ` \u2014 ${svc.description}` : ""} (${svc.baseUrl})`
|
|
8146
|
+
);
|
|
8147
|
+
}
|
|
8148
|
+
lines.push("");
|
|
8149
|
+
}
|
|
8150
|
+
} else {
|
|
8151
|
+
lines.push(
|
|
8152
|
+
"Configured external HTTP APIs. Use `ApiCall` to invoke, but first call `DescribeService(service)` to fetch that service's endpoint catalog. Auth is injected automatically."
|
|
8153
|
+
);
|
|
8154
|
+
lines.push("");
|
|
8155
|
+
for (const svc of withEndpoints) {
|
|
8156
|
+
const count = svc.endpoints.length;
|
|
8157
|
+
const suffix = svc.description ? ` \u2014 ${svc.description}` : "";
|
|
8158
|
+
lines.push(
|
|
8159
|
+
`- **${svc.name}**${suffix} \u2022 ${count} endpoint${count === 1 ? "" : "s"} \u2022 ${svc.baseUrl}`
|
|
8160
|
+
);
|
|
8161
|
+
}
|
|
8162
|
+
if (withoutEndpoints.length > 0) {
|
|
8163
|
+
lines.push("");
|
|
8164
|
+
lines.push("Services without a structured catalog (no DescribeService entry):");
|
|
8165
|
+
for (const svc of withoutEndpoints) {
|
|
8166
|
+
lines.push(
|
|
8167
|
+
`- ${svc.name}${svc.description ? ` \u2014 ${svc.description}` : ""} (${svc.baseUrl})`
|
|
8168
|
+
);
|
|
8169
|
+
}
|
|
8170
|
+
}
|
|
8171
|
+
}
|
|
8172
|
+
return lines.join("\n").trimEnd();
|
|
8173
|
+
}
|
|
8174
|
+
function resolveEffectiveMode(services, requested, threshold) {
|
|
8175
|
+
if (requested === "eager" || requested === "lazy") return requested;
|
|
8176
|
+
let total = 0;
|
|
8177
|
+
for (const svc of services) {
|
|
8178
|
+
if (svc.endpoints === void 0) continue;
|
|
8179
|
+
for (const ep of svc.endpoints) {
|
|
8180
|
+
total += ep.description.length;
|
|
8181
|
+
total += ep.method.length + ep.path.length + 4;
|
|
8182
|
+
}
|
|
8183
|
+
}
|
|
8184
|
+
return total > threshold ? "lazy" : "eager";
|
|
8185
|
+
}
|
|
8186
|
+
|
|
8050
8187
|
// src/prompts/systemPrompt.ts
|
|
8051
8188
|
async function buildSystemPrompt(options) {
|
|
8052
8189
|
const sections = [];
|
|
@@ -8073,6 +8210,14 @@ async function buildSystemPrompt(options) {
|
|
|
8073
8210
|
const mcpSection = getMcpSection({ mcpTools: options.mcpTools });
|
|
8074
8211
|
if (mcpSection !== null) sections.push(mcpSection);
|
|
8075
8212
|
}
|
|
8213
|
+
if (options.apiServices !== void 0 && options.apiServices.length > 0) {
|
|
8214
|
+
const apiSection = getApiServicesSection({
|
|
8215
|
+
services: options.apiServices,
|
|
8216
|
+
mode: options.apiCatalogMode ?? "lazy",
|
|
8217
|
+
...options.apiLazyTokenThreshold !== void 0 ? { lazyTokenThreshold: options.apiLazyTokenThreshold } : {}
|
|
8218
|
+
});
|
|
8219
|
+
if (apiSection !== null) sections.push(apiSection);
|
|
8220
|
+
}
|
|
8076
8221
|
const identity = await options.memory.recallIdentity();
|
|
8077
8222
|
if (identity.length > 0) {
|
|
8078
8223
|
sections.push(`# Identity
|
|
@@ -8273,6 +8418,12 @@ function createApiCallTool(opts) {
|
|
|
8273
8418
|
`createApiCallTool: service "${svc.name}" uses custom auth (id: ${svc.auth.id}) but no resolveAuth was supplied`
|
|
8274
8419
|
);
|
|
8275
8420
|
}
|
|
8421
|
+
const hasSecretHeaders = svc.secretHeaders !== void 0 && Object.keys(svc.secretHeaders).length > 0;
|
|
8422
|
+
if (hasSecretHeaders && opts.resolveAuth === void 0) {
|
|
8423
|
+
throw new Error(
|
|
8424
|
+
`createApiCallTool: service "${svc.name}" declares secretHeaders but no resolveAuth was supplied (the resolver is required to look up the secret values)`
|
|
8425
|
+
);
|
|
8426
|
+
}
|
|
8276
8427
|
}
|
|
8277
8428
|
const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
|
|
8278
8429
|
const maxResponseBytes = opts.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
@@ -8307,13 +8458,14 @@ function createApiCallTool(opts) {
|
|
|
8307
8458
|
if (!svc) {
|
|
8308
8459
|
return errResult(`ERR_API_UNKNOWN_SERVICE: ${input.service}`);
|
|
8309
8460
|
}
|
|
8310
|
-
const
|
|
8311
|
-
if (!
|
|
8461
|
+
const effectiveMethods = resolveAllowedMethods(svc);
|
|
8462
|
+
if (!effectiveMethods.includes(input.method)) {
|
|
8312
8463
|
return errResult(
|
|
8313
8464
|
`ERR_API_METHOD_NOT_ALLOWED: ${input.method} not permitted for service ${svc.name}`
|
|
8314
8465
|
);
|
|
8315
8466
|
}
|
|
8316
|
-
|
|
8467
|
+
const effectivePaths = resolveAllowedPaths(svc);
|
|
8468
|
+
if (!pathAllowed(input.path, effectivePaths)) {
|
|
8317
8469
|
return errResult(`ERR_API_PATH_NOT_ALLOWED: ${input.path} for service ${svc.name}`);
|
|
8318
8470
|
}
|
|
8319
8471
|
let bodyText;
|
|
@@ -8336,13 +8488,20 @@ function createApiCallTool(opts) {
|
|
|
8336
8488
|
return errResult(`ERR_API_BODY_TOO_LARGE: exceeds ${cap} bytes`);
|
|
8337
8489
|
}
|
|
8338
8490
|
}
|
|
8491
|
+
const secretHeaderRefs = svc.secretHeaders !== void 0 && Object.keys(svc.secretHeaders).length > 0 ? svc.secretHeaders : void 0;
|
|
8339
8492
|
let authHeaders;
|
|
8340
8493
|
try {
|
|
8341
8494
|
authHeaders = await resolveAuth({
|
|
8342
8495
|
auth: svc.auth ?? { type: "none" },
|
|
8343
8496
|
env: opts.env,
|
|
8344
8497
|
resolver: opts.resolveAuth,
|
|
8345
|
-
ctx: {
|
|
8498
|
+
ctx: {
|
|
8499
|
+
serviceName: svc.name,
|
|
8500
|
+
method: input.method,
|
|
8501
|
+
path: input.path,
|
|
8502
|
+
...secretHeaderRefs !== void 0 ? { secretHeaderRefs } : {}
|
|
8503
|
+
},
|
|
8504
|
+
forceResolve: secretHeaderRefs !== void 0
|
|
8346
8505
|
});
|
|
8347
8506
|
} catch (err) {
|
|
8348
8507
|
const raw2 = err instanceof Error ? err.message : String(err);
|
|
@@ -8409,6 +8568,27 @@ function pathAllowed(path, allowed) {
|
|
|
8409
8568
|
}
|
|
8410
8569
|
return false;
|
|
8411
8570
|
}
|
|
8571
|
+
function resolveAllowedMethods(svc) {
|
|
8572
|
+
if (svc.allowedMethods !== void 0) return svc.allowedMethods;
|
|
8573
|
+
if (svc.endpoints && svc.endpoints.length > 0) {
|
|
8574
|
+
const set = /* @__PURE__ */ new Set();
|
|
8575
|
+
for (const ep of svc.endpoints) set.add(ep.method);
|
|
8576
|
+
return Array.from(set);
|
|
8577
|
+
}
|
|
8578
|
+
return ALL_METHODS;
|
|
8579
|
+
}
|
|
8580
|
+
function resolveAllowedPaths(svc) {
|
|
8581
|
+
if (svc.allowedPaths !== void 0) return svc.allowedPaths;
|
|
8582
|
+
if (svc.endpoints && svc.endpoints.length > 0) {
|
|
8583
|
+
const prefixes = /* @__PURE__ */ new Set();
|
|
8584
|
+
for (const ep of svc.endpoints) {
|
|
8585
|
+
const brace = ep.path.indexOf("{");
|
|
8586
|
+
prefixes.add(brace === -1 ? ep.path : ep.path.slice(0, brace));
|
|
8587
|
+
}
|
|
8588
|
+
return Array.from(prefixes);
|
|
8589
|
+
}
|
|
8590
|
+
return void 0;
|
|
8591
|
+
}
|
|
8412
8592
|
function byteLength2(s) {
|
|
8413
8593
|
return new TextEncoder().encode(s).byteLength;
|
|
8414
8594
|
}
|
|
@@ -8430,22 +8610,27 @@ function sanitizeHeaders(user, auth) {
|
|
|
8430
8610
|
return out;
|
|
8431
8611
|
}
|
|
8432
8612
|
async function resolveAuth(args) {
|
|
8433
|
-
const { auth, env, resolver, ctx } = args;
|
|
8613
|
+
const { auth, env, resolver, ctx, forceResolve } = args;
|
|
8614
|
+
let primary;
|
|
8434
8615
|
switch (auth.type) {
|
|
8435
8616
|
case "none":
|
|
8436
|
-
|
|
8617
|
+
primary = {};
|
|
8618
|
+
break;
|
|
8437
8619
|
case "bearer": {
|
|
8438
8620
|
const token = envLookup(env, auth.tokenRef);
|
|
8439
|
-
|
|
8621
|
+
primary = { Authorization: `Bearer ${token}` };
|
|
8622
|
+
break;
|
|
8440
8623
|
}
|
|
8441
8624
|
case "header": {
|
|
8442
8625
|
const value = envLookup(env, auth.valueRef);
|
|
8443
|
-
|
|
8626
|
+
primary = { [auth.name]: value };
|
|
8627
|
+
break;
|
|
8444
8628
|
}
|
|
8445
8629
|
case "basic": {
|
|
8446
8630
|
const u = envLookup(env, auth.userRef);
|
|
8447
8631
|
const p = envLookup(env, auth.passRef);
|
|
8448
|
-
|
|
8632
|
+
primary = { Authorization: `Basic ${base64(`${u}:${p}`)}` };
|
|
8633
|
+
break;
|
|
8449
8634
|
}
|
|
8450
8635
|
case "custom":
|
|
8451
8636
|
if (resolver === void 0) {
|
|
@@ -8453,6 +8638,14 @@ async function resolveAuth(args) {
|
|
|
8453
8638
|
}
|
|
8454
8639
|
return resolver(auth, ctx);
|
|
8455
8640
|
}
|
|
8641
|
+
if (forceResolve === true) {
|
|
8642
|
+
if (resolver === void 0) {
|
|
8643
|
+
throw new Error("secretHeaders require a resolveAuth callback (host did not supply one)");
|
|
8644
|
+
}
|
|
8645
|
+
const extra = await resolver(auth, ctx);
|
|
8646
|
+
return { ...primary, ...extra };
|
|
8647
|
+
}
|
|
8648
|
+
return primary;
|
|
8456
8649
|
}
|
|
8457
8650
|
function envLookup(env, ref) {
|
|
8458
8651
|
if (env === void 0 || env[ref] === void 0) {
|
|
@@ -8474,12 +8667,74 @@ async function invokeHook(hook, event) {
|
|
|
8474
8667
|
}
|
|
8475
8668
|
}
|
|
8476
8669
|
|
|
8670
|
+
// src/tools/describeService.ts
|
|
8671
|
+
init_cjs_shims();
|
|
8672
|
+
var import_zod24 = require("zod");
|
|
8673
|
+
init_contract();
|
|
8674
|
+
function describe(svc) {
|
|
8675
|
+
const endpoints = (svc.endpoints ?? []).map(
|
|
8676
|
+
(ep) => ({
|
|
8677
|
+
method: ep.method,
|
|
8678
|
+
path: ep.path,
|
|
8679
|
+
description: ep.description,
|
|
8680
|
+
...ep.inputSchema !== void 0 ? { inputSchema: ep.inputSchema } : {},
|
|
8681
|
+
...ep.outputHint !== void 0 ? { outputHint: ep.outputHint } : {}
|
|
8682
|
+
})
|
|
8683
|
+
);
|
|
8684
|
+
return {
|
|
8685
|
+
service: svc.name,
|
|
8686
|
+
...svc.description !== void 0 ? { description: svc.description } : {},
|
|
8687
|
+
baseUrl: svc.baseUrl,
|
|
8688
|
+
endpoints
|
|
8689
|
+
};
|
|
8690
|
+
}
|
|
8691
|
+
function hasDescribableEndpoints(svc) {
|
|
8692
|
+
return svc.endpoints !== void 0 && svc.endpoints.length > 0;
|
|
8693
|
+
}
|
|
8694
|
+
function createDescribeServiceTool(opts) {
|
|
8695
|
+
const describable = opts.services.filter(hasDescribableEndpoints);
|
|
8696
|
+
if (describable.length === 0) {
|
|
8697
|
+
throw new Error(
|
|
8698
|
+
"createDescribeServiceTool: no services with endpoints[] \u2014 do not register this tool"
|
|
8699
|
+
);
|
|
8700
|
+
}
|
|
8701
|
+
const serviceMap = /* @__PURE__ */ new Map();
|
|
8702
|
+
for (const svc of describable) serviceMap.set(svc.name, svc);
|
|
8703
|
+
const serviceNames = [...serviceMap.keys()];
|
|
8704
|
+
const cache = /* @__PURE__ */ new Map();
|
|
8705
|
+
const inputSchema19 = import_zod24.z.object({
|
|
8706
|
+
service: import_zod24.z.enum(serviceNames)
|
|
8707
|
+
});
|
|
8708
|
+
const description = `Look up the endpoint catalog for one configured API service. Returns every endpoint's method, path, description, and input schema. Call this before invoking \`ApiCall\` when the service has lazy endpoints. Services: ${serviceNames.join(", ")}.`;
|
|
8709
|
+
return defineTool({
|
|
8710
|
+
name: opts.toolName ?? "DescribeService",
|
|
8711
|
+
description,
|
|
8712
|
+
inputSchema: inputSchema19,
|
|
8713
|
+
execute: async (input) => {
|
|
8714
|
+
const cached = cache.get(input.service);
|
|
8715
|
+
if (cached !== void 0) {
|
|
8716
|
+
return { content: JSON.stringify(cached), metadata: { cached: true } };
|
|
8717
|
+
}
|
|
8718
|
+
const svc = serviceMap.get(input.service);
|
|
8719
|
+
if (!svc) {
|
|
8720
|
+
return {
|
|
8721
|
+
content: `ERR_DESCRIBE_UNKNOWN_SERVICE: ${input.service}`,
|
|
8722
|
+
isError: true
|
|
8723
|
+
};
|
|
8724
|
+
}
|
|
8725
|
+
const payload = describe(svc);
|
|
8726
|
+
cache.set(input.service, payload);
|
|
8727
|
+
return { content: JSON.stringify(payload), metadata: { cached: false } };
|
|
8728
|
+
}
|
|
8729
|
+
});
|
|
8730
|
+
}
|
|
8731
|
+
|
|
8477
8732
|
// src/engine/engine.ts
|
|
8478
8733
|
init_fetchData();
|
|
8479
8734
|
|
|
8480
8735
|
// src/tools/searchKnowledge.ts
|
|
8481
8736
|
init_cjs_shims();
|
|
8482
|
-
var
|
|
8737
|
+
var import_zod25 = require("zod");
|
|
8483
8738
|
init_contract();
|
|
8484
8739
|
|
|
8485
8740
|
// src/knowledge/indexer.ts
|
|
@@ -8776,9 +9031,9 @@ function refInScope(folders, filePath) {
|
|
|
8776
9031
|
|
|
8777
9032
|
// src/tools/searchKnowledge.ts
|
|
8778
9033
|
var DEFAULT_MAX_RESULTS = 5;
|
|
8779
|
-
var inputSchema17 =
|
|
8780
|
-
query:
|
|
8781
|
-
maxResults:
|
|
9034
|
+
var inputSchema17 = import_zod25.z.object({
|
|
9035
|
+
query: import_zod25.z.string().min(1),
|
|
9036
|
+
maxResults: import_zod25.z.number().int().positive().optional()
|
|
8782
9037
|
});
|
|
8783
9038
|
function createSearchKnowledgeTool(opts) {
|
|
8784
9039
|
const scoped = opts.folders.map(parseFolderRef);
|
|
@@ -8883,7 +9138,7 @@ async function loadIndex(adapter, base, cache) {
|
|
|
8883
9138
|
|
|
8884
9139
|
// src/tools/readKnowledge.ts
|
|
8885
9140
|
init_cjs_shims();
|
|
8886
|
-
var
|
|
9141
|
+
var import_zod26 = require("zod");
|
|
8887
9142
|
init_contract();
|
|
8888
9143
|
|
|
8889
9144
|
// src/knowledge/extractors.ts
|
|
@@ -8995,8 +9250,8 @@ function getExtractor(format) {
|
|
|
8995
9250
|
|
|
8996
9251
|
// src/tools/readKnowledge.ts
|
|
8997
9252
|
var DEFAULT_MAX_READ_BYTES = 1e4;
|
|
8998
|
-
var inputSchema18 =
|
|
8999
|
-
ref:
|
|
9253
|
+
var inputSchema18 = import_zod26.z.object({
|
|
9254
|
+
ref: import_zod26.z.string().min(1)
|
|
9000
9255
|
});
|
|
9001
9256
|
function createReadKnowledgeTool(opts) {
|
|
9002
9257
|
const scoped = opts.folders.map(parseFolderRef);
|
|
@@ -10599,7 +10854,13 @@ var Engine = class {
|
|
|
10599
10854
|
provider: this.config.model.provider,
|
|
10600
10855
|
registeredToolNames: toolNameSet,
|
|
10601
10856
|
mcpTools,
|
|
10602
|
-
coordinatorMode: isCoordinatorMode(this.config)
|
|
10857
|
+
coordinatorMode: isCoordinatorMode(this.config),
|
|
10858
|
+
// Plan 047 — render API services catalog (lazy by default).
|
|
10859
|
+
...apiConfig !== void 0 && apiConfig.services.length > 0 ? {
|
|
10860
|
+
apiServices: apiConfig.services,
|
|
10861
|
+
apiCatalogMode: apiConfig.mode ?? "lazy",
|
|
10862
|
+
...apiConfig.lazyTokenThreshold !== void 0 ? { apiLazyTokenThreshold: apiConfig.lazyTokenThreshold } : {}
|
|
10863
|
+
} : {}
|
|
10603
10864
|
});
|
|
10604
10865
|
if (options.outputFormat === "json") {
|
|
10605
10866
|
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
@@ -10797,7 +11058,13 @@ var Engine = class {
|
|
|
10797
11058
|
provider: this.config.model.provider,
|
|
10798
11059
|
registeredToolNames: toolNameSet,
|
|
10799
11060
|
mcpTools,
|
|
10800
|
-
coordinatorMode: isCoordinatorMode(this.config)
|
|
11061
|
+
coordinatorMode: isCoordinatorMode(this.config),
|
|
11062
|
+
// Plan 047 — render API services catalog (lazy by default).
|
|
11063
|
+
...apiConfig !== void 0 && apiConfig.services.length > 0 ? {
|
|
11064
|
+
apiServices: apiConfig.services,
|
|
11065
|
+
apiCatalogMode: apiConfig.mode ?? "lazy",
|
|
11066
|
+
...apiConfig.lazyTokenThreshold !== void 0 ? { apiLazyTokenThreshold: apiConfig.lazyTokenThreshold } : {}
|
|
11067
|
+
} : {}
|
|
10801
11068
|
});
|
|
10802
11069
|
if (options.outputFormat === "json") {
|
|
10803
11070
|
systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
|
|
@@ -12088,6 +12355,21 @@ function buildToolRegistry(options) {
|
|
|
12088
12355
|
registry.register(apiTool);
|
|
12089
12356
|
childRegistry.register(apiTool);
|
|
12090
12357
|
}
|
|
12358
|
+
const describable = options.apiConfig.services.filter(
|
|
12359
|
+
(s) => s.endpoints !== void 0 && s.endpoints.length > 0
|
|
12360
|
+
);
|
|
12361
|
+
if (describable.length > 0) {
|
|
12362
|
+
const requested = options.apiConfig.mode ?? "lazy";
|
|
12363
|
+
const threshold = options.apiConfig.lazyTokenThreshold ?? DEFAULT_LAZY_TOKEN_THRESHOLD;
|
|
12364
|
+
const effective = resolveEffectiveMode(options.apiConfig.services, requested, threshold);
|
|
12365
|
+
if (effective === "lazy") {
|
|
12366
|
+
if (!disabled.has("DescribeService") && (wantAll || enabled.has("DescribeService"))) {
|
|
12367
|
+
const describeTool = createDescribeServiceTool({ services: describable });
|
|
12368
|
+
registry.register(describeTool);
|
|
12369
|
+
childRegistry.register(describeTool);
|
|
12370
|
+
}
|
|
12371
|
+
}
|
|
12372
|
+
}
|
|
12091
12373
|
}
|
|
12092
12374
|
if (options.toolResultOffload?.enabled === true) {
|
|
12093
12375
|
if (!disabled.has("FetchData") && (wantAll || enabled.has("FetchData"))) {
|
|
@@ -12174,9 +12456,9 @@ init_contract();
|
|
|
12174
12456
|
|
|
12175
12457
|
// src/tools/capabilityStub.ts
|
|
12176
12458
|
init_cjs_shims();
|
|
12177
|
-
var
|
|
12459
|
+
var import_zod28 = require("zod");
|
|
12178
12460
|
init_contract();
|
|
12179
|
-
var anyInput =
|
|
12461
|
+
var anyInput = import_zod28.z.unknown();
|
|
12180
12462
|
function capabilityStub(original) {
|
|
12181
12463
|
return defineTool({
|
|
12182
12464
|
name: original.name,
|
|
@@ -12287,6 +12569,7 @@ function resolveApiKey(config) {
|
|
|
12287
12569
|
canSpawnProcesses,
|
|
12288
12570
|
capabilityStub,
|
|
12289
12571
|
createApiCallTool,
|
|
12572
|
+
createDescribeServiceTool,
|
|
12290
12573
|
createFetchDataTool,
|
|
12291
12574
|
createLogger,
|
|
12292
12575
|
createModelAdapter,
|
|
@@ -12303,6 +12586,7 @@ function resolveApiKey(config) {
|
|
|
12303
12586
|
getCoordinatorBasePrompt,
|
|
12304
12587
|
getCoordinatorSystemPrompt,
|
|
12305
12588
|
getExtractor,
|
|
12589
|
+
hasDescribableEndpoints,
|
|
12306
12590
|
hasProcessLifecycle,
|
|
12307
12591
|
initEngine,
|
|
12308
12592
|
isCoordinatorMode,
|