wave-agent-sdk 0.0.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.
Files changed (170) hide show
  1. package/README.md +32 -0
  2. package/dist/agent.d.ts +96 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +286 -0
  5. package/dist/hooks/executor.d.ts +56 -0
  6. package/dist/hooks/executor.d.ts.map +1 -0
  7. package/dist/hooks/executor.js +312 -0
  8. package/dist/hooks/index.d.ts +17 -0
  9. package/dist/hooks/index.d.ts.map +1 -0
  10. package/dist/hooks/index.js +14 -0
  11. package/dist/hooks/manager.d.ts +90 -0
  12. package/dist/hooks/manager.d.ts.map +1 -0
  13. package/dist/hooks/manager.js +395 -0
  14. package/dist/hooks/matcher.d.ts +49 -0
  15. package/dist/hooks/matcher.d.ts.map +1 -0
  16. package/dist/hooks/matcher.js +147 -0
  17. package/dist/hooks/settings.d.ts +46 -0
  18. package/dist/hooks/settings.d.ts.map +1 -0
  19. package/dist/hooks/settings.js +100 -0
  20. package/dist/hooks/types.d.ts +80 -0
  21. package/dist/hooks/types.d.ts.map +1 -0
  22. package/dist/hooks/types.js +59 -0
  23. package/dist/index.d.ts +16 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +20 -0
  26. package/dist/managers/aiManager.d.ts +61 -0
  27. package/dist/managers/aiManager.d.ts.map +1 -0
  28. package/dist/managers/aiManager.js +415 -0
  29. package/dist/managers/backgroundBashManager.d.ts +27 -0
  30. package/dist/managers/backgroundBashManager.d.ts.map +1 -0
  31. package/dist/managers/backgroundBashManager.js +166 -0
  32. package/dist/managers/bashManager.d.ts +20 -0
  33. package/dist/managers/bashManager.d.ts.map +1 -0
  34. package/dist/managers/bashManager.js +66 -0
  35. package/dist/managers/mcpManager.d.ts +63 -0
  36. package/dist/managers/mcpManager.d.ts.map +1 -0
  37. package/dist/managers/mcpManager.js +378 -0
  38. package/dist/managers/messageManager.d.ts +85 -0
  39. package/dist/managers/messageManager.d.ts.map +1 -0
  40. package/dist/managers/messageManager.js +265 -0
  41. package/dist/managers/skillManager.d.ts +59 -0
  42. package/dist/managers/skillManager.d.ts.map +1 -0
  43. package/dist/managers/skillManager.js +317 -0
  44. package/dist/managers/slashCommandManager.d.ts +77 -0
  45. package/dist/managers/slashCommandManager.d.ts.map +1 -0
  46. package/dist/managers/slashCommandManager.js +208 -0
  47. package/dist/managers/toolManager.d.ts +23 -0
  48. package/dist/managers/toolManager.d.ts.map +1 -0
  49. package/dist/managers/toolManager.js +79 -0
  50. package/dist/services/aiService.d.ts +28 -0
  51. package/dist/services/aiService.d.ts.map +1 -0
  52. package/dist/services/aiService.js +180 -0
  53. package/dist/services/memory.d.ts +8 -0
  54. package/dist/services/memory.d.ts.map +1 -0
  55. package/dist/services/memory.js +128 -0
  56. package/dist/services/session.d.ts +54 -0
  57. package/dist/services/session.d.ts.map +1 -0
  58. package/dist/services/session.js +196 -0
  59. package/dist/tools/bashTool.d.ts +14 -0
  60. package/dist/tools/bashTool.d.ts.map +1 -0
  61. package/dist/tools/bashTool.js +351 -0
  62. package/dist/tools/deleteFileTool.d.ts +6 -0
  63. package/dist/tools/deleteFileTool.d.ts.map +1 -0
  64. package/dist/tools/deleteFileTool.js +67 -0
  65. package/dist/tools/editTool.d.ts +6 -0
  66. package/dist/tools/editTool.d.ts.map +1 -0
  67. package/dist/tools/editTool.js +168 -0
  68. package/dist/tools/globTool.d.ts +6 -0
  69. package/dist/tools/globTool.d.ts.map +1 -0
  70. package/dist/tools/globTool.js +113 -0
  71. package/dist/tools/grepTool.d.ts +6 -0
  72. package/dist/tools/grepTool.d.ts.map +1 -0
  73. package/dist/tools/grepTool.js +268 -0
  74. package/dist/tools/lsTool.d.ts +6 -0
  75. package/dist/tools/lsTool.d.ts.map +1 -0
  76. package/dist/tools/lsTool.js +160 -0
  77. package/dist/tools/multiEditTool.d.ts +6 -0
  78. package/dist/tools/multiEditTool.d.ts.map +1 -0
  79. package/dist/tools/multiEditTool.js +222 -0
  80. package/dist/tools/readTool.d.ts +6 -0
  81. package/dist/tools/readTool.d.ts.map +1 -0
  82. package/dist/tools/readTool.js +136 -0
  83. package/dist/tools/types.d.ts +35 -0
  84. package/dist/tools/types.d.ts.map +1 -0
  85. package/dist/tools/types.js +4 -0
  86. package/dist/tools/writeTool.d.ts +6 -0
  87. package/dist/tools/writeTool.d.ts.map +1 -0
  88. package/dist/tools/writeTool.js +138 -0
  89. package/dist/types.d.ts +212 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +13 -0
  92. package/dist/utils/bashHistory.d.ts +46 -0
  93. package/dist/utils/bashHistory.d.ts.map +1 -0
  94. package/dist/utils/bashHistory.js +236 -0
  95. package/dist/utils/commandArgumentParser.d.ts +34 -0
  96. package/dist/utils/commandArgumentParser.d.ts.map +1 -0
  97. package/dist/utils/commandArgumentParser.js +123 -0
  98. package/dist/utils/constants.d.ts +27 -0
  99. package/dist/utils/constants.d.ts.map +1 -0
  100. package/dist/utils/constants.js +28 -0
  101. package/dist/utils/convertMessagesForAPI.d.ts +9 -0
  102. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -0
  103. package/dist/utils/convertMessagesForAPI.js +189 -0
  104. package/dist/utils/customCommands.d.ts +14 -0
  105. package/dist/utils/customCommands.d.ts.map +1 -0
  106. package/dist/utils/customCommands.js +71 -0
  107. package/dist/utils/fileFilter.d.ts +26 -0
  108. package/dist/utils/fileFilter.d.ts.map +1 -0
  109. package/dist/utils/fileFilter.js +177 -0
  110. package/dist/utils/markdownParser.d.ts +27 -0
  111. package/dist/utils/markdownParser.d.ts.map +1 -0
  112. package/dist/utils/markdownParser.js +109 -0
  113. package/dist/utils/mcpUtils.d.ts +24 -0
  114. package/dist/utils/mcpUtils.d.ts.map +1 -0
  115. package/dist/utils/mcpUtils.js +51 -0
  116. package/dist/utils/messageOperations.d.ts +118 -0
  117. package/dist/utils/messageOperations.d.ts.map +1 -0
  118. package/dist/utils/messageOperations.js +334 -0
  119. package/dist/utils/path.d.ts +25 -0
  120. package/dist/utils/path.d.ts.map +1 -0
  121. package/dist/utils/path.js +109 -0
  122. package/dist/utils/skillParser.d.ts +18 -0
  123. package/dist/utils/skillParser.d.ts.map +1 -0
  124. package/dist/utils/skillParser.js +147 -0
  125. package/dist/utils/stringUtils.d.ts +13 -0
  126. package/dist/utils/stringUtils.d.ts.map +1 -0
  127. package/dist/utils/stringUtils.js +44 -0
  128. package/package.json +51 -0
  129. package/src/agent.ts +405 -0
  130. package/src/hooks/executor.ts +440 -0
  131. package/src/hooks/index.ts +52 -0
  132. package/src/hooks/manager.ts +618 -0
  133. package/src/hooks/matcher.ts +187 -0
  134. package/src/hooks/settings.ts +129 -0
  135. package/src/hooks/types.ts +169 -0
  136. package/src/index.ts +24 -0
  137. package/src/managers/aiManager.ts +573 -0
  138. package/src/managers/backgroundBashManager.ts +203 -0
  139. package/src/managers/bashManager.ts +97 -0
  140. package/src/managers/mcpManager.ts +493 -0
  141. package/src/managers/messageManager.ts +415 -0
  142. package/src/managers/skillManager.ts +404 -0
  143. package/src/managers/slashCommandManager.ts +293 -0
  144. package/src/managers/toolManager.ts +106 -0
  145. package/src/services/aiService.ts +252 -0
  146. package/src/services/memory.ts +149 -0
  147. package/src/services/session.ts +265 -0
  148. package/src/tools/bashTool.ts +402 -0
  149. package/src/tools/deleteFileTool.ts +81 -0
  150. package/src/tools/editTool.ts +192 -0
  151. package/src/tools/globTool.ts +135 -0
  152. package/src/tools/grepTool.ts +326 -0
  153. package/src/tools/lsTool.ts +187 -0
  154. package/src/tools/multiEditTool.ts +268 -0
  155. package/src/tools/readTool.ts +165 -0
  156. package/src/tools/types.ts +47 -0
  157. package/src/tools/writeTool.ts +163 -0
  158. package/src/types.ts +260 -0
  159. package/src/utils/bashHistory.ts +303 -0
  160. package/src/utils/commandArgumentParser.ts +153 -0
  161. package/src/utils/constants.ts +37 -0
  162. package/src/utils/convertMessagesForAPI.ts +236 -0
  163. package/src/utils/customCommands.ts +85 -0
  164. package/src/utils/fileFilter.ts +202 -0
  165. package/src/utils/markdownParser.ts +156 -0
  166. package/src/utils/mcpUtils.ts +81 -0
  167. package/src/utils/messageOperations.ts +506 -0
  168. package/src/utils/path.ts +118 -0
  169. package/src/utils/skillParser.ts +188 -0
  170. package/src/utils/stringUtils.ts +50 -0
@@ -0,0 +1,109 @@
1
+ import { readFileSync } from "fs";
2
+ /**
3
+ * Parse YAML frontmatter from markdown content
4
+ */
5
+ function parseFrontmatter(content) {
6
+ const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
7
+ const match = content.match(frontmatterRegex);
8
+ if (!match) {
9
+ return { content };
10
+ }
11
+ const [, frontmatterStr, bodyContent] = match;
12
+ try {
13
+ // Simple YAML parser for our use case (only supports key: value pairs)
14
+ const frontmatter = {};
15
+ const lines = frontmatterStr.split("\n");
16
+ for (const line of lines) {
17
+ const trimmedLine = line.trim();
18
+ if (!trimmedLine || trimmedLine.startsWith("#"))
19
+ continue;
20
+ const colonIndex = trimmedLine.indexOf(":");
21
+ if (colonIndex === -1)
22
+ continue;
23
+ const key = trimmedLine.slice(0, colonIndex).trim();
24
+ const value = trimmedLine.slice(colonIndex + 1).trim();
25
+ // Handle array values for allowed-tools
26
+ if (key === "allowed-tools" && value) {
27
+ // Simple array parsing: "tool1, tool2, tool3" or "[tool1, tool2]"
28
+ let arrayValue = value;
29
+ if (arrayValue.startsWith("[") && arrayValue.endsWith("]")) {
30
+ arrayValue = arrayValue.slice(1, -1);
31
+ }
32
+ frontmatter[key] = arrayValue
33
+ .split(",")
34
+ .map((s) => s.trim())
35
+ .filter(Boolean);
36
+ }
37
+ else if (value) {
38
+ frontmatter[key] = value;
39
+ }
40
+ }
41
+ return { frontmatter, content: bodyContent };
42
+ }
43
+ catch {
44
+ // If parsing fails, just return the content without frontmatter
45
+ return { content };
46
+ }
47
+ }
48
+ /**
49
+ * Parse markdown file and extract config and content
50
+ */
51
+ export function parseMarkdownFile(filePath) {
52
+ try {
53
+ const fileContent = readFileSync(filePath, "utf-8");
54
+ const { frontmatter, content } = parseFrontmatter(fileContent);
55
+ let config;
56
+ if (frontmatter) {
57
+ config = {};
58
+ if (frontmatter["allowed-tools"] &&
59
+ Array.isArray(frontmatter["allowed-tools"])) {
60
+ config.allowedTools = frontmatter["allowed-tools"];
61
+ }
62
+ if (frontmatter.model && typeof frontmatter.model === "string") {
63
+ config.model = frontmatter.model;
64
+ }
65
+ if (frontmatter.description &&
66
+ typeof frontmatter.description === "string") {
67
+ config.description = frontmatter.description;
68
+ }
69
+ }
70
+ return {
71
+ content: content.trim(),
72
+ config,
73
+ };
74
+ }
75
+ catch (error) {
76
+ throw new Error(`Failed to parse markdown file ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
77
+ }
78
+ }
79
+ export function parseBashCommands(content) {
80
+ const bashCommandRegex = /!`([^`]+)`/g;
81
+ const commands = [];
82
+ let match;
83
+ // Extract all bash commands
84
+ while ((match = bashCommandRegex.exec(content)) !== null) {
85
+ commands.push(match[1]);
86
+ }
87
+ // For now, return the content as-is. The actual command execution
88
+ // will be handled by the slash command manager
89
+ return {
90
+ commands,
91
+ processedContent: content,
92
+ };
93
+ }
94
+ /**
95
+ * Replace bash command placeholders with their outputs
96
+ */
97
+ export function replaceBashCommandsWithOutput(content, results) {
98
+ const bashCommandRegex = /!`([^`]+)`/g;
99
+ let processedContent = content;
100
+ let commandIndex = 0;
101
+ processedContent = processedContent.replace(bashCommandRegex, (match) => {
102
+ if (commandIndex < results.length) {
103
+ const result = results[commandIndex++];
104
+ return `\`\`\`\n$ ${result.command}\n${result.output}\n\`\`\``;
105
+ }
106
+ return match;
107
+ });
108
+ return processedContent;
109
+ }
@@ -0,0 +1,24 @@
1
+ import { ChatCompletionFunctionTool } from "openai/resources.js";
2
+ import type { ToolPlugin } from "../tools/types.js";
3
+ import type { McpTool, McpServerStatus } from "../types.js";
4
+ /**
5
+ * Convert MCP tool to OpenAI function tool format
6
+ */
7
+ export declare function mcpToolToOpenAITool(mcpTool: McpTool, serverName: string): ChatCompletionFunctionTool;
8
+ /**
9
+ * Create a tool plugin wrapper for an MCP tool
10
+ */
11
+ export declare function createMcpToolPlugin(mcpTool: McpTool, serverName: string, executeTool: (name: string, args: Record<string, unknown>) => Promise<{
12
+ success: boolean;
13
+ content: string;
14
+ serverName?: string;
15
+ images?: Array<{
16
+ data: string;
17
+ mediaType?: string;
18
+ }>;
19
+ }>): ToolPlugin;
20
+ /**
21
+ * Find which server a tool belongs to
22
+ */
23
+ export declare function findToolServer(toolName: string, servers: McpServerStatus[]): McpServerStatus | undefined;
24
+ //# sourceMappingURL=mcpUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpUtils.d.ts","sourceRoot":"","sources":["../../src/utils/mcpUtils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE5D;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,GACjB,0BAA0B,CAa5B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC1B,OAAO,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD,CAAC,GACD,UAAU,CA2BZ;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,eAAe,EAAE,GACzB,eAAe,GAAG,SAAS,CAK7B"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Convert MCP tool to OpenAI function tool format
3
+ */
4
+ export function mcpToolToOpenAITool(mcpTool, serverName) {
5
+ // Remove $schema field if it exists, as OpenAI API doesn't accept it
6
+ const cleanInputSchema = { ...mcpTool.inputSchema };
7
+ delete cleanInputSchema.$schema;
8
+ return {
9
+ type: "function",
10
+ function: {
11
+ name: mcpTool.name,
12
+ description: `${mcpTool.description || `Tool from MCP server ${serverName}`} (MCP: ${serverName})`,
13
+ parameters: cleanInputSchema,
14
+ },
15
+ };
16
+ }
17
+ /**
18
+ * Create a tool plugin wrapper for an MCP tool
19
+ */
20
+ export function createMcpToolPlugin(mcpTool, serverName, executeTool) {
21
+ return {
22
+ name: mcpTool.name,
23
+ config: mcpToolToOpenAITool(mcpTool, serverName),
24
+ async execute(args, context) {
25
+ try {
26
+ // Context is available for future use when MCP tools need execution context
27
+ if (context) {
28
+ // Future: Could pass working directory or other context to MCP tools
29
+ }
30
+ const result = await executeTool(mcpTool.name, args);
31
+ return {
32
+ success: true,
33
+ content: result.content || `Executed ${mcpTool.name}`,
34
+ };
35
+ }
36
+ catch (error) {
37
+ return {
38
+ success: false,
39
+ content: "",
40
+ error: error instanceof Error ? error.message : String(error),
41
+ };
42
+ }
43
+ },
44
+ };
45
+ }
46
+ /**
47
+ * Find which server a tool belongs to
48
+ */
49
+ export function findToolServer(toolName, servers) {
50
+ return servers.find((s) => s.status === "connected" && s.tools?.some((t) => t.name === toolName));
51
+ }
@@ -0,0 +1,118 @@
1
+ import type { Message } from "../types.js";
2
+ import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
3
+ export interface AddUserMessageParams {
4
+ messages: Message[];
5
+ content: string;
6
+ images?: Array<{
7
+ path: string;
8
+ mimeType: string;
9
+ }>;
10
+ customCommandBlock?: {
11
+ type: "custom_command";
12
+ commandName: string;
13
+ content: string;
14
+ originalInput?: string;
15
+ };
16
+ }
17
+ export interface UpdateToolBlockParams {
18
+ messages: Message[];
19
+ id: string;
20
+ parameters: string;
21
+ result?: string;
22
+ success?: boolean;
23
+ error?: string;
24
+ isRunning?: boolean;
25
+ name?: string;
26
+ shortResult?: string;
27
+ images?: Array<{
28
+ data: string;
29
+ mediaType?: string;
30
+ }>;
31
+ compactParams?: string;
32
+ }
33
+ export interface AgentToolBlockUpdateParams {
34
+ toolId: string;
35
+ args?: string;
36
+ result?: string;
37
+ success?: boolean;
38
+ error?: string;
39
+ isRunning?: boolean;
40
+ name?: string;
41
+ shortResult?: string;
42
+ compactParams?: string;
43
+ }
44
+ export interface AddDiffBlockParams {
45
+ messages: Message[];
46
+ path: string;
47
+ diffResult: Array<{
48
+ value: string;
49
+ added?: boolean;
50
+ removed?: boolean;
51
+ }>;
52
+ }
53
+ export interface AddErrorBlockParams {
54
+ messages: Message[];
55
+ error: string;
56
+ }
57
+ export interface AddMemoryBlockParams {
58
+ messages: Message[];
59
+ content: string;
60
+ isSuccess: boolean;
61
+ memoryType?: "project" | "user";
62
+ storagePath?: string;
63
+ }
64
+ export interface AddCommandOutputParams {
65
+ messages: Message[];
66
+ command: string;
67
+ }
68
+ export interface UpdateCommandOutputParams {
69
+ messages: Message[];
70
+ command: string;
71
+ output: string;
72
+ }
73
+ export interface CompleteCommandParams {
74
+ messages: Message[];
75
+ command: string;
76
+ exitCode: number;
77
+ }
78
+ /**
79
+ * Extract text content from user messages in the messages array
80
+ */
81
+ export declare const extractUserInputHistory: (messages: Message[]) => string[];
82
+ /**
83
+ * Convert image file path to base64 format
84
+ * @param imagePath Image file path
85
+ * @returns base64 format image data URL
86
+ */
87
+ export declare const convertImageToBase64: (imagePath: string) => string;
88
+ export declare const addUserMessageToMessages: ({ messages, content, images, customCommandBlock, }: AddUserMessageParams) => Message[];
89
+ export declare const addAssistantMessageToMessages: (messages: Message[], content?: string, toolCalls?: ChatCompletionMessageFunctionToolCall[]) => Message[];
90
+ export declare const addDiffBlockToMessage: ({ messages, path, diffResult, }: AddDiffBlockParams) => Message[];
91
+ export declare const updateToolBlockInMessage: ({ messages, id, parameters, result, success, error, isRunning, name, shortResult, images, compactParams, }: UpdateToolBlockParams) => Message[];
92
+ export declare const addErrorBlockToMessage: ({ messages, error, }: AddErrorBlockParams) => Message[];
93
+ export declare const addMemoryBlockToMessage: ({ messages, content, isSuccess, memoryType, storagePath, }: AddMemoryBlockParams) => Message[];
94
+ /**
95
+ * Count valid blocks from the end
96
+ * Only text, image, and tool type blocks are counted
97
+ * @param messages Message array
98
+ * @param targetCount Number of valid blocks to count
99
+ * @returns { messageIndex: number, blockCount: number } Message index and actual counted block count
100
+ */
101
+ export declare const countValidBlocksFromEnd: (messages: Message[], targetCount: number) => {
102
+ messageIndex: number;
103
+ blockCount: number;
104
+ };
105
+ /**
106
+ * Get messages to be compressed and insertion position
107
+ * @param messages Message array
108
+ * @param keepLastCount Keep the last few valid blocks uncompressed
109
+ * @returns { messagesToCompress: Message[], insertIndex: number }
110
+ */
111
+ export declare const getMessagesToCompress: (messages: Message[], keepLastCount?: number) => {
112
+ messagesToCompress: Message[];
113
+ insertIndex: number;
114
+ };
115
+ export declare const addCommandOutputMessage: ({ messages, command, }: AddCommandOutputParams) => Message[];
116
+ export declare const updateCommandOutputInMessage: ({ messages, command, output, }: UpdateCommandOutputParams) => Message[];
117
+ export declare const completeCommandInMessage: ({ messages, command, exitCode, }: CompleteCommandParams) => Message[];
118
+ //# sourceMappingURL=messageOperations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messageOperations.d.ts","sourceRoot":"","sources":["../../src/utils/messageOperations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,qCAAqC,EAAE,MAAM,qBAAqB,CAAC;AAG5E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,kBAAkB,CAAC,EAAE;QACnB,IAAI,EAAE,gBAAgB,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAGD,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,UAAU,OAAO,EAAE,KAAG,MAAM,EAcnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,WAAW,MAAM,KAAG,MAmCxD,CAAC;AAGF,eAAO,MAAM,wBAAwB,GAAI,oDAKtC,oBAAoB,KAAG,OAAO,EAwBhC,CAAC;AAGF,eAAO,MAAM,6BAA6B,GACxC,UAAU,OAAO,EAAE,EACnB,UAAU,MAAM,EAChB,YAAY,qCAAqC,EAAE,KAClD,OAAO,EA4BT,CAAC;AAGF,eAAO,MAAM,qBAAqB,GAAI,iCAInC,kBAAkB,KAAG,OAAO,EAe9B,CAAC;AAGF,eAAO,MAAM,wBAAwB,GAAI,4GAYtC,qBAAqB,KAAG,OAAO,EA0CjC,CAAC;AAGF,eAAO,MAAM,sBAAsB,GAAI,sBAGpC,mBAAmB,KAAG,OAAO,EAgC/B,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAAI,4DAMrC,oBAAoB,KAAG,OAAO,EAoBhC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,GAClC,UAAU,OAAO,EAAE,EACnB,aAAa,MAAM,KAClB;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CA2B5C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAChC,UAAU,OAAO,EAAE,EACnB,gBAAe,MAAU,KACxB;IAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CA4BtD,CAAC;AAGF,eAAO,MAAM,uBAAuB,GAAI,wBAGrC,sBAAsB,KAAG,OAAO,EAelC,CAAC;AAGF,eAAO,MAAM,4BAA4B,GAAI,gCAI1C,yBAAyB,KAAG,OAAO,EAmBrC,CAAC;AAGF,eAAO,MAAM,wBAAwB,GAAI,kCAItC,qBAAqB,KAAG,OAAO,EAoBjC,CAAC"}
@@ -0,0 +1,334 @@
1
+ import { readFileSync } from "fs";
2
+ import { extname } from "path";
3
+ /**
4
+ * Extract text content from user messages in the messages array
5
+ */
6
+ export const extractUserInputHistory = (messages) => {
7
+ return messages
8
+ .filter((message) => message.role === "user")
9
+ .map((message) => {
10
+ // Extract all text block content and merge
11
+ const textBlocks = message.blocks.filter((block) => block.type === "text");
12
+ return textBlocks
13
+ .map((block) => block.content)
14
+ .join(" ")
15
+ .trim();
16
+ })
17
+ .filter((text) => text.length > 0); // Filter out empty text
18
+ };
19
+ /**
20
+ * Convert image file path to base64 format
21
+ * @param imagePath Image file path
22
+ * @returns base64 format image data URL
23
+ */
24
+ export const convertImageToBase64 = (imagePath) => {
25
+ try {
26
+ const imageBuffer = readFileSync(imagePath);
27
+ const ext = extname(imagePath).toLowerCase().substring(1);
28
+ // Determine MIME type based on file extension
29
+ let mimeType = "image/png"; // Default
30
+ switch (ext) {
31
+ case "jpg":
32
+ case "jpeg":
33
+ mimeType = "image/jpeg";
34
+ break;
35
+ case "png":
36
+ mimeType = "image/png";
37
+ break;
38
+ case "gif":
39
+ mimeType = "image/gif";
40
+ break;
41
+ case "webp":
42
+ mimeType = "image/webp";
43
+ break;
44
+ case "bmp":
45
+ mimeType = "image/bmp";
46
+ break;
47
+ default:
48
+ mimeType = "image/png";
49
+ }
50
+ const base64String = imageBuffer.toString("base64");
51
+ return `data:${mimeType};base64,${base64String}`;
52
+ }
53
+ catch {
54
+ // logger.error(`Failed to convert image to base64: ${imagePath}`, error);
55
+ // Return an error placeholder or throw error
56
+ return `data:image/png;base64,`; // Empty base64, avoid program crash
57
+ }
58
+ };
59
+ // Add user message
60
+ export const addUserMessageToMessages = ({ messages, content, images, customCommandBlock, }) => {
61
+ const blocks = [];
62
+ // If there's a custom command block, use it instead of text content
63
+ if (customCommandBlock) {
64
+ blocks.push(customCommandBlock);
65
+ }
66
+ else {
67
+ blocks.push({ type: "text", content });
68
+ }
69
+ // If there are images, add image block
70
+ if (images && images.length > 0) {
71
+ const imageUrls = images.map((img) => img.path);
72
+ blocks.push({
73
+ type: "image",
74
+ imageUrls,
75
+ });
76
+ }
77
+ const userMessage = {
78
+ role: "user",
79
+ blocks,
80
+ };
81
+ return [...messages, userMessage];
82
+ };
83
+ // Add assistant message (support one-time addition of answer and tool calls)
84
+ export const addAssistantMessageToMessages = (messages, content, toolCalls) => {
85
+ const blocks = [];
86
+ // If there's answer content, add text block
87
+ if (content) {
88
+ blocks.push({ type: "text", content: content });
89
+ }
90
+ // If there are tool calls, add tool blocks
91
+ if (toolCalls && toolCalls.length > 0) {
92
+ toolCalls.forEach((toolCall) => {
93
+ blocks.push({
94
+ type: "tool",
95
+ parameters: toolCall.function.arguments || "",
96
+ result: "",
97
+ id: toolCall.id || "",
98
+ name: toolCall.function?.name || "",
99
+ isRunning: false,
100
+ });
101
+ });
102
+ }
103
+ const initialAssistantMessage = {
104
+ role: "assistant",
105
+ blocks,
106
+ };
107
+ return [...messages, initialAssistantMessage];
108
+ };
109
+ // Update File Operation Block of the last assistant message
110
+ export const addDiffBlockToMessage = ({ messages, path, diffResult, }) => {
111
+ const newMessages = [...messages];
112
+ // Find the last assistant message
113
+ for (let i = newMessages.length - 1; i >= 0; i--) {
114
+ if (newMessages[i].role === "assistant") {
115
+ // Directly add diff block instead of replacing existing blocks
116
+ newMessages[i].blocks.push({
117
+ type: "diff",
118
+ path: path,
119
+ diffResult: diffResult,
120
+ });
121
+ break;
122
+ }
123
+ }
124
+ return newMessages;
125
+ };
126
+ // Update Tool Block of the last assistant message
127
+ export const updateToolBlockInMessage = ({ messages, id, parameters, result, success, error, isRunning, name, shortResult, images, compactParams, }) => {
128
+ const newMessages = [...messages];
129
+ // Find the last assistant message
130
+ for (let i = newMessages.length - 1; i >= 0; i--) {
131
+ if (newMessages[i].role === "assistant") {
132
+ const toolBlockIndex = newMessages[i].blocks.findIndex((block) => block.type === "tool" && block.id === id);
133
+ if (toolBlockIndex !== -1) {
134
+ const toolBlock = newMessages[i].blocks[toolBlockIndex];
135
+ if (toolBlock.type === "tool") {
136
+ toolBlock.parameters = parameters;
137
+ if (result !== undefined)
138
+ toolBlock.result = result;
139
+ if (shortResult !== undefined)
140
+ toolBlock.shortResult = shortResult;
141
+ toolBlock.images = images; // Add image data update
142
+ if (success !== undefined)
143
+ toolBlock.success = success;
144
+ if (error !== undefined)
145
+ toolBlock.error = error;
146
+ if (isRunning !== undefined)
147
+ toolBlock.isRunning = isRunning;
148
+ if (compactParams !== undefined)
149
+ toolBlock.compactParams = compactParams;
150
+ }
151
+ }
152
+ else if (result !== undefined) {
153
+ // If existing block not found, create new one
154
+ newMessages[i].blocks.push({
155
+ type: "tool",
156
+ parameters: parameters,
157
+ result: result,
158
+ shortResult: shortResult,
159
+ images: images, // Add image data
160
+ id: id,
161
+ name: name || "unknown",
162
+ success: success,
163
+ error: error,
164
+ isRunning: isRunning ?? false,
165
+ compactParams: compactParams,
166
+ });
167
+ }
168
+ break;
169
+ }
170
+ }
171
+ return newMessages;
172
+ };
173
+ // Add Error Block to the last assistant message
174
+ export const addErrorBlockToMessage = ({ messages, error, }) => {
175
+ const newMessages = [...messages];
176
+ // Find the last assistant message
177
+ let assistantMessageFound = false;
178
+ for (let i = newMessages.length - 1; i >= 0; i--) {
179
+ if (newMessages[i].role === "assistant") {
180
+ newMessages[i].blocks = [
181
+ ...newMessages[i].blocks,
182
+ {
183
+ type: "error",
184
+ content: error,
185
+ },
186
+ ];
187
+ assistantMessageFound = true;
188
+ break;
189
+ }
190
+ }
191
+ // If no assistant message found, create a new assistant message with only error block
192
+ if (!assistantMessageFound) {
193
+ newMessages.push({
194
+ role: "assistant",
195
+ blocks: [
196
+ {
197
+ type: "error",
198
+ content: error,
199
+ },
200
+ ],
201
+ });
202
+ }
203
+ return newMessages;
204
+ };
205
+ // Add Memory Block as new assistant message
206
+ export const addMemoryBlockToMessage = ({ messages, content, isSuccess, memoryType, storagePath, }) => {
207
+ const newMessages = [...messages];
208
+ // Create new assistant message containing MemoryBlock
209
+ const memoryMessage = {
210
+ role: "assistant",
211
+ blocks: [
212
+ {
213
+ type: "memory",
214
+ content,
215
+ isSuccess,
216
+ memoryType,
217
+ storagePath,
218
+ },
219
+ ],
220
+ };
221
+ // Add to end of message list
222
+ newMessages.push(memoryMessage);
223
+ return newMessages;
224
+ };
225
+ /**
226
+ * Count valid blocks from the end
227
+ * Only text, image, and tool type blocks are counted
228
+ * @param messages Message array
229
+ * @param targetCount Number of valid blocks to count
230
+ * @returns { messageIndex: number, blockCount: number } Message index and actual counted block count
231
+ */
232
+ export const countValidBlocksFromEnd = (messages, targetCount) => {
233
+ let validBlockCount = 0;
234
+ // Iterate messages from end to beginning
235
+ for (let i = messages.length - 1; i >= 0; i--) {
236
+ const message = messages[i];
237
+ // Iterate through all blocks of current message
238
+ for (const block of message.blocks) {
239
+ // Only count valid block types
240
+ if (block.type === "text" ||
241
+ block.type === "image" ||
242
+ block.type === "tool") {
243
+ validBlockCount++;
244
+ // If target count reached, return current message index
245
+ if (validBlockCount >= targetCount) {
246
+ return { messageIndex: i, blockCount: validBlockCount };
247
+ }
248
+ }
249
+ }
250
+ }
251
+ // If target count not reached, return index 0
252
+ return { messageIndex: 0, blockCount: validBlockCount };
253
+ };
254
+ /**
255
+ * Get messages to be compressed and insertion position
256
+ * @param messages Message array
257
+ * @param keepLastCount Keep the last few valid blocks uncompressed
258
+ * @returns { messagesToCompress: Message[], insertIndex: number }
259
+ */
260
+ export const getMessagesToCompress = (messages, keepLastCount = 7) => {
261
+ // Calculate message position to keep from end to beginning
262
+ const { messageIndex } = countValidBlocksFromEnd(messages, keepLastCount);
263
+ // Find the last message containing compression block
264
+ let lastCompressIndex = -1;
265
+ for (let i = messages.length - 1; i >= 0; i--) {
266
+ const hasCompressBlock = messages[i].blocks.some((block) => block.type === "compress");
267
+ if (hasCompressBlock) {
268
+ lastCompressIndex = i;
269
+ break;
270
+ }
271
+ }
272
+ // Determine compression start position
273
+ // If compression block exists, start from compression block position (include compression block)
274
+ // If no compression block, start from beginning
275
+ const startIndex = lastCompressIndex >= 0 ? lastCompressIndex : 0;
276
+ // Messages to compress are all messages from start position to before calculated position
277
+ const messagesToCompress = messages.slice(startIndex, messageIndex);
278
+ // Change insertion position to negative number, indicating position from end
279
+ const insertIndex = messageIndex - messages.length;
280
+ return { messagesToCompress, insertIndex };
281
+ };
282
+ // Add command output block to message list
283
+ export const addCommandOutputMessage = ({ messages, command, }) => {
284
+ const outputMessage = {
285
+ role: "assistant",
286
+ blocks: [
287
+ {
288
+ type: "command_output",
289
+ command,
290
+ output: "",
291
+ isRunning: true,
292
+ exitCode: null,
293
+ },
294
+ ],
295
+ };
296
+ return [...messages, outputMessage];
297
+ };
298
+ // Update output content of command output block
299
+ export const updateCommandOutputInMessage = ({ messages, command, output, }) => {
300
+ const newMessages = [...messages];
301
+ // Find the last assistant message with a command_output block for this command
302
+ for (let i = newMessages.length - 1; i >= 0; i--) {
303
+ const msg = newMessages[i];
304
+ if (msg.role === "assistant") {
305
+ const commandBlock = msg.blocks.find((block) => block.type === "command_output" &&
306
+ block.command === command &&
307
+ block.isRunning);
308
+ if (commandBlock && commandBlock.type === "command_output") {
309
+ commandBlock.output = output.trim();
310
+ break;
311
+ }
312
+ }
313
+ }
314
+ return newMessages;
315
+ };
316
+ // Complete command execution, update exit status
317
+ export const completeCommandInMessage = ({ messages, command, exitCode, }) => {
318
+ const newMessages = [...messages];
319
+ // Find the last assistant message with a command_output block for this command
320
+ for (let i = newMessages.length - 1; i >= 0; i--) {
321
+ const msg = newMessages[i];
322
+ if (msg.role === "assistant") {
323
+ const commandBlock = msg.blocks.find((block) => block.type === "command_output" &&
324
+ block.command === command &&
325
+ block.isRunning);
326
+ if (commandBlock && commandBlock.type === "command_output") {
327
+ commandBlock.isRunning = false;
328
+ commandBlock.exitCode = exitCode;
329
+ break;
330
+ }
331
+ }
332
+ }
333
+ return newMessages;
334
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Handle paths, supporting ~ expansion
3
+ * @param filePath File path
4
+ * @param workdir Working directory
5
+ * @returns Resolved absolute path
6
+ */
7
+ export declare function resolvePath(filePath: string, workdir: string): string;
8
+ /**
9
+ * Binary file extension list
10
+ */
11
+ export declare const binaryExtensions: readonly ["png", "jpg", "jpeg", "gif", "bmp", "ico", "webp", "svg", "sketch", "mp3", "wav", "ogg", "aac", "mp4", "webm", "avi", "mov", "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "zip", "rar", "7z", "tar", "gz", "ttf", "otf", "woff", "woff2", "eot", "exe", "dll", "so", "dylib", "bin"];
12
+ /**
13
+ * Check if a file is a binary file
14
+ * @param filename File name
15
+ * @returns Whether it is a binary file
16
+ */
17
+ export declare const isBinary: (filename: string) => boolean;
18
+ /**
19
+ * Get relative path for display, use relative path if shorter and not in parent directory
20
+ * @param filePath Absolute path
21
+ * @param workdir Working directory
22
+ * @returns Path for display (relative or absolute)
23
+ */
24
+ export declare function getDisplayPath(filePath: string, workdir: string): string;
25
+ //# sourceMappingURL=path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../../src/utils/path.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAarE;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,uSA+CnB,CAAC;AACX;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,UAAU,MAAM,KAAG,OAI3C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAwBxE"}