wave-code 0.16.13 → 0.17.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.
@@ -23,6 +23,7 @@ export declare class WaveAcpAgent implements AcpAgent {
23
23
  private getToolContent;
24
24
  private getToolLocations;
25
25
  private getToolKind;
26
+ private replayConversationHistory;
26
27
  private createCallbacks;
27
28
  }
28
29
  //# sourceMappingURL=agent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAqBA,OAAO,EACL,KAAK,KAAK,IAAI,QAAQ,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAUzB,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EAOpC,MAAM,0BAA0B,CAAC;AAGlC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;gBAE5B,UAAU,EAAE,mBAAmB;IAI3C,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,uBAAuB;YAmCjB,gBAAgB;IASxB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAyBzC,YAAY,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;YAI5C,WAAW;IA0EnB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAalE,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAWrE,YAAY,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,oBAAoB,CAAC;IAuB1B,qBAAqB,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAc7B,SAAS,CACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAO7B,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D,sBAAsB,CAC1B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,8BAA8B,CAAC;IAuBpC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAyDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,OAAO,CAAC,kBAAkB;YA2BZ,uBAAuB;IA8LrC,OAAO,CAAC,cAAc;IAwGtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CAyOxB"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAyBA,OAAO,EACL,KAAK,KAAK,IAAI,QAAQ,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAUzB,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EAOpC,MAAM,0BAA0B,CAAC;AAGlC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;gBAE5B,UAAU,EAAE,mBAAmB;IAI3C,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,uBAAuB;YAmCjB,gBAAgB;IASxB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAyBzC,YAAY,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;YAI5C,WAAW;IA2EnB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAalE,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAcrE,YAAY,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,oBAAoB,CAAC;IAuB1B,qBAAqB,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAc7B,SAAS,CACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAO7B,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D,sBAAsB,CAC1B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,8BAA8B,CAAC;IAuBpC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAyDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,OAAO,CAAC,kBAAkB;YA2BZ,uBAAuB;IA8LrC,OAAO,CAAC,cAAc;IAwGtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;YAmBL,yBAAyB;IAiIvC,OAAO,CAAC,eAAe;CAyOxB"}
package/dist/acp/agent.js CHANGED
@@ -174,6 +174,8 @@ export class WaveAcpAgent {
174
174
  const { sessionId, cwd, mcpServers } = params;
175
175
  logger.info(`Loading session: ${sessionId} in ${cwd}`);
176
176
  const agent = await this.createAgent(sessionId, cwd, mcpServers);
177
+ // Replay conversation history via session/update notifications per ACP spec
178
+ await this.replayConversationHistory(agent);
177
179
  return {
178
180
  modes: this.getSessionModeState(agent),
179
181
  configOptions: this.getSessionConfigOptions(agent),
@@ -618,6 +620,119 @@ export class WaveAcpAgent {
618
620
  return "other";
619
621
  }
620
622
  }
623
+ async replayConversationHistory(agent) {
624
+ const sessionId = agent.sessionId;
625
+ let history;
626
+ try {
627
+ const thread = await agent.getFullMessageThread();
628
+ history = thread.messages;
629
+ }
630
+ catch {
631
+ // Fallback to in-memory messages if full thread fails
632
+ history = agent.messages;
633
+ }
634
+ for (const message of history) {
635
+ if (message.isMeta)
636
+ continue;
637
+ const messageId = message.id;
638
+ for (const block of message.blocks) {
639
+ if (block.type === "text") {
640
+ const textBlock = block;
641
+ const update = message.role === "user"
642
+ ? {
643
+ sessionUpdate: "user_message_chunk",
644
+ content: { type: "text", text: textBlock.content },
645
+ messageId,
646
+ }
647
+ : {
648
+ sessionUpdate: "agent_message_chunk",
649
+ content: { type: "text", text: textBlock.content },
650
+ messageId,
651
+ };
652
+ this.connection.sessionUpdate({ sessionId, update });
653
+ }
654
+ else if (block.type === "reasoning") {
655
+ const reasoningBlock = block;
656
+ this.connection.sessionUpdate({
657
+ sessionId,
658
+ update: {
659
+ sessionUpdate: "agent_thought_chunk",
660
+ content: { type: "text", text: reasoningBlock.content },
661
+ messageId,
662
+ },
663
+ });
664
+ }
665
+ else if (block.type === "tool") {
666
+ const toolBlock = block;
667
+ const toolCallId = toolBlock.id ||
668
+ "replay-" + Math.random().toString(36).substring(2, 9);
669
+ const effectiveName = toolBlock.name || "Tool";
670
+ const effectiveCompactParams = toolBlock.compactParams;
671
+ const displayTitle = effectiveName && effectiveCompactParams
672
+ ? `${effectiveName}: ${effectiveCompactParams}`
673
+ : effectiveName;
674
+ let parsedParameters;
675
+ if (toolBlock.parameters) {
676
+ try {
677
+ const parsed = JSON.parse(toolBlock.parameters);
678
+ parsedParameters = Array.isArray(parsed)
679
+ ? { args: parsed }
680
+ : parsed;
681
+ }
682
+ catch {
683
+ // Ignore parse errors
684
+ }
685
+ }
686
+ const content = effectiveName && (parsedParameters || toolBlock.shortResult)
687
+ ? this.getToolContent(effectiveName, parsedParameters, toolBlock.shortResult)
688
+ : undefined;
689
+ const locations = effectiveName && parsedParameters
690
+ ? this.getToolLocations(effectiveName, parsedParameters)
691
+ : undefined;
692
+ const kind = effectiveName
693
+ ? this.getToolKind(effectiveName)
694
+ : undefined;
695
+ // Emit tool_call (creation)
696
+ this.connection.sessionUpdate({
697
+ sessionId,
698
+ update: {
699
+ sessionUpdate: "tool_call",
700
+ toolCallId,
701
+ title: displayTitle,
702
+ status: "pending",
703
+ content,
704
+ locations,
705
+ kind,
706
+ rawInput: parsedParameters,
707
+ },
708
+ });
709
+ // Emit tool_call_update with final status
710
+ const status = toolBlock.stage === "end"
711
+ ? toolBlock.success
712
+ ? "completed"
713
+ : "failed"
714
+ : toolBlock.stage === "running"
715
+ ? "in_progress"
716
+ : "pending";
717
+ this.connection.sessionUpdate({
718
+ sessionId,
719
+ update: {
720
+ sessionUpdate: "tool_call_update",
721
+ toolCallId,
722
+ status,
723
+ title: displayTitle,
724
+ rawOutput: toolBlock.result || toolBlock.error,
725
+ content,
726
+ locations,
727
+ kind,
728
+ rawInput: parsedParameters,
729
+ },
730
+ });
731
+ }
732
+ // Skip: image, bang, compact, error, file_history, task_notification blocks
733
+ }
734
+ }
735
+ }
621
736
  createCallbacks(sessionId) {
622
737
  const getAgent = () => this.agents.get(sessionId);
623
738
  const toolStates = new Map();
@@ -821,10 +936,12 @@ function convertAcpMcpServers(servers) {
821
936
  for (const server of servers) {
822
937
  const config = {};
823
938
  if ("type" in server && server.type === "http") {
939
+ config.type = "http";
824
940
  config.url = server.url;
825
941
  config.headers = convertHttpHeaders(server.headers);
826
942
  }
827
943
  else if ("type" in server && server.type === "sse") {
944
+ config.type = "sse";
828
945
  config.url = server.url;
829
946
  config.headers = convertHttpHeaders(server.headers);
830
947
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAa3D,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EA+HjC,CAAC"}
1
+ {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAa3D,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAkIjC,CAAC"}
@@ -10,7 +10,7 @@ import { ConfirmationDetails } from "./ConfirmationDetails.js";
10
10
  import { ConfirmationSelector } from "./ConfirmationSelector.js";
11
11
  import { useChat } from "../contexts/useChat.js";
12
12
  export const ChatInterface = () => {
13
- const { messages, isLoading, isCommandRunning, isCompacting, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, hasPendingConfirmations, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, version, workdir, remountKey, requestRemount, } = useChat();
13
+ const { messages, isLoading, isCommandRunning, isCompacting, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, maxInputTokens, slashCommands, hasSlashCommand, isConfirmationVisible, hasPendingConfirmations, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, version, workdir, remountKey, requestRemount, } = useChat();
14
14
  const displayMessages = messages;
15
15
  const [forceStatic, setForceStatic] = useState(false);
16
16
  const { stdout } = useStdout();
@@ -37,5 +37,5 @@ export const ChatInterface = () => {
37
37
  ]);
38
38
  if (!sessionId)
39
39
  return null;
40
- return (_jsxs(Box, { ref: chatInterfaceRef, flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, version: version, workdir: workdir, forceStatic: forceStatic }, remountKey), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [(isLoading || isCommandRunning || isCompacting) && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompacting: isCompacting, latestTotalTokens: latestTotalTokens })), _jsx(TaskList, {}), _jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand })] })), isConfirmationVisible && (_jsxs(_Fragment, { children: [forceStatic ? (_jsx(Static, { items: [{ key: "confirmation-details" }], children: () => (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded }, "confirmation-details")) })) : (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: handleConfirmationDecision, onCancel: handleConfirmationCancel })] }))] }));
40
+ return (_jsxs(Box, { ref: chatInterfaceRef, flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, version: version, workdir: workdir, forceStatic: forceStatic }, remountKey), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [(isLoading || isCommandRunning || isCompacting) && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompacting: isCompacting, latestTotalTokens: latestTotalTokens })), _jsx(TaskList, {}), _jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand, latestTotalTokens: latestTotalTokens, maxInputTokens: maxInputTokens })] })), isConfirmationVisible && (_jsxs(_Fragment, { children: [forceStatic ? (_jsx(Static, { items: [{ key: "confirmation-details" }], children: () => (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded }, "confirmation-details")) })) : (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: handleConfirmationDecision, onCancel: handleConfirmationCancel })] }))] }));
41
41
  };
@@ -16,6 +16,8 @@ export interface InputBoxProps {
16
16
  disconnectMcpServer?: (serverName: string) => Promise<boolean>;
17
17
  slashCommands?: SlashCommand[];
18
18
  hasSlashCommand?: (commandId: string) => boolean;
19
+ latestTotalTokens?: number;
20
+ maxInputTokens?: number;
19
21
  }
20
22
  export declare const InputBox: React.FC<InputBoxProps>;
21
23
  //# sourceMappingURL=InputBox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAmBzC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA4R5C,CAAC"}
1
+ {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAmBzC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAEjD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAgS5C,CAAC"}
@@ -19,7 +19,7 @@ import { useInputManager } from "../hooks/useInputManager.js";
19
19
  import { useChat } from "../contexts/useChat.js";
20
20
  export const INPUT_PLACEHOLDER_TEXT = "Type your message (use /help for more info)...";
21
21
  export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
22
- export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
22
+ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, latestTotalTokens = 0, maxInputTokens = 128000, }) => {
23
23
  const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, currentModel, configuredModels, setModel, recreateAgent, } = useChat();
24
24
  // Input manager with all input state and functionality (including images)
25
25
  const { inputText, cursorPosition,
@@ -122,5 +122,5 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
122
122
  showHelp ||
123
123
  showStatusCommand ||
124
124
  showLoginCommand ||
125
- showPluginManager || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: btwState.isActive ? "cyan" : "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: btwState.isActive && isPlaceholder ? (_jsxs(_Fragment, { children: [_jsx(Text, { backgroundColor: "white", color: "black", children: " " }), _jsx(Text, { color: "cyan", children: "Type your side question..." })] })) : shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(StatusLine, { permissionMode: permissionMode, isShellCommand: isShellCommand, isBtwActive: btwState.isActive })] }))] }));
125
+ showPluginManager || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: btwState.isActive ? "cyan" : "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: btwState.isActive && isPlaceholder ? (_jsxs(_Fragment, { children: [_jsx(Text, { backgroundColor: "white", color: "black", children: " " }), _jsx(Text, { color: "cyan", children: "Type your side question..." })] })) : shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(StatusLine, { permissionMode: permissionMode, isShellCommand: isShellCommand, isBtwActive: btwState.isActive, latestTotalTokens: latestTotalTokens, maxInputTokens: maxInputTokens })] }))] }));
126
126
  };
@@ -1 +1 @@
1
- {"version":3,"file":"McpManager.d.ts","sourceRoot":"","sources":["../../src/components/McpManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAQD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA0RhD,CAAC"}
1
+ {"version":3,"file":"McpManager.d.ts","sourceRoot":"","sources":["../../src/components/McpManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAErD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAMjD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,kBAAkB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9D;AAQD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAiShD,CAAC"}
@@ -70,7 +70,7 @@ export const McpManager = ({ onCancel, servers, onConnectServer, onDisconnectSer
70
70
  });
71
71
  });
72
72
  if (state.viewMode === "detail" && selectedServer) {
73
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["MCP Server Details: ", selectedServer.name] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", _jsxs(Text, { color: getStatusColor(selectedServer.status), children: [getStatusIcon(selectedServer.status), " ", selectedServer.status] })] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Command:" }), " ", selectedServer.config.command] }) }), selectedServer.originalUrl && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "URL:" }), " ", selectedServer.originalUrl] }) })), selectedServer.config.args && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Args:" }), " ", selectedServer.config.args.join(" ")] }) })), selectedServer.toolCount !== undefined && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Tools:" }), " ", selectedServer.toolCount, " ", "tools"] }) })), selectedServer.capabilities && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Capabilities:" }), " ", selectedServer.capabilities.join(", ")] }) })), selectedServer.lastConnected && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Last Connected:" }), " ", formatTime(selectedServer.lastConnected)] }) })), selectedServer.error && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "red", children: "Error:" }), " ", selectedServer.error] }) }))] }), selectedServer.config.env &&
73
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["MCP Server Details: ", selectedServer.name] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", _jsxs(Text, { color: getStatusColor(selectedServer.status), children: [getStatusIcon(selectedServer.status), " ", selectedServer.status] })] }) }), selectedServer.config.type && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Type:" }), " ", selectedServer.config.type] }) })), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Command:" }), " ", selectedServer.config.command] }) }), selectedServer.originalUrl && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "URL:" }), " ", selectedServer.originalUrl] }) })), selectedServer.config.args && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Args:" }), " ", selectedServer.config.args.join(" ")] }) })), selectedServer.toolCount !== undefined && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Tools:" }), " ", selectedServer.toolCount, " ", "tools"] }) })), selectedServer.capabilities && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Capabilities:" }), " ", selectedServer.capabilities.join(", ")] }) })), selectedServer.lastConnected && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Last Connected:" }), " ", formatTime(selectedServer.lastConnected)] }) })), selectedServer.error && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "red", children: "Error:" }), " ", selectedServer.error] }) }))] }), selectedServer.config.env &&
74
74
  Object.keys(selectedServer.config.env).length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "blue", bold: true, children: "Environment Variables:" }), _jsx(Box, { borderStyle: "single", borderColor: "blue", padding: 1, children: Object.entries(selectedServer.config.env).map(([key, value]) => (_jsxs(Text, { children: [key, "=", value] }, key))) })] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [selectedServer.status === "disconnected" ||
75
75
  selectedServer.status === "error"
76
76
  ? "c to connect · "
@@ -1 +1 @@
1
- {"version":3,"file":"QueuedMessageList.d.ts","sourceRoot":"","sources":["../../src/components/QueuedMessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EA0BrC,CAAC"}
1
+ {"version":3,"file":"QueuedMessageList.d.ts","sourceRoot":"","sources":["../../src/components/QueuedMessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,EA2BrC,CAAC"}
@@ -9,7 +9,8 @@ export const QueuedMessageList = () => {
9
9
  return (_jsx(Box, { flexDirection: "column", children: queuedMessages.map((msg, index) => {
10
10
  const content = msg.content.trim();
11
11
  const hasImages = msg.images && msg.images.length > 0;
12
- const displayText = content || (hasImages ? "[Images]" : "");
12
+ const prefix = msg.type === "bang" ? "! " : "";
13
+ const displayText = prefix + (content || (hasImages ? "[Images]" : ""));
13
14
  return (_jsx(Box, { children: _jsx(Text, { color: "gray", italic: true, children: displayText.length > 60
14
15
  ? `${displayText.substring(0, 57)}...`
15
16
  : displayText }) }, index));
@@ -3,6 +3,8 @@ export interface StatusLineProps {
3
3
  permissionMode: string;
4
4
  isShellCommand: boolean;
5
5
  isBtwActive: boolean;
6
+ latestTotalTokens?: number;
7
+ maxInputTokens?: number;
6
8
  }
7
9
  export declare const StatusLine: React.FC<StatusLineProps>;
8
10
  //# sourceMappingURL=StatusLine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../src/components/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAmChD,CAAC"}
1
+ {"version":3,"file":"StatusLine.d.ts","sourceRoot":"","sources":["../../src/components/StatusLine.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAgDhD,CAAC"}
@@ -1,9 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
- export const StatusLine = ({ permissionMode, isShellCommand, isBtwActive, }) => {
4
- return (_jsx(Box, { paddingRight: 1, justifyContent: "space-between", width: "100%", children: isBtwActive ? (_jsxs(Text, { color: "gray", children: ["Mode: ", _jsx(Text, { color: "cyan", children: "BTW" }), " (ESC to dismiss)"] })) : isShellCommand ? (_jsxs(Text, { color: "gray", children: ["Shell: ", _jsx(Text, { color: "yellow", children: "Run shell command" })] })) : (_jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan"
5
- ? "yellow"
6
- : permissionMode === "bypassPermissions"
7
- ? "red"
8
- : "cyan", bold: permissionMode === "bypassPermissions", children: permissionMode }), " ", "(Shift+Tab to cycle)"] })) }));
3
+ export const StatusLine = ({ permissionMode, isShellCommand, isBtwActive, latestTotalTokens = 0, maxInputTokens = 128000, }) => {
4
+ const percentage = latestTotalTokens > 0
5
+ ? Math.min(Math.round((latestTotalTokens / maxInputTokens) * 100), 100)
6
+ : 0;
7
+ const contextColor = percentage > 95 ? "red" : percentage > 80 ? "yellow" : "gray";
8
+ return (_jsxs(Box, { paddingRight: 1, justifyContent: "space-between", width: "100%", children: [isBtwActive ? (_jsxs(Text, { color: "gray", children: ["Mode: ", _jsx(Text, { color: "cyan", children: "BTW" }), " (ESC to dismiss)"] })) : isShellCommand ? (_jsxs(Text, { color: "gray", children: ["Shell: ", _jsx(Text, { color: "yellow", children: "Run shell command" })] })) : (_jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan"
9
+ ? "yellow"
10
+ : permissionMode === "bypassPermissions"
11
+ ? "red"
12
+ : "cyan", bold: permissionMode === "bypassPermissions", children: permissionMode }), " ", "(Shift+Tab to cycle)"] })), percentage > 0 && (_jsxs(Text, { color: contextColor, children: [percentage, "% context"] }))] }));
9
13
  };
@@ -18,6 +18,7 @@ export interface ChatContextType {
18
18
  askBtw: (question: string) => Promise<string>;
19
19
  abortMessage: () => void;
20
20
  latestTotalTokens: number;
21
+ maxInputTokens: number;
21
22
  currentModel: string;
22
23
  configuredModels: string[];
23
24
  getConfiguredModels: () => string[];
@@ -1 +1 @@
1
- {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
@@ -24,6 +24,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
24
24
  const [isTaskListVisible, setIsTaskListVisible] = useState(true);
25
25
  const [messages, setMessages] = useState([]);
26
26
  const [latestTotalTokens, setLatestTotalTokens] = useState(0);
27
+ const [maxInputTokens, setMaxInputTokens] = useState(128000);
27
28
  const throttledSetMessages = useMemo(() => throttle(() => {
28
29
  if (!isExpandedRef.current && agentRef.current) {
29
30
  const msgs = [...agentRef.current.messages];
@@ -69,7 +70,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
69
70
  const [remountKey, setRemountKey] = useState(0);
70
71
  const prevSessionId = useRef(null);
71
72
  const requestRemount = useMemo(() => throttle(() => {
72
- logger.info("requesting remount");
73
+ logger.debug("requesting remount");
73
74
  stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", () => {
74
75
  setRemountKey((prev) => prev + 1);
75
76
  });
@@ -195,6 +196,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
195
196
  setWorkingDirectory(agent.workingDirectory);
196
197
  setCurrentModelState(agent.getModelConfig().model);
197
198
  setConfiguredModels(agent.getConfiguredModels());
199
+ setMaxInputTokens(agent.getMaxInputTokens());
198
200
  // Get initial MCP servers state
199
201
  const initialMcpServers = agent.getMcpServers?.() || [];
200
202
  setMcpServerStatuses(initialMcpServers);
@@ -239,6 +241,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
239
241
  setSessionId("");
240
242
  setIsLoading(false);
241
243
  setLatestTotalTokens(0);
244
+ setMaxInputTokens(128000);
242
245
  setIsCommandRunning(false);
243
246
  setIsCompacting(false);
244
247
  if (currentSessionId) {
@@ -476,6 +479,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
476
479
  askBtw,
477
480
  abortMessage,
478
481
  latestTotalTokens,
482
+ maxInputTokens,
479
483
  currentModel,
480
484
  configuredModels,
481
485
  getConfiguredModels,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.16.13",
3
+ "version": "0.17.1",
4
4
  "description": "CLI-based code assistant powered by AI, built with React and Ink",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,7 +42,7 @@
42
42
  "semver": "^7.7.4",
43
43
  "yargs": "^17.7.2",
44
44
  "zod": "^3.23.8",
45
- "wave-agent-sdk": "0.16.13"
45
+ "wave-agent-sdk": "0.17.1"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^19.1.8",
package/src/acp/agent.ts CHANGED
@@ -17,6 +17,10 @@ import {
17
17
  ASK_USER_QUESTION_TOOL_NAME,
18
18
  AskUserQuestion,
19
19
  AskUserQuestionOption,
20
+ type Message,
21
+ type TextBlock,
22
+ type ReasoningBlock,
23
+ type ToolBlock,
20
24
  } from "wave-agent-sdk";
21
25
  import { logger } from "../utils/logger.js";
22
26
  import {
@@ -211,7 +215,8 @@ export class WaveAcpAgent implements AcpAgent {
211
215
  callbacks.onPermissionModeChange?.(mode),
212
216
  onModelChange: (model) => callbacks.onModelChange?.(model),
213
217
  onUserMessageAdded: (params) => callbacks.onUserMessageAdded?.(params),
214
- onMcpServersChange: (servers) => callbacks.onMcpServersChange?.(servers),
218
+ onMcpServersChange: (servers) =>
219
+ callbacks.onMcpServersChange?.(servers),
215
220
  },
216
221
  });
217
222
 
@@ -261,6 +266,9 @@ export class WaveAcpAgent implements AcpAgent {
261
266
  logger.info(`Loading session: ${sessionId} in ${cwd}`);
262
267
  const agent = await this.createAgent(sessionId, cwd, mcpServers);
263
268
 
269
+ // Replay conversation history via session/update notifications per ACP spec
270
+ await this.replayConversationHistory(agent);
271
+
264
272
  return {
265
273
  modes: this.getSessionModeState(agent),
266
274
  configOptions: this.getSessionConfigOptions(agent),
@@ -798,6 +806,135 @@ export class WaveAcpAgent implements AcpAgent {
798
806
  }
799
807
  }
800
808
 
809
+ private async replayConversationHistory(agent: WaveAgent): Promise<void> {
810
+ const sessionId = agent.sessionId as AcpSessionId;
811
+
812
+ let history: Message[];
813
+ try {
814
+ const thread = await agent.getFullMessageThread();
815
+ history = thread.messages;
816
+ } catch {
817
+ // Fallback to in-memory messages if full thread fails
818
+ history = agent.messages;
819
+ }
820
+
821
+ for (const message of history) {
822
+ if (message.isMeta) continue;
823
+
824
+ const messageId = message.id;
825
+
826
+ for (const block of message.blocks) {
827
+ if (block.type === "text") {
828
+ const textBlock = block as TextBlock;
829
+ const update =
830
+ message.role === "user"
831
+ ? {
832
+ sessionUpdate: "user_message_chunk" as const,
833
+ content: { type: "text" as const, text: textBlock.content },
834
+ messageId,
835
+ }
836
+ : {
837
+ sessionUpdate: "agent_message_chunk" as const,
838
+ content: { type: "text" as const, text: textBlock.content },
839
+ messageId,
840
+ };
841
+ this.connection.sessionUpdate({ sessionId, update });
842
+ } else if (block.type === "reasoning") {
843
+ const reasoningBlock = block as ReasoningBlock;
844
+ this.connection.sessionUpdate({
845
+ sessionId,
846
+ update: {
847
+ sessionUpdate: "agent_thought_chunk",
848
+ content: { type: "text", text: reasoningBlock.content },
849
+ messageId,
850
+ },
851
+ });
852
+ } else if (block.type === "tool") {
853
+ const toolBlock = block as ToolBlock;
854
+ const toolCallId =
855
+ toolBlock.id ||
856
+ "replay-" + Math.random().toString(36).substring(2, 9);
857
+ const effectiveName = toolBlock.name || "Tool";
858
+ const effectiveCompactParams = toolBlock.compactParams;
859
+
860
+ const displayTitle =
861
+ effectiveName && effectiveCompactParams
862
+ ? `${effectiveName}: ${effectiveCompactParams}`
863
+ : effectiveName;
864
+
865
+ let parsedParameters: Record<string, unknown> | undefined;
866
+ if (toolBlock.parameters) {
867
+ try {
868
+ const parsed = JSON.parse(toolBlock.parameters);
869
+ parsedParameters = Array.isArray(parsed)
870
+ ? { args: parsed }
871
+ : parsed;
872
+ } catch {
873
+ // Ignore parse errors
874
+ }
875
+ }
876
+
877
+ const content =
878
+ effectiveName && (parsedParameters || toolBlock.shortResult)
879
+ ? this.getToolContent(
880
+ effectiveName,
881
+ parsedParameters,
882
+ toolBlock.shortResult,
883
+ )
884
+ : undefined;
885
+ const locations =
886
+ effectiveName && parsedParameters
887
+ ? this.getToolLocations(effectiveName, parsedParameters)
888
+ : undefined;
889
+ const kind = effectiveName
890
+ ? this.getToolKind(effectiveName)
891
+ : undefined;
892
+
893
+ // Emit tool_call (creation)
894
+ this.connection.sessionUpdate({
895
+ sessionId,
896
+ update: {
897
+ sessionUpdate: "tool_call",
898
+ toolCallId,
899
+ title: displayTitle,
900
+ status: "pending",
901
+ content,
902
+ locations,
903
+ kind,
904
+ rawInput: parsedParameters,
905
+ },
906
+ });
907
+
908
+ // Emit tool_call_update with final status
909
+ const status: ToolCallStatus =
910
+ toolBlock.stage === "end"
911
+ ? toolBlock.success
912
+ ? "completed"
913
+ : "failed"
914
+ : toolBlock.stage === "running"
915
+ ? "in_progress"
916
+ : "pending";
917
+
918
+ this.connection.sessionUpdate({
919
+ sessionId,
920
+ update: {
921
+ sessionUpdate: "tool_call_update",
922
+ toolCallId,
923
+ status,
924
+ title: displayTitle,
925
+ rawOutput: toolBlock.result || toolBlock.error,
926
+ content,
927
+ locations,
928
+ kind,
929
+ rawInput: parsedParameters,
930
+ },
931
+ });
932
+ }
933
+ // Skip: image, bang, compact, error, file_history, task_notification blocks
934
+ }
935
+ }
936
+ }
937
+
801
938
  private createCallbacks(sessionId: string): AgentOptions["callbacks"] {
802
939
  const getAgent = () => this.agents.get(sessionId);
803
940
  const toolStates = new Map<
@@ -1043,9 +1180,11 @@ function convertAcpMcpServers(
1043
1180
  for (const server of servers) {
1044
1181
  const config: McpServerConfig = {};
1045
1182
  if ("type" in server && server.type === "http") {
1183
+ config.type = "http";
1046
1184
  config.url = server.url;
1047
1185
  config.headers = convertHttpHeaders(server.headers);
1048
1186
  } else if ("type" in server && server.type === "sse") {
1187
+ config.type = "sse";
1049
1188
  config.url = server.url;
1050
1189
  config.headers = convertHttpHeaders(server.headers);
1051
1190
  } else {
@@ -25,6 +25,7 @@ export const ChatInterface: React.FC = () => {
25
25
  isExpanded,
26
26
  sessionId,
27
27
  latestTotalTokens,
28
+ maxInputTokens,
28
29
  slashCommands,
29
30
  hasSlashCommand,
30
31
  isConfirmationVisible,
@@ -99,6 +100,8 @@ export const ChatInterface: React.FC = () => {
99
100
  disconnectMcpServer={disconnectMcpServer}
100
101
  slashCommands={slashCommands}
101
102
  hasSlashCommand={hasSlashCommand}
103
+ latestTotalTokens={latestTotalTokens}
104
+ maxInputTokens={maxInputTokens}
102
105
  />
103
106
  </>
104
107
  )}
@@ -44,6 +44,9 @@ export interface InputBoxProps {
44
44
  // Slash Command related properties
45
45
  slashCommands?: SlashCommand[];
46
46
  hasSlashCommand?: (commandId: string) => boolean;
47
+ // Token usage
48
+ latestTotalTokens?: number;
49
+ maxInputTokens?: number;
47
50
  }
48
51
 
49
52
  export const InputBox: React.FC<InputBoxProps> = ({
@@ -54,6 +57,8 @@ export const InputBox: React.FC<InputBoxProps> = ({
54
57
  disconnectMcpServer = async () => false,
55
58
  slashCommands = [],
56
59
  hasSlashCommand = () => false,
60
+ latestTotalTokens = 0,
61
+ maxInputTokens = 128000,
57
62
  }) => {
58
63
  const {
59
64
  permissionMode: chatPermissionMode,
@@ -325,6 +330,8 @@ export const InputBox: React.FC<InputBoxProps> = ({
325
330
  permissionMode={permissionMode}
326
331
  isShellCommand={isShellCommand}
327
332
  isBtwActive={btwState.isActive}
333
+ latestTotalTokens={latestTotalTokens}
334
+ maxInputTokens={maxInputTokens}
328
335
  />
329
336
  </Box>
330
337
  )}
@@ -122,6 +122,13 @@ export const McpManager: React.FC<McpManagerProps> = ({
122
122
  </Text>
123
123
  </Text>
124
124
  </Box>
125
+ {selectedServer.config.type && (
126
+ <Box>
127
+ <Text>
128
+ <Text color="blue">Type:</Text> {selectedServer.config.type}
129
+ </Text>
130
+ </Box>
131
+ )}
125
132
  <Box>
126
133
  <Text>
127
134
  <Text color="blue">Command:</Text> {selectedServer.config.command}
@@ -14,7 +14,8 @@ export const QueuedMessageList: React.FC = () => {
14
14
  {queuedMessages.map((msg, index) => {
15
15
  const content = msg.content.trim();
16
16
  const hasImages = msg.images && msg.images.length > 0;
17
- const displayText = content || (hasImages ? "[Images]" : "");
17
+ const prefix = msg.type === "bang" ? "! " : "";
18
+ const displayText = prefix + (content || (hasImages ? "[Images]" : ""));
18
19
 
19
20
  return (
20
21
  <Box key={index}>
@@ -5,13 +5,25 @@ export interface StatusLineProps {
5
5
  permissionMode: string;
6
6
  isShellCommand: boolean;
7
7
  isBtwActive: boolean;
8
+ latestTotalTokens?: number;
9
+ maxInputTokens?: number;
8
10
  }
9
11
 
10
12
  export const StatusLine: React.FC<StatusLineProps> = ({
11
13
  permissionMode,
12
14
  isShellCommand,
13
15
  isBtwActive,
16
+ latestTotalTokens = 0,
17
+ maxInputTokens = 128000,
14
18
  }) => {
19
+ const percentage =
20
+ latestTotalTokens > 0
21
+ ? Math.min(Math.round((latestTotalTokens / maxInputTokens) * 100), 100)
22
+ : 0;
23
+
24
+ const contextColor =
25
+ percentage > 95 ? "red" : percentage > 80 ? "yellow" : "gray";
26
+
15
27
  return (
16
28
  <Box paddingRight={1} justifyContent="space-between" width="100%">
17
29
  {isBtwActive ? (
@@ -40,6 +52,9 @@ export const StatusLine: React.FC<StatusLineProps> = ({
40
52
  (Shift+Tab to cycle)
41
53
  </Text>
42
54
  )}
55
+ {percentage > 0 && (
56
+ <Text color={contextColor}>{percentage}% context</Text>
57
+ )}
43
58
  </Box>
44
59
  );
45
60
  };
@@ -54,6 +54,7 @@ export interface ChatContextType {
54
54
  askBtw: (question: string) => Promise<string>;
55
55
  abortMessage: () => void;
56
56
  latestTotalTokens: number;
57
+ maxInputTokens: number;
57
58
  // Model functionality
58
59
  currentModel: string;
59
60
  configuredModels: string[];
@@ -162,6 +163,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
162
163
 
163
164
  const [messages, setMessages] = useState<Message[]>([]);
164
165
  const [latestTotalTokens, setLatestTotalTokens] = useState(0);
166
+ const [maxInputTokens, setMaxInputTokens] = useState(128000);
165
167
 
166
168
  const throttledSetMessages = useMemo(
167
169
  () =>
@@ -260,7 +262,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
260
262
  () =>
261
263
  throttle(
262
264
  () => {
263
- logger.info("requesting remount");
265
+ logger.debug("requesting remount");
264
266
  stdout?.write("\u001b[2J\u001b[3J\u001b[0;0H", () => {
265
267
  setRemountKey((prev) => prev + 1);
266
268
  });
@@ -424,6 +426,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
424
426
  setWorkingDirectory(agent.workingDirectory);
425
427
  setCurrentModelState(agent.getModelConfig().model);
426
428
  setConfiguredModels(agent.getConfiguredModels());
429
+ setMaxInputTokens(agent.getMaxInputTokens());
427
430
 
428
431
  // Get initial MCP servers state
429
432
  const initialMcpServers = agent.getMcpServers?.() || [];
@@ -471,6 +474,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
471
474
  setSessionId("");
472
475
  setIsLoading(false);
473
476
  setLatestTotalTokens(0);
477
+ setMaxInputTokens(128000);
474
478
  setIsCommandRunning(false);
475
479
  setIsCompacting(false);
476
480
  if (currentSessionId) {
@@ -750,6 +754,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
750
754
  askBtw,
751
755
  abortMessage,
752
756
  latestTotalTokens,
757
+ maxInputTokens,
753
758
  currentModel,
754
759
  configuredModels,
755
760
  getConfiguredModels,