wave-code 0.17.5 → 0.17.7
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/acp/agent.d.ts +3 -0
- package/dist/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +307 -172
- package/dist/components/BtwDisplay.d.ts.map +1 -1
- package/dist/components/BtwDisplay.js +2 -2
- package/dist/components/InputBox.js +14 -9
- package/dist/components/StatusLine.d.ts +0 -1
- package/dist/components/StatusLine.d.ts.map +1 -1
- package/dist/components/StatusLine.js +2 -2
- package/dist/constants/commands.d.ts.map +1 -1
- package/dist/constants/commands.js +18 -0
- package/dist/contexts/useChat.d.ts +3 -0
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +21 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +13 -38
- package/dist/managers/inputHandlers.d.ts.map +1 -1
- package/dist/managers/inputHandlers.js +22 -40
- package/dist/managers/inputReducer.d.ts +4 -1
- package/dist/managers/inputReducer.d.ts.map +1 -1
- package/dist/managers/inputReducer.js +21 -34
- package/package.json +2 -2
- package/src/acp/agent.ts +418 -201
- package/src/components/BtwDisplay.tsx +4 -1
- package/src/components/InputBox.tsx +46 -46
- package/src/components/StatusLine.tsx +1 -7
- package/src/constants/commands.ts +18 -0
- package/src/contexts/useChat.tsx +27 -0
- package/src/hooks/useInputManager.ts +13 -38
- package/src/managers/inputHandlers.ts +20 -49
- package/src/managers/inputReducer.ts +27 -40
package/dist/acp/agent.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type Agent as AcpAgent, type AgentSideConnection, type InitializeRespon
|
|
|
2
2
|
export declare class WaveAcpAgent implements AcpAgent {
|
|
3
3
|
private agents;
|
|
4
4
|
private connection;
|
|
5
|
+
private taskCache;
|
|
5
6
|
constructor(connection: AgentSideConnection);
|
|
6
7
|
private getSessionModeState;
|
|
7
8
|
private getSessionConfigOptions;
|
|
@@ -19,6 +20,8 @@ export declare class WaveAcpAgent implements AcpAgent {
|
|
|
19
20
|
prompt(params: PromptRequest): Promise<PromptResponse>;
|
|
20
21
|
cancel(params: CancelNotification): Promise<void>;
|
|
21
22
|
private getAllowAlwaysName;
|
|
23
|
+
private handleAskQuestion;
|
|
24
|
+
private handleCreatePlan;
|
|
22
25
|
private handlePermissionRequest;
|
|
23
26
|
private getToolContent;
|
|
24
27
|
private getToolLocations;
|
package/dist/acp/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAwBlC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,SAAS,CAA6B;gBAElC,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;IA8EnB,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,iBAAiB;YAsEjB,gBAAgB;YAyDhB,uBAAuB;IAmNrC,OAAO,CAAC,cAAc;IA6FtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;YAmBL,yBAAyB;IAoIvC,OAAO,CAAC,eAAe;CAkRxB"}
|
package/dist/acp/agent.js
CHANGED
|
@@ -4,6 +4,7 @@ import { AGENT_METHODS, } from "@agentclientprotocol/sdk";
|
|
|
4
4
|
export class WaveAcpAgent {
|
|
5
5
|
constructor(connection) {
|
|
6
6
|
this.agents = new Map();
|
|
7
|
+
this.taskCache = new Map();
|
|
7
8
|
this.connection = connection;
|
|
8
9
|
}
|
|
9
10
|
getSessionModeState(agent) {
|
|
@@ -133,13 +134,15 @@ export class WaveAcpAgent {
|
|
|
133
134
|
onModelChange: (model) => callbacks.onModelChange?.(model),
|
|
134
135
|
onUserMessageAdded: (params) => callbacks.onUserMessageAdded?.(params),
|
|
135
136
|
onMcpServersChange: (servers) => callbacks.onMcpServersChange?.(servers),
|
|
137
|
+
onSessionIdChange: (newSessionId) => callbacks.onSessionIdChange?.(newSessionId),
|
|
136
138
|
},
|
|
137
139
|
});
|
|
138
140
|
agentRef.instance = agent;
|
|
139
141
|
const actualSessionId = agent.sessionId;
|
|
140
142
|
this.agents.set(actualSessionId, agent);
|
|
141
143
|
// Update the callbacks object with the correct sessionId
|
|
142
|
-
|
|
144
|
+
const { callbacks: cb } = this.createCallbacks(actualSessionId);
|
|
145
|
+
Object.assign(callbacks, cb);
|
|
143
146
|
// Send initial available commands after agent creation
|
|
144
147
|
// Use setImmediate to ensure the client receives the session response before the update
|
|
145
148
|
setImmediate(() => {
|
|
@@ -327,6 +330,87 @@ export class WaveAcpAgent {
|
|
|
327
330
|
}
|
|
328
331
|
return "Allow Always";
|
|
329
332
|
}
|
|
333
|
+
async handleAskQuestion(sessionId, toolCallId, context) {
|
|
334
|
+
try {
|
|
335
|
+
const questions = context.toolInput?.questions || [];
|
|
336
|
+
const request = {
|
|
337
|
+
toolCallId,
|
|
338
|
+
title: questions.length === 1 ? questions[0].header : undefined,
|
|
339
|
+
questions: questions.map((q, qi) => ({
|
|
340
|
+
id: `q${qi}`,
|
|
341
|
+
prompt: q.question,
|
|
342
|
+
options: q.options.map((opt, oi) => ({
|
|
343
|
+
id: String(oi),
|
|
344
|
+
label: opt.label,
|
|
345
|
+
description: opt.description,
|
|
346
|
+
})),
|
|
347
|
+
allowMultiple: q.multiSelect,
|
|
348
|
+
})),
|
|
349
|
+
};
|
|
350
|
+
const response = await this.connection.extMethod("wave/ask_question", request);
|
|
351
|
+
const outcome = response.outcome;
|
|
352
|
+
if (outcome === "cancelled") {
|
|
353
|
+
return { behavior: "deny", message: "Cancelled by user" };
|
|
354
|
+
}
|
|
355
|
+
// outcome === "answered"
|
|
356
|
+
const answers = response.answers || [];
|
|
357
|
+
const answerMap = {};
|
|
358
|
+
for (const answer of answers) {
|
|
359
|
+
const qIndex = parseInt(answer.questionId.replace("q", ""), 10);
|
|
360
|
+
const question = questions[qIndex];
|
|
361
|
+
if (!question)
|
|
362
|
+
continue;
|
|
363
|
+
const selectedLabels = answer.selectedOptionIds
|
|
364
|
+
.map((id) => question.options[parseInt(id, 10)]?.label)
|
|
365
|
+
.filter(Boolean);
|
|
366
|
+
answerMap[question.question] = selectedLabels.join(", ");
|
|
367
|
+
}
|
|
368
|
+
return { behavior: "allow", message: JSON.stringify(answerMap) };
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
logger.warn("wave/ask_question extMethod failed, falling back to requestPermission", { error });
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
async handleCreatePlan(sessionId, toolCallId, context) {
|
|
376
|
+
try {
|
|
377
|
+
const cachedTasks = this.taskCache.get(sessionId) || [];
|
|
378
|
+
const request = {
|
|
379
|
+
toolCallId,
|
|
380
|
+
plan: context.planContent || "",
|
|
381
|
+
todos: cachedTasks
|
|
382
|
+
.filter((t) => t.status !== "deleted")
|
|
383
|
+
.map((t) => ({
|
|
384
|
+
id: t.id,
|
|
385
|
+
content: t.subject,
|
|
386
|
+
status: t.status === "completed"
|
|
387
|
+
? "completed"
|
|
388
|
+
: t.status === "in_progress"
|
|
389
|
+
? "in_progress"
|
|
390
|
+
: "pending",
|
|
391
|
+
})),
|
|
392
|
+
};
|
|
393
|
+
const response = await this.connection.extMethod("wave/create_plan", request);
|
|
394
|
+
const outcome = response.outcome;
|
|
395
|
+
if (outcome === "accepted") {
|
|
396
|
+
const mode = response.mode;
|
|
397
|
+
return {
|
|
398
|
+
behavior: "allow",
|
|
399
|
+
newPermissionMode: (mode || "default"),
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
if (outcome === "rejected") {
|
|
403
|
+
const reason = response.reason;
|
|
404
|
+
return { behavior: "deny", message: reason || "Plan rejected" };
|
|
405
|
+
}
|
|
406
|
+
// cancelled or unknown outcome
|
|
407
|
+
return { behavior: "deny", message: "Cancelled by user" };
|
|
408
|
+
}
|
|
409
|
+
catch (error) {
|
|
410
|
+
logger.warn("wave/create_plan extMethod failed, falling back to requestPermission", { error });
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
330
414
|
async handlePermissionRequest(sessionId, context) {
|
|
331
415
|
logger.info(`Handling permission request for ${context.toolName} in session ${sessionId}`);
|
|
332
416
|
const agent = this.agents.get(sessionId);
|
|
@@ -420,6 +504,19 @@ export class WaveAcpAgent {
|
|
|
420
504
|
const kind = context.toolName
|
|
421
505
|
? this.getToolKind(context.toolName)
|
|
422
506
|
: undefined;
|
|
507
|
+
// Try extension methods first, fall back to requestPermission
|
|
508
|
+
if (context.toolName === ASK_USER_QUESTION_TOOL_NAME) {
|
|
509
|
+
const extResult = await this.handleAskQuestion(sessionId, toolCallId, context);
|
|
510
|
+
if (extResult !== null)
|
|
511
|
+
return extResult;
|
|
512
|
+
// Fall through to existing requestPermission logic
|
|
513
|
+
}
|
|
514
|
+
if (context.toolName === EXIT_PLAN_MODE_TOOL_NAME) {
|
|
515
|
+
const extResult = await this.handleCreatePlan(sessionId, toolCallId, context);
|
|
516
|
+
if (extResult !== null)
|
|
517
|
+
return extResult;
|
|
518
|
+
// Fall through to existing requestPermission logic
|
|
519
|
+
}
|
|
423
520
|
try {
|
|
424
521
|
const response = await this.connection.requestPermission({
|
|
425
522
|
sessionId: sessionId,
|
|
@@ -612,15 +709,7 @@ export class WaveAcpAgent {
|
|
|
612
709
|
}
|
|
613
710
|
async replayConversationHistory(agent) {
|
|
614
711
|
const sessionId = agent.sessionId;
|
|
615
|
-
|
|
616
|
-
try {
|
|
617
|
-
const thread = await agent.getFullMessageThread();
|
|
618
|
-
history = thread.messages;
|
|
619
|
-
}
|
|
620
|
-
catch {
|
|
621
|
-
// Fallback to in-memory messages if full thread fails
|
|
622
|
-
history = agent.messages;
|
|
623
|
-
}
|
|
712
|
+
const history = agent.messages;
|
|
624
713
|
for (const message of history) {
|
|
625
714
|
if (message.isMeta)
|
|
626
715
|
continue;
|
|
@@ -719,202 +808,248 @@ export class WaveAcpAgent {
|
|
|
719
808
|
},
|
|
720
809
|
});
|
|
721
810
|
}
|
|
722
|
-
|
|
811
|
+
else if (block.type === "compact") {
|
|
812
|
+
const compactBlock = block;
|
|
813
|
+
this.connection.sessionUpdate({
|
|
814
|
+
sessionId,
|
|
815
|
+
update: {
|
|
816
|
+
sessionUpdate: "agent_message_chunk",
|
|
817
|
+
content: { type: "text", text: compactBlock.content },
|
|
818
|
+
messageId,
|
|
819
|
+
},
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
// Skip: image, bang, error, file_history, task_notification blocks
|
|
723
823
|
}
|
|
724
824
|
}
|
|
725
825
|
}
|
|
726
826
|
createCallbacks(sessionId) {
|
|
727
|
-
const
|
|
827
|
+
const sessionRef = { id: sessionId };
|
|
828
|
+
const getAgent = () => this.agents.get(sessionRef.id);
|
|
728
829
|
const toolStates = new Map();
|
|
729
830
|
return {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
831
|
+
callbacks: {
|
|
832
|
+
onAssistantContentUpdated: (chunk) => {
|
|
833
|
+
this.connection.sessionUpdate({
|
|
834
|
+
sessionId: sessionRef.id,
|
|
835
|
+
update: {
|
|
836
|
+
sessionUpdate: "agent_message_chunk",
|
|
837
|
+
content: {
|
|
838
|
+
type: "text",
|
|
839
|
+
text: chunk,
|
|
840
|
+
},
|
|
738
841
|
},
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
842
|
+
});
|
|
843
|
+
},
|
|
844
|
+
onAssistantReasoningUpdated: (chunk) => {
|
|
845
|
+
this.connection.sessionUpdate({
|
|
846
|
+
sessionId: sessionRef.id,
|
|
847
|
+
update: {
|
|
848
|
+
sessionUpdate: "agent_thought_chunk",
|
|
849
|
+
content: {
|
|
850
|
+
type: "text",
|
|
851
|
+
text: chunk,
|
|
852
|
+
},
|
|
750
853
|
},
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
toolStates.set(id, state);
|
|
760
|
-
}
|
|
761
|
-
if (name)
|
|
762
|
-
state.name = name;
|
|
763
|
-
if (compactParams)
|
|
764
|
-
state.compactParams = compactParams;
|
|
765
|
-
if (shortResult)
|
|
766
|
-
state.shortResult = shortResult;
|
|
767
|
-
if (startLineNumber !== undefined)
|
|
768
|
-
state.startLineNumber = startLineNumber;
|
|
769
|
-
const effectiveName = state.name || name;
|
|
770
|
-
const effectiveCompactParams = state.compactParams || compactParams;
|
|
771
|
-
const effectiveShortResult = state.shortResult || shortResult;
|
|
772
|
-
const effectiveStartLineNumber = state.startLineNumber !== undefined
|
|
773
|
-
? state.startLineNumber
|
|
774
|
-
: startLineNumber;
|
|
775
|
-
const displayTitle = effectiveName && effectiveCompactParams
|
|
776
|
-
? `${effectiveName}: ${effectiveCompactParams}`
|
|
777
|
-
: effectiveName || "Tool Call";
|
|
778
|
-
let parsedParameters = undefined;
|
|
779
|
-
if (parameters) {
|
|
780
|
-
try {
|
|
781
|
-
const parsed = JSON.parse(parameters);
|
|
782
|
-
parsedParameters = Array.isArray(parsed)
|
|
783
|
-
? { args: parsed }
|
|
784
|
-
: parsed;
|
|
854
|
+
});
|
|
855
|
+
},
|
|
856
|
+
onToolBlockUpdated: (params) => {
|
|
857
|
+
const { id, name, stage, success, error, result, parameters, compactParams, shortResult, startLineNumber, } = params;
|
|
858
|
+
let state = toolStates.get(id);
|
|
859
|
+
if (!state) {
|
|
860
|
+
state = {};
|
|
861
|
+
toolStates.set(id, state);
|
|
785
862
|
}
|
|
786
|
-
|
|
787
|
-
|
|
863
|
+
if (name)
|
|
864
|
+
state.name = name;
|
|
865
|
+
if (compactParams)
|
|
866
|
+
state.compactParams = compactParams;
|
|
867
|
+
if (shortResult)
|
|
868
|
+
state.shortResult = shortResult;
|
|
869
|
+
if (startLineNumber !== undefined)
|
|
870
|
+
state.startLineNumber = startLineNumber;
|
|
871
|
+
const effectiveName = state.name || name;
|
|
872
|
+
const effectiveCompactParams = state.compactParams || compactParams;
|
|
873
|
+
const effectiveShortResult = state.shortResult || shortResult;
|
|
874
|
+
const effectiveStartLineNumber = state.startLineNumber !== undefined
|
|
875
|
+
? state.startLineNumber
|
|
876
|
+
: startLineNumber;
|
|
877
|
+
const displayTitle = effectiveName && effectiveCompactParams
|
|
878
|
+
? `${effectiveName}: ${effectiveCompactParams}`
|
|
879
|
+
: effectiveName || "Tool Call";
|
|
880
|
+
let parsedParameters = undefined;
|
|
881
|
+
if (parameters) {
|
|
882
|
+
try {
|
|
883
|
+
const parsed = JSON.parse(parameters);
|
|
884
|
+
parsedParameters = Array.isArray(parsed)
|
|
885
|
+
? { args: parsed }
|
|
886
|
+
: parsed;
|
|
887
|
+
}
|
|
888
|
+
catch {
|
|
889
|
+
// Ignore parse errors during streaming
|
|
890
|
+
}
|
|
788
891
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
892
|
+
const content = effectiveName && (parsedParameters || effectiveShortResult)
|
|
893
|
+
? this.getToolContent(effectiveName, parsedParameters, effectiveShortResult)
|
|
894
|
+
: undefined;
|
|
895
|
+
const locations = effectiveName && parsedParameters
|
|
896
|
+
? this.getToolLocations(effectiveName, parsedParameters, effectiveStartLineNumber)
|
|
897
|
+
: undefined;
|
|
898
|
+
const kind = effectiveName
|
|
899
|
+
? this.getToolKind(effectiveName)
|
|
900
|
+
: undefined;
|
|
901
|
+
if (stage === "start") {
|
|
902
|
+
this.connection.sessionUpdate({
|
|
903
|
+
sessionId: sessionRef.id,
|
|
904
|
+
update: {
|
|
905
|
+
sessionUpdate: "tool_call",
|
|
906
|
+
toolCallId: id,
|
|
907
|
+
title: displayTitle,
|
|
908
|
+
status: "pending",
|
|
909
|
+
content,
|
|
910
|
+
locations,
|
|
911
|
+
kind,
|
|
912
|
+
rawInput: parsedParameters,
|
|
913
|
+
},
|
|
914
|
+
});
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
if (stage === "streaming") {
|
|
918
|
+
// We don't support streaming tool arguments in ACP yet
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
const status = stage === "end"
|
|
922
|
+
? success
|
|
923
|
+
? "completed"
|
|
924
|
+
: "failed"
|
|
925
|
+
: stage === "running"
|
|
926
|
+
? "in_progress"
|
|
927
|
+
: "pending";
|
|
800
928
|
this.connection.sessionUpdate({
|
|
801
|
-
sessionId:
|
|
929
|
+
sessionId: sessionRef.id,
|
|
802
930
|
update: {
|
|
803
|
-
sessionUpdate: "
|
|
931
|
+
sessionUpdate: "tool_call_update",
|
|
804
932
|
toolCallId: id,
|
|
933
|
+
status,
|
|
805
934
|
title: displayTitle,
|
|
806
|
-
|
|
935
|
+
rawOutput: result || error,
|
|
807
936
|
content,
|
|
808
937
|
locations,
|
|
809
938
|
kind,
|
|
810
939
|
rawInput: parsedParameters,
|
|
811
940
|
},
|
|
812
941
|
});
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
const status = stage === "end"
|
|
820
|
-
? success
|
|
821
|
-
? "completed"
|
|
822
|
-
: "failed"
|
|
823
|
-
: stage === "running"
|
|
824
|
-
? "in_progress"
|
|
825
|
-
: "pending";
|
|
826
|
-
this.connection.sessionUpdate({
|
|
827
|
-
sessionId: sessionId,
|
|
828
|
-
update: {
|
|
829
|
-
sessionUpdate: "tool_call_update",
|
|
830
|
-
toolCallId: id,
|
|
831
|
-
status,
|
|
832
|
-
title: displayTitle,
|
|
833
|
-
rawOutput: result || error,
|
|
834
|
-
content,
|
|
835
|
-
locations,
|
|
836
|
-
kind,
|
|
837
|
-
rawInput: parsedParameters,
|
|
838
|
-
},
|
|
839
|
-
});
|
|
840
|
-
if (stage === "end") {
|
|
841
|
-
toolStates.delete(id);
|
|
842
|
-
}
|
|
843
|
-
},
|
|
844
|
-
onTasksChange: (tasks) => {
|
|
845
|
-
this.connection.sessionUpdate({
|
|
846
|
-
sessionId: sessionId,
|
|
847
|
-
update: {
|
|
848
|
-
sessionUpdate: "plan",
|
|
849
|
-
entries: tasks.map((task) => ({
|
|
850
|
-
content: task.subject,
|
|
851
|
-
status: task.status === "completed"
|
|
852
|
-
? "completed"
|
|
853
|
-
: task.status === "in_progress"
|
|
854
|
-
? "in_progress"
|
|
855
|
-
: "pending",
|
|
856
|
-
priority: "medium",
|
|
857
|
-
})),
|
|
858
|
-
},
|
|
859
|
-
});
|
|
860
|
-
},
|
|
861
|
-
onPermissionModeChange: (mode) => {
|
|
862
|
-
this.connection.sessionUpdate({
|
|
863
|
-
sessionId: sessionId,
|
|
864
|
-
update: {
|
|
865
|
-
sessionUpdate: "current_mode_update",
|
|
866
|
-
currentModeId: mode,
|
|
867
|
-
},
|
|
868
|
-
});
|
|
869
|
-
const agent = getAgent();
|
|
870
|
-
if (agent) {
|
|
942
|
+
if (stage === "end") {
|
|
943
|
+
toolStates.delete(id);
|
|
944
|
+
}
|
|
945
|
+
},
|
|
946
|
+
onTasksChange: (tasks) => {
|
|
947
|
+
this.taskCache.set(sessionRef.id, tasks);
|
|
871
948
|
this.connection.sessionUpdate({
|
|
872
|
-
sessionId:
|
|
949
|
+
sessionId: sessionRef.id,
|
|
873
950
|
update: {
|
|
874
|
-
sessionUpdate: "
|
|
875
|
-
|
|
951
|
+
sessionUpdate: "plan",
|
|
952
|
+
entries: tasks
|
|
953
|
+
.filter((t) => t.status !== "deleted")
|
|
954
|
+
.map((task) => ({
|
|
955
|
+
content: task.subject,
|
|
956
|
+
status: task.status === "completed"
|
|
957
|
+
? "completed"
|
|
958
|
+
: task.status === "in_progress"
|
|
959
|
+
? "in_progress"
|
|
960
|
+
: "pending",
|
|
961
|
+
priority: "medium",
|
|
962
|
+
})),
|
|
876
963
|
},
|
|
877
964
|
});
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
onModelChange: () => {
|
|
881
|
-
const agent = getAgent();
|
|
882
|
-
if (agent) {
|
|
965
|
+
},
|
|
966
|
+
onPermissionModeChange: (mode) => {
|
|
883
967
|
this.connection.sessionUpdate({
|
|
884
|
-
sessionId:
|
|
968
|
+
sessionId: sessionRef.id,
|
|
885
969
|
update: {
|
|
886
|
-
sessionUpdate: "
|
|
887
|
-
|
|
970
|
+
sessionUpdate: "current_mode_update",
|
|
971
|
+
currentModeId: mode,
|
|
888
972
|
},
|
|
889
973
|
});
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
974
|
+
const agent = getAgent();
|
|
975
|
+
if (agent) {
|
|
976
|
+
this.connection.sessionUpdate({
|
|
977
|
+
sessionId: sessionRef.id,
|
|
978
|
+
update: {
|
|
979
|
+
sessionUpdate: "config_option_update",
|
|
980
|
+
configOptions: this.getSessionConfigOptions(agent),
|
|
981
|
+
},
|
|
982
|
+
});
|
|
983
|
+
}
|
|
984
|
+
},
|
|
985
|
+
onModelChange: () => {
|
|
986
|
+
const agent = getAgent();
|
|
987
|
+
if (agent) {
|
|
988
|
+
this.connection.sessionUpdate({
|
|
989
|
+
sessionId: sessionRef.id,
|
|
990
|
+
update: {
|
|
991
|
+
sessionUpdate: "config_option_update",
|
|
992
|
+
configOptions: this.getSessionConfigOptions(agent),
|
|
993
|
+
},
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
onUserMessageAdded: (params) => {
|
|
903
998
|
this.connection.sessionUpdate({
|
|
904
|
-
sessionId:
|
|
999
|
+
sessionId: sessionRef.id,
|
|
905
1000
|
update: {
|
|
906
|
-
sessionUpdate: "
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
1001
|
+
sessionUpdate: "user_message_chunk",
|
|
1002
|
+
content: { type: "text", text: params.content },
|
|
1003
|
+
},
|
|
1004
|
+
});
|
|
1005
|
+
},
|
|
1006
|
+
onMcpServersChange: (servers) => {
|
|
1007
|
+
for (const server of servers) {
|
|
1008
|
+
this.connection.sessionUpdate({
|
|
1009
|
+
sessionId: sessionRef.id,
|
|
1010
|
+
update: {
|
|
1011
|
+
sessionUpdate: "ext_notification",
|
|
1012
|
+
method: "mcp_server_status",
|
|
1013
|
+
params: {
|
|
1014
|
+
name: server.name,
|
|
1015
|
+
status: server.status,
|
|
1016
|
+
toolCount: server.toolCount,
|
|
1017
|
+
error: server.error,
|
|
1018
|
+
},
|
|
913
1019
|
},
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
},
|
|
1023
|
+
onSessionIdChange: (newSessionId) => {
|
|
1024
|
+
const oldSessionId = sessionRef.id;
|
|
1025
|
+
if (oldSessionId === newSessionId)
|
|
1026
|
+
return;
|
|
1027
|
+
// Update agents Map key
|
|
1028
|
+
const agent = this.agents.get(oldSessionId);
|
|
1029
|
+
if (agent) {
|
|
1030
|
+
this.agents.delete(oldSessionId);
|
|
1031
|
+
this.agents.set(newSessionId, agent);
|
|
1032
|
+
}
|
|
1033
|
+
// Update taskCache key
|
|
1034
|
+
const tasks = this.taskCache.get(oldSessionId);
|
|
1035
|
+
if (tasks) {
|
|
1036
|
+
this.taskCache.delete(oldSessionId);
|
|
1037
|
+
this.taskCache.set(newSessionId, tasks);
|
|
1038
|
+
}
|
|
1039
|
+
// Update ref so all subsequent callbacks use new ID
|
|
1040
|
+
sessionRef.id = newSessionId;
|
|
1041
|
+
// Notify ACP client
|
|
1042
|
+
this.connection.sessionUpdate({
|
|
1043
|
+
sessionId: oldSessionId,
|
|
1044
|
+
update: {
|
|
1045
|
+
sessionUpdate: "ext_notification",
|
|
1046
|
+
method: "session_id_change",
|
|
1047
|
+
params: { oldSessionId, newSessionId },
|
|
914
1048
|
},
|
|
915
1049
|
});
|
|
916
|
-
}
|
|
1050
|
+
},
|
|
917
1051
|
},
|
|
1052
|
+
sessionRef,
|
|
918
1053
|
};
|
|
919
1054
|
}
|
|
920
1055
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BtwDisplay.d.ts","sourceRoot":"","sources":["../../src/components/BtwDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEvD,UAAU,eAAe;IACvB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"BtwDisplay.d.ts","sourceRoot":"","sources":["../../src/components/BtwDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEvD,UAAU,eAAe;IACvB,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA0BhD,CAAC"}
|
|
@@ -2,8 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { Markdown } from "./Markdown.js";
|
|
4
4
|
export const BtwDisplay = ({ btwState }) => {
|
|
5
|
-
if (!btwState.
|
|
5
|
+
if (!btwState.question) {
|
|
6
6
|
return null;
|
|
7
7
|
}
|
|
8
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 0, marginBottom: 0, children: [btwState.question && (_jsxs(Box, { children: [_jsx(Text, { color: btwState.isLoading ? "yellow" : "green", children: "/ " }), _jsxs(Text, { italic: true, color: "gray", children: ["btw ", btwState.question] })] })), btwState.answer && (
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 0, marginBottom: 0, children: [btwState.question && (_jsxs(Box, { children: [_jsx(Text, { color: btwState.isLoading ? "yellow" : "green", children: "/ " }), _jsxs(Text, { italic: true, color: "gray", children: ["btw ", btwState.question] })] })), btwState.answer && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Markdown, { children: btwState.answer }), _jsx(Text, { color: "gray", dimColor: true, children: "ESC to dismiss" })] }))] }));
|
|
9
9
|
};
|
|
@@ -21,7 +21,7 @@ import { useChat } from "../contexts/useChat.js";
|
|
|
21
21
|
export const INPUT_PLACEHOLDER_TEXT = "Type your message (use /help for more info)...";
|
|
22
22
|
export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
|
|
23
23
|
export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, latestTotalTokens = 0, maxInputTokens = 128000, isGoalActive, goalElapsed, }) => {
|
|
24
|
-
const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, currentModel, configuredModels, setModel, recreateAgent, recallQueuedMessage, queuedMessages, } = useChat();
|
|
24
|
+
const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, clearMessages, compact, goalCommand, currentModel, configuredModels, setModel, recreateAgent, recallQueuedMessage, queuedMessages, } = useChat();
|
|
25
25
|
// Ref to hold setInputText so queue callbacks can access it before useInputManager returns
|
|
26
26
|
const setInputTextRef = useRef(() => { });
|
|
27
27
|
const hasQueuedMessages = (queuedMessages?.length ?? 0) > 0;
|
|
@@ -56,6 +56,9 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
56
56
|
setInputText, } = useInputManager({
|
|
57
57
|
onSendMessage: sendMessage,
|
|
58
58
|
onAskBtw: askBtw,
|
|
59
|
+
onClearMessages: clearMessages,
|
|
60
|
+
onCompact: compact,
|
|
61
|
+
onGoalCommand: goalCommand,
|
|
59
62
|
onHasSlashCommand: hasSlashCommand,
|
|
60
63
|
onAbortMessage: abortMessage,
|
|
61
64
|
onBackgroundCurrentTask: backgroundCurrentTask,
|
|
@@ -136,12 +139,14 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
136
139
|
if (showModelSelector) {
|
|
137
140
|
return (_jsx(ModelSelector, { onCancel: () => setShowModelSelector(false), currentModel: currentModel, configuredModels: configuredModels, onSelectModel: setModel }));
|
|
138
141
|
}
|
|
139
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BtwDisplay, { btwState: btwState }), showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, isLoading: isFileSearching, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showBackgroundTaskManager && (_jsx(BackgroundTaskManager, { onCancel: () => setShowBackgroundTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showWorkflowManager && (_jsx(WorkflowManager, { onCancel: () => setShowWorkflowManager(false) })),
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BtwDisplay, { btwState: btwState }), showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, isLoading: isFileSearching, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showBackgroundTaskManager && (_jsx(BackgroundTaskManager, { onCancel: () => setShowBackgroundTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showWorkflowManager && (_jsx(WorkflowManager, { onCancel: () => setShowWorkflowManager(false) })), btwState.question
|
|
143
|
+
? null
|
|
144
|
+
: showBackgroundTaskManager ||
|
|
145
|
+
showMcpManager ||
|
|
146
|
+
showRewindManager ||
|
|
147
|
+
showHelp ||
|
|
148
|
+
showStatusCommand ||
|
|
149
|
+
showLoginCommand ||
|
|
150
|
+
showPluginManager ||
|
|
151
|
+
showWorkflowManager || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(StatusLine, { permissionMode: permissionMode, isShellCommand: isShellCommand, isGoalActive: isGoalActive, goalElapsed: goalElapsed, latestTotalTokens: latestTotalTokens, maxInputTokens: maxInputTokens })] }))] }));
|
|
147
152
|
};
|