flavor-code 1.3.9 → 1.3.11
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/{app-XAV5LRM7.js → app-L52CTVNR.js} +43 -6
- package/dist/{chunk-M3U2JICC.js → chunk-IGFN2DM5.js} +174 -36
- package/dist/{chunk-D4334NAE.js → chunk-JZ5FVBET.js} +1 -1
- package/dist/cli.js +3 -3
- package/dist/desktop/main.js +177 -36
- package/dist/desktop-renderer/assets/{index-bFGsR_uj.js → index-Bl5dmm02.js} +4 -4
- package/dist/desktop-renderer/assets/index-CDxzMJ9C.css +1 -0
- package/dist/desktop-renderer/assets/{interactive-terminal-BwS6MvIe.js → interactive-terminal-CNgUWG7b.js} +1 -1
- package/dist/desktop-renderer/index.html +2 -2
- package/dist/models/structured.d.ts +13 -4
- package/dist/production.d.ts +2 -0
- package/dist/sdk/index.js +2 -2
- package/dist/tools/runtime.d.ts +5 -0
- package/dist/tools/search.d.ts +2 -2
- package/dist/ui/commands.d.ts +7 -3
- package/dist/ui/session.d.ts +5 -0
- package/package.json +1 -1
- package/dist/desktop-renderer/assets/index-CdeAi527.css +0 -1
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
redactErrorText,
|
|
17
17
|
transcriptReducer,
|
|
18
18
|
withTimeout
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-IGFN2DM5.js";
|
|
20
20
|
import "./chunk-IG4Z23CL.js";
|
|
21
21
|
import {
|
|
22
22
|
Box_default,
|
|
@@ -1257,7 +1257,7 @@ function slashCandidatePresentation(selected) {
|
|
|
1257
1257
|
matchStyle: { color: "ansi:cyan", bold: true }
|
|
1258
1258
|
};
|
|
1259
1259
|
}
|
|
1260
|
-
function buildSlashCandidates(commands, plugins, skills) {
|
|
1260
|
+
function buildSlashCandidates(commands, plugins, skills, tools = []) {
|
|
1261
1261
|
const candidates = /* @__PURE__ */ new Map();
|
|
1262
1262
|
for (const command of commands) {
|
|
1263
1263
|
candidates.set(command.name, { name: command.name, kind: "command", description: command.description });
|
|
@@ -1267,6 +1267,11 @@ function buildSlashCandidates(commands, plugins, skills) {
|
|
|
1267
1267
|
candidates.set(plugin.name, plugin.description === void 0 ? { name: plugin.name, kind: "plugin" } : { name: plugin.name, kind: "plugin", description: plugin.description });
|
|
1268
1268
|
}
|
|
1269
1269
|
}
|
|
1270
|
+
for (const tool of tools) {
|
|
1271
|
+
if (!candidates.has(tool.name)) {
|
|
1272
|
+
candidates.set(tool.name, tool.description === void 0 ? { name: tool.name, kind: "tool" } : { name: tool.name, kind: "tool", description: tool.description });
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1270
1275
|
for (const skill of skills) {
|
|
1271
1276
|
if (!candidates.has(skill.name)) {
|
|
1272
1277
|
candidates.set(skill.name, {
|
|
@@ -1850,7 +1855,8 @@ function appRuntimeOptions(props, output, onApprovalChange) {
|
|
|
1850
1855
|
...props.palAlias === void 0 ? {} : { alias: props.palAlias }
|
|
1851
1856
|
},
|
|
1852
1857
|
output,
|
|
1853
|
-
onApprovalChange
|
|
1858
|
+
onApprovalChange,
|
|
1859
|
+
onToolsChange: onApprovalChange
|
|
1854
1860
|
};
|
|
1855
1861
|
}
|
|
1856
1862
|
function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
@@ -1954,13 +1960,23 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
1954
1960
|
}
|
|
1955
1961
|
dispatch({ type: "restore", state: created.restoredTranscript });
|
|
1956
1962
|
runtimeRef.current = created;
|
|
1957
|
-
setSlashCandidates(buildSlashCandidates(
|
|
1963
|
+
setSlashCandidates(buildSlashCandidates(
|
|
1964
|
+
BUILTIN_SLASH_CANDIDATES,
|
|
1965
|
+
created.services.pluginCommands(),
|
|
1966
|
+
[],
|
|
1967
|
+
created.services.managedToolCommands()
|
|
1968
|
+
));
|
|
1958
1969
|
setRuntime(created);
|
|
1959
1970
|
await created.session.start();
|
|
1960
1971
|
try {
|
|
1961
1972
|
const skills = await created.services.skills();
|
|
1962
1973
|
if (!disposed) {
|
|
1963
|
-
setSlashCandidates(buildSlashCandidates(
|
|
1974
|
+
setSlashCandidates(buildSlashCandidates(
|
|
1975
|
+
BUILTIN_SLASH_CANDIDATES,
|
|
1976
|
+
created.services.pluginCommands(),
|
|
1977
|
+
skills,
|
|
1978
|
+
created.services.managedToolCommands()
|
|
1979
|
+
));
|
|
1964
1980
|
}
|
|
1965
1981
|
} catch {
|
|
1966
1982
|
}
|
|
@@ -1975,6 +1991,28 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
1975
1991
|
`));
|
|
1976
1992
|
};
|
|
1977
1993
|
}, [workspace, home, resumeSession, instanceId, palAlias]);
|
|
1994
|
+
useEffect3(() => {
|
|
1995
|
+
if (runtime === void 0) return;
|
|
1996
|
+
let disposed = false;
|
|
1997
|
+
void runtime.services.skills().then((skills) => {
|
|
1998
|
+
if (!disposed) setSlashCandidates(buildSlashCandidates(
|
|
1999
|
+
BUILTIN_SLASH_CANDIDATES,
|
|
2000
|
+
runtime.services.pluginCommands(),
|
|
2001
|
+
skills,
|
|
2002
|
+
runtime.services.managedToolCommands()
|
|
2003
|
+
));
|
|
2004
|
+
}).catch(() => {
|
|
2005
|
+
if (!disposed) setSlashCandidates(buildSlashCandidates(
|
|
2006
|
+
BUILTIN_SLASH_CANDIDATES,
|
|
2007
|
+
runtime.services.pluginCommands(),
|
|
2008
|
+
[],
|
|
2009
|
+
runtime.services.managedToolCommands()
|
|
2010
|
+
));
|
|
2011
|
+
});
|
|
2012
|
+
return () => {
|
|
2013
|
+
disposed = true;
|
|
2014
|
+
};
|
|
2015
|
+
}, [runtime, revision]);
|
|
1978
2016
|
useEffect3(() => installSigintHandler(process, interrupt), [interrupt]);
|
|
1979
2017
|
useEffect3(() => {
|
|
1980
2018
|
if (runtime?.services.ideContext === void 0) {
|
|
@@ -2347,7 +2385,6 @@ function App({ workspace, home, resumeSession, instanceId, palAlias }) {
|
|
|
2347
2385
|
setDismissedMentionInput(void 0);
|
|
2348
2386
|
}
|
|
2349
2387
|
});
|
|
2350
|
-
void revision;
|
|
2351
2388
|
if (runtime === void 0) return /* @__PURE__ */ jsx5(
|
|
2352
2389
|
StartingLayout,
|
|
2353
2390
|
{
|
|
@@ -56,6 +56,8 @@ function normalizeProviderError(error) {
|
|
|
56
56
|
code = "context_overflow";
|
|
57
57
|
} else if (status === 404 || /model.*not.?found|not.?found.*model/.test(searchable)) {
|
|
58
58
|
code = "model_not_found";
|
|
59
|
+
} else if (status !== void 0 && status >= 500 && status <= 599) {
|
|
60
|
+
code = "network";
|
|
59
61
|
} else if (status === void 0 && /econn|enet|socket|network|fetch failed|connection|timeout/.test(searchable)) {
|
|
60
62
|
code = "network";
|
|
61
63
|
}
|
|
@@ -1981,10 +1983,17 @@ var FILE_TYPE_EXTENSIONS = {
|
|
|
1981
1983
|
python: [".py", ".pyi"],
|
|
1982
1984
|
typescript: [".ts", ".tsx", ".mts", ".cts"]
|
|
1983
1985
|
};
|
|
1986
|
+
var BooleanInput = z.preprocess((value) => {
|
|
1987
|
+
if (typeof value !== "string") return value;
|
|
1988
|
+
const normalized = value.trim().toLowerCase();
|
|
1989
|
+
if (normalized === "true") return true;
|
|
1990
|
+
if (normalized === "false") return false;
|
|
1991
|
+
return value;
|
|
1992
|
+
}, z.boolean());
|
|
1984
1993
|
var GlobInput = z.object({
|
|
1985
1994
|
pattern: z.string().min(1),
|
|
1986
1995
|
path: z.string().min(1).describe('Workspace-relative search directory. Use JSON null, not the string "null", for the workspace root.').nullable().optional(),
|
|
1987
|
-
includeIgnored:
|
|
1996
|
+
includeIgnored: BooleanInput.describe("Include files excluded by .gitignore or .ignore. Git metadata remains excluded.").nullable().optional(),
|
|
1988
1997
|
limit: z.coerce.number().int().positive().max(1e5).nullable().optional()
|
|
1989
1998
|
});
|
|
1990
1999
|
var GrepInput = z.object({
|
|
@@ -1992,7 +2001,7 @@ var GrepInput = z.object({
|
|
|
1992
2001
|
path: z.string().min(1).describe('Workspace-relative search path. Use JSON null, not the string "null", for the workspace root.').nullable().optional(),
|
|
1993
2002
|
glob: z.string().min(1).nullable().optional(),
|
|
1994
2003
|
fileType: z.enum(FILE_TYPES).nullable().optional(),
|
|
1995
|
-
includeIgnored:
|
|
2004
|
+
includeIgnored: BooleanInput.describe("Include files excluded by .gitignore or .ignore. Git metadata remains excluded.").nullable().optional(),
|
|
1996
2005
|
context: z.coerce.number().int().nonnegative().max(100).nullable().optional(),
|
|
1997
2006
|
limit: z.coerce.number().int().positive().max(1e5).nullable().optional()
|
|
1998
2007
|
});
|
|
@@ -2987,7 +2996,8 @@ var MVP_COMMANDS = [
|
|
|
2987
2996
|
"fork",
|
|
2988
2997
|
"pals",
|
|
2989
2998
|
"chat",
|
|
2990
|
-
"co-work"
|
|
2999
|
+
"co-work",
|
|
3000
|
+
"tool"
|
|
2991
3001
|
];
|
|
2992
3002
|
var COMMAND_DESCRIPTIONS = {
|
|
2993
3003
|
model: "Switch the active model",
|
|
@@ -3025,16 +3035,24 @@ var COMMAND_DESCRIPTIONS = {
|
|
|
3025
3035
|
fork: "Continue context from a prior session node",
|
|
3026
3036
|
pals: "List, rename, or inspect active Flavor pals",
|
|
3027
3037
|
chat: "Send a task to another Flavor pal",
|
|
3028
|
-
"co-work": "Coordinate a shared goal with another Flavor pal"
|
|
3038
|
+
"co-work": "Coordinate a shared goal with another Flavor pal",
|
|
3039
|
+
tool: "Run a registered managed tool with a JSON object"
|
|
3029
3040
|
};
|
|
3030
|
-
function parseSlashCommand(input, dynamicCommands = [], skillCommands = []) {
|
|
3041
|
+
function parseSlashCommand(input, dynamicCommands = [], skillCommands = [], managedTools = []) {
|
|
3031
3042
|
const trimmed = input.trim();
|
|
3032
3043
|
if (!trimmed.startsWith("/")) return null;
|
|
3033
|
-
const
|
|
3044
|
+
const match = /^(\S+)(?:\s+([\s\S]*))?$/u.exec(trimmed.slice(1));
|
|
3045
|
+
const rawName = match?.[1] ?? "";
|
|
3046
|
+
const rawArguments = match?.[2] ?? "";
|
|
3047
|
+
const args = rawArguments.length === 0 ? [] : rawArguments.split(/\s+/u);
|
|
3034
3048
|
const name = rawName.toLowerCase();
|
|
3035
3049
|
if (!MVP_COMMANDS.includes(name) && dynamicCommands.includes(name)) {
|
|
3036
3050
|
return { name: "plugin", command: name, args };
|
|
3037
3051
|
}
|
|
3052
|
+
if (!MVP_COMMANDS.includes(name)) {
|
|
3053
|
+
const managedTool = managedTools.find((tool) => tool.toLowerCase() === name);
|
|
3054
|
+
if (managedTool !== void 0) return { name: "managed-tool", tool: managedTool, input: rawArguments };
|
|
3055
|
+
}
|
|
3038
3056
|
if (!MVP_COMMANDS.includes(name) && skillCommands.includes(name)) {
|
|
3039
3057
|
return { name: "skill", skill: name, prompt: args.join(" ") };
|
|
3040
3058
|
}
|
|
@@ -3056,6 +3074,15 @@ function parseSlashCommand(input, dynamicCommands = [], skillCommands = []) {
|
|
|
3056
3074
|
}
|
|
3057
3075
|
return { name, mode: normalized };
|
|
3058
3076
|
}
|
|
3077
|
+
if (name === "tool") {
|
|
3078
|
+
const [requested] = args;
|
|
3079
|
+
const managedTool = requested === void 0 ? void 0 : managedTools.find((candidate) => candidate.toLowerCase() === requested.toLowerCase());
|
|
3080
|
+
if (managedTool === void 0) {
|
|
3081
|
+
return { name: "invalid", command: name, message: "Use /tool <registered-tool> [JSON object]." };
|
|
3082
|
+
}
|
|
3083
|
+
const inputStart = rawArguments.search(/\s/u);
|
|
3084
|
+
return { name: "managed-tool", tool: managedTool, input: inputStart < 0 ? "" : rawArguments.slice(inputStart).trimStart() };
|
|
3085
|
+
}
|
|
3059
3086
|
if (name === "audit") {
|
|
3060
3087
|
const toolFilter = args.length > 0 ? args.join(" ") : void 0;
|
|
3061
3088
|
return { name, toolFilter };
|
|
@@ -3283,6 +3310,7 @@ var HELP = [
|
|
|
3283
3310
|
"/review [focus] review uncommitted changes before committing",
|
|
3284
3311
|
"/evolve <signals|suggest|improve <id>|verify <name>|reload <name>|test|revert <name>|done <id>> self-improvement loop",
|
|
3285
3312
|
"/mcp [status|tools|reconnect|enable|disable] manage MCP servers",
|
|
3313
|
+
"/tool <registered-tool> [JSON object] run a registered tool (or use /<tool-name>)",
|
|
3286
3314
|
"/ide show VS Code connection and cursor/selection",
|
|
3287
3315
|
"/pals [--verbose|rename <alias>|info <alias-or-uuid>]",
|
|
3288
3316
|
"/chat <alias-or-uuid> <goal> send a task that starts on the receiving pal",
|
|
@@ -3554,7 +3582,12 @@ var FlavorSession = class {
|
|
|
3554
3582
|
} catch {
|
|
3555
3583
|
}
|
|
3556
3584
|
}
|
|
3557
|
-
const command = parseSlashCommand(
|
|
3585
|
+
const command = parseSlashCommand(
|
|
3586
|
+
prompt,
|
|
3587
|
+
this.#services.pluginCommands().map(({ name }) => name),
|
|
3588
|
+
skillNames,
|
|
3589
|
+
this.#services.managedToolCommands().map(({ name }) => name)
|
|
3590
|
+
);
|
|
3558
3591
|
if (command !== null) await this.#dispatch(command, controller.signal);
|
|
3559
3592
|
else for await (const event of this.#services.run(prompt, controller.signal, {
|
|
3560
3593
|
getSteeringMessages: () => this.#drainMessages("steer", true).map((item) => item.text),
|
|
@@ -3656,6 +3689,8 @@ var FlavorSession = class {
|
|
|
3656
3689
|
this.#notice(`Main permissions set to ${command.mode}. Child approvals use bubble mode unless plan mode is active.`);
|
|
3657
3690
|
} else if (command.name === "plugin") {
|
|
3658
3691
|
this.#notice(format(await this.#services.runPluginCommand(command.command, command.args, signal)));
|
|
3692
|
+
} else if (command.name === "managed-tool") {
|
|
3693
|
+
this.#notice(format(await this.#services.runManagedTool(command.tool, command.input, signal)));
|
|
3659
3694
|
} else if (command.name === "skill") {
|
|
3660
3695
|
for await (const event of this.#services.runSkill(command.skill, command.prompt, signal)) this.#services.output(event);
|
|
3661
3696
|
} else if (command.name === "loop") {
|
|
@@ -6527,9 +6562,10 @@ function withStructuredOutput(options) {
|
|
|
6527
6562
|
throw new Error("Structured output retry delays must be non-negative integers");
|
|
6528
6563
|
}
|
|
6529
6564
|
}
|
|
6530
|
-
const
|
|
6565
|
+
const generatedTool = options.modelInputSchema === void 0 ? modelToolFromZod(options.name, options.description, options.schema) : { name: options.name, description: options.description, inputSchema: options.modelInputSchema };
|
|
6566
|
+
const tool = options.modelStrict === void 0 ? generatedTool : { ...generatedTool, strict: options.modelStrict };
|
|
6531
6567
|
const maxAttempts = retry.maxRetries + 1;
|
|
6532
|
-
const
|
|
6568
|
+
const validationSchema = jsonSchemaFromZod(options.schema);
|
|
6533
6569
|
const model = {
|
|
6534
6570
|
async *stream(request) {
|
|
6535
6571
|
let candidate;
|
|
@@ -6602,7 +6638,7 @@ function withStructuredOutput(options) {
|
|
|
6602
6638
|
}
|
|
6603
6639
|
}
|
|
6604
6640
|
if (candidateCount === 1 && candidate !== null && typeof candidate === "object") {
|
|
6605
|
-
candidate = coerceByJsonSchema(candidate,
|
|
6641
|
+
candidate = coerceByJsonSchema(candidate, validationSchema);
|
|
6606
6642
|
}
|
|
6607
6643
|
if (candidateCount !== 1) {
|
|
6608
6644
|
attemptError = {
|
|
@@ -6674,7 +6710,13 @@ function withStructuredOutput(options) {
|
|
|
6674
6710
|
return model;
|
|
6675
6711
|
}
|
|
6676
6712
|
function strictJsonSchema(schema) {
|
|
6677
|
-
return
|
|
6713
|
+
return strictJsonSchemaObject(jsonSchemaFromZod(schema));
|
|
6714
|
+
}
|
|
6715
|
+
function jsonSchemaFromZod(schema) {
|
|
6716
|
+
return z7.toJSONSchema(schema);
|
|
6717
|
+
}
|
|
6718
|
+
function strictJsonSchemaObject(schema) {
|
|
6719
|
+
return ensureStrictSchema(schema);
|
|
6678
6720
|
}
|
|
6679
6721
|
function extractJsonObject(text) {
|
|
6680
6722
|
const trimmed = text.trim();
|
|
@@ -6722,6 +6764,7 @@ function coerceByJsonSchema(value, schema) {
|
|
|
6722
6764
|
const node = schema;
|
|
6723
6765
|
const branches = [
|
|
6724
6766
|
...Array.isArray(node.anyOf) ? node.anyOf : [],
|
|
6767
|
+
...Array.isArray(node.oneOf) ? node.oneOf : [],
|
|
6725
6768
|
...Array.isArray(node.allOf) ? node.allOf : []
|
|
6726
6769
|
].filter((branch) => branch !== null && typeof branch === "object");
|
|
6727
6770
|
const types = [];
|
|
@@ -6741,40 +6784,108 @@ function coerceByJsonSchema(value, schema) {
|
|
|
6741
6784
|
if (lowered === "true") return true;
|
|
6742
6785
|
if (lowered === "false") return false;
|
|
6743
6786
|
}
|
|
6787
|
+
if (types.includes("object") && !types.includes("string") && typeof value === "string") {
|
|
6788
|
+
const trimmed = value.trim();
|
|
6789
|
+
if (trimmed.startsWith("{")) {
|
|
6790
|
+
try {
|
|
6791
|
+
const parsed = JSON.parse(trimmed);
|
|
6792
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
6793
|
+
return coerceByJsonSchema(parsed, node);
|
|
6794
|
+
}
|
|
6795
|
+
} catch {
|
|
6796
|
+
}
|
|
6797
|
+
}
|
|
6798
|
+
}
|
|
6799
|
+
if (types.includes("array") && !Array.isArray(value) && value !== null && value !== void 0 && !types.some((type) => matchesJsonSchemaType(value, type))) {
|
|
6800
|
+
const arraySchema = [node, ...branches].find((candidate) => {
|
|
6801
|
+
const type = candidate.type;
|
|
6802
|
+
return type === "array" || Array.isArray(type) && type.includes("array");
|
|
6803
|
+
});
|
|
6804
|
+
if (typeof value === "string" && value.trim().startsWith("[")) {
|
|
6805
|
+
try {
|
|
6806
|
+
const parsed = JSON.parse(value.trim());
|
|
6807
|
+
if (Array.isArray(parsed)) return coerceByJsonSchema(parsed, arraySchema ?? node);
|
|
6808
|
+
} catch {
|
|
6809
|
+
}
|
|
6810
|
+
}
|
|
6811
|
+
return [arraySchema?.items === void 0 ? value : coerceByJsonSchema(value, arraySchema.items)];
|
|
6812
|
+
}
|
|
6744
6813
|
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
6745
|
-
const
|
|
6814
|
+
const objectSchema = [node, ...branches].find((candidate) => candidate.type === "object" || candidate.properties !== void 0);
|
|
6815
|
+
const properties = objectSchema?.properties;
|
|
6746
6816
|
if (properties !== void 0) {
|
|
6747
6817
|
const output = {};
|
|
6818
|
+
const required2 = new Set(Array.isArray(objectSchema?.required) ? objectSchema.required : []);
|
|
6748
6819
|
for (const [key, child] of Object.entries(value)) {
|
|
6749
|
-
|
|
6820
|
+
const childSchema = properties[key];
|
|
6821
|
+
if (child === null && childSchema !== void 0 && !required2.has(key) && !jsonSchemaAllowsNull(childSchema)) {
|
|
6822
|
+
continue;
|
|
6823
|
+
}
|
|
6824
|
+
output[key] = childSchema !== void 0 ? coerceByJsonSchema(child, childSchema) : child;
|
|
6750
6825
|
}
|
|
6751
6826
|
return output;
|
|
6752
6827
|
}
|
|
6753
6828
|
}
|
|
6754
|
-
if (types.includes("array") && Array.isArray(value)
|
|
6755
|
-
|
|
6829
|
+
if (types.includes("array") && Array.isArray(value)) {
|
|
6830
|
+
const arraySchema = [node, ...branches].find((candidate) => {
|
|
6831
|
+
const type = candidate.type;
|
|
6832
|
+
return type === "array" || Array.isArray(type) && type.includes("array");
|
|
6833
|
+
});
|
|
6834
|
+
if (arraySchema?.items !== void 0) {
|
|
6835
|
+
return value.map((item) => coerceByJsonSchema(item, arraySchema.items));
|
|
6836
|
+
}
|
|
6756
6837
|
}
|
|
6757
6838
|
return value;
|
|
6758
6839
|
}
|
|
6840
|
+
function matchesJsonSchemaType(value, type) {
|
|
6841
|
+
if (type === "null") return value === null;
|
|
6842
|
+
if (type === "array") return Array.isArray(value);
|
|
6843
|
+
if (type === "object") return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
6844
|
+
if (type === "integer") return typeof value === "number" && Number.isInteger(value);
|
|
6845
|
+
if (type === "number") return typeof value === "number";
|
|
6846
|
+
return typeof value === type;
|
|
6847
|
+
}
|
|
6848
|
+
function jsonSchemaAllowsNull(schema) {
|
|
6849
|
+
if (schema === null || typeof schema !== "object") return false;
|
|
6850
|
+
const node = schema;
|
|
6851
|
+
if (node.type === "null" || Array.isArray(node.type) && node.type.includes("null")) return true;
|
|
6852
|
+
return [node.anyOf, node.oneOf].some((branches) => Array.isArray(branches) && branches.some((branch) => jsonSchemaAllowsNull(branch)));
|
|
6853
|
+
}
|
|
6759
6854
|
function modelToolFromZod(name, description, schema) {
|
|
6760
6855
|
return { name, description, inputSchema: strictJsonSchema(schema) };
|
|
6761
6856
|
}
|
|
6762
6857
|
function ensureStrictSchema(schema) {
|
|
6858
|
+
const output = { ...schema };
|
|
6859
|
+
for (const keyword of ["anyOf", "oneOf", "allOf", "prefixItems"]) {
|
|
6860
|
+
const branches = schema[keyword];
|
|
6861
|
+
if (Array.isArray(branches)) {
|
|
6862
|
+
output[keyword] = branches.map((branch) => typeof branch === "object" && branch !== null ? ensureStrictSchema(branch) : branch);
|
|
6863
|
+
}
|
|
6864
|
+
}
|
|
6865
|
+
if (typeof schema.items === "object" && schema.items !== null) {
|
|
6866
|
+
output.items = ensureStrictSchema(schema.items);
|
|
6867
|
+
}
|
|
6868
|
+
for (const keyword of ["$defs", "definitions"]) {
|
|
6869
|
+
const definitions = schema[keyword];
|
|
6870
|
+
if (typeof definitions === "object" && definitions !== null && !Array.isArray(definitions)) {
|
|
6871
|
+
output[keyword] = Object.fromEntries(Object.entries(definitions).map(([key, definition]) => [
|
|
6872
|
+
key,
|
|
6873
|
+
typeof definition === "object" && definition !== null ? ensureStrictSchema(definition) : definition
|
|
6874
|
+
]));
|
|
6875
|
+
}
|
|
6876
|
+
}
|
|
6763
6877
|
if (schema.type !== "object" || typeof schema.properties !== "object" || schema.properties === null) {
|
|
6764
|
-
return
|
|
6878
|
+
return output;
|
|
6765
6879
|
}
|
|
6766
|
-
const
|
|
6767
|
-
const requiredSet = new Set(required2);
|
|
6880
|
+
const requiredSet = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
6768
6881
|
const properties = {};
|
|
6769
6882
|
for (const [key, value] of Object.entries(schema.properties)) {
|
|
6770
6883
|
const child = typeof value === "object" && value !== null ? ensureStrictSchema(value) : value;
|
|
6771
|
-
if (requiredSet.has(key)) properties[key] = child;
|
|
6772
|
-
else {
|
|
6773
|
-
|
|
6774
|
-
requiredSet.add(key);
|
|
6775
|
-
}
|
|
6884
|
+
if (requiredSet.has(key) || jsonSchemaAllowsNull(child)) properties[key] = child;
|
|
6885
|
+
else properties[key] = { anyOf: [child, { type: "null" }] };
|
|
6886
|
+
requiredSet.add(key);
|
|
6776
6887
|
}
|
|
6777
|
-
return { ...
|
|
6888
|
+
return { ...output, additionalProperties: false, required: [...requiredSet], properties };
|
|
6778
6889
|
}
|
|
6779
6890
|
function repairMessages(messages, tool, original, candidate, error) {
|
|
6780
6891
|
const details = [
|
|
@@ -7144,19 +7255,11 @@ var AgentLoop = class {
|
|
|
7144
7255
|
});
|
|
7145
7256
|
continue;
|
|
7146
7257
|
}
|
|
7147
|
-
const validation = collected.kind === "valid" ? this.#options.runtime.
|
|
7258
|
+
const validation = collected.kind === "valid" ? this.#options.runtime.normalize(collected) : { ok: false, error: collected.error };
|
|
7148
7259
|
if (validation.ok) {
|
|
7149
7260
|
toolCalls.push({ id: collected.id, name: collected.name, input: validation.input });
|
|
7150
7261
|
continue;
|
|
7151
7262
|
}
|
|
7152
|
-
if (collected.kind === "valid") {
|
|
7153
|
-
const coerced = coerceByJsonSchema(collected.input, strictJsonSchema(definition.inputSchema));
|
|
7154
|
-
const revalidation = this.#options.runtime.validate({ ...collected, input: coerced });
|
|
7155
|
-
if (revalidation.ok) {
|
|
7156
|
-
toolCalls.push({ id: collected.id, name: collected.name, input: revalidation.input });
|
|
7157
|
-
continue;
|
|
7158
|
-
}
|
|
7159
|
-
}
|
|
7160
7263
|
const repairModelId = this.#options.fallbackModelId ?? this.#options.modelId;
|
|
7161
7264
|
const invalidOutput = collected.kind === "invalid" ? collected.rawInput : serializeToolInput(collected.input);
|
|
7162
7265
|
const structured = withStructuredOutput({
|
|
@@ -7165,6 +7268,8 @@ var AgentLoop = class {
|
|
|
7165
7268
|
name: definition.name,
|
|
7166
7269
|
description: definition.description,
|
|
7167
7270
|
schema: definition.inputSchema,
|
|
7271
|
+
...definition.modelInputSchema === void 0 ? {} : { modelInputSchema: definition.modelInputSchema },
|
|
7272
|
+
...definition.modelStrict === void 0 ? {} : { modelStrict: definition.modelStrict },
|
|
7168
7273
|
beforeAttempt: async ({ attempt: repairAttempt, maxAttempts: repairMaxAttempts, messageCount }) => {
|
|
7169
7274
|
const before = await this.#options.hooks.emit({
|
|
7170
7275
|
version: 1,
|
|
@@ -7645,12 +7750,24 @@ var ToolRuntime = class {
|
|
|
7645
7750
|
throw error;
|
|
7646
7751
|
}
|
|
7647
7752
|
}
|
|
7753
|
+
/**
|
|
7754
|
+
* Validates a call and applies the same conservative provider-argument
|
|
7755
|
+
* normalization used by the agent loop before falling back to repair.
|
|
7756
|
+
*/
|
|
7757
|
+
normalize(call) {
|
|
7758
|
+
const validation = this.validate(call);
|
|
7759
|
+
if (validation.ok || validation.error.code === "unknown_tool") return validation;
|
|
7760
|
+
const tool = this.#tools.get(call.name);
|
|
7761
|
+
if (tool === void 0) return validation;
|
|
7762
|
+
const input = coerceByJsonSchema(call.input, jsonSchemaFromZod(tool.inputSchema));
|
|
7763
|
+
return this.validate({ ...call, input });
|
|
7764
|
+
}
|
|
7648
7765
|
async #execute(call, context) {
|
|
7649
7766
|
const tool = this.#tools.get(call.name);
|
|
7650
7767
|
if (tool === void 0) return { ok: false, error: { code: "unknown_tool", message: `Unknown tool: ${call.name}` } };
|
|
7651
7768
|
const signal = context.signal ?? new AbortController().signal;
|
|
7652
7769
|
const toolCallId = call.id ?? randomUUID7();
|
|
7653
|
-
const validation = this.
|
|
7770
|
+
const validation = this.normalize(call);
|
|
7654
7771
|
if (!validation.ok) {
|
|
7655
7772
|
return this.#fail(toolCallId, call.name, call.input, context.agent, validation.error.code, validation.error.message);
|
|
7656
7773
|
}
|
|
@@ -9379,6 +9496,7 @@ var PluginHost = class {
|
|
|
9379
9496
|
description: contribution.description,
|
|
9380
9497
|
inputSchema: z13.unknown(),
|
|
9381
9498
|
...contribution.modelInputSchema === void 0 ? {} : { modelInputSchema: contribution.modelInputSchema },
|
|
9499
|
+
...contribution.modelInputSchema === void 0 ? {} : { modelStrict: false },
|
|
9382
9500
|
...contribution.readOnly === void 0 ? {} : { readOnly: contribution.readOnly },
|
|
9383
9501
|
paths: () => [],
|
|
9384
9502
|
execute: (input, _signal, toolContext) => session.invoke("tool", contribution.name, [
|
|
@@ -17786,7 +17904,7 @@ function compileDefinition(record, scope2, workspace) {
|
|
|
17786
17904
|
name: record.name,
|
|
17787
17905
|
description: record.description,
|
|
17788
17906
|
inputSchema,
|
|
17789
|
-
modelInputSchema: record.inputSchema,
|
|
17907
|
+
modelInputSchema: strictJsonSchemaObject(record.inputSchema),
|
|
17790
17908
|
modelStrict: true,
|
|
17791
17909
|
...record.agents === void 0 ? {} : { agents: record.agents },
|
|
17792
17910
|
paths: () => [],
|
|
@@ -20850,6 +20968,7 @@ async function createProductionRuntime(options) {
|
|
|
20850
20968
|
managedTools.push(tool);
|
|
20851
20969
|
}
|
|
20852
20970
|
if (harnessCreated) harness.replaceMainTools(tools);
|
|
20971
|
+
options.onToolsChange?.();
|
|
20853
20972
|
};
|
|
20854
20973
|
tools.push(...createManagedToolManagementTools({
|
|
20855
20974
|
store: managedToolStore,
|
|
@@ -22179,6 +22298,25 @@ ${renderMemoryDocument(entries)}`;
|
|
|
22179
22298
|
signal.throwIfAborted();
|
|
22180
22299
|
return awaitWithSignal(Promise.resolve(handler(args, { workspace, signal })), signal);
|
|
22181
22300
|
},
|
|
22301
|
+
managedToolCommands: () => managedTools.map(({ name, description }) => ({ name, description })).sort((left, right) => left.name.localeCompare(right.name)),
|
|
22302
|
+
runManagedTool: async (name, rawInput, signal) => {
|
|
22303
|
+
const tool = managedTools.find((candidate) => sameToolName(candidate.name, name));
|
|
22304
|
+
if (tool === void 0) throw new Error(`Registered tool "${name}" is no longer available.`);
|
|
22305
|
+
signal.throwIfAborted();
|
|
22306
|
+
const input = normalizeToolCallInput(rawInput);
|
|
22307
|
+
const call = { name: tool.name, input };
|
|
22308
|
+
const validation = harness.main.runtime.normalize(call);
|
|
22309
|
+
if (!validation.ok) throw new Error(`Invalid input for registered tool "${tool.name}": ${validation.error.message}`);
|
|
22310
|
+
harness.main.runtime.beginTurn();
|
|
22311
|
+
const result = await harness.main.runtime.execute(
|
|
22312
|
+
{ name: tool.name, input: validation.input },
|
|
22313
|
+
{ agent: "main", ownerId: "main", signal }
|
|
22314
|
+
);
|
|
22315
|
+
if (!result.ok) {
|
|
22316
|
+
throw new Error(`Registered tool "${tool.name}" failed (${result.error?.code ?? "unknown"}): ${result.error?.message ?? "Unknown error"}`);
|
|
22317
|
+
}
|
|
22318
|
+
return result.output !== void 0 ? result.output : result.content;
|
|
22319
|
+
},
|
|
22182
22320
|
output: emitOutput,
|
|
22183
22321
|
questions,
|
|
22184
22322
|
async login() {
|
|
@@ -22573,7 +22711,7 @@ ${expandSkillArguments(await skills.loadBody(skill), prompt)}`);
|
|
|
22573
22711
|
...additionalContext === void 0 ? {} : { additionalContext },
|
|
22574
22712
|
...getSteeringMessages === void 0 ? {} : { getSteeringMessages }
|
|
22575
22713
|
})) {
|
|
22576
|
-
if (event.type === "error" && /adapter|provider|api.?key|model/i.test(event.error.message)) {
|
|
22714
|
+
if (event.type === "error" && event.error.code !== "network" && event.error.code !== "rate_limit" && /adapter|provider|api.?key|model/i.test(event.error.message)) {
|
|
22577
22715
|
yield { ...event, error: {
|
|
22578
22716
|
...event.error,
|
|
22579
22717
|
message: `${event.error.message}. Configure providers and agents in .flavor/flavor.json or set OPENAI_API_KEY/ANTHROPIC_API_KEY.`
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module"; const require = createRequire(impor
|
|
|
3
3
|
import {
|
|
4
4
|
FlavorRpcServer,
|
|
5
5
|
TraceRecorder
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JZ5FVBET.js";
|
|
7
7
|
import {
|
|
8
8
|
staticTaskLines
|
|
9
9
|
} from "./chunk-KKIBYDJI.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
packageVersion,
|
|
24
24
|
redactErrorText,
|
|
25
25
|
runPalBroker
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-IGFN2DM5.js";
|
|
27
27
|
import {
|
|
28
28
|
McpServerConfigSchema,
|
|
29
29
|
McpServerNameSchema,
|
|
@@ -877,7 +877,7 @@ async function runInteractiveCli(props) {
|
|
|
877
877
|
const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
|
|
878
878
|
import("./claude-ink-ORUA7GWG.js"),
|
|
879
879
|
import("react"),
|
|
880
|
-
import("./app-
|
|
880
|
+
import("./app-L52CTVNR.js")
|
|
881
881
|
]);
|
|
882
882
|
const instance = await render(createElement(
|
|
883
883
|
AlternateScreen,
|