wave-code 0.17.0 → 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;IA2EnB,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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.17.0",
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.17.0"
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 {
@@ -262,6 +266,9 @@ export class WaveAcpAgent implements AcpAgent {
262
266
  logger.info(`Loading session: ${sessionId} in ${cwd}`);
263
267
  const agent = await this.createAgent(sessionId, cwd, mcpServers);
264
268
 
269
+ // Replay conversation history via session/update notifications per ACP spec
270
+ await this.replayConversationHistory(agent);
271
+
265
272
  return {
266
273
  modes: this.getSessionModeState(agent),
267
274
  configOptions: this.getSessionConfigOptions(agent),
@@ -799,6 +806,135 @@ export class WaveAcpAgent implements AcpAgent {
799
806
  }
800
807
  }
801
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
+
802
938
  private createCallbacks(sessionId: string): AgentOptions["callbacks"] {
803
939
  const getAgent = () => this.agents.get(sessionId);
804
940
  const toolStates = new Map<