@robota-sdk/agent-cli 3.0.0-beta.35 → 3.0.0-beta.36
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/node/bin.cjs +99 -57
- package/dist/node/bin.js +1 -1
- package/dist/node/{chunk-27OPEZHA.js → chunk-ERF646KY.js} +97 -50
- package/dist/node/index.cjs +99 -57
- package/dist/node/index.js +1 -1
- package/package.json +3 -3
package/dist/node/bin.cjs
CHANGED
|
@@ -168,7 +168,8 @@ var import_ink14 = require("ink");
|
|
|
168
168
|
// src/ui/App.tsx
|
|
169
169
|
var import_react16 = require("react");
|
|
170
170
|
var import_ink13 = require("ink");
|
|
171
|
-
var
|
|
171
|
+
var import_agent_core6 = require("@robota-sdk/agent-core");
|
|
172
|
+
var import_agent_core7 = require("@robota-sdk/agent-core");
|
|
172
173
|
|
|
173
174
|
// src/ui/hooks/useSession.ts
|
|
174
175
|
var import_react = require("react");
|
|
@@ -264,6 +265,7 @@ var NOOP_TERMINAL = {
|
|
|
264
265
|
function useSession(props) {
|
|
265
266
|
const [permissionRequest, setPermissionRequest] = (0, import_react.useState)(null);
|
|
266
267
|
const [streamingText, setStreamingText] = (0, import_react.useState)("");
|
|
268
|
+
const streamingTextRef = (0, import_react.useRef)("");
|
|
267
269
|
const [activeTools, setActiveTools] = (0, import_react.useState)([]);
|
|
268
270
|
const permissionQueueRef = (0, import_react.useRef)([]);
|
|
269
271
|
const processingRef = (0, import_react.useRef)(false);
|
|
@@ -295,8 +297,15 @@ function useSession(props) {
|
|
|
295
297
|
processNextPermission();
|
|
296
298
|
});
|
|
297
299
|
};
|
|
300
|
+
let flushTimer = null;
|
|
298
301
|
const onTextDelta = (delta) => {
|
|
299
|
-
|
|
302
|
+
streamingTextRef.current += delta;
|
|
303
|
+
if (!flushTimer) {
|
|
304
|
+
flushTimer = setTimeout(() => {
|
|
305
|
+
setStreamingText(streamingTextRef.current);
|
|
306
|
+
flushTimer = null;
|
|
307
|
+
}, 16);
|
|
308
|
+
}
|
|
300
309
|
};
|
|
301
310
|
const onToolExecution = (event) => {
|
|
302
311
|
if (event.type === "start") {
|
|
@@ -375,6 +384,7 @@ function useSession(props) {
|
|
|
375
384
|
}
|
|
376
385
|
const clearStreamingText = (0, import_react.useCallback)(() => {
|
|
377
386
|
setStreamingText("");
|
|
387
|
+
streamingTextRef.current = "";
|
|
378
388
|
setActiveTools([]);
|
|
379
389
|
}, []);
|
|
380
390
|
return {
|
|
@@ -389,16 +399,11 @@ function useSession(props) {
|
|
|
389
399
|
// src/ui/hooks/useMessages.ts
|
|
390
400
|
var import_react2 = require("react");
|
|
391
401
|
var MAX_RENDERED_MESSAGES = 100;
|
|
392
|
-
var msgIdCounter = 0;
|
|
393
|
-
function nextId() {
|
|
394
|
-
msgIdCounter += 1;
|
|
395
|
-
return `msg_${msgIdCounter}`;
|
|
396
|
-
}
|
|
397
402
|
function useMessages() {
|
|
398
403
|
const [messages, setMessages] = (0, import_react2.useState)([]);
|
|
399
404
|
const addMessage = (0, import_react2.useCallback)((msg) => {
|
|
400
405
|
setMessages((prev) => {
|
|
401
|
-
const updated = [...prev,
|
|
406
|
+
const updated = [...prev, msg];
|
|
402
407
|
if (updated.length > MAX_RENDERED_MESSAGES) {
|
|
403
408
|
return updated.slice(-MAX_RENDERED_MESSAGES);
|
|
404
409
|
}
|
|
@@ -410,6 +415,7 @@ function useMessages() {
|
|
|
410
415
|
|
|
411
416
|
// src/ui/hooks/useSlashCommands.ts
|
|
412
417
|
var import_react3 = require("react");
|
|
418
|
+
var import_agent_core = require("@robota-sdk/agent-core");
|
|
413
419
|
|
|
414
420
|
// src/commands/slash-executor.ts
|
|
415
421
|
var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
@@ -676,11 +682,14 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
676
682
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
677
683
|
const args = parts.slice(1).join(" ");
|
|
678
684
|
const clearMessages = () => setMessages([]);
|
|
685
|
+
const slashAddMessage = (msg) => {
|
|
686
|
+
addMessage((0, import_agent_core.createSystemMessage)(msg.content));
|
|
687
|
+
};
|
|
679
688
|
const result = await executeSlashCommand(
|
|
680
689
|
cmd,
|
|
681
690
|
args,
|
|
682
691
|
session,
|
|
683
|
-
|
|
692
|
+
slashAddMessage,
|
|
684
693
|
clearMessages,
|
|
685
694
|
registry,
|
|
686
695
|
pluginCallbacks
|
|
@@ -713,7 +722,9 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
713
722
|
|
|
714
723
|
// src/ui/hooks/useSubmitHandler.ts
|
|
715
724
|
var import_react4 = require("react");
|
|
725
|
+
var import_node_crypto = require("crypto");
|
|
716
726
|
var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
|
|
727
|
+
var import_agent_core2 = require("@robota-sdk/agent-core");
|
|
717
728
|
|
|
718
729
|
// src/utils/tool-call-extractor.ts
|
|
719
730
|
var TOOL_ARG_MAX_LENGTH = 80;
|
|
@@ -870,21 +881,50 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
870
881
|
historyBefore
|
|
871
882
|
);
|
|
872
883
|
if (toolSummaries.length > 0) {
|
|
873
|
-
addMessage(
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
884
|
+
addMessage(
|
|
885
|
+
(0, import_agent_core2.createToolMessage)(JSON.stringify(toolSummaries), {
|
|
886
|
+
toolCallId: (0, import_node_crypto.randomUUID)(),
|
|
887
|
+
name: `${toolSummaries.length} tools`
|
|
888
|
+
})
|
|
889
|
+
);
|
|
878
890
|
}
|
|
879
|
-
addMessage(
|
|
891
|
+
addMessage((0, import_agent_core2.createAssistantMessage)(response || "(empty response)"));
|
|
880
892
|
syncContextState(session, setContextState);
|
|
881
893
|
} catch (err) {
|
|
882
894
|
clearStreamingText();
|
|
883
|
-
|
|
884
|
-
|
|
895
|
+
const isAbortError = err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
|
|
896
|
+
if (isAbortError) {
|
|
897
|
+
const history = session.getHistory();
|
|
898
|
+
const toolSummaries = extractToolCallsWithDiff(
|
|
899
|
+
history,
|
|
900
|
+
historyBefore
|
|
901
|
+
);
|
|
902
|
+
if (toolSummaries.length > 0) {
|
|
903
|
+
addMessage(
|
|
904
|
+
(0, import_agent_core2.createToolMessage)(JSON.stringify(toolSummaries), {
|
|
905
|
+
toolCallId: (0, import_node_crypto.randomUUID)(),
|
|
906
|
+
name: `${toolSummaries.length} tools`
|
|
907
|
+
})
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
const assistantParts = [];
|
|
911
|
+
let lastAssistantState = "complete";
|
|
912
|
+
for (let i = historyBefore; i < history.length; i++) {
|
|
913
|
+
const msg = history[i];
|
|
914
|
+
if (msg && msg.role === "assistant" && msg.content) {
|
|
915
|
+
assistantParts.push(msg.content);
|
|
916
|
+
if (msg.state === "interrupted") lastAssistantState = "interrupted";
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
if (assistantParts.length > 0) {
|
|
920
|
+
addMessage(
|
|
921
|
+
(0, import_agent_core2.createAssistantMessage)(assistantParts.join("\n\n"), { state: lastAssistantState })
|
|
922
|
+
);
|
|
923
|
+
}
|
|
924
|
+
addMessage((0, import_agent_core2.createSystemMessage)("Interrupted by user."));
|
|
885
925
|
} else {
|
|
886
926
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
887
|
-
addMessage(
|
|
927
|
+
addMessage((0, import_agent_core2.createSystemMessage)(`Error: ${errMsg}`));
|
|
888
928
|
}
|
|
889
929
|
} finally {
|
|
890
930
|
setIsThinking(false);
|
|
@@ -937,7 +977,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
937
977
|
const runInFork = createForkRunner(session);
|
|
938
978
|
const result = await executeSkill(skill, args, { runInFork });
|
|
939
979
|
if (result.mode === "fork") {
|
|
940
|
-
addMessage(
|
|
980
|
+
addMessage((0, import_agent_core2.createAssistantMessage)(result.result ?? "(empty response)"));
|
|
941
981
|
syncContextState(session, setContextState);
|
|
942
982
|
return;
|
|
943
983
|
}
|
|
@@ -972,7 +1012,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
972
1012
|
hookInput
|
|
973
1013
|
);
|
|
974
1014
|
}
|
|
975
|
-
addMessage(
|
|
1015
|
+
addMessage((0, import_agent_core2.createUserMessage)(input));
|
|
976
1016
|
return runSessionPrompt(
|
|
977
1017
|
input,
|
|
978
1018
|
session,
|
|
@@ -1039,16 +1079,16 @@ var CommandRegistry = class {
|
|
|
1039
1079
|
};
|
|
1040
1080
|
|
|
1041
1081
|
// src/commands/builtin-source.ts
|
|
1042
|
-
var
|
|
1082
|
+
var import_agent_core3 = require("@robota-sdk/agent-core");
|
|
1043
1083
|
function buildModelSubcommands() {
|
|
1044
1084
|
const seen = /* @__PURE__ */ new Set();
|
|
1045
1085
|
const commands = [];
|
|
1046
|
-
for (const model of Object.values(
|
|
1086
|
+
for (const model of Object.values(import_agent_core3.CLAUDE_MODELS)) {
|
|
1047
1087
|
if (seen.has(model.name)) continue;
|
|
1048
1088
|
seen.add(model.name);
|
|
1049
1089
|
commands.push({
|
|
1050
1090
|
name: model.id,
|
|
1051
|
-
description: `${model.name} (${(0,
|
|
1091
|
+
description: `${model.name} (${(0, import_agent_core3.formatTokenCount)(model.contextWindow).toUpperCase()})`,
|
|
1052
1092
|
source: "builtin"
|
|
1053
1093
|
});
|
|
1054
1094
|
}
|
|
@@ -1443,6 +1483,7 @@ function usePluginCallbacks(cwd) {
|
|
|
1443
1483
|
// src/ui/MessageList.tsx
|
|
1444
1484
|
var import_react7 = __toESM(require("react"), 1);
|
|
1445
1485
|
var import_ink2 = require("ink");
|
|
1486
|
+
var import_agent_core4 = require("@robota-sdk/agent-core");
|
|
1446
1487
|
|
|
1447
1488
|
// src/ui/render-markdown.ts
|
|
1448
1489
|
var import_marked = require("marked");
|
|
@@ -1528,9 +1569,14 @@ function RoleLabel({ role }) {
|
|
|
1528
1569
|
}
|
|
1529
1570
|
}
|
|
1530
1571
|
function ToolMessage({ message }) {
|
|
1572
|
+
if (!(0, import_agent_core4.isToolMessage)(message)) {
|
|
1573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, {});
|
|
1574
|
+
}
|
|
1575
|
+
const toolName = message.name;
|
|
1576
|
+
const content = message.content;
|
|
1531
1577
|
let summaries = null;
|
|
1532
1578
|
try {
|
|
1533
|
-
const parsed = JSON.parse(
|
|
1579
|
+
const parsed = JSON.parse(content);
|
|
1534
1580
|
if (Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0].line === "string") {
|
|
1535
1581
|
summaries = parsed;
|
|
1536
1582
|
}
|
|
@@ -1543,9 +1589,9 @@ function ToolMessage({ message }) {
|
|
|
1543
1589
|
"Tool:",
|
|
1544
1590
|
" "
|
|
1545
1591
|
] }),
|
|
1546
|
-
|
|
1592
|
+
toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1547
1593
|
"[",
|
|
1548
|
-
|
|
1594
|
+
toolName,
|
|
1549
1595
|
"]"
|
|
1550
1596
|
] })
|
|
1551
1597
|
] }),
|
|
@@ -1561,16 +1607,16 @@ function ToolMessage({ message }) {
|
|
|
1561
1607
|
] }, i))
|
|
1562
1608
|
] });
|
|
1563
1609
|
}
|
|
1564
|
-
const lines =
|
|
1610
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
1565
1611
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1566
1612
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
|
|
1567
1613
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
|
|
1568
1614
|
"Tool:",
|
|
1569
1615
|
" "
|
|
1570
1616
|
] }),
|
|
1571
|
-
|
|
1617
|
+
toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1572
1618
|
"[",
|
|
1573
|
-
|
|
1619
|
+
toolName,
|
|
1574
1620
|
"]"
|
|
1575
1621
|
] })
|
|
1576
1622
|
] }),
|
|
@@ -1586,21 +1632,15 @@ function ToolMessage({ message }) {
|
|
|
1586
1632
|
var MessageItem = import_react7.default.memo(function MessageItem2({
|
|
1587
1633
|
message
|
|
1588
1634
|
}) {
|
|
1589
|
-
if (
|
|
1635
|
+
if ((0, import_agent_core4.isToolMessage)(message)) {
|
|
1590
1636
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToolMessage, { message });
|
|
1591
1637
|
}
|
|
1638
|
+
const content = message.content ?? "";
|
|
1639
|
+
const isInterrupted = message.state === "interrupted";
|
|
1592
1640
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1593
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
1594
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }),
|
|
1595
|
-
message.toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "magenta", dimColor: true, children: [
|
|
1596
|
-
"[",
|
|
1597
|
-
message.toolName,
|
|
1598
|
-
"]",
|
|
1599
|
-
" "
|
|
1600
|
-
] })
|
|
1601
|
-
] }),
|
|
1641
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }) }),
|
|
1602
1642
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
|
|
1603
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: message
|
|
1643
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: (0, import_agent_core4.isAssistantMessage)(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
|
|
1604
1644
|
] });
|
|
1605
1645
|
});
|
|
1606
1646
|
function MessageList({ messages }) {
|
|
@@ -1609,7 +1649,7 @@ function MessageList({ messages }) {
|
|
|
1609
1649
|
|
|
1610
1650
|
// src/ui/StatusBar.tsx
|
|
1611
1651
|
var import_ink3 = require("ink");
|
|
1612
|
-
var
|
|
1652
|
+
var import_agent_core5 = require("@robota-sdk/agent-core");
|
|
1613
1653
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1614
1654
|
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
1615
1655
|
var CONTEXT_RED_THRESHOLD = 90;
|
|
@@ -1649,9 +1689,9 @@ function StatusBar({
|
|
|
1649
1689
|
"Context: ",
|
|
1650
1690
|
Math.round(contextPercentage),
|
|
1651
1691
|
"% (",
|
|
1652
|
-
(0,
|
|
1692
|
+
(0, import_agent_core5.formatTokenCount)(contextUsedTokens),
|
|
1653
1693
|
"/",
|
|
1654
|
-
(0,
|
|
1694
|
+
(0, import_agent_core5.formatTokenCount)(contextMaxTokens),
|
|
1655
1695
|
")"
|
|
1656
1696
|
] })
|
|
1657
1697
|
] }),
|
|
@@ -1979,7 +2019,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1979
2019
|
isSubcommandMode
|
|
1980
2020
|
}
|
|
1981
2021
|
),
|
|
1982
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response..." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
|
|
2022
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
|
|
1983
2023
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "green", bold: true, children: "> " }),
|
|
1984
2024
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1985
2025
|
CjkTextInput,
|
|
@@ -2115,7 +2155,7 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2115
2155
|
const hasTools = activeTools.length > 0;
|
|
2116
2156
|
const hasText = text.length > 0;
|
|
2117
2157
|
if (!hasTools && !hasText) {
|
|
2118
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2158
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
|
|
2119
2159
|
}
|
|
2120
2160
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
|
|
2121
2161
|
hasTools && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
@@ -2689,7 +2729,7 @@ function App(props) {
|
|
|
2689
2729
|
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2690
2730
|
ConfirmPrompt,
|
|
2691
2731
|
{
|
|
2692
|
-
message: `Change model to ${(0,
|
|
2732
|
+
message: `Change model to ${(0, import_agent_core6.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
2693
2733
|
onSelect: (index) => {
|
|
2694
2734
|
setPendingModelId(null);
|
|
2695
2735
|
pendingModelChangeRef.current = null;
|
|
@@ -2697,19 +2737,21 @@ function App(props) {
|
|
|
2697
2737
|
try {
|
|
2698
2738
|
const settingsPath = getUserSettingsPath();
|
|
2699
2739
|
updateModelInSettings(settingsPath, pendingModelId);
|
|
2700
|
-
addMessage(
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2740
|
+
addMessage(
|
|
2741
|
+
(0, import_agent_core7.createSystemMessage)(
|
|
2742
|
+
`Model changed to ${(0, import_agent_core6.getModelName)(pendingModelId)}. Restarting...`
|
|
2743
|
+
)
|
|
2744
|
+
);
|
|
2704
2745
|
setTimeout(() => exit(), EXIT_DELAY_MS2);
|
|
2705
2746
|
} catch (err) {
|
|
2706
|
-
addMessage(
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2747
|
+
addMessage(
|
|
2748
|
+
(0, import_agent_core7.createSystemMessage)(
|
|
2749
|
+
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2750
|
+
)
|
|
2751
|
+
);
|
|
2710
2752
|
}
|
|
2711
2753
|
} else {
|
|
2712
|
-
addMessage(
|
|
2754
|
+
addMessage((0, import_agent_core7.createSystemMessage)("Model change cancelled."));
|
|
2713
2755
|
}
|
|
2714
2756
|
}
|
|
2715
2757
|
}
|
|
@@ -2719,14 +2761,14 @@ function App(props) {
|
|
|
2719
2761
|
{
|
|
2720
2762
|
callbacks: pluginCallbacks,
|
|
2721
2763
|
onClose: () => setShowPluginTUI(false),
|
|
2722
|
-
addMessage: (msg) => addMessage(msg)
|
|
2764
|
+
addMessage: (msg) => addMessage((0, import_agent_core7.createSystemMessage)(msg.content))
|
|
2723
2765
|
}
|
|
2724
2766
|
),
|
|
2725
2767
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2726
2768
|
StatusBar,
|
|
2727
2769
|
{
|
|
2728
2770
|
permissionMode: session.getPermissionMode(),
|
|
2729
|
-
modelName: (0,
|
|
2771
|
+
modelName: (0, import_agent_core6.getModelName)(props.config.provider.model),
|
|
2730
2772
|
sessionId: session.getSessionId(),
|
|
2731
2773
|
messageCount: messages.length,
|
|
2732
2774
|
isThinking,
|
package/dist/node/bin.js
CHANGED
|
@@ -152,6 +152,7 @@ import { render } from "ink";
|
|
|
152
152
|
import { useState as useState10, useRef as useRef8 } from "react";
|
|
153
153
|
import { Box as Box11, Text as Text13, useApp, useInput as useInput7 } from "ink";
|
|
154
154
|
import { getModelName } from "@robota-sdk/agent-core";
|
|
155
|
+
import { createSystemMessage as createSystemMessage3 } from "@robota-sdk/agent-core";
|
|
155
156
|
|
|
156
157
|
// src/ui/hooks/useSession.ts
|
|
157
158
|
import { useState, useCallback, useRef } from "react";
|
|
@@ -247,6 +248,7 @@ var NOOP_TERMINAL = {
|
|
|
247
248
|
function useSession(props) {
|
|
248
249
|
const [permissionRequest, setPermissionRequest] = useState(null);
|
|
249
250
|
const [streamingText, setStreamingText] = useState("");
|
|
251
|
+
const streamingTextRef = useRef("");
|
|
250
252
|
const [activeTools, setActiveTools] = useState([]);
|
|
251
253
|
const permissionQueueRef = useRef([]);
|
|
252
254
|
const processingRef = useRef(false);
|
|
@@ -278,8 +280,15 @@ function useSession(props) {
|
|
|
278
280
|
processNextPermission();
|
|
279
281
|
});
|
|
280
282
|
};
|
|
283
|
+
let flushTimer = null;
|
|
281
284
|
const onTextDelta = (delta) => {
|
|
282
|
-
|
|
285
|
+
streamingTextRef.current += delta;
|
|
286
|
+
if (!flushTimer) {
|
|
287
|
+
flushTimer = setTimeout(() => {
|
|
288
|
+
setStreamingText(streamingTextRef.current);
|
|
289
|
+
flushTimer = null;
|
|
290
|
+
}, 16);
|
|
291
|
+
}
|
|
283
292
|
};
|
|
284
293
|
const onToolExecution = (event) => {
|
|
285
294
|
if (event.type === "start") {
|
|
@@ -358,6 +367,7 @@ function useSession(props) {
|
|
|
358
367
|
}
|
|
359
368
|
const clearStreamingText = useCallback(() => {
|
|
360
369
|
setStreamingText("");
|
|
370
|
+
streamingTextRef.current = "";
|
|
361
371
|
setActiveTools([]);
|
|
362
372
|
}, []);
|
|
363
373
|
return {
|
|
@@ -372,16 +382,11 @@ function useSession(props) {
|
|
|
372
382
|
// src/ui/hooks/useMessages.ts
|
|
373
383
|
import { useState as useState2, useCallback as useCallback2 } from "react";
|
|
374
384
|
var MAX_RENDERED_MESSAGES = 100;
|
|
375
|
-
var msgIdCounter = 0;
|
|
376
|
-
function nextId() {
|
|
377
|
-
msgIdCounter += 1;
|
|
378
|
-
return `msg_${msgIdCounter}`;
|
|
379
|
-
}
|
|
380
385
|
function useMessages() {
|
|
381
386
|
const [messages, setMessages] = useState2([]);
|
|
382
387
|
const addMessage = useCallback2((msg) => {
|
|
383
388
|
setMessages((prev) => {
|
|
384
|
-
const updated = [...prev,
|
|
389
|
+
const updated = [...prev, msg];
|
|
385
390
|
if (updated.length > MAX_RENDERED_MESSAGES) {
|
|
386
391
|
return updated.slice(-MAX_RENDERED_MESSAGES);
|
|
387
392
|
}
|
|
@@ -393,6 +398,7 @@ function useMessages() {
|
|
|
393
398
|
|
|
394
399
|
// src/ui/hooks/useSlashCommands.ts
|
|
395
400
|
import { useCallback as useCallback3 } from "react";
|
|
401
|
+
import { createSystemMessage } from "@robota-sdk/agent-core";
|
|
396
402
|
|
|
397
403
|
// src/commands/slash-executor.ts
|
|
398
404
|
var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
@@ -659,11 +665,14 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
659
665
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
660
666
|
const args = parts.slice(1).join(" ");
|
|
661
667
|
const clearMessages = () => setMessages([]);
|
|
668
|
+
const slashAddMessage = (msg) => {
|
|
669
|
+
addMessage(createSystemMessage(msg.content));
|
|
670
|
+
};
|
|
662
671
|
const result = await executeSlashCommand(
|
|
663
672
|
cmd,
|
|
664
673
|
args,
|
|
665
674
|
session,
|
|
666
|
-
|
|
675
|
+
slashAddMessage,
|
|
667
676
|
clearMessages,
|
|
668
677
|
registry,
|
|
669
678
|
pluginCallbacks
|
|
@@ -696,11 +705,18 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
696
705
|
|
|
697
706
|
// src/ui/hooks/useSubmitHandler.ts
|
|
698
707
|
import { useCallback as useCallback4 } from "react";
|
|
708
|
+
import { randomUUID } from "crypto";
|
|
699
709
|
import {
|
|
700
710
|
createSubagentSession,
|
|
701
711
|
getBuiltInAgent,
|
|
702
712
|
retrieveAgentToolDeps
|
|
703
713
|
} from "@robota-sdk/agent-sdk";
|
|
714
|
+
import {
|
|
715
|
+
createUserMessage,
|
|
716
|
+
createAssistantMessage,
|
|
717
|
+
createSystemMessage as createSystemMessage2,
|
|
718
|
+
createToolMessage
|
|
719
|
+
} from "@robota-sdk/agent-core";
|
|
704
720
|
|
|
705
721
|
// src/utils/tool-call-extractor.ts
|
|
706
722
|
var TOOL_ARG_MAX_LENGTH = 80;
|
|
@@ -857,21 +873,50 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
857
873
|
historyBefore
|
|
858
874
|
);
|
|
859
875
|
if (toolSummaries.length > 0) {
|
|
860
|
-
addMessage(
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
876
|
+
addMessage(
|
|
877
|
+
createToolMessage(JSON.stringify(toolSummaries), {
|
|
878
|
+
toolCallId: randomUUID(),
|
|
879
|
+
name: `${toolSummaries.length} tools`
|
|
880
|
+
})
|
|
881
|
+
);
|
|
865
882
|
}
|
|
866
|
-
addMessage(
|
|
883
|
+
addMessage(createAssistantMessage(response || "(empty response)"));
|
|
867
884
|
syncContextState(session, setContextState);
|
|
868
885
|
} catch (err) {
|
|
869
886
|
clearStreamingText();
|
|
870
|
-
|
|
871
|
-
|
|
887
|
+
const isAbortError = err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
|
|
888
|
+
if (isAbortError) {
|
|
889
|
+
const history = session.getHistory();
|
|
890
|
+
const toolSummaries = extractToolCallsWithDiff(
|
|
891
|
+
history,
|
|
892
|
+
historyBefore
|
|
893
|
+
);
|
|
894
|
+
if (toolSummaries.length > 0) {
|
|
895
|
+
addMessage(
|
|
896
|
+
createToolMessage(JSON.stringify(toolSummaries), {
|
|
897
|
+
toolCallId: randomUUID(),
|
|
898
|
+
name: `${toolSummaries.length} tools`
|
|
899
|
+
})
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
const assistantParts = [];
|
|
903
|
+
let lastAssistantState = "complete";
|
|
904
|
+
for (let i = historyBefore; i < history.length; i++) {
|
|
905
|
+
const msg = history[i];
|
|
906
|
+
if (msg && msg.role === "assistant" && msg.content) {
|
|
907
|
+
assistantParts.push(msg.content);
|
|
908
|
+
if (msg.state === "interrupted") lastAssistantState = "interrupted";
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (assistantParts.length > 0) {
|
|
912
|
+
addMessage(
|
|
913
|
+
createAssistantMessage(assistantParts.join("\n\n"), { state: lastAssistantState })
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
addMessage(createSystemMessage2("Interrupted by user."));
|
|
872
917
|
} else {
|
|
873
918
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
874
|
-
addMessage(
|
|
919
|
+
addMessage(createSystemMessage2(`Error: ${errMsg}`));
|
|
875
920
|
}
|
|
876
921
|
} finally {
|
|
877
922
|
setIsThinking(false);
|
|
@@ -924,7 +969,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
924
969
|
const runInFork = createForkRunner(session);
|
|
925
970
|
const result = await executeSkill(skill, args, { runInFork });
|
|
926
971
|
if (result.mode === "fork") {
|
|
927
|
-
addMessage(
|
|
972
|
+
addMessage(createAssistantMessage(result.result ?? "(empty response)"));
|
|
928
973
|
syncContextState(session, setContextState);
|
|
929
974
|
return;
|
|
930
975
|
}
|
|
@@ -959,7 +1004,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
959
1004
|
hookInput
|
|
960
1005
|
);
|
|
961
1006
|
}
|
|
962
|
-
addMessage(
|
|
1007
|
+
addMessage(createUserMessage(input));
|
|
963
1008
|
return runSessionPrompt(
|
|
964
1009
|
input,
|
|
965
1010
|
session,
|
|
@@ -1435,6 +1480,7 @@ function usePluginCallbacks(cwd) {
|
|
|
1435
1480
|
// src/ui/MessageList.tsx
|
|
1436
1481
|
import React2 from "react";
|
|
1437
1482
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
1483
|
+
import { isToolMessage, isAssistantMessage } from "@robota-sdk/agent-core";
|
|
1438
1484
|
|
|
1439
1485
|
// src/ui/render-markdown.ts
|
|
1440
1486
|
import { marked } from "marked";
|
|
@@ -1494,7 +1540,7 @@ function DiffBlock({ file, lines }) {
|
|
|
1494
1540
|
}
|
|
1495
1541
|
|
|
1496
1542
|
// src/ui/MessageList.tsx
|
|
1497
|
-
import { jsx, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1543
|
+
import { Fragment, jsx, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1498
1544
|
function RoleLabel({ role }) {
|
|
1499
1545
|
switch (role) {
|
|
1500
1546
|
case "user":
|
|
@@ -1520,9 +1566,14 @@ function RoleLabel({ role }) {
|
|
|
1520
1566
|
}
|
|
1521
1567
|
}
|
|
1522
1568
|
function ToolMessage({ message }) {
|
|
1569
|
+
if (!isToolMessage(message)) {
|
|
1570
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
1571
|
+
}
|
|
1572
|
+
const toolName = message.name;
|
|
1573
|
+
const content = message.content;
|
|
1523
1574
|
let summaries = null;
|
|
1524
1575
|
try {
|
|
1525
|
-
const parsed = JSON.parse(
|
|
1576
|
+
const parsed = JSON.parse(content);
|
|
1526
1577
|
if (Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0].line === "string") {
|
|
1527
1578
|
summaries = parsed;
|
|
1528
1579
|
}
|
|
@@ -1535,9 +1586,9 @@ function ToolMessage({ message }) {
|
|
|
1535
1586
|
"Tool:",
|
|
1536
1587
|
" "
|
|
1537
1588
|
] }),
|
|
1538
|
-
|
|
1589
|
+
toolName && /* @__PURE__ */ jsxs2(Text2, { color: "white", dimColor: true, children: [
|
|
1539
1590
|
"[",
|
|
1540
|
-
|
|
1591
|
+
toolName,
|
|
1541
1592
|
"]"
|
|
1542
1593
|
] })
|
|
1543
1594
|
] }),
|
|
@@ -1553,16 +1604,16 @@ function ToolMessage({ message }) {
|
|
|
1553
1604
|
] }, i))
|
|
1554
1605
|
] });
|
|
1555
1606
|
}
|
|
1556
|
-
const lines =
|
|
1607
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
1557
1608
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
1558
1609
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
1559
1610
|
/* @__PURE__ */ jsxs2(Text2, { color: "white", bold: true, children: [
|
|
1560
1611
|
"Tool:",
|
|
1561
1612
|
" "
|
|
1562
1613
|
] }),
|
|
1563
|
-
|
|
1614
|
+
toolName && /* @__PURE__ */ jsxs2(Text2, { color: "white", dimColor: true, children: [
|
|
1564
1615
|
"[",
|
|
1565
|
-
|
|
1616
|
+
toolName,
|
|
1566
1617
|
"]"
|
|
1567
1618
|
] })
|
|
1568
1619
|
] }),
|
|
@@ -1578,21 +1629,15 @@ function ToolMessage({ message }) {
|
|
|
1578
1629
|
var MessageItem = React2.memo(function MessageItem2({
|
|
1579
1630
|
message
|
|
1580
1631
|
}) {
|
|
1581
|
-
if (message
|
|
1632
|
+
if (isToolMessage(message)) {
|
|
1582
1633
|
return /* @__PURE__ */ jsx(ToolMessage, { message });
|
|
1583
1634
|
}
|
|
1635
|
+
const content = message.content ?? "";
|
|
1636
|
+
const isInterrupted = message.state === "interrupted";
|
|
1584
1637
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
1585
|
-
/* @__PURE__ */
|
|
1586
|
-
/* @__PURE__ */ jsx(RoleLabel, { role: message.role }),
|
|
1587
|
-
message.toolName && /* @__PURE__ */ jsxs2(Text2, { color: "magenta", dimColor: true, children: [
|
|
1588
|
-
"[",
|
|
1589
|
-
message.toolName,
|
|
1590
|
-
"]",
|
|
1591
|
-
" "
|
|
1592
|
-
] })
|
|
1593
|
-
] }),
|
|
1638
|
+
/* @__PURE__ */ jsx(Box2, { children: /* @__PURE__ */ jsx(RoleLabel, { role: message.role }) }),
|
|
1594
1639
|
/* @__PURE__ */ jsx(Text2, { children: " " }),
|
|
1595
|
-
/* @__PURE__ */ jsx(Box2, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text2, { wrap: "wrap", children: message
|
|
1640
|
+
/* @__PURE__ */ jsx(Box2, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text2, { wrap: "wrap", children: isAssistantMessage(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
|
|
1596
1641
|
] });
|
|
1597
1642
|
});
|
|
1598
1643
|
function MessageList({ messages }) {
|
|
@@ -1971,7 +2016,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1971
2016
|
isSubcommandMode
|
|
1972
2017
|
}
|
|
1973
2018
|
),
|
|
1974
|
-
/* @__PURE__ */ jsx6(Box5, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ jsx6(WaveText, { text: " Waiting for response..." }) : /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
2019
|
+
/* @__PURE__ */ jsx6(Box5, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ jsx6(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
1975
2020
|
/* @__PURE__ */ jsx6(Text7, { color: "green", bold: true, children: "> " }),
|
|
1976
2021
|
/* @__PURE__ */ jsx6(
|
|
1977
2022
|
CjkTextInput,
|
|
@@ -2096,7 +2141,7 @@ function PermissionPrompt({ request }) {
|
|
|
2096
2141
|
|
|
2097
2142
|
// src/ui/StreamingIndicator.tsx
|
|
2098
2143
|
import { Box as Box8, Text as Text10 } from "ink";
|
|
2099
|
-
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2144
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2100
2145
|
function getToolStyle(t) {
|
|
2101
2146
|
if (t.isRunning) return { color: "yellow", icon: "\u27F3", strikethrough: false };
|
|
2102
2147
|
if (t.result === "error") return { color: "red", icon: "\u2717", strikethrough: true };
|
|
@@ -2107,7 +2152,7 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2107
2152
|
const hasTools = activeTools.length > 0;
|
|
2108
2153
|
const hasText = text.length > 0;
|
|
2109
2154
|
if (!hasTools && !hasText) {
|
|
2110
|
-
return /* @__PURE__ */ jsx9(
|
|
2155
|
+
return /* @__PURE__ */ jsx9(Fragment2, {});
|
|
2111
2156
|
}
|
|
2112
2157
|
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2113
2158
|
hasTools && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginBottom: 1, children: [
|
|
@@ -2689,19 +2734,21 @@ function App(props) {
|
|
|
2689
2734
|
try {
|
|
2690
2735
|
const settingsPath = getUserSettingsPath();
|
|
2691
2736
|
updateModelInSettings(settingsPath, pendingModelId);
|
|
2692
|
-
addMessage(
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2737
|
+
addMessage(
|
|
2738
|
+
createSystemMessage3(
|
|
2739
|
+
`Model changed to ${getModelName(pendingModelId)}. Restarting...`
|
|
2740
|
+
)
|
|
2741
|
+
);
|
|
2696
2742
|
setTimeout(() => exit(), EXIT_DELAY_MS2);
|
|
2697
2743
|
} catch (err) {
|
|
2698
|
-
addMessage(
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2744
|
+
addMessage(
|
|
2745
|
+
createSystemMessage3(
|
|
2746
|
+
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2747
|
+
)
|
|
2748
|
+
);
|
|
2702
2749
|
}
|
|
2703
2750
|
} else {
|
|
2704
|
-
addMessage(
|
|
2751
|
+
addMessage(createSystemMessage3("Model change cancelled."));
|
|
2705
2752
|
}
|
|
2706
2753
|
}
|
|
2707
2754
|
}
|
|
@@ -2711,7 +2758,7 @@ function App(props) {
|
|
|
2711
2758
|
{
|
|
2712
2759
|
callbacks: pluginCallbacks,
|
|
2713
2760
|
onClose: () => setShowPluginTUI(false),
|
|
2714
|
-
addMessage: (msg) => addMessage(msg)
|
|
2761
|
+
addMessage: (msg) => addMessage(createSystemMessage3(msg.content))
|
|
2715
2762
|
}
|
|
2716
2763
|
),
|
|
2717
2764
|
/* @__PURE__ */ jsx13(
|
package/dist/node/index.cjs
CHANGED
|
@@ -184,7 +184,8 @@ var import_ink14 = require("ink");
|
|
|
184
184
|
// src/ui/App.tsx
|
|
185
185
|
var import_react16 = require("react");
|
|
186
186
|
var import_ink13 = require("ink");
|
|
187
|
-
var
|
|
187
|
+
var import_agent_core6 = require("@robota-sdk/agent-core");
|
|
188
|
+
var import_agent_core7 = require("@robota-sdk/agent-core");
|
|
188
189
|
|
|
189
190
|
// src/ui/hooks/useSession.ts
|
|
190
191
|
var import_react = require("react");
|
|
@@ -280,6 +281,7 @@ var NOOP_TERMINAL = {
|
|
|
280
281
|
function useSession(props) {
|
|
281
282
|
const [permissionRequest, setPermissionRequest] = (0, import_react.useState)(null);
|
|
282
283
|
const [streamingText, setStreamingText] = (0, import_react.useState)("");
|
|
284
|
+
const streamingTextRef = (0, import_react.useRef)("");
|
|
283
285
|
const [activeTools, setActiveTools] = (0, import_react.useState)([]);
|
|
284
286
|
const permissionQueueRef = (0, import_react.useRef)([]);
|
|
285
287
|
const processingRef = (0, import_react.useRef)(false);
|
|
@@ -311,8 +313,15 @@ function useSession(props) {
|
|
|
311
313
|
processNextPermission();
|
|
312
314
|
});
|
|
313
315
|
};
|
|
316
|
+
let flushTimer = null;
|
|
314
317
|
const onTextDelta = (delta) => {
|
|
315
|
-
|
|
318
|
+
streamingTextRef.current += delta;
|
|
319
|
+
if (!flushTimer) {
|
|
320
|
+
flushTimer = setTimeout(() => {
|
|
321
|
+
setStreamingText(streamingTextRef.current);
|
|
322
|
+
flushTimer = null;
|
|
323
|
+
}, 16);
|
|
324
|
+
}
|
|
316
325
|
};
|
|
317
326
|
const onToolExecution = (event) => {
|
|
318
327
|
if (event.type === "start") {
|
|
@@ -391,6 +400,7 @@ function useSession(props) {
|
|
|
391
400
|
}
|
|
392
401
|
const clearStreamingText = (0, import_react.useCallback)(() => {
|
|
393
402
|
setStreamingText("");
|
|
403
|
+
streamingTextRef.current = "";
|
|
394
404
|
setActiveTools([]);
|
|
395
405
|
}, []);
|
|
396
406
|
return {
|
|
@@ -405,16 +415,11 @@ function useSession(props) {
|
|
|
405
415
|
// src/ui/hooks/useMessages.ts
|
|
406
416
|
var import_react2 = require("react");
|
|
407
417
|
var MAX_RENDERED_MESSAGES = 100;
|
|
408
|
-
var msgIdCounter = 0;
|
|
409
|
-
function nextId() {
|
|
410
|
-
msgIdCounter += 1;
|
|
411
|
-
return `msg_${msgIdCounter}`;
|
|
412
|
-
}
|
|
413
418
|
function useMessages() {
|
|
414
419
|
const [messages, setMessages] = (0, import_react2.useState)([]);
|
|
415
420
|
const addMessage = (0, import_react2.useCallback)((msg) => {
|
|
416
421
|
setMessages((prev) => {
|
|
417
|
-
const updated = [...prev,
|
|
422
|
+
const updated = [...prev, msg];
|
|
418
423
|
if (updated.length > MAX_RENDERED_MESSAGES) {
|
|
419
424
|
return updated.slice(-MAX_RENDERED_MESSAGES);
|
|
420
425
|
}
|
|
@@ -426,6 +431,7 @@ function useMessages() {
|
|
|
426
431
|
|
|
427
432
|
// src/ui/hooks/useSlashCommands.ts
|
|
428
433
|
var import_react3 = require("react");
|
|
434
|
+
var import_agent_core = require("@robota-sdk/agent-core");
|
|
429
435
|
|
|
430
436
|
// src/commands/slash-executor.ts
|
|
431
437
|
var VALID_MODES2 = ["plan", "default", "acceptEdits", "bypassPermissions"];
|
|
@@ -692,11 +698,14 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
692
698
|
const cmd = parts[0]?.toLowerCase() ?? "";
|
|
693
699
|
const args = parts.slice(1).join(" ");
|
|
694
700
|
const clearMessages = () => setMessages([]);
|
|
701
|
+
const slashAddMessage = (msg) => {
|
|
702
|
+
addMessage((0, import_agent_core.createSystemMessage)(msg.content));
|
|
703
|
+
};
|
|
695
704
|
const result = await executeSlashCommand(
|
|
696
705
|
cmd,
|
|
697
706
|
args,
|
|
698
707
|
session,
|
|
699
|
-
|
|
708
|
+
slashAddMessage,
|
|
700
709
|
clearMessages,
|
|
701
710
|
registry,
|
|
702
711
|
pluginCallbacks
|
|
@@ -729,7 +738,9 @@ function useSlashCommands(session, addMessage, setMessages, exit, registry, pend
|
|
|
729
738
|
|
|
730
739
|
// src/ui/hooks/useSubmitHandler.ts
|
|
731
740
|
var import_react4 = require("react");
|
|
741
|
+
var import_node_crypto = require("crypto");
|
|
732
742
|
var import_agent_sdk2 = require("@robota-sdk/agent-sdk");
|
|
743
|
+
var import_agent_core2 = require("@robota-sdk/agent-core");
|
|
733
744
|
|
|
734
745
|
// src/utils/tool-call-extractor.ts
|
|
735
746
|
var TOOL_ARG_MAX_LENGTH = 80;
|
|
@@ -886,21 +897,50 @@ async function runSessionPrompt(prompt, session, addMessage, clearStreamingText,
|
|
|
886
897
|
historyBefore
|
|
887
898
|
);
|
|
888
899
|
if (toolSummaries.length > 0) {
|
|
889
|
-
addMessage(
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
900
|
+
addMessage(
|
|
901
|
+
(0, import_agent_core2.createToolMessage)(JSON.stringify(toolSummaries), {
|
|
902
|
+
toolCallId: (0, import_node_crypto.randomUUID)(),
|
|
903
|
+
name: `${toolSummaries.length} tools`
|
|
904
|
+
})
|
|
905
|
+
);
|
|
894
906
|
}
|
|
895
|
-
addMessage(
|
|
907
|
+
addMessage((0, import_agent_core2.createAssistantMessage)(response || "(empty response)"));
|
|
896
908
|
syncContextState(session, setContextState);
|
|
897
909
|
} catch (err) {
|
|
898
910
|
clearStreamingText();
|
|
899
|
-
|
|
900
|
-
|
|
911
|
+
const isAbortError = err instanceof DOMException && err.name === "AbortError" || err instanceof Error && (err.message.includes("aborted") || err.message.includes("abort"));
|
|
912
|
+
if (isAbortError) {
|
|
913
|
+
const history = session.getHistory();
|
|
914
|
+
const toolSummaries = extractToolCallsWithDiff(
|
|
915
|
+
history,
|
|
916
|
+
historyBefore
|
|
917
|
+
);
|
|
918
|
+
if (toolSummaries.length > 0) {
|
|
919
|
+
addMessage(
|
|
920
|
+
(0, import_agent_core2.createToolMessage)(JSON.stringify(toolSummaries), {
|
|
921
|
+
toolCallId: (0, import_node_crypto.randomUUID)(),
|
|
922
|
+
name: `${toolSummaries.length} tools`
|
|
923
|
+
})
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
const assistantParts = [];
|
|
927
|
+
let lastAssistantState = "complete";
|
|
928
|
+
for (let i = historyBefore; i < history.length; i++) {
|
|
929
|
+
const msg = history[i];
|
|
930
|
+
if (msg && msg.role === "assistant" && msg.content) {
|
|
931
|
+
assistantParts.push(msg.content);
|
|
932
|
+
if (msg.state === "interrupted") lastAssistantState = "interrupted";
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
if (assistantParts.length > 0) {
|
|
936
|
+
addMessage(
|
|
937
|
+
(0, import_agent_core2.createAssistantMessage)(assistantParts.join("\n\n"), { state: lastAssistantState })
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
addMessage((0, import_agent_core2.createSystemMessage)("Interrupted by user."));
|
|
901
941
|
} else {
|
|
902
942
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
903
|
-
addMessage(
|
|
943
|
+
addMessage((0, import_agent_core2.createSystemMessage)(`Error: ${errMsg}`));
|
|
904
944
|
}
|
|
905
945
|
} finally {
|
|
906
946
|
setIsThinking(false);
|
|
@@ -953,7 +993,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
953
993
|
const runInFork = createForkRunner(session);
|
|
954
994
|
const result = await executeSkill(skill, args, { runInFork });
|
|
955
995
|
if (result.mode === "fork") {
|
|
956
|
-
addMessage(
|
|
996
|
+
addMessage((0, import_agent_core2.createAssistantMessage)(result.result ?? "(empty response)"));
|
|
957
997
|
syncContextState(session, setContextState);
|
|
958
998
|
return;
|
|
959
999
|
}
|
|
@@ -988,7 +1028,7 @@ function useSubmitHandler(session, addMessage, handleSlashCommand, clearStreamin
|
|
|
988
1028
|
hookInput
|
|
989
1029
|
);
|
|
990
1030
|
}
|
|
991
|
-
addMessage(
|
|
1031
|
+
addMessage((0, import_agent_core2.createUserMessage)(input));
|
|
992
1032
|
return runSessionPrompt(
|
|
993
1033
|
input,
|
|
994
1034
|
session,
|
|
@@ -1055,16 +1095,16 @@ var CommandRegistry = class {
|
|
|
1055
1095
|
};
|
|
1056
1096
|
|
|
1057
1097
|
// src/commands/builtin-source.ts
|
|
1058
|
-
var
|
|
1098
|
+
var import_agent_core3 = require("@robota-sdk/agent-core");
|
|
1059
1099
|
function buildModelSubcommands() {
|
|
1060
1100
|
const seen = /* @__PURE__ */ new Set();
|
|
1061
1101
|
const commands = [];
|
|
1062
|
-
for (const model of Object.values(
|
|
1102
|
+
for (const model of Object.values(import_agent_core3.CLAUDE_MODELS)) {
|
|
1063
1103
|
if (seen.has(model.name)) continue;
|
|
1064
1104
|
seen.add(model.name);
|
|
1065
1105
|
commands.push({
|
|
1066
1106
|
name: model.id,
|
|
1067
|
-
description: `${model.name} (${(0,
|
|
1107
|
+
description: `${model.name} (${(0, import_agent_core3.formatTokenCount)(model.contextWindow).toUpperCase()})`,
|
|
1068
1108
|
source: "builtin"
|
|
1069
1109
|
});
|
|
1070
1110
|
}
|
|
@@ -1459,6 +1499,7 @@ function usePluginCallbacks(cwd) {
|
|
|
1459
1499
|
// src/ui/MessageList.tsx
|
|
1460
1500
|
var import_react7 = __toESM(require("react"), 1);
|
|
1461
1501
|
var import_ink2 = require("ink");
|
|
1502
|
+
var import_agent_core4 = require("@robota-sdk/agent-core");
|
|
1462
1503
|
|
|
1463
1504
|
// src/ui/render-markdown.ts
|
|
1464
1505
|
var import_marked = require("marked");
|
|
@@ -1544,9 +1585,14 @@ function RoleLabel({ role }) {
|
|
|
1544
1585
|
}
|
|
1545
1586
|
}
|
|
1546
1587
|
function ToolMessage({ message }) {
|
|
1588
|
+
if (!(0, import_agent_core4.isToolMessage)(message)) {
|
|
1589
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, {});
|
|
1590
|
+
}
|
|
1591
|
+
const toolName = message.name;
|
|
1592
|
+
const content = message.content;
|
|
1547
1593
|
let summaries = null;
|
|
1548
1594
|
try {
|
|
1549
|
-
const parsed = JSON.parse(
|
|
1595
|
+
const parsed = JSON.parse(content);
|
|
1550
1596
|
if (Array.isArray(parsed) && parsed.length > 0 && typeof parsed[0].line === "string") {
|
|
1551
1597
|
summaries = parsed;
|
|
1552
1598
|
}
|
|
@@ -1559,9 +1605,9 @@ function ToolMessage({ message }) {
|
|
|
1559
1605
|
"Tool:",
|
|
1560
1606
|
" "
|
|
1561
1607
|
] }),
|
|
1562
|
-
|
|
1608
|
+
toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1563
1609
|
"[",
|
|
1564
|
-
|
|
1610
|
+
toolName,
|
|
1565
1611
|
"]"
|
|
1566
1612
|
] })
|
|
1567
1613
|
] }),
|
|
@@ -1577,16 +1623,16 @@ function ToolMessage({ message }) {
|
|
|
1577
1623
|
] }, i))
|
|
1578
1624
|
] });
|
|
1579
1625
|
}
|
|
1580
|
-
const lines =
|
|
1626
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
1581
1627
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1582
1628
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { children: [
|
|
1583
1629
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", bold: true, children: [
|
|
1584
1630
|
"Tool:",
|
|
1585
1631
|
" "
|
|
1586
1632
|
] }),
|
|
1587
|
-
|
|
1633
|
+
toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "white", dimColor: true, children: [
|
|
1588
1634
|
"[",
|
|
1589
|
-
|
|
1635
|
+
toolName,
|
|
1590
1636
|
"]"
|
|
1591
1637
|
] })
|
|
1592
1638
|
] }),
|
|
@@ -1602,21 +1648,15 @@ function ToolMessage({ message }) {
|
|
|
1602
1648
|
var MessageItem = import_react7.default.memo(function MessageItem2({
|
|
1603
1649
|
message
|
|
1604
1650
|
}) {
|
|
1605
|
-
if (
|
|
1651
|
+
if ((0, import_agent_core4.isToolMessage)(message)) {
|
|
1606
1652
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToolMessage, { message });
|
|
1607
1653
|
}
|
|
1654
|
+
const content = message.content ?? "";
|
|
1655
|
+
const isInterrupted = message.state === "interrupted";
|
|
1608
1656
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
1609
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
1610
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }),
|
|
1611
|
-
message.toolName && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_ink2.Text, { color: "magenta", dimColor: true, children: [
|
|
1612
|
-
"[",
|
|
1613
|
-
message.toolName,
|
|
1614
|
-
"]",
|
|
1615
|
-
" "
|
|
1616
|
-
] })
|
|
1617
|
-
] }),
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RoleLabel, { role: message.role }) }),
|
|
1618
1658
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { children: " " }),
|
|
1619
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: message
|
|
1659
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Box, { marginLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_ink2.Text, { wrap: "wrap", children: (0, import_agent_core4.isAssistantMessage)(message) ? renderMarkdown(content + (isInterrupted ? "\n\n_(interrupted)_" : "")) : content }) })
|
|
1620
1660
|
] });
|
|
1621
1661
|
});
|
|
1622
1662
|
function MessageList({ messages }) {
|
|
@@ -1625,7 +1665,7 @@ function MessageList({ messages }) {
|
|
|
1625
1665
|
|
|
1626
1666
|
// src/ui/StatusBar.tsx
|
|
1627
1667
|
var import_ink3 = require("ink");
|
|
1628
|
-
var
|
|
1668
|
+
var import_agent_core5 = require("@robota-sdk/agent-core");
|
|
1629
1669
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1630
1670
|
var CONTEXT_YELLOW_THRESHOLD = 70;
|
|
1631
1671
|
var CONTEXT_RED_THRESHOLD = 90;
|
|
@@ -1665,9 +1705,9 @@ function StatusBar({
|
|
|
1665
1705
|
"Context: ",
|
|
1666
1706
|
Math.round(contextPercentage),
|
|
1667
1707
|
"% (",
|
|
1668
|
-
(0,
|
|
1708
|
+
(0, import_agent_core5.formatTokenCount)(contextUsedTokens),
|
|
1669
1709
|
"/",
|
|
1670
|
-
(0,
|
|
1710
|
+
(0, import_agent_core5.formatTokenCount)(contextMaxTokens),
|
|
1671
1711
|
")"
|
|
1672
1712
|
] })
|
|
1673
1713
|
] }),
|
|
@@ -1995,7 +2035,7 @@ function InputArea({ onSubmit, isDisabled, registry }) {
|
|
|
1995
2035
|
isSubcommandMode
|
|
1996
2036
|
}
|
|
1997
2037
|
),
|
|
1998
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response..." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
|
|
2038
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Box, { borderStyle: "single", borderColor: isDisabled ? "gray" : "green", paddingLeft: 1, children: isDisabled ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(WaveText, { text: " Waiting for response... (ESC to interrupt)" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_ink7.Box, { children: [
|
|
1999
2039
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_ink7.Text, { color: "green", bold: true, children: "> " }),
|
|
2000
2040
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2001
2041
|
CjkTextInput,
|
|
@@ -2131,7 +2171,7 @@ function StreamingIndicator({ text, activeTools }) {
|
|
|
2131
2171
|
const hasTools = activeTools.length > 0;
|
|
2132
2172
|
const hasText = text.length > 0;
|
|
2133
2173
|
if (!hasTools && !hasText) {
|
|
2134
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
2174
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, {});
|
|
2135
2175
|
}
|
|
2136
2176
|
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", children: [
|
|
2137
2177
|
hasTools && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_ink10.Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
@@ -2705,7 +2745,7 @@ function App(props) {
|
|
|
2705
2745
|
pendingModelId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2706
2746
|
ConfirmPrompt,
|
|
2707
2747
|
{
|
|
2708
|
-
message: `Change model to ${(0,
|
|
2748
|
+
message: `Change model to ${(0, import_agent_core6.getModelName)(pendingModelId)}? This will restart the session.`,
|
|
2709
2749
|
onSelect: (index) => {
|
|
2710
2750
|
setPendingModelId(null);
|
|
2711
2751
|
pendingModelChangeRef.current = null;
|
|
@@ -2713,19 +2753,21 @@ function App(props) {
|
|
|
2713
2753
|
try {
|
|
2714
2754
|
const settingsPath = getUserSettingsPath();
|
|
2715
2755
|
updateModelInSettings(settingsPath, pendingModelId);
|
|
2716
|
-
addMessage(
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2756
|
+
addMessage(
|
|
2757
|
+
(0, import_agent_core7.createSystemMessage)(
|
|
2758
|
+
`Model changed to ${(0, import_agent_core6.getModelName)(pendingModelId)}. Restarting...`
|
|
2759
|
+
)
|
|
2760
|
+
);
|
|
2720
2761
|
setTimeout(() => exit(), EXIT_DELAY_MS2);
|
|
2721
2762
|
} catch (err) {
|
|
2722
|
-
addMessage(
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2763
|
+
addMessage(
|
|
2764
|
+
(0, import_agent_core7.createSystemMessage)(
|
|
2765
|
+
`Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2766
|
+
)
|
|
2767
|
+
);
|
|
2726
2768
|
}
|
|
2727
2769
|
} else {
|
|
2728
|
-
addMessage(
|
|
2770
|
+
addMessage((0, import_agent_core7.createSystemMessage)("Model change cancelled."));
|
|
2729
2771
|
}
|
|
2730
2772
|
}
|
|
2731
2773
|
}
|
|
@@ -2735,14 +2777,14 @@ function App(props) {
|
|
|
2735
2777
|
{
|
|
2736
2778
|
callbacks: pluginCallbacks,
|
|
2737
2779
|
onClose: () => setShowPluginTUI(false),
|
|
2738
|
-
addMessage: (msg) => addMessage(msg)
|
|
2780
|
+
addMessage: (msg) => addMessage((0, import_agent_core7.createSystemMessage)(msg.content))
|
|
2739
2781
|
}
|
|
2740
2782
|
),
|
|
2741
2783
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
2742
2784
|
StatusBar,
|
|
2743
2785
|
{
|
|
2744
2786
|
permissionMode: session.getPermissionMode(),
|
|
2745
|
-
modelName: (0,
|
|
2787
|
+
modelName: (0, import_agent_core6.getModelName)(props.config.provider.model),
|
|
2746
2788
|
sessionId: session.getSessionId(),
|
|
2747
2789
|
messageCount: messages.length,
|
|
2748
2790
|
isThinking,
|
package/dist/node/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-cli",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.36",
|
|
4
4
|
"description": "AI coding assistant CLI built on Robota SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"marked-terminal": "^7.3.0",
|
|
36
36
|
"react": "19.2.4",
|
|
37
37
|
"string-width": "^8.2.0",
|
|
38
|
-
"@robota-sdk/agent-
|
|
39
|
-
"@robota-sdk/agent-
|
|
38
|
+
"@robota-sdk/agent-core": "3.0.0-beta.33",
|
|
39
|
+
"@robota-sdk/agent-sdk": "3.0.0-beta.33"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/marked": "^6.0.0",
|