@kmugalkhod/lightcode 0.6.0 → 0.7.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/README.md +28 -0
- package/cli.js +633 -236
- package/package.json +1 -1
- package/server.js +220 -104
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -147,7 +147,7 @@ var init_src = __esm(() => {
|
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
// packages/ai/src/constants.ts
|
|
150
|
-
var MAX_TOOL_TEXT_OUTPUT_CHARS = 12000, DEFAULT_TOOL_TEXT_OUTPUT_CHARS = 6000, MAX_TOOL_LIST_ENTRIES = 200, MAX_TOOL_SEARCH_RESULTS = 200, ANTHROPIC_TOOL_OPTIONAL_PARAMETER_BUDGET = 24;
|
|
150
|
+
var MAX_TOOL_TEXT_OUTPUT_CHARS = 12000, DEFAULT_TOOL_TEXT_OUTPUT_CHARS = 6000, MAX_TOOL_LIST_ENTRIES = 200, MAX_TOOL_SEARCH_RESULTS = 200, ANTHROPIC_TOOL_OPTIONAL_PARAMETER_BUDGET = 24, TODO_CONTENT_MAX_CHARS = 200, TODO_ACTIVE_FORM_MAX_CHARS = 80, PROGRESS_NOTE_PRUNE_MIN_CHARS = 200;
|
|
151
151
|
|
|
152
152
|
// packages/ai/src/coding-agent-modes.ts
|
|
153
153
|
import { z } from "zod";
|
|
@@ -1045,20 +1045,22 @@ var init_schema10 = __esm(() => {
|
|
|
1045
1045
|
todoPrioritySchema = z14.enum(["low", "medium", "high"]);
|
|
1046
1046
|
todoItemSchema = z14.object({
|
|
1047
1047
|
id: z14.string().min(1).max(120).optional(),
|
|
1048
|
-
content: z14.string().min(1).max(
|
|
1048
|
+
content: z14.string().min(1).max(TODO_CONTENT_MAX_CHARS),
|
|
1049
1049
|
status: todoStatusSchema,
|
|
1050
1050
|
priority: todoPrioritySchema.optional().default("medium"),
|
|
1051
|
-
notes: z14.string().max(1000).optional()
|
|
1051
|
+
notes: z14.string().max(1000).optional(),
|
|
1052
|
+
activeForm: z14.string().min(1).max(TODO_ACTIVE_FORM_MAX_CHARS).optional()
|
|
1052
1053
|
});
|
|
1053
1054
|
todoItemProviderSchema = z14.object({
|
|
1054
|
-
content: z14.string().min(1).max(
|
|
1055
|
-
status: todoStatusSchema
|
|
1055
|
+
content: z14.string().min(1).max(TODO_CONTENT_MAX_CHARS),
|
|
1056
|
+
status: todoStatusSchema,
|
|
1057
|
+
activeForm: z14.string().min(1).max(TODO_ACTIVE_FORM_MAX_CHARS).optional().describe(`Short present-tense active label for this task, e.g. "Adding tests" or "Editing schema". Set it primarily for the in_progress item so the UI can show what's actively happening; the UI falls back to content when omitted.`)
|
|
1056
1058
|
});
|
|
1057
1059
|
todoWriteInputSchema = z14.object({
|
|
1058
1060
|
todos: z14.array(todoItemSchema).max(50)
|
|
1059
1061
|
});
|
|
1060
1062
|
todoWriteProviderInputSchema = z14.object({
|
|
1061
|
-
todos: z14.array(todoItemProviderSchema)
|
|
1063
|
+
todos: z14.array(todoItemProviderSchema).max(20)
|
|
1062
1064
|
});
|
|
1063
1065
|
todoWriteOutputSchema = z14.object({
|
|
1064
1066
|
sessionId: z14.string(),
|
|
@@ -1070,7 +1072,8 @@ var init_schema10 = __esm(() => {
|
|
|
1070
1072
|
inProgress: z14.number().int().nonnegative(),
|
|
1071
1073
|
completed: z14.number().int().nonnegative(),
|
|
1072
1074
|
canceled: z14.number().int().nonnegative()
|
|
1073
|
-
})
|
|
1075
|
+
}),
|
|
1076
|
+
warnings: z14.array(z14.string()).optional()
|
|
1074
1077
|
});
|
|
1075
1078
|
});
|
|
1076
1079
|
|
|
@@ -1904,14 +1907,139 @@ ${environmentContext.trim()}` : "");
|
|
|
1904
1907
|
var cwdPromptPlaceholder = "{cwd}", defaultCodingAgentSystemPrompt, toolCallingDisciplineAddendum;
|
|
1905
1908
|
var init_coding_agent_prompt = __esm(() => {
|
|
1906
1909
|
init_coding_agent_modes();
|
|
1907
|
-
defaultCodingAgentSystemPrompt = "You are a coding agent working inside the user's project at this working directory: {cwd}. " + 'You can already see the project \u2014 proactively read it. When the user asks you to review, explain, or work on "my code"/"this", inspect the working directory yourself with list_files, glob_search, grep, and read_file; NEVER ask the user to paste or share code that lives in this directory \u2014 open it. ' + "Use tools for filesystem and codebase tasks instead of guessing, and only interact with files under the working directory. " + "Prefer dedicated tools \u2014 glob_search for paths, grep for text search, structured git tools for repository inspection \u2014 and bash only when those are not enough. " + `
|
|
1910
|
+
defaultCodingAgentSystemPrompt = "You are a coding agent working inside the user's project at this working directory: {cwd}. " + 'You can already see the project \u2014 proactively read it. When the user asks you to review, explain, or work on "my code"/"this", inspect the working directory yourself with list_files, glob_search, grep, and read_file; NEVER ask the user to paste or share code that lives in this directory \u2014 open it. ' + "Use tools for filesystem and codebase tasks instead of guessing, and only interact with files under the working directory. " + "Prefer dedicated tools \u2014 glob_search for paths, grep for text search, structured git tools for repository inspection \u2014 and bash only when those are not enough. " + `Inspect context before risky operations. Progress notes: before a major tool action you may emit ONE short note (one sentence, ~15 words) saying what you are about to do. After a tool returns, mention a finding only if it changes your plan, and state it as fact grounded in what the tool actually returned \u2014 cite the file/line/symbol. NEVER claim you found, changed, or fixed something before a tool result confirms it. Skip notes for routine reads, and do not restate the todo list in prose.
|
|
1911
|
+
|
|
1912
|
+
` + `Task list discipline \u2014 use the todo_write tool to keep a visible, evolving checklist:
|
|
1913
|
+
` + `- Create the list FIRST. For any task with roughly three or more distinct steps, or any multi-file or multi-stage work, call todo_write as your very first action \u2014 before reading or editing \u2014 with every step listed and all of them set to pending.
|
|
1914
|
+
` + `- Keep exactly ONE item in_progress at a time. Mark an item in_progress immediately before you start it; never have two items in_progress at once.
|
|
1915
|
+
` + `- Mark an item completed only after a tool result confirms it is actually done (test passed, file written, build clean) \u2014 not on intent. Do this the MOMENT it is confirmed; do not batch completions or wait until the end of the turn.
|
|
1916
|
+
` + `- Completions are monotonic: once a task is completed, do not silently move it back to pending or in_progress. Reopen it only if it genuinely regressed.
|
|
1917
|
+
` + `- Every todo_write call is a FULL REWRITE of the list: always send every task with its current status (re-state the completed and pending ones too \u2014 never send only the changed item). Keep each item terse (a short label, not a paragraph).
|
|
1918
|
+
` + `- Skip the list for trivial, single-step, or purely conversational requests \u2014 a checklist there is just noise.
|
|
1908
1919
|
|
|
1909
1920
|
` + `You are an agent \u2014 keep working until the request is fully resolved. Never stop with a partial answer; if you say you will do something, do it in the same turn by calling a tool. Do not finish while any todo is pending or in_progress \u2014 end your turn only when the task is complete or you are blocked on input that only the user can provide.
|
|
1910
1921
|
|
|
1922
|
+
` + `When the task is complete, end with a short summary (a few lines) grounded in the todos you actually completed and the real file diffs \u2014 name the files you edited, do not list steps you did not verify, and do not repeat the todo card verbatim. If anything is incomplete or you are blocked, say so plainly.
|
|
1923
|
+
|
|
1911
1924
|
` + "Long-running processes (dev servers, watchers): never run them as plain foreground bash \u2014 the bash tool enforces a timeout and will kill them. Start them detached with output redirected to a log " + '(Windows: start /B cmd /c "npm run dev > dev.log 2>&1"; Unix: nohup npm run dev > dev.log 2>&1 &), then read the log to confirm startup and the actual port (do not assume the default). ' + "Never kill processes or free ports you did not open yourself.";
|
|
1912
1925
|
toolCallingDisciplineAddendum = "Invoke tools only through the function-calling interface. " + "Never write tool calls as XML or plain text such as <tool_call>, <function_call>, <invoke>, or bare JSON in your message. " + "Tool arguments must be valid JSON matching the tool's schema. " + "Call one tool at a time and wait for its result before deciding the next step.";
|
|
1913
1926
|
});
|
|
1914
1927
|
|
|
1928
|
+
// packages/ai/src/common/coerce-tool-input.ts
|
|
1929
|
+
function coercePrimitive(current, expected) {
|
|
1930
|
+
if (current === undefined || current === null) {
|
|
1931
|
+
return NO_CHANGE;
|
|
1932
|
+
}
|
|
1933
|
+
switch (expected) {
|
|
1934
|
+
case "number": {
|
|
1935
|
+
if (typeof current === "string") {
|
|
1936
|
+
const trimmed = current.trim();
|
|
1937
|
+
if (trimmed !== "" && Number.isFinite(Number(trimmed))) {
|
|
1938
|
+
return Number(trimmed);
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
return NO_CHANGE;
|
|
1942
|
+
}
|
|
1943
|
+
case "boolean": {
|
|
1944
|
+
if (typeof current === "string") {
|
|
1945
|
+
const lowered = current.trim().toLowerCase();
|
|
1946
|
+
if (lowered === "true" || lowered === "1" || lowered === "yes") {
|
|
1947
|
+
return true;
|
|
1948
|
+
}
|
|
1949
|
+
if (lowered === "false" || lowered === "0" || lowered === "no") {
|
|
1950
|
+
return false;
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
if (current === 1)
|
|
1954
|
+
return true;
|
|
1955
|
+
if (current === 0)
|
|
1956
|
+
return false;
|
|
1957
|
+
return NO_CHANGE;
|
|
1958
|
+
}
|
|
1959
|
+
case "string": {
|
|
1960
|
+
if (typeof current === "number" || typeof current === "boolean") {
|
|
1961
|
+
return String(current);
|
|
1962
|
+
}
|
|
1963
|
+
return NO_CHANGE;
|
|
1964
|
+
}
|
|
1965
|
+
case "object":
|
|
1966
|
+
case "array": {
|
|
1967
|
+
if (typeof current === "string") {
|
|
1968
|
+
try {
|
|
1969
|
+
const parsed = JSON.parse(current);
|
|
1970
|
+
const isArray = Array.isArray(parsed);
|
|
1971
|
+
const matches = expected === "array" ? isArray : parsed !== null && typeof parsed === "object" && !isArray;
|
|
1972
|
+
if (matches) {
|
|
1973
|
+
return parsed;
|
|
1974
|
+
}
|
|
1975
|
+
} catch {}
|
|
1976
|
+
}
|
|
1977
|
+
return NO_CHANGE;
|
|
1978
|
+
}
|
|
1979
|
+
default:
|
|
1980
|
+
return NO_CHANGE;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
function coerceAtPath(root, path3, expected) {
|
|
1984
|
+
if (path3.length === 0 || root === null || typeof root !== "object") {
|
|
1985
|
+
return false;
|
|
1986
|
+
}
|
|
1987
|
+
let parent = root;
|
|
1988
|
+
for (let index = 0;index < path3.length - 1; index += 1) {
|
|
1989
|
+
const next = parent[path3[index]];
|
|
1990
|
+
if (next === null || typeof next !== "object") {
|
|
1991
|
+
return false;
|
|
1992
|
+
}
|
|
1993
|
+
parent = next;
|
|
1994
|
+
}
|
|
1995
|
+
const key = path3[path3.length - 1];
|
|
1996
|
+
const coerced = coercePrimitive(parent[key], expected);
|
|
1997
|
+
if (coerced === NO_CHANGE) {
|
|
1998
|
+
return false;
|
|
1999
|
+
}
|
|
2000
|
+
parent[key] = coerced;
|
|
2001
|
+
return true;
|
|
2002
|
+
}
|
|
2003
|
+
function coerceToolInputToSchema(value, schema) {
|
|
2004
|
+
if (value === null || typeof value !== "object") {
|
|
2005
|
+
return null;
|
|
2006
|
+
}
|
|
2007
|
+
let current;
|
|
2008
|
+
try {
|
|
2009
|
+
current = structuredClone(value);
|
|
2010
|
+
} catch {
|
|
2011
|
+
current = value;
|
|
2012
|
+
}
|
|
2013
|
+
for (let pass = 0;pass < MAX_PASSES; pass += 1) {
|
|
2014
|
+
const result = schema.safeParse(current);
|
|
2015
|
+
if (result.success) {
|
|
2016
|
+
return result.data;
|
|
2017
|
+
}
|
|
2018
|
+
let changed = false;
|
|
2019
|
+
for (const issue of result.error.issues) {
|
|
2020
|
+
if (issue.code !== "invalid_type") {
|
|
2021
|
+
continue;
|
|
2022
|
+
}
|
|
2023
|
+
const expected = issue.expected;
|
|
2024
|
+
if (typeof expected !== "string") {
|
|
2025
|
+
continue;
|
|
2026
|
+
}
|
|
2027
|
+
if (coerceAtPath(current, issue.path, expected)) {
|
|
2028
|
+
changed = true;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
if (!changed) {
|
|
2032
|
+
break;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
const final = schema.safeParse(current);
|
|
2036
|
+
return final.success ? final.data : null;
|
|
2037
|
+
}
|
|
2038
|
+
var NO_CHANGE, MAX_PASSES = 4;
|
|
2039
|
+
var init_coerce_tool_input = __esm(() => {
|
|
2040
|
+
NO_CHANGE = Symbol("no-change");
|
|
2041
|
+
});
|
|
2042
|
+
|
|
1915
2043
|
// packages/ai/src/providers/tool-call-json-repair.ts
|
|
1916
2044
|
import { parsePartialJson } from "ai";
|
|
1917
2045
|
async function repairToolJson(raw) {
|
|
@@ -2106,15 +2234,19 @@ async function repairCodingAgentToolCall({
|
|
|
2106
2234
|
if (!repairedInput || typeof repairedInput !== "object") {
|
|
2107
2235
|
return null;
|
|
2108
2236
|
}
|
|
2237
|
+
const schema = codingToolProviderInputSchemas[toolCall.toolName];
|
|
2238
|
+
const coerced = schema ? coerceToolInputToSchema(repairedInput, schema) : null;
|
|
2109
2239
|
return {
|
|
2110
2240
|
...toolCall,
|
|
2111
|
-
input: JSON.stringify(repairedInput)
|
|
2241
|
+
input: JSON.stringify(coerced ?? repairedInput)
|
|
2112
2242
|
};
|
|
2113
2243
|
}
|
|
2114
2244
|
return null;
|
|
2115
2245
|
}
|
|
2116
2246
|
var toolNameAliases;
|
|
2117
2247
|
var init_coding_agent_tool_repair = __esm(() => {
|
|
2248
|
+
init_agent_tools();
|
|
2249
|
+
init_coerce_tool_input();
|
|
2118
2250
|
init_tool_call_json_repair();
|
|
2119
2251
|
toolNameAliases = {
|
|
2120
2252
|
read: "read_file",
|
|
@@ -2203,19 +2335,6 @@ function getLastUserText(messages, prompt) {
|
|
|
2203
2335
|
}
|
|
2204
2336
|
return collectTextFromUnknown(prompt).trim();
|
|
2205
2337
|
}
|
|
2206
|
-
function pushUniqueTool(tools, toolName) {
|
|
2207
|
-
if (!tools.includes(toolName)) {
|
|
2208
|
-
tools.push(toolName);
|
|
2209
|
-
}
|
|
2210
|
-
}
|
|
2211
|
-
function includesAny(text, tokens) {
|
|
2212
|
-
return tokens.some((token) => {
|
|
2213
|
-
if (token.includes("://") || token.includes(" ")) {
|
|
2214
|
-
return text.includes(token);
|
|
2215
|
-
}
|
|
2216
|
-
return new RegExp(`(^|[^a-z0-9])${token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}([^a-z0-9]|$)`).test(text);
|
|
2217
|
-
});
|
|
2218
|
-
}
|
|
2219
2338
|
function selectCodingAgentIntentTools({
|
|
2220
2339
|
mode,
|
|
2221
2340
|
prompt,
|
|
@@ -2226,75 +2345,7 @@ function selectCodingAgentIntentTools({
|
|
|
2226
2345
|
if (!normalizedText || casualPromptPattern.test(normalizedText)) {
|
|
2227
2346
|
return [];
|
|
2228
2347
|
}
|
|
2229
|
-
|
|
2230
|
-
const hasGitIntent = includesAny(normalizedText, [
|
|
2231
|
-
"git",
|
|
2232
|
-
"diff",
|
|
2233
|
-
"status",
|
|
2234
|
-
"commit",
|
|
2235
|
-
"log",
|
|
2236
|
-
"show",
|
|
2237
|
-
"revision",
|
|
2238
|
-
"changes"
|
|
2239
|
-
]);
|
|
2240
|
-
if (hasGitIntent) {
|
|
2241
|
-
if (includesAny(normalizedText, ["status", "state", "dirty", "working tree"]) || !includesAny(normalizedText, ["diff", "log", "show", "history", "commit"])) {
|
|
2242
|
-
pushUniqueTool(situational, "git_status");
|
|
2243
|
-
}
|
|
2244
|
-
if (includesAny(normalizedText, ["diff", "changes", "patch"])) {
|
|
2245
|
-
pushUniqueTool(situational, "git_diff");
|
|
2246
|
-
}
|
|
2247
|
-
if (includesAny(normalizedText, ["log", "history", "commits"])) {
|
|
2248
|
-
pushUniqueTool(situational, "git_log");
|
|
2249
|
-
}
|
|
2250
|
-
if (includesAny(normalizedText, ["show", "revision", "commit"])) {
|
|
2251
|
-
pushUniqueTool(situational, "git_show");
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2254
|
-
if (mode === "build" && includesAny(normalizedText, ["todo", "tasks", "checklist", "steps", "epic", "ticket"])) {
|
|
2255
|
-
pushUniqueTool(situational, "todo_write");
|
|
2256
|
-
}
|
|
2257
|
-
if (includesAny(normalizedText, ["tool_search", "tool search", "find tool", "available tool"])) {
|
|
2258
|
-
pushUniqueTool(situational, "tool_search");
|
|
2259
|
-
}
|
|
2260
|
-
if (includesAny(normalizedText, ["skill", "skills", "load skill"])) {
|
|
2261
|
-
pushUniqueTool(situational, "skill");
|
|
2262
|
-
}
|
|
2263
|
-
if (includesAny(normalizedText, ["mcp", "resource", "resources", "mcp tool", "mcp server"])) {
|
|
2264
|
-
pushUniqueTool(situational, "list_mcp_resources");
|
|
2265
|
-
if (includesAny(normalizedText, ["read", "resource", "resources"])) {
|
|
2266
|
-
pushUniqueTool(situational, "read_mcp_resource");
|
|
2267
|
-
}
|
|
2268
|
-
if (mode === "build" && includesAny(normalizedText, ["call", "execute", "run"])) {
|
|
2269
|
-
pushUniqueTool(situational, "call_mcp_tool");
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
if (includesAny(normalizedText, [
|
|
2273
|
-
"http://",
|
|
2274
|
-
"https://",
|
|
2275
|
-
"url",
|
|
2276
|
-
"fetch",
|
|
2277
|
-
"website",
|
|
2278
|
-
"web",
|
|
2279
|
-
"online",
|
|
2280
|
-
"search internet",
|
|
2281
|
-
"latest"
|
|
2282
|
-
])) {
|
|
2283
|
-
pushUniqueTool(situational, "web_fetch");
|
|
2284
|
-
pushUniqueTool(situational, "web_search");
|
|
2285
|
-
}
|
|
2286
|
-
if (mode === "plan" && includesAny(normalizedText, ["question", "ask", "clarify"])) {
|
|
2287
|
-
pushUniqueTool(situational, "request_user_input");
|
|
2288
|
-
}
|
|
2289
|
-
const ordered = [...baseReadTools, ...situational];
|
|
2290
|
-
if (mode === "build") {
|
|
2291
|
-
ordered.push("write_file", "edit_file", "bash");
|
|
2292
|
-
}
|
|
2293
|
-
const selected = [];
|
|
2294
|
-
for (const toolName of ordered) {
|
|
2295
|
-
pushUniqueTool(selected, toolName);
|
|
2296
|
-
}
|
|
2297
|
-
return selected.slice(0, maxProviderActiveTools);
|
|
2348
|
+
return [...getCodingAgentModeDefinition(mode).activeTools];
|
|
2298
2349
|
}
|
|
2299
2350
|
function limitProviderActiveTools(tools, maxTools = maxProviderActiveTools) {
|
|
2300
2351
|
if (tools.length <= maxTools) {
|
|
@@ -2303,15 +2354,10 @@ function limitProviderActiveTools(tools, maxTools = maxProviderActiveTools) {
|
|
|
2303
2354
|
const toolSet = new Set(tools);
|
|
2304
2355
|
return providerToolPriority.filter((toolName) => toolSet.has(toolName)).slice(0, maxTools);
|
|
2305
2356
|
}
|
|
2306
|
-
var casualPromptPattern,
|
|
2357
|
+
var casualPromptPattern, maxProviderActiveTools = 24, providerToolPriority;
|
|
2307
2358
|
var init_intent_tool_selection = __esm(() => {
|
|
2359
|
+
init_coding_agent_modes();
|
|
2308
2360
|
casualPromptPattern = /^(hi|hello|hey|how are you|how r you|what'?s up|whats up|sup|thanks|thank you|ok|okay|yes|no|nice|cool|great)[\s?!.,]*$/i;
|
|
2309
|
-
baseReadTools = [
|
|
2310
|
-
"list_files",
|
|
2311
|
-
"glob_search",
|
|
2312
|
-
"read_file",
|
|
2313
|
-
"grep"
|
|
2314
|
-
];
|
|
2315
2361
|
providerToolPriority = [
|
|
2316
2362
|
"list_files",
|
|
2317
2363
|
"glob_search",
|
|
@@ -2984,6 +3030,16 @@ function getPartState(part) {
|
|
|
2984
3030
|
const state = isRecord3(part) ? Reflect.get(part, "state") : undefined;
|
|
2985
3031
|
return typeof state === "string" ? state : null;
|
|
2986
3032
|
}
|
|
3033
|
+
function getPlainTextPartContent(part) {
|
|
3034
|
+
if (!isRecord3(part) || Reflect.get(part, "type") !== "text") {
|
|
3035
|
+
return null;
|
|
3036
|
+
}
|
|
3037
|
+
const text = Reflect.get(part, "text");
|
|
3038
|
+
return typeof text === "string" ? text : null;
|
|
3039
|
+
}
|
|
3040
|
+
function messageHasToolPart(message) {
|
|
3041
|
+
return message.parts.some((part) => getToolNameFromPart(part) !== null);
|
|
3042
|
+
}
|
|
2987
3043
|
function computePruneCutoffIndex(messages, preserveRecentMessages, quantizeUserTurns = DEFAULT_PRUNE_QUANTIZE_USER_TURNS) {
|
|
2988
3044
|
const candidate = messages.length - preserveRecentMessages;
|
|
2989
3045
|
if (candidate <= 0) {
|
|
@@ -3033,15 +3089,29 @@ function pruneToolOutputs(messages, options) {
|
|
|
3033
3089
|
});
|
|
3034
3090
|
let elidedToolOutputs = 0;
|
|
3035
3091
|
let dedupedFileReads = 0;
|
|
3092
|
+
let elidedProgressNotes = 0;
|
|
3036
3093
|
let savedChars = 0;
|
|
3037
3094
|
const prunedMessages = messages.map((message, messageIndex) => {
|
|
3038
3095
|
if (messageIndex >= cutoff) {
|
|
3039
3096
|
return message;
|
|
3040
3097
|
}
|
|
3098
|
+
const noteCandidate = message.role === "assistant" && messageHasToolPart(message);
|
|
3041
3099
|
let changed = false;
|
|
3042
3100
|
const parts = message.parts.map((part, partIndex) => {
|
|
3043
3101
|
const toolName = getToolNameFromPart(part);
|
|
3044
3102
|
if (!toolName || getPartState(part) !== "output-available") {
|
|
3103
|
+
if (noteCandidate && toolName === null) {
|
|
3104
|
+
const text = getPlainTextPartContent(part);
|
|
3105
|
+
if (text !== null && text !== PROGRESS_NOTE_ELISION_STUB && text.length > PROGRESS_NOTE_PRUNE_MIN_CHARS) {
|
|
3106
|
+
elidedProgressNotes += 1;
|
|
3107
|
+
savedChars += Math.max(0, text.length - PROGRESS_NOTE_ELISION_STUB.length);
|
|
3108
|
+
changed = true;
|
|
3109
|
+
return {
|
|
3110
|
+
...part,
|
|
3111
|
+
text: PROGRESS_NOTE_ELISION_STUB
|
|
3112
|
+
};
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3045
3115
|
return part;
|
|
3046
3116
|
}
|
|
3047
3117
|
const output = isRecord3(part) ? Reflect.get(part, "output") : undefined;
|
|
@@ -3058,7 +3128,7 @@ function pruneToolOutputs(messages, options) {
|
|
|
3058
3128
|
}
|
|
3059
3129
|
const stub = {
|
|
3060
3130
|
lightcodeElided: true,
|
|
3061
|
-
note: isStaleRead ? "Earlier read of this file elided;
|
|
3131
|
+
note: isStaleRead ? "Earlier read of this file elided; its current content is already shown later in this conversation \u2014 do not read it again." : "Large tool output elided to preserve context budget. Re-run the tool only if this output is needed again.",
|
|
3062
3132
|
originalChars: serializedOutput.length
|
|
3063
3133
|
};
|
|
3064
3134
|
if (isStaleRead) {
|
|
@@ -3076,10 +3146,11 @@ function pruneToolOutputs(messages, options) {
|
|
|
3076
3146
|
messages: prunedMessages,
|
|
3077
3147
|
elidedToolOutputs,
|
|
3078
3148
|
dedupedFileReads,
|
|
3149
|
+
elidedProgressNotes,
|
|
3079
3150
|
savedChars
|
|
3080
3151
|
};
|
|
3081
3152
|
}
|
|
3082
|
-
var DEFAULT_PRUNE_MIN_OUTPUT_CHARS = 2000, DEFAULT_PRUNE_QUANTIZE_USER_TURNS = 4;
|
|
3153
|
+
var DEFAULT_PRUNE_MIN_OUTPUT_CHARS = 2000, PROGRESS_NOTE_ELISION_STUB = "[progress note elided]", DEFAULT_PRUNE_QUANTIZE_USER_TURNS = 4;
|
|
3083
3154
|
var init_tier1_prune = __esm(() => {
|
|
3084
3155
|
init_estimate();
|
|
3085
3156
|
init_message_parts();
|
|
@@ -6104,6 +6175,22 @@ function mergeFinishedMessagesIntoFullHistory({
|
|
|
6104
6175
|
return [...fullMessages, ...appendedMessages];
|
|
6105
6176
|
}
|
|
6106
6177
|
|
|
6178
|
+
// packages/ai/src/tool-call-repeat-guard.ts
|
|
6179
|
+
var guardedTools, lastCallByTurn;
|
|
6180
|
+
var init_tool_call_repeat_guard = __esm(() => {
|
|
6181
|
+
guardedTools = new Set([
|
|
6182
|
+
"read_file",
|
|
6183
|
+
"list_files",
|
|
6184
|
+
"glob_search",
|
|
6185
|
+
"grep",
|
|
6186
|
+
"git_status",
|
|
6187
|
+
"git_diff",
|
|
6188
|
+
"git_log",
|
|
6189
|
+
"git_show"
|
|
6190
|
+
]);
|
|
6191
|
+
lastCallByTurn = new Map;
|
|
6192
|
+
});
|
|
6193
|
+
|
|
6107
6194
|
// packages/ai/src/common/resolve-within-workspace.ts
|
|
6108
6195
|
import path8 from "path";
|
|
6109
6196
|
import {
|
|
@@ -6483,6 +6570,8 @@ var init_runtime16 = __esm(() => {
|
|
|
6483
6570
|
// packages/ai/src/runtime-registry.ts
|
|
6484
6571
|
var init_runtime_registry = __esm(() => {
|
|
6485
6572
|
init_agent_tools();
|
|
6573
|
+
init_coerce_tool_input();
|
|
6574
|
+
init_tool_call_repeat_guard();
|
|
6486
6575
|
init_runtime4();
|
|
6487
6576
|
init_runtime6();
|
|
6488
6577
|
init_runtime7();
|
|
@@ -7418,6 +7507,26 @@ var init_session_auto_title = __esm(() => {
|
|
|
7418
7507
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
7419
7508
|
import { platform as platform3 } from "os";
|
|
7420
7509
|
import path11 from "path";
|
|
7510
|
+
function formatAvailableSkills(skills) {
|
|
7511
|
+
if (skills.length === 0) {
|
|
7512
|
+
return "";
|
|
7513
|
+
}
|
|
7514
|
+
const shown = skills.slice(0, maxListedSkills);
|
|
7515
|
+
const lines = shown.map((skill) => `- ${skill.name}${skill.description ? `: ${skill.description}` : ""}`);
|
|
7516
|
+
const more = skills.length > shown.length ? `
|
|
7517
|
+
\u2026 and ${skills.length - shown.length} more` : "";
|
|
7518
|
+
return `Available skills (load by name with the skill tool):
|
|
7519
|
+
${lines.join(`
|
|
7520
|
+
`)}${more}`;
|
|
7521
|
+
}
|
|
7522
|
+
function buildAvailableSkills(cwd) {
|
|
7523
|
+
try {
|
|
7524
|
+
return formatAvailableSkills(listSkills({ cwd }));
|
|
7525
|
+
} catch (error) {
|
|
7526
|
+
logger7.warn("workspace_skills_failed", { cwd, error: getErrorMessage(error) });
|
|
7527
|
+
return "";
|
|
7528
|
+
}
|
|
7529
|
+
}
|
|
7421
7530
|
function describePlatform() {
|
|
7422
7531
|
const map = {
|
|
7423
7532
|
darwin: "macOS",
|
|
@@ -7493,6 +7602,7 @@ async function buildWorkspaceContext({
|
|
|
7493
7602
|
buildGitSummary(cwd),
|
|
7494
7603
|
buildProjectDocs(cwd)
|
|
7495
7604
|
]);
|
|
7605
|
+
const skills = buildAvailableSkills(cwd);
|
|
7496
7606
|
const today = new Date().toISOString().slice(0, 10);
|
|
7497
7607
|
const parts = [
|
|
7498
7608
|
"<environment>",
|
|
@@ -7508,6 +7618,8 @@ async function buildWorkspaceContext({
|
|
|
7508
7618
|
docs ? `
|
|
7509
7619
|
Project instructions:
|
|
7510
7620
|
${docs}` : "",
|
|
7621
|
+
skills ? `
|
|
7622
|
+
${skills}` : "",
|
|
7511
7623
|
"</environment>"
|
|
7512
7624
|
];
|
|
7513
7625
|
const block = parts.join(`
|
|
@@ -7516,7 +7628,7 @@ ${docs}` : "",
|
|
|
7516
7628
|
\u2026 (environment truncated)
|
|
7517
7629
|
</environment>` : block;
|
|
7518
7630
|
}
|
|
7519
|
-
var logger7, projectDocNames, maxListedEntries = 40, maxDocChars = 1500, maxBlockChars = 8000;
|
|
7631
|
+
var logger7, projectDocNames, maxListedEntries = 40, maxListedSkills = 20, maxDocChars = 1500, maxBlockChars = 8000;
|
|
7520
7632
|
var init_workspace_context = __esm(() => {
|
|
7521
7633
|
init_runtime17();
|
|
7522
7634
|
init_src();
|
|
@@ -7555,7 +7667,8 @@ function messagesHaveToolActivity(messages) {
|
|
|
7555
7667
|
function shouldUseFastChatPath({
|
|
7556
7668
|
messages,
|
|
7557
7669
|
mode,
|
|
7558
|
-
allowedTools
|
|
7670
|
+
allowedTools,
|
|
7671
|
+
availableSkillNames = []
|
|
7559
7672
|
}) {
|
|
7560
7673
|
if (allowedTools && allowedTools.length > 0) {
|
|
7561
7674
|
return false;
|
|
@@ -7566,7 +7679,8 @@ function shouldUseFastChatPath({
|
|
|
7566
7679
|
return selectCodingAgentIntentTools({
|
|
7567
7680
|
mode,
|
|
7568
7681
|
prompt: "",
|
|
7569
|
-
messages
|
|
7682
|
+
messages,
|
|
7683
|
+
availableSkillNames
|
|
7570
7684
|
}).length === 0;
|
|
7571
7685
|
}
|
|
7572
7686
|
async function countPendingChatInteractions(sessionId) {
|
|
@@ -7884,11 +7998,13 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7884
7998
|
};
|
|
7885
7999
|
};
|
|
7886
8000
|
const environmentContext = await buildWorkspaceContext({ cwd });
|
|
8001
|
+
const availableSkillNames = listSkills({ cwd }).map((skill) => skill.name);
|
|
7887
8002
|
try {
|
|
7888
8003
|
if (shouldUseFastChatPath({
|
|
7889
8004
|
messages: providerMessages,
|
|
7890
8005
|
mode,
|
|
7891
|
-
allowedTools
|
|
8006
|
+
allowedTools,
|
|
8007
|
+
availableSkillNames
|
|
7892
8008
|
})) {
|
|
7893
8009
|
logger8.info("chat_fast_path", {
|
|
7894
8010
|
sessionId,
|