code-ollama 0.24.0 → 0.24.1
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.
|
@@ -1411,7 +1411,7 @@ function ChatInput({ history: sessionHistory, isDisabled = false, onInterrupt, o
|
|
|
1411
1411
|
}
|
|
1412
1412
|
//#endregion
|
|
1413
1413
|
//#region src/components/Chat/constants.ts
|
|
1414
|
-
var ACTION_NOT_PERFORMED = "The requested action
|
|
1414
|
+
var ACTION_NOT_PERFORMED = "The requested action did not complete successfully";
|
|
1415
1415
|
var PLAN_CHECKLIST_REMINDER = "Then display the plan using either the Plan Needs Input or Proposed Plan Markdown template";
|
|
1416
1416
|
var PLAN_EXECUTION_REMINDER = `Do not claim success and do not call ${Array.from(WRITE_TOOLS).join(", ")} until the user approves execution`;
|
|
1417
1417
|
var ChatActionType = /* @__PURE__ */ function(ChatActionType) {
|
|
@@ -1445,6 +1445,18 @@ function hasExecutablePlan(content) {
|
|
|
1445
1445
|
const nextSectionIndex = lines.findIndex((line, index) => index > executionStepsIndex && /^#{1,6}\s+\S/.test(line.trim()));
|
|
1446
1446
|
return lines.slice(executionStepsIndex + 1, nextSectionIndex === -1 ? void 0 : nextSectionIndex).some((line) => /^(?:[-*]|\d+[.)])\s+\S/.test(line.trim()));
|
|
1447
1447
|
}
|
|
1448
|
+
function isPlanModeFinal(content) {
|
|
1449
|
+
const firstHeading = content.split("\n").find((line) => line.trim())?.trim().toLowerCase();
|
|
1450
|
+
return isPlanNeedsInput(content) || firstHeading === "## proposed plan";
|
|
1451
|
+
}
|
|
1452
|
+
function isPlanNeedsInput(content) {
|
|
1453
|
+
return content.split("\n").find((line) => line.trim())?.trim().toLowerCase() === "## plan needs input";
|
|
1454
|
+
}
|
|
1455
|
+
function isDirectPlanAnswer(content) {
|
|
1456
|
+
const normalized = content.trim();
|
|
1457
|
+
if (!normalized || isPlanModeFinal(normalized)) return false;
|
|
1458
|
+
return !/^(?:research(?: is)? complete|done)\.?$/i.test(normalized);
|
|
1459
|
+
}
|
|
1448
1460
|
//#endregion
|
|
1449
1461
|
//#region src/components/Chat/reducer.ts
|
|
1450
1462
|
function createInitialChatState(messages = []) {
|
|
@@ -1667,7 +1679,9 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1667
1679
|
toolResultMessages.push(buildToolResultMessage(toolCall.function.name, {
|
|
1668
1680
|
content: "",
|
|
1669
1681
|
// v8 ignore next
|
|
1670
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1682
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1683
|
+
// v8 ignore next
|
|
1684
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
1671
1685
|
}));
|
|
1672
1686
|
}
|
|
1673
1687
|
nextMessages = [...updatedMessages, ...toolResultMessages];
|
|
@@ -1746,7 +1760,7 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1746
1760
|
mode,
|
|
1747
1761
|
theme
|
|
1748
1762
|
]);
|
|
1749
|
-
const processStreamReadOnly = useCallback(async (currentMessages) => {
|
|
1763
|
+
const processStreamReadOnly = useCallback(async (currentMessages, toolIntentCorrections = 0) => {
|
|
1750
1764
|
const modelName = model;
|
|
1751
1765
|
// v8 ignore next
|
|
1752
1766
|
if (!modelName) throw new Error("Model is required");
|
|
@@ -1843,7 +1857,9 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1843
1857
|
/* v8 ignore start */
|
|
1844
1858
|
const toolResultMessage = buildToolResultMessage(toolCall.function.name, {
|
|
1845
1859
|
content: "",
|
|
1846
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1860
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1861
|
+
// v8 ignore next
|
|
1862
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
1847
1863
|
});
|
|
1848
1864
|
const newMessages = [...updatedMessages, toolResultMessage];
|
|
1849
1865
|
dispatch({
|
|
@@ -1866,6 +1882,13 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1866
1882
|
}
|
|
1867
1883
|
await prewarmCodeBlocks(assistantMessage.content, theme);
|
|
1868
1884
|
const researchMessages = commitAssistantMessage();
|
|
1885
|
+
if (isPlanNeedsInput(assistantMessage.content)) {
|
|
1886
|
+
dispatch({
|
|
1887
|
+
type: ChatActionType.SetLoading,
|
|
1888
|
+
isLoading: false
|
|
1889
|
+
});
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1869
1892
|
if (hasExecutablePlan(assistantMessage.content)) {
|
|
1870
1893
|
dispatch({
|
|
1871
1894
|
type: ChatActionType.RequestPlanReview,
|
|
@@ -1876,6 +1899,32 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
1876
1899
|
});
|
|
1877
1900
|
return;
|
|
1878
1901
|
}
|
|
1902
|
+
if (hasUncalledToolIntent(assistantMessage.content) && toolIntentCorrections < MAX_TOOL_INTENT_CORRECTIONS) {
|
|
1903
|
+
const correctedMessages = [...researchMessages, {
|
|
1904
|
+
role: SYSTEM,
|
|
1905
|
+
content: TOOL_INTENT_CORRECTION
|
|
1906
|
+
}];
|
|
1907
|
+
dispatch({
|
|
1908
|
+
type: ChatActionType.CommitMessages,
|
|
1909
|
+
messages: correctedMessages
|
|
1910
|
+
});
|
|
1911
|
+
await processStreamReadOnly(correctedMessages, toolIntentCorrections + 1);
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
if (isPlanModeFinal(assistantMessage.content)) {
|
|
1915
|
+
dispatch({
|
|
1916
|
+
type: ChatActionType.SetLoading,
|
|
1917
|
+
isLoading: false
|
|
1918
|
+
});
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
if (currentMessages.some((message) => !!message.toolResult) && isDirectPlanAnswer(assistantMessage.content)) {
|
|
1922
|
+
dispatch({
|
|
1923
|
+
type: ChatActionType.SetLoading,
|
|
1924
|
+
isLoading: false
|
|
1925
|
+
});
|
|
1926
|
+
return;
|
|
1927
|
+
}
|
|
1879
1928
|
const planInstruction = {
|
|
1880
1929
|
role: SYSTEM,
|
|
1881
1930
|
content: PLAN_GENERATION_INSTRUCTION
|
|
@@ -2003,6 +2052,13 @@ function Chat({ initialMessages, model, onCommand, onMessagesChange, mode, onMod
|
|
|
2003
2052
|
});
|
|
2004
2053
|
switch (decision) {
|
|
2005
2054
|
case APPROVE: {
|
|
2055
|
+
dispatch({
|
|
2056
|
+
type: ChatActionType.SetStreamingMessage,
|
|
2057
|
+
message: {
|
|
2058
|
+
role: ASSISTANT,
|
|
2059
|
+
content: ""
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2006
2062
|
const result = await executeToolCall(toolCall);
|
|
2007
2063
|
const toolResultMessage = buildToolResultMessage(toolCall.function.name, result, toolCall.function.arguments);
|
|
2008
2064
|
const newMessages = [...approvedMessages, toolResultMessage];
|
package/dist/cli.js
CHANGED
|
@@ -50,7 +50,7 @@ var LIST$1 = [
|
|
|
50
50
|
//#endregion
|
|
51
51
|
//#region package.json
|
|
52
52
|
var name = "code-ollama";
|
|
53
|
-
var version = "0.24.
|
|
53
|
+
var version = "0.24.1";
|
|
54
54
|
//#endregion
|
|
55
55
|
//#region src/constants/package.ts
|
|
56
56
|
var NAME = name;
|
|
@@ -230,10 +230,18 @@ Use the exact headings shown below
|
|
|
230
230
|
${PLAN_RESPONSE_TEMPLATE}`;
|
|
231
231
|
var PLAN_INSTRUCTION = `Plan mode is active
|
|
232
232
|
|
|
233
|
+
Explore first:
|
|
234
|
+
- If the user provides an exact file path, inspect it with read_file before planning changes
|
|
235
|
+
- If the user asks "where", names an identifier/symbol, or asks where behavior is implemented, search the codebase with grep_search before answering
|
|
236
|
+
- If the user asks about project structure without a target identifier or path, use list_dir or find_files to locate likely files
|
|
237
|
+
- Prefer targeted grep_search for exact names over broad directory listing when the user provides an identifier
|
|
238
|
+
- After each read-only tool result, decide whether another read-only tool would materially improve the answer
|
|
239
|
+
- Do not produce Plan Needs Input while also saying you will use another read-only tool; call that tool instead
|
|
240
|
+
|
|
233
241
|
Only use read-only tools: ${PLAN_READ_TOOLS}
|
|
234
242
|
Do not call ${PLAN_WRITE_TOOLS} during Plan mode
|
|
235
243
|
Use read-only tools to resolve discoverable facts before asking questions
|
|
236
|
-
If the user asks to search, inspect, find, read, or
|
|
244
|
+
If the user asks to search, inspect, find, read, locate, change, adjust, update, edit, configure, or identify something, use read-only tools immediately
|
|
237
245
|
Only ask questions for user preferences or product decisions that cannot be discovered from available tools
|
|
238
246
|
When enough context is available, stop calling tools and produce either Plan Needs Input or Proposed Plan using the required template
|
|
239
247
|
|
|
@@ -956,6 +964,11 @@ var SHELL_EXEC_OPTIONS = {
|
|
|
956
964
|
timeout: 3e4,
|
|
957
965
|
maxBuffer: 1024 * 1024
|
|
958
966
|
};
|
|
967
|
+
function getErrorOutput(error) {
|
|
968
|
+
if (typeof error !== "object" || error === null) return "";
|
|
969
|
+
const output = error;
|
|
970
|
+
return [output.stdout, output.stderr].filter((value) => typeof value === "string" && !!value).join("\n");
|
|
971
|
+
}
|
|
959
972
|
/**
|
|
960
973
|
* Execute shell command with shared options (throws on error)
|
|
961
974
|
*/
|
|
@@ -970,9 +983,12 @@ async function runShell(command) {
|
|
|
970
983
|
const { stdout, stderr } = await execShell(command);
|
|
971
984
|
return { content: stdout || stderr };
|
|
972
985
|
} catch (error) {
|
|
986
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
973
987
|
return {
|
|
974
|
-
content:
|
|
975
|
-
error: `Command failed: ${
|
|
988
|
+
content: getErrorOutput(error),
|
|
989
|
+
error: `Command failed: ${message}`,
|
|
990
|
+
// v8 ignore next
|
|
991
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
976
992
|
};
|
|
977
993
|
}
|
|
978
994
|
}
|
|
@@ -1617,14 +1633,16 @@ function normalizeToolCall(toolCall) {
|
|
|
1617
1633
|
}
|
|
1618
1634
|
function formatToolResultContent(toolName, result, args) {
|
|
1619
1635
|
const formattedArgs = args ? `(${formatToolArguments(args)})` : "";
|
|
1620
|
-
const status = result.error ? "The requested action
|
|
1636
|
+
const status = result.error ? "The requested action did not complete successfully" : "";
|
|
1621
1637
|
const content = result.content ? `\n${result.content}` : "";
|
|
1622
1638
|
const error = result.error ? `\nError: ${result.error}` : "";
|
|
1639
|
+
const stack = result.error && result.stack ? `\nStack trace:\n${result.stack}` : "";
|
|
1623
1640
|
return [
|
|
1624
1641
|
`Tool ${toolName}${formattedArgs} result:`,
|
|
1625
1642
|
status,
|
|
1626
1643
|
content.trim(),
|
|
1627
|
-
error.trim()
|
|
1644
|
+
error.trim(),
|
|
1645
|
+
stack.trim()
|
|
1628
1646
|
].filter(Boolean).join("\n");
|
|
1629
1647
|
}
|
|
1630
1648
|
function formatToolArguments(args) {
|
|
@@ -1642,7 +1660,9 @@ async function executeToolCall(toolCall, options) {
|
|
|
1642
1660
|
return {
|
|
1643
1661
|
content: "",
|
|
1644
1662
|
// v8 ignore next
|
|
1645
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1663
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1664
|
+
// v8 ignore next
|
|
1665
|
+
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
1646
1666
|
};
|
|
1647
1667
|
}
|
|
1648
1668
|
}
|
|
@@ -1820,7 +1840,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
1820
1840
|
else await launchTui();
|
|
1821
1841
|
}
|
|
1822
1842
|
async function launchTui(sessionId) {
|
|
1823
|
-
const { renderApp } = await import("./assets/tui-
|
|
1843
|
+
const { renderApp } = await import("./assets/tui-CboegfoT.js");
|
|
1824
1844
|
reset();
|
|
1825
1845
|
renderApp(sessionId);
|
|
1826
1846
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-ollama",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"description": "Ollama coding agent that runs in your terminal",
|
|
5
5
|
"author": "Mark <mark@remarkablemark.org> (https://remarkablemark.org)",
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"prepublishOnly": "npm run build && npm run lint && npm run lint:tsc && npm run test:ci",
|
|
21
21
|
"test": "vitest run",
|
|
22
22
|
"test:ci": "CI=true npm test -- --color --coverage",
|
|
23
|
-
"test:watch": "vitest
|
|
23
|
+
"test:watch": "vitest"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|