la-machina-engine 0.13.0 → 0.14.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 CHANGED
@@ -137,23 +137,23 @@ var init_fetchData = __esm({
137
137
  });
138
138
 
139
139
  // src/orchestrator/types.ts
140
- var import_zod26, PlanStepSchema, PlanSchema;
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
- import_zod26 = require("zod");
146
- PlanStepSchema = import_zod26.z.object({
147
- id: import_zod26.z.string().min(1),
148
- description: import_zod26.z.string().min(1),
149
- action: import_zod26.z.enum(["research", "implement", "verify", "review", "custom"]),
150
- files: import_zod26.z.array(import_zod26.z.string()).optional(),
151
- spec: import_zod26.z.string().optional(),
152
- dependsOn: import_zod26.z.array(import_zod26.z.string()).optional()
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 = import_zod26.z.object({
155
- summary: import_zod26.z.string().min(1),
156
- steps: import_zod26.z.array(PlanStepSchema).min(1)
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,16 @@ 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();
1262
1274
  var ApiServiceSchema = import_zod.z.object({
1263
1275
  name: import_zod.z.string().min(1),
1264
1276
  description: import_zod.z.string().optional(),
@@ -1269,11 +1281,15 @@ var ApiServiceSchema = import_zod.z.object({
1269
1281
  allowedPaths: import_zod.z.array(import_zod.z.union([import_zod.z.string(), import_zod.z.instanceof(RegExp)])).optional(),
1270
1282
  allowedMethods: import_zod.z.array(ApiHttpMethodEnum).optional(),
1271
1283
  defaultHeaders: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
1272
- maxBodyBytes: import_zod.z.number().int().positive().optional()
1284
+ maxBodyBytes: import_zod.z.number().int().positive().optional(),
1285
+ endpoints: import_zod.z.array(ApiEndpointSchema).optional()
1273
1286
  }).strict();
1287
+ var ApiCatalogModeEnum = import_zod.z.enum(["eager", "lazy", "auto"]);
1274
1288
  var ApiConfigResolved = import_zod.z.object({
1275
1289
  services: import_zod.z.array(ApiServiceSchema),
1276
- maxResponseBytes: import_zod.z.number().int().positive().optional()
1290
+ maxResponseBytes: import_zod.z.number().int().positive().optional(),
1291
+ mode: ApiCatalogModeEnum.optional(),
1292
+ lazyTokenThreshold: import_zod.z.number().int().positive().optional()
1277
1293
  }).strict();
1278
1294
  var KnowledgeConfigResolved = import_zod.z.object({
1279
1295
  enabled: import_zod.z.boolean(),
@@ -8047,6 +8063,89 @@ function getMcpSection(options) {
8047
8063
  return lines.join("\n");
8048
8064
  }
8049
8065
 
8066
+ // src/prompts/sections/apiServices.ts
8067
+ init_cjs_shims();
8068
+ var DEFAULT_LAZY_TOKEN_THRESHOLD = 6e3;
8069
+ function getApiServicesSection(opts) {
8070
+ if (opts.services.length === 0) return null;
8071
+ const threshold = opts.lazyTokenThreshold ?? DEFAULT_LAZY_TOKEN_THRESHOLD;
8072
+ const effective = resolveEffectiveMode(opts.services, opts.mode, threshold);
8073
+ const withEndpoints = [];
8074
+ const withoutEndpoints = [];
8075
+ for (const svc of opts.services) {
8076
+ if (svc.endpoints !== void 0 && svc.endpoints.length > 0) {
8077
+ withEndpoints.push(svc);
8078
+ } else {
8079
+ withoutEndpoints.push(svc);
8080
+ }
8081
+ }
8082
+ const lines = ["# API Services"];
8083
+ lines.push("");
8084
+ if (effective === "eager") {
8085
+ lines.push(
8086
+ "Configured external HTTP APIs. Use the `ApiCall` tool to invoke \u2014 auth is injected automatically. Do not pass credentials via headers."
8087
+ );
8088
+ lines.push("");
8089
+ for (const svc of withEndpoints) {
8090
+ lines.push(`## ${svc.name}${svc.description ? ` \u2014 ${svc.description}` : ""}`);
8091
+ lines.push(`baseUrl: ${svc.baseUrl}`);
8092
+ lines.push("");
8093
+ lines.push("Endpoints:");
8094
+ for (const ep of svc.endpoints) {
8095
+ lines.push(`- ${ep.method} ${ep.path} \u2014 ${ep.description}`);
8096
+ if (ep.outputHint !== void 0) {
8097
+ lines.push(` (${ep.outputHint})`);
8098
+ }
8099
+ }
8100
+ lines.push("");
8101
+ }
8102
+ if (withoutEndpoints.length > 0) {
8103
+ lines.push("## Services without a structured catalog");
8104
+ lines.push("Supply the endpoint path from context; `ApiCall` accepts any path.");
8105
+ for (const svc of withoutEndpoints) {
8106
+ lines.push(
8107
+ `- ${svc.name}${svc.description ? ` \u2014 ${svc.description}` : ""} (${svc.baseUrl})`
8108
+ );
8109
+ }
8110
+ lines.push("");
8111
+ }
8112
+ } else {
8113
+ lines.push(
8114
+ "Configured external HTTP APIs. Use `ApiCall` to invoke, but first call `DescribeService(service)` to fetch that service's endpoint catalog. Auth is injected automatically."
8115
+ );
8116
+ lines.push("");
8117
+ for (const svc of withEndpoints) {
8118
+ const count = svc.endpoints.length;
8119
+ const suffix = svc.description ? ` \u2014 ${svc.description}` : "";
8120
+ lines.push(
8121
+ `- **${svc.name}**${suffix} \u2022 ${count} endpoint${count === 1 ? "" : "s"} \u2022 ${svc.baseUrl}`
8122
+ );
8123
+ }
8124
+ if (withoutEndpoints.length > 0) {
8125
+ lines.push("");
8126
+ lines.push("Services without a structured catalog (no DescribeService entry):");
8127
+ for (const svc of withoutEndpoints) {
8128
+ lines.push(
8129
+ `- ${svc.name}${svc.description ? ` \u2014 ${svc.description}` : ""} (${svc.baseUrl})`
8130
+ );
8131
+ }
8132
+ }
8133
+ }
8134
+ return lines.join("\n").trimEnd();
8135
+ }
8136
+ function resolveEffectiveMode(services, requested, threshold) {
8137
+ if (requested === "eager" || requested === "lazy") return requested;
8138
+ let total = 0;
8139
+ for (const svc of services) {
8140
+ if (svc.endpoints === void 0) continue;
8141
+ for (const ep of svc.endpoints) {
8142
+ total += ep.description.length;
8143
+ total += ep.method.length + ep.path.length + 4;
8144
+ }
8145
+ }
8146
+ return total > threshold ? "lazy" : "eager";
8147
+ }
8148
+
8050
8149
  // src/prompts/systemPrompt.ts
8051
8150
  async function buildSystemPrompt(options) {
8052
8151
  const sections = [];
@@ -8073,6 +8172,14 @@ async function buildSystemPrompt(options) {
8073
8172
  const mcpSection = getMcpSection({ mcpTools: options.mcpTools });
8074
8173
  if (mcpSection !== null) sections.push(mcpSection);
8075
8174
  }
8175
+ if (options.apiServices !== void 0 && options.apiServices.length > 0) {
8176
+ const apiSection = getApiServicesSection({
8177
+ services: options.apiServices,
8178
+ mode: options.apiCatalogMode ?? "lazy",
8179
+ ...options.apiLazyTokenThreshold !== void 0 ? { lazyTokenThreshold: options.apiLazyTokenThreshold } : {}
8180
+ });
8181
+ if (apiSection !== null) sections.push(apiSection);
8182
+ }
8076
8183
  const identity = await options.memory.recallIdentity();
8077
8184
  if (identity.length > 0) {
8078
8185
  sections.push(`# Identity
@@ -8307,13 +8414,14 @@ function createApiCallTool(opts) {
8307
8414
  if (!svc) {
8308
8415
  return errResult(`ERR_API_UNKNOWN_SERVICE: ${input.service}`);
8309
8416
  }
8310
- const allowedMethods = svc.allowedMethods ?? ALL_METHODS;
8311
- if (!allowedMethods.includes(input.method)) {
8417
+ const effectiveMethods = resolveAllowedMethods(svc);
8418
+ if (!effectiveMethods.includes(input.method)) {
8312
8419
  return errResult(
8313
8420
  `ERR_API_METHOD_NOT_ALLOWED: ${input.method} not permitted for service ${svc.name}`
8314
8421
  );
8315
8422
  }
8316
- if (!pathAllowed(input.path, svc.allowedPaths)) {
8423
+ const effectivePaths = resolveAllowedPaths(svc);
8424
+ if (!pathAllowed(input.path, effectivePaths)) {
8317
8425
  return errResult(`ERR_API_PATH_NOT_ALLOWED: ${input.path} for service ${svc.name}`);
8318
8426
  }
8319
8427
  let bodyText;
@@ -8409,6 +8517,27 @@ function pathAllowed(path, allowed) {
8409
8517
  }
8410
8518
  return false;
8411
8519
  }
8520
+ function resolveAllowedMethods(svc) {
8521
+ if (svc.allowedMethods !== void 0) return svc.allowedMethods;
8522
+ if (svc.endpoints && svc.endpoints.length > 0) {
8523
+ const set = /* @__PURE__ */ new Set();
8524
+ for (const ep of svc.endpoints) set.add(ep.method);
8525
+ return Array.from(set);
8526
+ }
8527
+ return ALL_METHODS;
8528
+ }
8529
+ function resolveAllowedPaths(svc) {
8530
+ if (svc.allowedPaths !== void 0) return svc.allowedPaths;
8531
+ if (svc.endpoints && svc.endpoints.length > 0) {
8532
+ const prefixes = /* @__PURE__ */ new Set();
8533
+ for (const ep of svc.endpoints) {
8534
+ const brace = ep.path.indexOf("{");
8535
+ prefixes.add(brace === -1 ? ep.path : ep.path.slice(0, brace));
8536
+ }
8537
+ return Array.from(prefixes);
8538
+ }
8539
+ return void 0;
8540
+ }
8412
8541
  function byteLength2(s) {
8413
8542
  return new TextEncoder().encode(s).byteLength;
8414
8543
  }
@@ -8474,12 +8603,74 @@ async function invokeHook(hook, event) {
8474
8603
  }
8475
8604
  }
8476
8605
 
8606
+ // src/tools/describeService.ts
8607
+ init_cjs_shims();
8608
+ var import_zod24 = require("zod");
8609
+ init_contract();
8610
+ function describe(svc) {
8611
+ const endpoints = (svc.endpoints ?? []).map(
8612
+ (ep) => ({
8613
+ method: ep.method,
8614
+ path: ep.path,
8615
+ description: ep.description,
8616
+ ...ep.inputSchema !== void 0 ? { inputSchema: ep.inputSchema } : {},
8617
+ ...ep.outputHint !== void 0 ? { outputHint: ep.outputHint } : {}
8618
+ })
8619
+ );
8620
+ return {
8621
+ service: svc.name,
8622
+ ...svc.description !== void 0 ? { description: svc.description } : {},
8623
+ baseUrl: svc.baseUrl,
8624
+ endpoints
8625
+ };
8626
+ }
8627
+ function hasDescribableEndpoints(svc) {
8628
+ return svc.endpoints !== void 0 && svc.endpoints.length > 0;
8629
+ }
8630
+ function createDescribeServiceTool(opts) {
8631
+ const describable = opts.services.filter(hasDescribableEndpoints);
8632
+ if (describable.length === 0) {
8633
+ throw new Error(
8634
+ "createDescribeServiceTool: no services with endpoints[] \u2014 do not register this tool"
8635
+ );
8636
+ }
8637
+ const serviceMap = /* @__PURE__ */ new Map();
8638
+ for (const svc of describable) serviceMap.set(svc.name, svc);
8639
+ const serviceNames = [...serviceMap.keys()];
8640
+ const cache = /* @__PURE__ */ new Map();
8641
+ const inputSchema19 = import_zod24.z.object({
8642
+ service: import_zod24.z.enum(serviceNames)
8643
+ });
8644
+ 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(", ")}.`;
8645
+ return defineTool({
8646
+ name: opts.toolName ?? "DescribeService",
8647
+ description,
8648
+ inputSchema: inputSchema19,
8649
+ execute: async (input) => {
8650
+ const cached = cache.get(input.service);
8651
+ if (cached !== void 0) {
8652
+ return { content: JSON.stringify(cached), metadata: { cached: true } };
8653
+ }
8654
+ const svc = serviceMap.get(input.service);
8655
+ if (!svc) {
8656
+ return {
8657
+ content: `ERR_DESCRIBE_UNKNOWN_SERVICE: ${input.service}`,
8658
+ isError: true
8659
+ };
8660
+ }
8661
+ const payload = describe(svc);
8662
+ cache.set(input.service, payload);
8663
+ return { content: JSON.stringify(payload), metadata: { cached: false } };
8664
+ }
8665
+ });
8666
+ }
8667
+
8477
8668
  // src/engine/engine.ts
8478
8669
  init_fetchData();
8479
8670
 
8480
8671
  // src/tools/searchKnowledge.ts
8481
8672
  init_cjs_shims();
8482
- var import_zod24 = require("zod");
8673
+ var import_zod25 = require("zod");
8483
8674
  init_contract();
8484
8675
 
8485
8676
  // src/knowledge/indexer.ts
@@ -8776,9 +8967,9 @@ function refInScope(folders, filePath) {
8776
8967
 
8777
8968
  // src/tools/searchKnowledge.ts
8778
8969
  var DEFAULT_MAX_RESULTS = 5;
8779
- var inputSchema17 = import_zod24.z.object({
8780
- query: import_zod24.z.string().min(1),
8781
- maxResults: import_zod24.z.number().int().positive().optional()
8970
+ var inputSchema17 = import_zod25.z.object({
8971
+ query: import_zod25.z.string().min(1),
8972
+ maxResults: import_zod25.z.number().int().positive().optional()
8782
8973
  });
8783
8974
  function createSearchKnowledgeTool(opts) {
8784
8975
  const scoped = opts.folders.map(parseFolderRef);
@@ -8883,7 +9074,7 @@ async function loadIndex(adapter, base, cache) {
8883
9074
 
8884
9075
  // src/tools/readKnowledge.ts
8885
9076
  init_cjs_shims();
8886
- var import_zod25 = require("zod");
9077
+ var import_zod26 = require("zod");
8887
9078
  init_contract();
8888
9079
 
8889
9080
  // src/knowledge/extractors.ts
@@ -8995,8 +9186,8 @@ function getExtractor(format) {
8995
9186
 
8996
9187
  // src/tools/readKnowledge.ts
8997
9188
  var DEFAULT_MAX_READ_BYTES = 1e4;
8998
- var inputSchema18 = import_zod25.z.object({
8999
- ref: import_zod25.z.string().min(1)
9189
+ var inputSchema18 = import_zod26.z.object({
9190
+ ref: import_zod26.z.string().min(1)
9000
9191
  });
9001
9192
  function createReadKnowledgeTool(opts) {
9002
9193
  const scoped = opts.folders.map(parseFolderRef);
@@ -10599,7 +10790,13 @@ var Engine = class {
10599
10790
  provider: this.config.model.provider,
10600
10791
  registeredToolNames: toolNameSet,
10601
10792
  mcpTools,
10602
- coordinatorMode: isCoordinatorMode(this.config)
10793
+ coordinatorMode: isCoordinatorMode(this.config),
10794
+ // Plan 047 — render API services catalog (lazy by default).
10795
+ ...apiConfig !== void 0 && apiConfig.services.length > 0 ? {
10796
+ apiServices: apiConfig.services,
10797
+ apiCatalogMode: apiConfig.mode ?? "lazy",
10798
+ ...apiConfig.lazyTokenThreshold !== void 0 ? { apiLazyTokenThreshold: apiConfig.lazyTokenThreshold } : {}
10799
+ } : {}
10603
10800
  });
10604
10801
  if (options.outputFormat === "json") {
10605
10802
  systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
@@ -10797,7 +10994,13 @@ var Engine = class {
10797
10994
  provider: this.config.model.provider,
10798
10995
  registeredToolNames: toolNameSet,
10799
10996
  mcpTools,
10800
- coordinatorMode: isCoordinatorMode(this.config)
10997
+ coordinatorMode: isCoordinatorMode(this.config),
10998
+ // Plan 047 — render API services catalog (lazy by default).
10999
+ ...apiConfig !== void 0 && apiConfig.services.length > 0 ? {
11000
+ apiServices: apiConfig.services,
11001
+ apiCatalogMode: apiConfig.mode ?? "lazy",
11002
+ ...apiConfig.lazyTokenThreshold !== void 0 ? { apiLazyTokenThreshold: apiConfig.lazyTokenThreshold } : {}
11003
+ } : {}
10801
11004
  });
10802
11005
  if (options.outputFormat === "json") {
10803
11006
  systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
@@ -12088,6 +12291,21 @@ function buildToolRegistry(options) {
12088
12291
  registry.register(apiTool);
12089
12292
  childRegistry.register(apiTool);
12090
12293
  }
12294
+ const describable = options.apiConfig.services.filter(
12295
+ (s) => s.endpoints !== void 0 && s.endpoints.length > 0
12296
+ );
12297
+ if (describable.length > 0) {
12298
+ const requested = options.apiConfig.mode ?? "lazy";
12299
+ const threshold = options.apiConfig.lazyTokenThreshold ?? DEFAULT_LAZY_TOKEN_THRESHOLD;
12300
+ const effective = resolveEffectiveMode(options.apiConfig.services, requested, threshold);
12301
+ if (effective === "lazy") {
12302
+ if (!disabled.has("DescribeService") && (wantAll || enabled.has("DescribeService"))) {
12303
+ const describeTool = createDescribeServiceTool({ services: describable });
12304
+ registry.register(describeTool);
12305
+ childRegistry.register(describeTool);
12306
+ }
12307
+ }
12308
+ }
12091
12309
  }
12092
12310
  if (options.toolResultOffload?.enabled === true) {
12093
12311
  if (!disabled.has("FetchData") && (wantAll || enabled.has("FetchData"))) {
@@ -12174,9 +12392,9 @@ init_contract();
12174
12392
 
12175
12393
  // src/tools/capabilityStub.ts
12176
12394
  init_cjs_shims();
12177
- var import_zod27 = require("zod");
12395
+ var import_zod28 = require("zod");
12178
12396
  init_contract();
12179
- var anyInput = import_zod27.z.unknown();
12397
+ var anyInput = import_zod28.z.unknown();
12180
12398
  function capabilityStub(original) {
12181
12399
  return defineTool({
12182
12400
  name: original.name,
@@ -12287,6 +12505,7 @@ function resolveApiKey(config) {
12287
12505
  canSpawnProcesses,
12288
12506
  capabilityStub,
12289
12507
  createApiCallTool,
12508
+ createDescribeServiceTool,
12290
12509
  createFetchDataTool,
12291
12510
  createLogger,
12292
12511
  createModelAdapter,
@@ -12303,6 +12522,7 @@ function resolveApiKey(config) {
12303
12522
  getCoordinatorBasePrompt,
12304
12523
  getCoordinatorSystemPrompt,
12305
12524
  getExtractor,
12525
+ hasDescribableEndpoints,
12306
12526
  hasProcessLifecycle,
12307
12527
  initEngine,
12308
12528
  isCoordinatorMode,