la-machina-engine 0.7.2 → 0.7.4
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 +94 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -8
- package/dist/index.d.ts +65 -8
- package/dist/index.js +94 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1280,6 +1280,18 @@ interface StreamRequest {
|
|
|
1280
1280
|
readonly tools?: readonly ModelToolDefinition[] | undefined;
|
|
1281
1281
|
readonly maxTokens?: number | undefined;
|
|
1282
1282
|
readonly temperature?: number | undefined;
|
|
1283
|
+
/**
|
|
1284
|
+
* Tool-call policy (Plan 025). Default: `'auto'` (model decides).
|
|
1285
|
+
* - `'auto'` — model picks; pass-through behavior
|
|
1286
|
+
* - `'required'` — model MUST call a tool on its next response;
|
|
1287
|
+
* translated per-provider (Anthropic:
|
|
1288
|
+
* `tool_choice: { type: 'any' }`; OpenAI / AI SDK:
|
|
1289
|
+
* `toolChoice: 'required'`).
|
|
1290
|
+
*
|
|
1291
|
+
* Note: `'none'` is handled engine-side by stripping `tools` before
|
|
1292
|
+
* the request reaches the adapter, so adapters never see it.
|
|
1293
|
+
*/
|
|
1294
|
+
readonly toolChoice?: 'auto' | 'required' | undefined;
|
|
1283
1295
|
}
|
|
1284
1296
|
|
|
1285
1297
|
interface ModelAdapter {
|
|
@@ -2000,7 +2012,30 @@ interface RunOptions {
|
|
|
2000
2012
|
readonly runId?: string;
|
|
2001
2013
|
readonly nodeId: string;
|
|
2002
2014
|
readonly task: string;
|
|
2015
|
+
/**
|
|
2016
|
+
* Per-run tool allowlist (Plan 025). When undefined, the run sees
|
|
2017
|
+
* every tool registered at engine init (subject to
|
|
2018
|
+
* `config.tools.enabled / disabled`). When provided, the visible
|
|
2019
|
+
* tool set is further restricted to this exact list — names that
|
|
2020
|
+
* aren't registered are silently ignored. Pass `[]` to disable
|
|
2021
|
+
* all tools for this run; equivalent to `toolChoice: 'none'`.
|
|
2022
|
+
*/
|
|
2003
2023
|
readonly tools?: readonly string[] | undefined;
|
|
2024
|
+
/**
|
|
2025
|
+
* Tool-call policy for this run (Plan 025). Default: `'auto'`.
|
|
2026
|
+
* - `'auto'` — model decides whether to call tools
|
|
2027
|
+
* - `'none'` — model is told it has no tools; tools list is
|
|
2028
|
+
* stripped before the model adapter sees it
|
|
2029
|
+
* - `'required'` — model MUST call a tool on its next response;
|
|
2030
|
+
* plumbed to the provider as the "force tool use"
|
|
2031
|
+
* flag (Anthropic: `tool_choice: { type: 'any' }`,
|
|
2032
|
+
* OpenAI / AI SDK: `toolChoice: 'required'`)
|
|
2033
|
+
*
|
|
2034
|
+
* Precedence: `'none'` wins over any `tools: [...]` allowlist.
|
|
2035
|
+
* `'required'` paired with an empty effective tool set throws
|
|
2036
|
+
* `ERR_TOOL_CHOICE_CONFLICT` at run start.
|
|
2037
|
+
*/
|
|
2038
|
+
readonly toolChoice?: 'auto' | 'none' | 'required' | undefined;
|
|
2004
2039
|
readonly context?: Readonly<Record<string, unknown>> | undefined;
|
|
2005
2040
|
/** Override maxTurns for this run only. Used by the orchestrator for per-phase budgets. */
|
|
2006
2041
|
readonly maxTurns?: number | undefined;
|
|
@@ -2020,11 +2055,19 @@ interface RunOptions {
|
|
|
2020
2055
|
*/
|
|
2021
2056
|
readonly outputFormat?: 'text' | 'json' | undefined;
|
|
2022
2057
|
/**
|
|
2023
|
-
*
|
|
2024
|
-
* Injected into system prompt
|
|
2025
|
-
* validate the model's response.
|
|
2058
|
+
* Schema for structured output. Only used when outputFormat is 'json'.
|
|
2059
|
+
* Injected into the system prompt and (for Zod schemas) used to
|
|
2060
|
+
* validate the model's response.
|
|
2061
|
+
*
|
|
2062
|
+
* Two shapes accepted:
|
|
2063
|
+
* - A Zod schema — strictly validated via `safeParse`; retries
|
|
2064
|
+
* once on failure with a corrective prompt.
|
|
2065
|
+
* - A plain JSON Schema object — used verbatim in the prompt; no
|
|
2066
|
+
* server-side strict validation (callers wanting that should
|
|
2067
|
+
* pass Zod). This shape is what serialized workflow definitions
|
|
2068
|
+
* (e.g. nikaido) carry, since they can't embed Zod instances.
|
|
2026
2069
|
*/
|
|
2027
|
-
readonly outputSchema?: zod.ZodTypeAny | undefined;
|
|
2070
|
+
readonly outputSchema?: zod.ZodTypeAny | Record<string, unknown> | undefined;
|
|
2028
2071
|
/**
|
|
2029
2072
|
* Per-run skill override (Plan 017). When present, the engine IGNORES
|
|
2030
2073
|
* `config.skills.autoload` + `config.skills.path` and uses this list
|
|
@@ -3047,11 +3090,21 @@ declare const defaultToolResultSummarizer: ToolResultSummarizerV1;
|
|
|
3047
3090
|
* All pure JS — no `node:` imports, Workers-compatible.
|
|
3048
3091
|
*/
|
|
3049
3092
|
|
|
3093
|
+
/**
|
|
3094
|
+
* Schema users can supply for structured output. Either:
|
|
3095
|
+
* - a Zod schema (typed validation, runs `safeParse` post-parse), or
|
|
3096
|
+
* - a plain JSON Schema object (used verbatim in the system prompt;
|
|
3097
|
+
* no strict server-side validation in v1).
|
|
3098
|
+
*
|
|
3099
|
+
* Workflow definitions stored as JSON (e.g. nikaido) can only carry
|
|
3100
|
+
* the JSON Schema variant; native TS callers may use either.
|
|
3101
|
+
*/
|
|
3102
|
+
type OutputSchema = ZodTypeAny | Record<string, unknown>;
|
|
3050
3103
|
/**
|
|
3051
3104
|
* Build the output format section to append to the system prompt.
|
|
3052
3105
|
* Called when outputFormat is 'json'.
|
|
3053
3106
|
*/
|
|
3054
|
-
declare function buildSchemaPrompt(schema?:
|
|
3107
|
+
declare function buildSchemaPrompt(schema?: OutputSchema): string;
|
|
3055
3108
|
interface ParseResult {
|
|
3056
3109
|
readonly ok: boolean;
|
|
3057
3110
|
readonly value?: unknown;
|
|
@@ -3065,10 +3118,14 @@ interface ParseResult {
|
|
|
3065
3118
|
*/
|
|
3066
3119
|
declare function tryParseJSON(text: string): ParseResult;
|
|
3067
3120
|
/**
|
|
3068
|
-
* Validate parsed JSON against a
|
|
3069
|
-
*
|
|
3121
|
+
* Validate parsed JSON against a schema.
|
|
3122
|
+
*
|
|
3123
|
+
* Zod schemas get strict `safeParse` validation. Plain JSON Schema
|
|
3124
|
+
* objects are NOT strictly validated (skipping ajv keeps the bundle
|
|
3125
|
+
* small for Workers); the prompt-injected schema is the contract and
|
|
3126
|
+
* the caller can validate downstream if needed.
|
|
3070
3127
|
*/
|
|
3071
|
-
declare function validateOutput(value: unknown, schema:
|
|
3128
|
+
declare function validateOutput(value: unknown, schema: OutputSchema): {
|
|
3072
3129
|
ok: true;
|
|
3073
3130
|
data: unknown;
|
|
3074
3131
|
} | {
|
package/dist/index.d.ts
CHANGED
|
@@ -1280,6 +1280,18 @@ interface StreamRequest {
|
|
|
1280
1280
|
readonly tools?: readonly ModelToolDefinition[] | undefined;
|
|
1281
1281
|
readonly maxTokens?: number | undefined;
|
|
1282
1282
|
readonly temperature?: number | undefined;
|
|
1283
|
+
/**
|
|
1284
|
+
* Tool-call policy (Plan 025). Default: `'auto'` (model decides).
|
|
1285
|
+
* - `'auto'` — model picks; pass-through behavior
|
|
1286
|
+
* - `'required'` — model MUST call a tool on its next response;
|
|
1287
|
+
* translated per-provider (Anthropic:
|
|
1288
|
+
* `tool_choice: { type: 'any' }`; OpenAI / AI SDK:
|
|
1289
|
+
* `toolChoice: 'required'`).
|
|
1290
|
+
*
|
|
1291
|
+
* Note: `'none'` is handled engine-side by stripping `tools` before
|
|
1292
|
+
* the request reaches the adapter, so adapters never see it.
|
|
1293
|
+
*/
|
|
1294
|
+
readonly toolChoice?: 'auto' | 'required' | undefined;
|
|
1283
1295
|
}
|
|
1284
1296
|
|
|
1285
1297
|
interface ModelAdapter {
|
|
@@ -2000,7 +2012,30 @@ interface RunOptions {
|
|
|
2000
2012
|
readonly runId?: string;
|
|
2001
2013
|
readonly nodeId: string;
|
|
2002
2014
|
readonly task: string;
|
|
2015
|
+
/**
|
|
2016
|
+
* Per-run tool allowlist (Plan 025). When undefined, the run sees
|
|
2017
|
+
* every tool registered at engine init (subject to
|
|
2018
|
+
* `config.tools.enabled / disabled`). When provided, the visible
|
|
2019
|
+
* tool set is further restricted to this exact list — names that
|
|
2020
|
+
* aren't registered are silently ignored. Pass `[]` to disable
|
|
2021
|
+
* all tools for this run; equivalent to `toolChoice: 'none'`.
|
|
2022
|
+
*/
|
|
2003
2023
|
readonly tools?: readonly string[] | undefined;
|
|
2024
|
+
/**
|
|
2025
|
+
* Tool-call policy for this run (Plan 025). Default: `'auto'`.
|
|
2026
|
+
* - `'auto'` — model decides whether to call tools
|
|
2027
|
+
* - `'none'` — model is told it has no tools; tools list is
|
|
2028
|
+
* stripped before the model adapter sees it
|
|
2029
|
+
* - `'required'` — model MUST call a tool on its next response;
|
|
2030
|
+
* plumbed to the provider as the "force tool use"
|
|
2031
|
+
* flag (Anthropic: `tool_choice: { type: 'any' }`,
|
|
2032
|
+
* OpenAI / AI SDK: `toolChoice: 'required'`)
|
|
2033
|
+
*
|
|
2034
|
+
* Precedence: `'none'` wins over any `tools: [...]` allowlist.
|
|
2035
|
+
* `'required'` paired with an empty effective tool set throws
|
|
2036
|
+
* `ERR_TOOL_CHOICE_CONFLICT` at run start.
|
|
2037
|
+
*/
|
|
2038
|
+
readonly toolChoice?: 'auto' | 'none' | 'required' | undefined;
|
|
2004
2039
|
readonly context?: Readonly<Record<string, unknown>> | undefined;
|
|
2005
2040
|
/** Override maxTurns for this run only. Used by the orchestrator for per-phase budgets. */
|
|
2006
2041
|
readonly maxTurns?: number | undefined;
|
|
@@ -2020,11 +2055,19 @@ interface RunOptions {
|
|
|
2020
2055
|
*/
|
|
2021
2056
|
readonly outputFormat?: 'text' | 'json' | undefined;
|
|
2022
2057
|
/**
|
|
2023
|
-
*
|
|
2024
|
-
* Injected into system prompt
|
|
2025
|
-
* validate the model's response.
|
|
2058
|
+
* Schema for structured output. Only used when outputFormat is 'json'.
|
|
2059
|
+
* Injected into the system prompt and (for Zod schemas) used to
|
|
2060
|
+
* validate the model's response.
|
|
2061
|
+
*
|
|
2062
|
+
* Two shapes accepted:
|
|
2063
|
+
* - A Zod schema — strictly validated via `safeParse`; retries
|
|
2064
|
+
* once on failure with a corrective prompt.
|
|
2065
|
+
* - A plain JSON Schema object — used verbatim in the prompt; no
|
|
2066
|
+
* server-side strict validation (callers wanting that should
|
|
2067
|
+
* pass Zod). This shape is what serialized workflow definitions
|
|
2068
|
+
* (e.g. nikaido) carry, since they can't embed Zod instances.
|
|
2026
2069
|
*/
|
|
2027
|
-
readonly outputSchema?: zod.ZodTypeAny | undefined;
|
|
2070
|
+
readonly outputSchema?: zod.ZodTypeAny | Record<string, unknown> | undefined;
|
|
2028
2071
|
/**
|
|
2029
2072
|
* Per-run skill override (Plan 017). When present, the engine IGNORES
|
|
2030
2073
|
* `config.skills.autoload` + `config.skills.path` and uses this list
|
|
@@ -3047,11 +3090,21 @@ declare const defaultToolResultSummarizer: ToolResultSummarizerV1;
|
|
|
3047
3090
|
* All pure JS — no `node:` imports, Workers-compatible.
|
|
3048
3091
|
*/
|
|
3049
3092
|
|
|
3093
|
+
/**
|
|
3094
|
+
* Schema users can supply for structured output. Either:
|
|
3095
|
+
* - a Zod schema (typed validation, runs `safeParse` post-parse), or
|
|
3096
|
+
* - a plain JSON Schema object (used verbatim in the system prompt;
|
|
3097
|
+
* no strict server-side validation in v1).
|
|
3098
|
+
*
|
|
3099
|
+
* Workflow definitions stored as JSON (e.g. nikaido) can only carry
|
|
3100
|
+
* the JSON Schema variant; native TS callers may use either.
|
|
3101
|
+
*/
|
|
3102
|
+
type OutputSchema = ZodTypeAny | Record<string, unknown>;
|
|
3050
3103
|
/**
|
|
3051
3104
|
* Build the output format section to append to the system prompt.
|
|
3052
3105
|
* Called when outputFormat is 'json'.
|
|
3053
3106
|
*/
|
|
3054
|
-
declare function buildSchemaPrompt(schema?:
|
|
3107
|
+
declare function buildSchemaPrompt(schema?: OutputSchema): string;
|
|
3055
3108
|
interface ParseResult {
|
|
3056
3109
|
readonly ok: boolean;
|
|
3057
3110
|
readonly value?: unknown;
|
|
@@ -3065,10 +3118,14 @@ interface ParseResult {
|
|
|
3065
3118
|
*/
|
|
3066
3119
|
declare function tryParseJSON(text: string): ParseResult;
|
|
3067
3120
|
/**
|
|
3068
|
-
* Validate parsed JSON against a
|
|
3069
|
-
*
|
|
3121
|
+
* Validate parsed JSON against a schema.
|
|
3122
|
+
*
|
|
3123
|
+
* Zod schemas get strict `safeParse` validation. Plain JSON Schema
|
|
3124
|
+
* objects are NOT strictly validated (skipping ajv keeps the bundle
|
|
3125
|
+
* small for Workers); the prompt-injected schema is the contract and
|
|
3126
|
+
* the caller can validate downstream if needed.
|
|
3070
3127
|
*/
|
|
3071
|
-
declare function validateOutput(value: unknown, schema:
|
|
3128
|
+
declare function validateOutput(value: unknown, schema: OutputSchema): {
|
|
3072
3129
|
ok: true;
|
|
3073
3130
|
data: unknown;
|
|
3074
3131
|
} | {
|
package/dist/index.js
CHANGED
|
@@ -1716,7 +1716,11 @@ var AnthropicClient = class {
|
|
|
1716
1716
|
messages: request.messages,
|
|
1717
1717
|
stream: true,
|
|
1718
1718
|
...request.system !== void 0 ? { system: request.system } : {},
|
|
1719
|
-
...request.tools !== void 0 ? { tools: request.tools } : {}
|
|
1719
|
+
...request.tools !== void 0 ? { tools: request.tools } : {},
|
|
1720
|
+
// Plan 025 — `'required'` maps to Anthropic's `tool_choice: { type: 'any' }`,
|
|
1721
|
+
// which forces the model to call SOME tool but doesn't pin which.
|
|
1722
|
+
// `'auto'` is the SDK default — omit to let it through unchanged.
|
|
1723
|
+
...request.toolChoice === "required" ? { tool_choice: { type: "any" } } : {}
|
|
1720
1724
|
};
|
|
1721
1725
|
const requestOptions = {};
|
|
1722
1726
|
if (betas.length > 0) {
|
|
@@ -1898,6 +1902,9 @@ var AISdkAdapter = class {
|
|
|
1898
1902
|
tools,
|
|
1899
1903
|
...request.maxTokens !== void 0 ? { maxOutputTokens: request.maxTokens } : {},
|
|
1900
1904
|
...request.temperature !== void 0 ? { temperature: request.temperature } : {},
|
|
1905
|
+
// Plan 025 — pass through `'required'` so the AI SDK forwards it
|
|
1906
|
+
// to the provider as that provider's "force tool call" flag.
|
|
1907
|
+
...request.toolChoice === "required" ? { toolChoice: "required" } : {},
|
|
1901
1908
|
maxRetries: this.options.maxRetries ?? 2
|
|
1902
1909
|
});
|
|
1903
1910
|
for await (const event of result.fullStream) {
|
|
@@ -2517,6 +2524,17 @@ function ensureToolResultPairing(messages) {
|
|
|
2517
2524
|
return messages;
|
|
2518
2525
|
}
|
|
2519
2526
|
|
|
2527
|
+
// src/engine/lastTurnGuard.ts
|
|
2528
|
+
init_esm_shims();
|
|
2529
|
+
var LAST_TURN_INSTRUCTION_JSON = "SYSTEM NOTE: This is your final allowed turn. Emit ONLY the JSON object that satisfies the output schema in the system prompt. Do not call any more tools. Do not write any explanation, narration, or markdown \u2014 only the raw JSON.";
|
|
2530
|
+
var LAST_TURN_INSTRUCTION_TEXT = "SYSTEM NOTE: This is your final allowed turn. Stop calling tools and deliver your final answer now. The next turn will not happen.";
|
|
2531
|
+
function lastTurnInstruction(outputFormat) {
|
|
2532
|
+
return outputFormat === "json" ? LAST_TURN_INSTRUCTION_JSON : LAST_TURN_INSTRUCTION_TEXT;
|
|
2533
|
+
}
|
|
2534
|
+
function shouldInjectLastTurnInstruction(opts) {
|
|
2535
|
+
return opts.turnCount + 1 === opts.maxTurns;
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2520
2538
|
// src/compact/compactor.ts
|
|
2521
2539
|
init_esm_shims();
|
|
2522
2540
|
|
|
@@ -3008,15 +3026,29 @@ async function agentLoop(options) {
|
|
|
3008
3026
|
const toolCalls = [];
|
|
3009
3027
|
let stopReason = null;
|
|
3010
3028
|
let turnUsage = { input: 0, output: 0 };
|
|
3029
|
+
let messagesForApi = messages;
|
|
3030
|
+
if (shouldInjectLastTurnInstruction({
|
|
3031
|
+
turnCount: ctx.getTurnCount(),
|
|
3032
|
+
maxTurns: ctx.getMaxTurns()
|
|
3033
|
+
})) {
|
|
3034
|
+
messagesForApi = [
|
|
3035
|
+
...messages,
|
|
3036
|
+
{
|
|
3037
|
+
role: "user",
|
|
3038
|
+
content: [{ type: "text", text: lastTurnInstruction(options.outputFormat) }]
|
|
3039
|
+
}
|
|
3040
|
+
];
|
|
3041
|
+
}
|
|
3011
3042
|
const normalizedMessages = normalizeMessages(
|
|
3012
|
-
|
|
3043
|
+
messagesForApi
|
|
3013
3044
|
);
|
|
3014
3045
|
try {
|
|
3015
3046
|
for await (const event of client.streamMessage({
|
|
3016
3047
|
messages: normalizedMessages,
|
|
3017
3048
|
system,
|
|
3018
3049
|
tools: anthropicTools,
|
|
3019
|
-
...escalatedMaxTokens !== void 0 ? { maxTokens: escalatedMaxTokens } : {}
|
|
3050
|
+
...escalatedMaxTokens !== void 0 ? { maxTokens: escalatedMaxTokens } : {},
|
|
3051
|
+
...options.toolChoice !== void 0 ? { toolChoice: options.toolChoice } : {}
|
|
3020
3052
|
})) {
|
|
3021
3053
|
const handled = consumeEvent(event);
|
|
3022
3054
|
if (handled.text !== void 0) textBlocks.push(handled.text);
|
|
@@ -3567,6 +3599,9 @@ var RunContext = class {
|
|
|
3567
3599
|
getTurnCount() {
|
|
3568
3600
|
return this.turnCount;
|
|
3569
3601
|
}
|
|
3602
|
+
getMaxTurns() {
|
|
3603
|
+
return this.maxTurns;
|
|
3604
|
+
}
|
|
3570
3605
|
getTokensUsed() {
|
|
3571
3606
|
return this.tokensUsed;
|
|
3572
3607
|
}
|
|
@@ -7767,6 +7802,9 @@ async function collectSkills(storage, skillsDir) {
|
|
|
7767
7802
|
// src/engine/jsonOutput.ts
|
|
7768
7803
|
init_esm_shims();
|
|
7769
7804
|
import { zodToJsonSchema as zodToJsonSchema2 } from "zod-to-json-schema";
|
|
7805
|
+
function isZodSchema(s) {
|
|
7806
|
+
return s !== null && typeof s === "object" && "_def" in s && typeof s.safeParse === "function";
|
|
7807
|
+
}
|
|
7770
7808
|
function buildSchemaPrompt(schema) {
|
|
7771
7809
|
const lines = [
|
|
7772
7810
|
"# Output Format",
|
|
@@ -7776,11 +7814,18 @@ function buildSchemaPrompt(schema) {
|
|
|
7776
7814
|
"Do NOT wrap in ```json ... ```. Just raw JSON."
|
|
7777
7815
|
];
|
|
7778
7816
|
if (schema) {
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7817
|
+
let clean;
|
|
7818
|
+
if (isZodSchema(schema)) {
|
|
7819
|
+
const jsonSchema2 = zodToJsonSchema2(schema, {
|
|
7820
|
+
target: "jsonSchema7",
|
|
7821
|
+
$refStrategy: "none"
|
|
7822
|
+
});
|
|
7823
|
+
const { $schema: _z, ...rest } = jsonSchema2;
|
|
7824
|
+
clean = rest;
|
|
7825
|
+
} else {
|
|
7826
|
+
const { $schema: _j, ...rest } = schema;
|
|
7827
|
+
clean = rest;
|
|
7828
|
+
}
|
|
7784
7829
|
lines.push("", "The JSON MUST conform to this schema:", JSON.stringify(clean, null, 2));
|
|
7785
7830
|
} else {
|
|
7786
7831
|
lines.push("", "Return a JSON object with the relevant data.");
|
|
@@ -7816,6 +7861,9 @@ function tryParseJSON2(text2) {
|
|
|
7816
7861
|
return { ok: false, error: "No valid JSON found in response" };
|
|
7817
7862
|
}
|
|
7818
7863
|
function validateOutput(value, schema) {
|
|
7864
|
+
if (!isZodSchema(schema)) {
|
|
7865
|
+
return { ok: true, data: value };
|
|
7866
|
+
}
|
|
7819
7867
|
const result = schema.safeParse(value);
|
|
7820
7868
|
if (result.success) {
|
|
7821
7869
|
return { ok: true, data: result.data };
|
|
@@ -9552,6 +9600,35 @@ var TranscriptReader = class {
|
|
|
9552
9600
|
}
|
|
9553
9601
|
};
|
|
9554
9602
|
|
|
9603
|
+
// src/engine/runToolFilter.ts
|
|
9604
|
+
init_esm_shims();
|
|
9605
|
+
function applyRunToolFilter(registry, options) {
|
|
9606
|
+
const stripAll = options.toolChoice === "none" || options.tools !== void 0 && options.tools.length === 0;
|
|
9607
|
+
if (stripAll) {
|
|
9608
|
+
if (options.toolChoice === "required") {
|
|
9609
|
+
throw new EngineError(
|
|
9610
|
+
"ERR_TOOL_CHOICE_CONFLICT",
|
|
9611
|
+
"toolChoice: 'required' is incompatible with an empty tool set (received tools: [] or toolChoice: 'none')."
|
|
9612
|
+
);
|
|
9613
|
+
}
|
|
9614
|
+
for (const tool of registry.list()) {
|
|
9615
|
+
registry.unregister(tool.name);
|
|
9616
|
+
}
|
|
9617
|
+
return;
|
|
9618
|
+
}
|
|
9619
|
+
if (options.tools === void 0) return;
|
|
9620
|
+
const allow = new Set(options.tools);
|
|
9621
|
+
for (const tool of registry.list()) {
|
|
9622
|
+
if (!allow.has(tool.name)) registry.unregister(tool.name);
|
|
9623
|
+
}
|
|
9624
|
+
if (options.toolChoice === "required" && registry.count() === 0) {
|
|
9625
|
+
throw new EngineError(
|
|
9626
|
+
"ERR_TOOL_CHOICE_CONFLICT",
|
|
9627
|
+
"toolChoice: 'required' was requested but no tools matched the per-run allowlist after applying config filters."
|
|
9628
|
+
);
|
|
9629
|
+
}
|
|
9630
|
+
}
|
|
9631
|
+
|
|
9555
9632
|
// src/engine/rehydrate.ts
|
|
9556
9633
|
init_esm_shims();
|
|
9557
9634
|
function rebuildMessagesFromEntries(entries) {
|
|
@@ -10028,6 +10105,7 @@ var Engine = class {
|
|
|
10028
10105
|
...knowledgeRuntime !== void 0 ? { knowledge: knowledgeRuntime } : {},
|
|
10029
10106
|
...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
|
|
10030
10107
|
});
|
|
10108
|
+
applyRunToolFilter(registry, options);
|
|
10031
10109
|
const writer = new TranscriptWriter({
|
|
10032
10110
|
storage: storage.workspace,
|
|
10033
10111
|
logPath,
|
|
@@ -10082,7 +10160,14 @@ var Engine = class {
|
|
|
10082
10160
|
...runTimeout.signal !== void 0 ? { runSignal: runTimeout.signal, runTimeoutMs: this.config.execution.runTimeoutMs } : {},
|
|
10083
10161
|
...gate !== void 0 ? { gateBeforeTool: gate } : {},
|
|
10084
10162
|
..._internal?.handoffToRunner === true ? { handoffToRunner: true } : {},
|
|
10085
|
-
...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {}
|
|
10163
|
+
...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {},
|
|
10164
|
+
// Plan 025 — output mode + tool-choice plumbed down so the
|
|
10165
|
+
// last-turn guard picks the right instruction text and the
|
|
10166
|
+
// model adapter can pass `'required'` to the provider. `'none'`
|
|
10167
|
+
// is already handled above by stripping the tool list, so the
|
|
10168
|
+
// loop only ever sees `'auto'` or `'required'`.
|
|
10169
|
+
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|
|
10170
|
+
...options.toolChoice === "required" ? { toolChoice: "required" } : {}
|
|
10086
10171
|
});
|
|
10087
10172
|
const result = await this.finalizeResult(loopResult, writer, logPath, {
|
|
10088
10173
|
...options.outputFormat !== void 0 ? { outputFormat: options.outputFormat } : {},
|