la-machina-engine 0.12.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);
@@ -10427,16 +10618,8 @@ var NodeBackgroundExecutor = class {
10427
10618
  // src/engine/webhook.ts
10428
10619
  init_cjs_shims();
10429
10620
  var RETRY_DELAYS_MS = [
10430
- 0,
10431
- // attempt 1: immediate
10432
- 1e4,
10433
- // attempt 2: 10s after failure
10434
- 6e4,
10435
- // attempt 3: 60s after failure
10436
- 5 * 6e4,
10437
- // attempt 4: 5min after failure
10438
- 30 * 6e4
10439
- // attempt 5: 30min after failure
10621
+ 0
10622
+ // attempt 1: immediate (Plan 046 — single attempt only)
10440
10623
  ];
10441
10624
  var MAX_ATTEMPTS = RETRY_DELAYS_MS.length;
10442
10625
  async function signPayload(secret, timestamp, body) {
@@ -10607,7 +10790,13 @@ var Engine = class {
10607
10790
  provider: this.config.model.provider,
10608
10791
  registeredToolNames: toolNameSet,
10609
10792
  mcpTools,
10610
- 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
+ } : {}
10611
10800
  });
10612
10801
  if (options.outputFormat === "json") {
10613
10802
  systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
@@ -10805,7 +10994,13 @@ var Engine = class {
10805
10994
  provider: this.config.model.provider,
10806
10995
  registeredToolNames: toolNameSet,
10807
10996
  mcpTools,
10808
- 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
+ } : {}
10809
11004
  });
10810
11005
  if (options.outputFormat === "json") {
10811
11006
  systemPrompt += "\n\n" + buildSchemaPrompt(options.outputSchema);
@@ -12096,6 +12291,21 @@ function buildToolRegistry(options) {
12096
12291
  registry.register(apiTool);
12097
12292
  childRegistry.register(apiTool);
12098
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
+ }
12099
12309
  }
12100
12310
  if (options.toolResultOffload?.enabled === true) {
12101
12311
  if (!disabled.has("FetchData") && (wantAll || enabled.has("FetchData"))) {
@@ -12182,9 +12392,9 @@ init_contract();
12182
12392
 
12183
12393
  // src/tools/capabilityStub.ts
12184
12394
  init_cjs_shims();
12185
- var import_zod27 = require("zod");
12395
+ var import_zod28 = require("zod");
12186
12396
  init_contract();
12187
- var anyInput = import_zod27.z.unknown();
12397
+ var anyInput = import_zod28.z.unknown();
12188
12398
  function capabilityStub(original) {
12189
12399
  return defineTool({
12190
12400
  name: original.name,
@@ -12295,6 +12505,7 @@ function resolveApiKey(config) {
12295
12505
  canSpawnProcesses,
12296
12506
  capabilityStub,
12297
12507
  createApiCallTool,
12508
+ createDescribeServiceTool,
12298
12509
  createFetchDataTool,
12299
12510
  createLogger,
12300
12511
  createModelAdapter,
@@ -12311,6 +12522,7 @@ function resolveApiKey(config) {
12311
12522
  getCoordinatorBasePrompt,
12312
12523
  getCoordinatorSystemPrompt,
12313
12524
  getExtractor,
12525
+ hasDescribableEndpoints,
12314
12526
  hasProcessLifecycle,
12315
12527
  initEngine,
12316
12528
  isCoordinatorMode,