@kirosnn/mosaic 0.0.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.
Files changed (154) hide show
  1. package/.mosaic/mosaic.local.jsonc +0 -0
  2. package/MOSAIC.md +188 -0
  3. package/README.md +127 -0
  4. package/docs/mosaic.png +0 -0
  5. package/package.json +42 -0
  6. package/src/agent/Agent.ts +131 -0
  7. package/src/agent/context.ts +96 -0
  8. package/src/agent/index.ts +2 -0
  9. package/src/agent/prompts/systemPrompt.ts +138 -0
  10. package/src/agent/prompts/toolsPrompt.ts +139 -0
  11. package/src/agent/provider/anthropic.ts +122 -0
  12. package/src/agent/provider/google.ts +124 -0
  13. package/src/agent/provider/mistral.ts +117 -0
  14. package/src/agent/provider/ollama.ts +531 -0
  15. package/src/agent/provider/openai.ts +220 -0
  16. package/src/agent/provider/xai.ts +122 -0
  17. package/src/agent/tools/bash.ts +20 -0
  18. package/src/agent/tools/definitions.ts +27 -0
  19. package/src/agent/tools/edit.ts +23 -0
  20. package/src/agent/tools/executor.ts +751 -0
  21. package/src/agent/tools/explore.ts +18 -0
  22. package/src/agent/tools/exploreExecutor.ts +320 -0
  23. package/src/agent/tools/glob.ts +16 -0
  24. package/src/agent/tools/grep.ts +19 -0
  25. package/src/agent/tools/index.ts +4 -0
  26. package/src/agent/tools/list.ts +20 -0
  27. package/src/agent/tools/question.ts +20 -0
  28. package/src/agent/tools/read.ts +15 -0
  29. package/src/agent/tools/write.ts +21 -0
  30. package/src/agent/types.ts +155 -0
  31. package/src/components/App.tsx +174 -0
  32. package/src/components/CommandsModal.tsx +77 -0
  33. package/src/components/CustomInput.tsx +328 -0
  34. package/src/components/Main.tsx +1112 -0
  35. package/src/components/Notification.tsx +91 -0
  36. package/src/components/SelectList.tsx +47 -0
  37. package/src/components/Setup.tsx +528 -0
  38. package/src/components/ShortcutsModal.tsx +67 -0
  39. package/src/components/Welcome.tsx +39 -0
  40. package/src/components/main/ApprovalPanel.tsx +134 -0
  41. package/src/components/main/ChatPage.tsx +516 -0
  42. package/src/components/main/HomePage.tsx +111 -0
  43. package/src/components/main/QuestionPanel.tsx +85 -0
  44. package/src/components/main/ThinkingIndicator.tsx +101 -0
  45. package/src/components/main/types.ts +55 -0
  46. package/src/components/main/wrapText.ts +41 -0
  47. package/src/index.tsx +212 -0
  48. package/src/utils/approvalBridge.ts +129 -0
  49. package/src/utils/commands/echo.ts +22 -0
  50. package/src/utils/commands/help.ts +25 -0
  51. package/src/utils/commands/index.ts +68 -0
  52. package/src/utils/commands/init.ts +68 -0
  53. package/src/utils/commands/redo.ts +74 -0
  54. package/src/utils/commands/registry.ts +29 -0
  55. package/src/utils/commands/sessions.ts +129 -0
  56. package/src/utils/commands/types.ts +20 -0
  57. package/src/utils/commands/undo.ts +75 -0
  58. package/src/utils/commands/web.ts +77 -0
  59. package/src/utils/config.ts +357 -0
  60. package/src/utils/diff.ts +201 -0
  61. package/src/utils/diffRendering.tsx +62 -0
  62. package/src/utils/exploreBridge.ts +87 -0
  63. package/src/utils/fileChangeTracker.ts +98 -0
  64. package/src/utils/fileChangesBridge.ts +18 -0
  65. package/src/utils/history.ts +106 -0
  66. package/src/utils/markdown.tsx +232 -0
  67. package/src/utils/models.ts +304 -0
  68. package/src/utils/questionBridge.ts +122 -0
  69. package/src/utils/terminalUtils.ts +25 -0
  70. package/src/utils/toolFormatting.ts +384 -0
  71. package/src/utils/undoRedo.ts +429 -0
  72. package/src/utils/undoRedoBridge.ts +45 -0
  73. package/src/utils/undoRedoDb.ts +338 -0
  74. package/src/utils/uninstall.ts +45 -0
  75. package/src/utils/version.ts +3 -0
  76. package/src/web/app.tsx +606 -0
  77. package/src/web/assets/css/ChatPage.css +212 -0
  78. package/src/web/assets/css/FileExplorer.css +202 -0
  79. package/src/web/assets/css/HomePage.css +119 -0
  80. package/src/web/assets/css/Markdown.css +178 -0
  81. package/src/web/assets/css/MessageItem.css +160 -0
  82. package/src/web/assets/css/Sidebar.css +208 -0
  83. package/src/web/assets/css/SidebarModal.css +137 -0
  84. package/src/web/assets/css/ThinkingIndicator.css +47 -0
  85. package/src/web/assets/css/ToolMessage.css +148 -0
  86. package/src/web/assets/css/global.css +226 -0
  87. package/src/web/assets/fonts/Geist-Black.woff2 +0 -0
  88. package/src/web/assets/fonts/Geist-BlackItalic.woff2 +0 -0
  89. package/src/web/assets/fonts/Geist-Bold.woff2 +0 -0
  90. package/src/web/assets/fonts/Geist-BoldItalic.woff2 +0 -0
  91. package/src/web/assets/fonts/Geist-ExtraBold.woff2 +0 -0
  92. package/src/web/assets/fonts/Geist-ExtraBoldItalic.woff2 +0 -0
  93. package/src/web/assets/fonts/Geist-ExtraLight.woff2 +0 -0
  94. package/src/web/assets/fonts/Geist-ExtraLightItalic.woff2 +0 -0
  95. package/src/web/assets/fonts/Geist-Italic[wght].woff2 +0 -0
  96. package/src/web/assets/fonts/Geist-Light.woff2 +0 -0
  97. package/src/web/assets/fonts/Geist-LightItalic.woff2 +0 -0
  98. package/src/web/assets/fonts/Geist-Medium.woff2 +0 -0
  99. package/src/web/assets/fonts/Geist-MediumItalic.woff2 +0 -0
  100. package/src/web/assets/fonts/Geist-Regular.woff2 +0 -0
  101. package/src/web/assets/fonts/Geist-RegularItalic.woff2 +0 -0
  102. package/src/web/assets/fonts/Geist-SemiBold.woff2 +0 -0
  103. package/src/web/assets/fonts/Geist-SemiBoldItalic.woff2 +0 -0
  104. package/src/web/assets/fonts/Geist-Thin.woff2 +0 -0
  105. package/src/web/assets/fonts/Geist-ThinItalic.woff2 +0 -0
  106. package/src/web/assets/fonts/GeistMono-Black.woff2 +0 -0
  107. package/src/web/assets/fonts/GeistMono-BlackItalic.woff2 +0 -0
  108. package/src/web/assets/fonts/GeistMono-Bold.woff2 +0 -0
  109. package/src/web/assets/fonts/GeistMono-BoldItalic.woff2 +0 -0
  110. package/src/web/assets/fonts/GeistMono-ExtraBold.woff2 +0 -0
  111. package/src/web/assets/fonts/GeistMono-ExtraBoldItalic.woff2 +0 -0
  112. package/src/web/assets/fonts/GeistMono-ExtraLight.woff2 +0 -0
  113. package/src/web/assets/fonts/GeistMono-ExtraLightItalic.woff2 +0 -0
  114. package/src/web/assets/fonts/GeistMono-Italic.woff2 +0 -0
  115. package/src/web/assets/fonts/GeistMono-Italic[wght].woff2 +0 -0
  116. package/src/web/assets/fonts/GeistMono-Light.woff2 +0 -0
  117. package/src/web/assets/fonts/GeistMono-LightItalic.woff2 +0 -0
  118. package/src/web/assets/fonts/GeistMono-Medium.woff2 +0 -0
  119. package/src/web/assets/fonts/GeistMono-MediumItalic.woff2 +0 -0
  120. package/src/web/assets/fonts/GeistMono-Regular.woff2 +0 -0
  121. package/src/web/assets/fonts/GeistMono-SemiBold.woff2 +0 -0
  122. package/src/web/assets/fonts/GeistMono-SemiBoldItalic.woff2 +0 -0
  123. package/src/web/assets/fonts/GeistMono-Thin.woff2 +0 -0
  124. package/src/web/assets/fonts/GeistMono-ThinItalic.woff2 +0 -0
  125. package/src/web/assets/fonts/GeistMono[wght].woff2 +0 -0
  126. package/src/web/assets/fonts/Geist[wght].woff2 +0 -0
  127. package/src/web/assets/fonts/blauer-nue-regular.woff2 +0 -0
  128. package/src/web/assets/fonts/neue-montreal-regular.woff2 +0 -0
  129. package/src/web/assets/images/favicon-v2.svg +6 -0
  130. package/src/web/assets/images/favicon.png +0 -0
  131. package/src/web/assets/images/foruse.svg +5 -0
  132. package/src/web/assets/images/logo_black.svg +5 -0
  133. package/src/web/assets/images/logo_white.svg +5 -0
  134. package/src/web/assets/images/logoblack.png +0 -0
  135. package/src/web/assets/images/logowhite.png +0 -0
  136. package/src/web/build.ts +23 -0
  137. package/src/web/components/ApprovalPanel.tsx +191 -0
  138. package/src/web/components/ChatPage.tsx +273 -0
  139. package/src/web/components/FileExplorer.tsx +162 -0
  140. package/src/web/components/HomePage.tsx +121 -0
  141. package/src/web/components/MessageItem.tsx +178 -0
  142. package/src/web/components/Modal.tsx +30 -0
  143. package/src/web/components/QuestionPanel.tsx +149 -0
  144. package/src/web/components/Setup.tsx +211 -0
  145. package/src/web/components/Sidebar.tsx +292 -0
  146. package/src/web/components/ThinkingIndicator.tsx +85 -0
  147. package/src/web/logo_black.svg +5 -0
  148. package/src/web/logo_white.svg +5 -0
  149. package/src/web/router.ts +46 -0
  150. package/src/web/server.tsx +662 -0
  151. package/src/web/storage.ts +92 -0
  152. package/src/web/types.ts +17 -0
  153. package/src/web/utils.ts +61 -0
  154. package/tsconfig.json +33 -0
@@ -0,0 +1,138 @@
1
+ import { homedir, platform, arch } from 'os';
2
+ import { readFileSync, existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { getToolsPrompt } from './toolsPrompt';
5
+
6
+ export const DEFAULT_SYSTEM_PROMPT = `You are Mosaic, an AI coding assistant operating in the user's terminal.
7
+ Your purpose is to assist with software engineering tasks: coding, debugging, refactoring, and documentation.
8
+
9
+ IMPORTANT: Refuse to write code or explain code that may be used maliciously; even if the user claims it is for educational purposes. When working with files, if they seem related to improving, explaining, or interacting with malware or any malicious code you MUST refuse. IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure. If it seems malicious, refuse to work on it or answer questions about it, even if the request does not seem malicious (for instance, just asking to explain or speed up the code).
10
+
11
+ MEMORY:
12
+ If the current working directory contains a file called MOSAIC.md, it will be automatically added to your context. This file serves multiple purposes:
13
+
14
+ - Storing frequently used bash commands (build, test, lint, etc.) so you can use them without searching each time
15
+ - Recording the user's code style preferences (naming conventions, preferred libraries, etc.)
16
+ - Maintaining useful information about the codebase structure and organization
17
+ When you spend time searching for commands to typecheck, lint, build, or test, you should ask the user if it's okay to add those commands to MOSAIC.md. Similarly, when learning about code style preferences or important codebase information, ask if it's okay to add that to MOSAIC.md so you can remember it for next time.
18
+
19
+ ENVIRONMENT:
20
+ - Current workspace: {{WORKSPACE}}
21
+ - Operating system: {{OS}}
22
+ - Architecture: {{ARCH}}
23
+ - Date: {{DATE}}
24
+ - Time: {{TIME}}
25
+
26
+ LANGUAGE RULES:
27
+ - STRICTLY match the user's language for ALL text output, unless the user indicates otherwise.
28
+ - Never mix languages.
29
+ - Don't use emojis.
30
+ - Exception: code, file names, technical identifiers remain unchanged.
31
+ - Do not use codeblocks (no triple backticks \`\`\`).
32
+ - Do not use Markdown bold tags in Markdown headings.
33
+
34
+ SCOPE:
35
+ - All user requests refer to the current workspace ({{WORKSPACE}}).
36
+ - Questions like "how does this work?" or "fix this" always refer to the user's project, never to Mosaic itself.
37
+
38
+ RESPONSE PROTOCOL:
39
+ - ALWAYS start your first reply only with a <title> tag. The title MUST be in English, maximum 3 words, describing the general task. Example: <title>Fix login</title> or <title>Add feature</title> or <title>Greeting</title>; never use it again unless the conversation clearly switches to a new, unrelated task.
40
+ - After the title tag, write a single sentence IN THE USER'S LANGUAGE describing what you will do. Generate this sentence dynamically based on the user's request - adapt the phrasing to their language naturally.
41
+ - ALWAYS provide a text response to the user IN THEIR LANGUAGE, NEVER just use tools without explanation. The user needs to understand what you're doing and the results.
42
+ - After stating your intention, proceed with tool usage as needed.
43
+
44
+ ASKING QUESTIONS - CRITICAL RULE:
45
+ - NEVER ask questions to the user in plain text responses.
46
+ - ALWAYS use the "question" tool when you need user input, clarification, confirmation, or choices.
47
+ - The "question" tool is MANDATORY for ANY interaction that requires a user response.
48
+ - Examples of when to use the question tool:
49
+ * "Which file should I modify?" → Use question tool with file options
50
+ * "Should I proceed?" → Use question tool with "Yes"/"No" options
51
+ * "Do you want A or B?" → Use question tool with "A"/"B" options
52
+ * "Can you clarify X?" → Use question tool with relevant options
53
+ * When a tool fails and you need to know how to proceed → Use question tool
54
+ - If you're uncertain or need clarification, IMMEDIATELY use the question tool - do NOT ask in plain text.
55
+ - Plain text questions are STRICTLY FORBIDDEN. You will be penalized for asking questions without using the question tool.
56
+
57
+ ERROR HANDLING:
58
+ - If a tool execution fails, ALWAYS announce IN THE USER'S LANGUAGE that you will retry with a brief explanation.
59
+ - Only give up after multiple failed attempts or if the error is clearly unrecoverable and tell to the user the problems.
60
+ - Keep the user informed about what went wrong and what you're trying next, always IN THEIR LANGUAGE.
61
+
62
+ COMMAND EXECUTION PROTOCOL:
63
+ - CRITICAL: You are running on {{OS}}. You MUST adapt all terminal commands to this operating system.
64
+ - Windows ('win32'):
65
+ * Use PowerShell syntax exclusively.
66
+ * DO NOT use Unix-specific commands or flags (e.g., used 'ls -la', 'touch', 'export', 'rm -rf').
67
+ * Use PowerShell equivalents (e.g., 'Get-ChildItem', 'New-Item', '$env:VAR="val"', 'Remove-Item -Recurse -Force').
68
+ - macOS ('darwin') / Linux ('linux'):
69
+ * Use standard Bash/Zsh syntax.
70
+
71
+ EFFICIENCY:
72
+ - You can use up to 30 steps, BUT you must respond to the user as soon as you have enough information.
73
+
74
+ EXPLORATION:
75
+ - When you need to understand the codebase structure, find implementations, or gather information across multiple files, use the "explore" tool.
76
+ - The explore tool launches an autonomous agent that will search through the codebase for you.
77
+ - Use explore for open-ended questions like "where is X implemented?", "how does Y work?", or "find all Z".
78
+ - Example: explore(purpose="Find the main entry points and understand the project structure")
79
+ `;
80
+
81
+ export function processSystemPrompt(prompt: string, includeTools: boolean = true): string {
82
+ const now = new Date();
83
+ const workspace = process.cwd();
84
+ const os = platform();
85
+ const architecture = arch();
86
+
87
+ const replacements: Record<string, string> = {
88
+ '{{WORKSPACE}}': workspace,
89
+ '{{CWD}}': workspace,
90
+ '{{OS}}': os,
91
+ '{{ARCH}}': architecture,
92
+ '{{DATE}}': now.toLocaleDateString('en-US', {
93
+ year: 'numeric',
94
+ month: 'long',
95
+ day: 'numeric'
96
+ }),
97
+ '{{TIME}}': now.toLocaleTimeString('en-US', {
98
+ hour: '2-digit',
99
+ minute: '2-digit',
100
+ hour12: false
101
+ }),
102
+ '{{HOMEDIR}}': homedir(),
103
+ };
104
+
105
+ let processed = prompt;
106
+ for (const [placeholder, value] of Object.entries(replacements)) {
107
+ processed = processed.replace(new RegExp(placeholder, 'g'), value);
108
+ }
109
+
110
+ const mosaicMdPath = join(workspace, 'MOSAIC.md');
111
+ if (existsSync(mosaicMdPath)) {
112
+ try {
113
+ const mosaicContent = readFileSync(mosaicMdPath, 'utf-8');
114
+ processed = `${processed}\n\nPROJECT CONTEXT (MOSAIC.md):
115
+ IMPORTANT: A MOSAIC.md file exists in this workspace. This is a specialized context file that provides crucial information about this project's architecture, patterns, and conventions.
116
+
117
+ Read and understand this context BEFORE making changes to the codebase. This will help you:
118
+ - Understand the project structure and architectural decisions
119
+ - Follow the correct coding standards and conventions
120
+ - Know where different types of files should be located
121
+ - Use the right patterns and tools for this specific project
122
+
123
+ ${mosaicContent}`;
124
+ } catch (error) {
125
+ console.error('Failed to read MOSAIC.md:', error);
126
+ }
127
+ } else {
128
+ processed = `${processed}\n\nNOTE: No MOSAIC.md file found in this workspace. You can create one using the /init command to provide better context for future AI agents working on this project.`;
129
+ }
130
+
131
+ if (includeTools) {
132
+ const toolsPrompt = getToolsPrompt();
133
+ const processedToolsPrompt = toolsPrompt.replace(new RegExp('{{WORKSPACE}}', 'g'), workspace);
134
+ processed = `${processed}\n\n${processedToolsPrompt}`;
135
+ }
136
+
137
+ return processed;
138
+ }
@@ -0,0 +1,139 @@
1
+ export const TOOLS_PROMPT = `
2
+ AVAILABLE TOOLS:
3
+
4
+ You have access to the following tools to interact with the workspace:
5
+
6
+ FILE READING:
7
+ 1. read: Read the complete contents of a file
8
+ - Use this to examine existing code, configuration, or documentation
9
+ - Parameters: path (string)
10
+
11
+ FILE WRITING & EDITING:
12
+ 2. write: Write or overwrite a file (with advanced features)
13
+ - Creates parent directories automatically if they don't exist
14
+ - Can append to existing files instead of overwriting
15
+ - Parameters: path (string), content (string, optional), append (boolean, optional)
16
+ - Note: content can be omitted or empty to create an empty file
17
+
18
+ 3. edit: Edit a specific part of a file without rewriting everything
19
+ - More efficient for targeted changes - replace specific text content
20
+ - Parameters: path (string), old_content (string), new_content (string), occurrence (number, optional)
21
+
22
+ FILE & DIRECTORY OPERATIONS:
23
+ 4. list: List files and directories with filtering
24
+ - Supports recursive listing through subdirectories
25
+ - Can filter by glob patterns (e.g., "*.ts")
26
+ - Can include or exclude hidden files
27
+ - Parameters: path (string), recursive (boolean, optional), filter (string, optional), include_hidden (boolean, optional)
28
+
29
+ SEARCH & DISCOVERY:
30
+ 5. glob: Fast file pattern matching
31
+ - Find files matching a glob pattern
32
+ - REQUIRED: pattern (string) - Glob pattern to match files (e.g., "*.ts", "**/*.tsx", "src/**/*.js")
33
+ - OPTIONAL: path (string) - Directory to search in (default: workspace root)
34
+
35
+ Examples:
36
+ - Find all TypeScript files: glob(pattern="**/*.ts")
37
+ - Find React components: glob(pattern="**/*.tsx")
38
+ - Search in specific directory: glob(pattern="*.js", path="src")
39
+
40
+ 6. grep: Search for text content within files
41
+ - Search for text within files matching a glob pattern
42
+ - REQUIRED: pattern (string) - Glob pattern to match files (e.g., "*.ts", "**/*.tsx")
43
+ - REQUIRED: query (string) - Text content to search for
44
+ - OPTIONAL: path (string) - Directory to search in (default: workspace root)
45
+ - OPTIONAL: case_sensitive (boolean) - Case-sensitive search (default: false)
46
+ - OPTIONAL: max_results (number) - Maximum results (default: 100)
47
+
48
+ Examples:
49
+ - Find interface in TypeScript files: grep(pattern="**/*.ts", query="interface User")
50
+ - Search in specific directory: grep(pattern="*.js", query="console.log", path="src")
51
+ - Case-sensitive search: grep(pattern="**/*.ts", query="UserModel", case_sensitive=true)
52
+
53
+ AUTONOMOUS EXPLORATION:
54
+ 7. explore: Launch an autonomous exploration agent
55
+ - Explores the codebase iteratively to gather information
56
+ - The agent uses read, glob, grep, and list tools autonomously
57
+ - Continues until it has enough information or reaches its limit
58
+ - Use for open-ended exploration tasks
59
+ - Parameters: purpose (string) - The goal of the exploration
60
+
61
+ Examples:
62
+ - Understand project structure:
63
+ explore(purpose="Understand the project structure and main entry points")
64
+ - Find implementations:
65
+ explore(purpose="Find all React components that handle user authentication")
66
+ - Investigate code patterns:
67
+ explore(purpose="Find how errors are handled throughout the codebase")
68
+
69
+ COMMAND EXECUTION:
70
+ 8. bash: Execute a shell command
71
+ - Use this to run build tools, tests, git commands, or other CLI tools
72
+ - Parameters: command (string)
73
+ - CRITICAL: You MUST add --timeout <ms> at the END of commands that might hang:
74
+ * Dev servers: ALWAYS add --timeout 5000
75
+ Example: bash(command="npm run dev --timeout 5000")
76
+ * Build commands: ALWAYS add --timeout 120000
77
+ Example: bash(command="npm run build --timeout 120000")
78
+ * Test runners: ALWAYS add --timeout 60000
79
+ Example: bash(command="pytest tests/ --timeout 60000")
80
+ * Package installs: ALWAYS add --timeout 120000
81
+ Example: bash(command="npm install --timeout 120000")
82
+ * Interactive CLIs: ALWAYS add --timeout 5000 or avoid entirely
83
+ Example: bash(command="npx create-react-app myapp --timeout 5000")
84
+ - Quick commands (ls, cat, git status, echo): No --timeout needed (default: 30s)
85
+
86
+ USER INTERACTION:
87
+ 9. question: Ask the user a question with predefined options
88
+ - CRITICAL: This is the ONLY way to ask the user questions. NEVER ask questions in plain text.
89
+ - MANDATORY usage scenarios:
90
+ * When you need user to pick between choices
91
+ * When you need user's confirmation or approval
92
+ * When you need clarification on ambiguous requests
93
+ * When you're unsure how to proceed
94
+ * When a tool operation is rejected and you need to know why
95
+ * When multiple approaches are possible and user input is needed
96
+ - The UI will show the prompt and options and return the selected option
97
+ - Parameters:
98
+ - prompt (string) - The question to ask in the user's language
99
+ - options (array of objects) - At least 2 options required:
100
+ - label (string) - The option text shown to user
101
+ - value (string | null) - Optional value returned (use null if not needed)
102
+ - Returns: { id, index, label, value }
103
+ - Example: question(prompt="Which approach do you prefer?", options=[{label:"Approach A", value:"a"}, {label:"Approach B", value:"b"}])
104
+
105
+ TOOL USAGE GUIDELINES:
106
+
107
+ - Use explore for open-ended exploration tasks (autonomous agent)
108
+ - Use glob to find files by pattern (fast file discovery)
109
+ - Use grep to search for text content within files
110
+ - Use edit for small changes to avoid rewriting entire files
111
+ - Always use read before modifying files to understand the current state
112
+ - When writing files, preserve existing code structure and style
113
+ - Use list with recursive:true to explore deep directory structures
114
+ - All file paths are relative to the workspace root: {{WORKSPACE}}
115
+
116
+ ERRORS:
117
+ - Some tools return an object like {"error": "..."} when something went wrong. Treat this as a TOOL ERROR (not an API error).
118
+ - When a tool returns an error, continue the task using that information (e.g., adjust path, create missing parent directory, retry with correct tool).
119
+
120
+ WORKFLOW BEST PRACTICES:
121
+
122
+ 1. Discover: Use explore for open-ended exploration, or glob/grep for targeted searches
123
+ 2. Understand: Use read to examine files
124
+ 3. Plan: Think through modifications before acting
125
+ 4. Execute: Use edit for small changes, write for new/complete rewrites
126
+ 5. Verify: Use bash to run tests and verify changes
127
+ 6. Communicate: Explain your actions to the user in their language
128
+
129
+ CRITICAL REMINDERS:
130
+ - NEVER ask questions in plain text - ALWAYS use the question tool
131
+ - When write/edit/bash operations are rejected by the user, IMMEDIATELY use the question tool to understand why and what to do instead
132
+ - The question tool is NOT optional - it's MANDATORY for any user interaction requiring a response
133
+ - If you catch yourself about to ask something in text, STOP and use the question tool instead
134
+
135
+ Remember: The user can see your tool usage, so be transparent about what you're doing and why.`;
136
+
137
+ export function getToolsPrompt(): string {
138
+ return TOOLS_PROMPT;
139
+ }
@@ -0,0 +1,122 @@
1
+ import { streamText, CoreMessage } from 'ai';
2
+ import { createAnthropic } from '@ai-sdk/anthropic';
3
+ import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
4
+
5
+ export class AnthropicProvider implements Provider {
6
+ async *sendMessage(
7
+ messages: CoreMessage[],
8
+ config: ProviderConfig,
9
+ options?: ProviderSendOptions
10
+ ): AsyncGenerator<AgentEvent> {
11
+ const cleanApiKey = config.apiKey?.trim().replace(/[\r\n]+/g, '');
12
+ const cleanModel = config.model.trim().replace(/[\r\n]+/g, '');
13
+
14
+ const anthropic = createAnthropic({
15
+ apiKey: cleanApiKey,
16
+ });
17
+
18
+ const result = streamText({
19
+ model: anthropic(cleanModel),
20
+ messages: messages,
21
+ system: config.systemPrompt,
22
+ tools: config.tools,
23
+ maxSteps: config.maxSteps || 10,
24
+ abortSignal: options?.abortSignal,
25
+ experimental_providerMetadata: {
26
+ anthropic: {
27
+ thinkingBudgetTokens: 10000,
28
+ },
29
+ },
30
+ });
31
+
32
+ try {
33
+ let stepCounter = 0;
34
+
35
+ for await (const chunk of result.fullStream as any) {
36
+ const c: any = chunk;
37
+ switch (c.type) {
38
+ case 'reasoning':
39
+ if (c.textDelta) {
40
+ yield {
41
+ type: 'reasoning-delta',
42
+ content: c.textDelta,
43
+ };
44
+ }
45
+ break;
46
+
47
+ case 'text-delta':
48
+ yield {
49
+ type: 'text-delta',
50
+ content: c.textDelta,
51
+ };
52
+ break;
53
+
54
+ case 'step-start':
55
+ yield {
56
+ type: 'step-start',
57
+ stepNumber: typeof c.stepIndex === 'number' ? c.stepIndex : stepCounter,
58
+ };
59
+ stepCounter++;
60
+ break;
61
+
62
+ case 'step-finish':
63
+ yield {
64
+ type: 'step-finish',
65
+ stepNumber:
66
+ typeof c.stepIndex === 'number' ? c.stepIndex : Math.max(0, stepCounter - 1),
67
+ finishReason: String(c.finishReason ?? 'stop'),
68
+ };
69
+ break;
70
+
71
+ case 'tool-call':
72
+ yield {
73
+ type: 'tool-call-end',
74
+ toolCallId: String(c.toolCallId ?? ''),
75
+ toolName: String(c.toolName ?? ''),
76
+ args: (c.args ?? {}) as Record<string, unknown>,
77
+ };
78
+ break;
79
+
80
+ case 'tool-result':
81
+ yield {
82
+ type: 'tool-result',
83
+ toolCallId: String(c.toolCallId ?? ''),
84
+ toolName: String(c.toolName ?? ''),
85
+ result: c.result,
86
+ };
87
+ break;
88
+
89
+ case 'finish':
90
+ yield {
91
+ type: 'finish',
92
+ finishReason: String(c.finishReason ?? 'stop'),
93
+ usage: c.usage,
94
+ };
95
+ break;
96
+
97
+ case 'error':
98
+ {
99
+ const err = c.error;
100
+ const msg =
101
+ err instanceof Error
102
+ ? err.message
103
+ : typeof err === 'string'
104
+ ? err
105
+ : 'Unknown error';
106
+ yield {
107
+ type: 'error',
108
+ error: msg,
109
+ };
110
+ }
111
+ break;
112
+ }
113
+ }
114
+ } catch (error) {
115
+ if (options?.abortSignal?.aborted) return;
116
+ yield {
117
+ type: 'error',
118
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
119
+ };
120
+ }
121
+ }
122
+ }
@@ -0,0 +1,124 @@
1
+ import { streamText, CoreMessage } from 'ai';
2
+ import { createGoogleGenerativeAI } from '@ai-sdk/google';
3
+ import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
4
+
5
+ export class GoogleProvider implements Provider {
6
+ async *sendMessage(
7
+ messages: CoreMessage[],
8
+ config: ProviderConfig,
9
+ options?: ProviderSendOptions
10
+ ): AsyncGenerator<AgentEvent> {
11
+ const cleanApiKey = config.apiKey?.trim().replace(/[\r\n]+/g, '');
12
+ const cleanModel = config.model.trim().replace(/[\r\n]+/g, '');
13
+
14
+ const google = createGoogleGenerativeAI({
15
+ apiKey: cleanApiKey,
16
+ });
17
+
18
+ const result = streamText({
19
+ model: google(cleanModel),
20
+ messages: messages,
21
+ system: config.systemPrompt,
22
+ tools: config.tools,
23
+ maxSteps: config.maxSteps || 10,
24
+ abortSignal: options?.abortSignal,
25
+ providerOptions: {
26
+ google: {
27
+ thinkingConfig: {
28
+ style: 'THINKING_STYLE_DETAILED',
29
+ },
30
+ },
31
+ },
32
+ });
33
+
34
+ try {
35
+ let stepCounter = 0;
36
+
37
+ for await (const chunk of result.fullStream as any) {
38
+ const c: any = chunk;
39
+ switch (c.type) {
40
+ case 'reasoning':
41
+ if (c.textDelta) {
42
+ yield {
43
+ type: 'reasoning-delta',
44
+ content: c.textDelta,
45
+ };
46
+ }
47
+ break;
48
+
49
+ case 'text-delta':
50
+ yield {
51
+ type: 'text-delta',
52
+ content: c.textDelta,
53
+ };
54
+ break;
55
+
56
+ case 'step-start':
57
+ yield {
58
+ type: 'step-start',
59
+ stepNumber: typeof c.stepIndex === 'number' ? c.stepIndex : stepCounter,
60
+ };
61
+ stepCounter++;
62
+ break;
63
+
64
+ case 'step-finish':
65
+ yield {
66
+ type: 'step-finish',
67
+ stepNumber:
68
+ typeof c.stepIndex === 'number' ? c.stepIndex : Math.max(0, stepCounter - 1),
69
+ finishReason: String(c.finishReason ?? 'stop'),
70
+ };
71
+ break;
72
+
73
+ case 'tool-call':
74
+ yield {
75
+ type: 'tool-call-end',
76
+ toolCallId: String(c.toolCallId ?? ''),
77
+ toolName: String(c.toolName ?? ''),
78
+ args: (c.args ?? {}) as Record<string, unknown>,
79
+ };
80
+ break;
81
+
82
+ case 'tool-result':
83
+ yield {
84
+ type: 'tool-result',
85
+ toolCallId: String(c.toolCallId ?? ''),
86
+ toolName: String(c.toolName ?? ''),
87
+ result: c.result,
88
+ };
89
+ break;
90
+
91
+ case 'finish':
92
+ yield {
93
+ type: 'finish',
94
+ finishReason: String(c.finishReason ?? 'stop'),
95
+ usage: c.usage,
96
+ };
97
+ break;
98
+
99
+ case 'error':
100
+ {
101
+ const err = c.error;
102
+ const msg =
103
+ err instanceof Error
104
+ ? err.message
105
+ : typeof err === 'string'
106
+ ? err
107
+ : 'Unknown error';
108
+ yield {
109
+ type: 'error',
110
+ error: msg,
111
+ };
112
+ }
113
+ break;
114
+ }
115
+ }
116
+ } catch (error) {
117
+ if (options?.abortSignal?.aborted) return;
118
+ yield {
119
+ type: 'error',
120
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
121
+ };
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,117 @@
1
+ import { streamText, CoreMessage } from 'ai';
2
+ import { createMistral } from '@ai-sdk/mistral';
3
+ import { AgentEvent, Provider, ProviderConfig, ProviderSendOptions } from '../types';
4
+
5
+ export class MistralProvider implements Provider {
6
+ async *sendMessage(
7
+ messages: CoreMessage[],
8
+ config: ProviderConfig,
9
+ options?: ProviderSendOptions
10
+ ): AsyncGenerator<AgentEvent> {
11
+ const cleanApiKey = config.apiKey?.trim().replace(/[\r\n]+/g, '');
12
+ const cleanModel = config.model.trim().replace(/[\r\n]+/g, '');
13
+
14
+ const mistral = createMistral({
15
+ apiKey: cleanApiKey,
16
+ });
17
+
18
+ const result = streamText({
19
+ model: mistral(cleanModel),
20
+ messages: messages,
21
+ system: config.systemPrompt,
22
+ tools: config.tools,
23
+ maxSteps: config.maxSteps || 10,
24
+ abortSignal: options?.abortSignal
25
+ });
26
+
27
+ try {
28
+ let stepCounter = 0;
29
+
30
+ for await (const chunk of result.fullStream as any) {
31
+ const c: any = chunk;
32
+ switch (c.type) {
33
+ case 'reasoning':
34
+ if (c.textDelta) {
35
+ yield {
36
+ type: 'reasoning-delta',
37
+ content: c.textDelta,
38
+ };
39
+ }
40
+ break;
41
+
42
+ case 'text-delta':
43
+ yield {
44
+ type: 'text-delta',
45
+ content: c.textDelta,
46
+ };
47
+ break;
48
+
49
+ case 'step-start':
50
+ yield {
51
+ type: 'step-start',
52
+ stepNumber: typeof c.stepIndex === 'number' ? c.stepIndex : stepCounter,
53
+ };
54
+ stepCounter++;
55
+ break;
56
+
57
+ case 'step-finish':
58
+ yield {
59
+ type: 'step-finish',
60
+ stepNumber:
61
+ typeof c.stepIndex === 'number' ? c.stepIndex : Math.max(0, stepCounter - 1),
62
+ finishReason: String(c.finishReason ?? 'stop'),
63
+ };
64
+ break;
65
+
66
+ case 'tool-call':
67
+ yield {
68
+ type: 'tool-call-end',
69
+ toolCallId: String(c.toolCallId ?? ''),
70
+ toolName: String(c.toolName ?? ''),
71
+ args: (c.args ?? {}) as Record<string, unknown>,
72
+ };
73
+ break;
74
+
75
+ case 'tool-result':
76
+ yield {
77
+ type: 'tool-result',
78
+ toolCallId: String(c.toolCallId ?? ''),
79
+ toolName: String(c.toolName ?? ''),
80
+ result: c.result,
81
+ };
82
+ break;
83
+
84
+ case 'finish':
85
+ yield {
86
+ type: 'finish',
87
+ finishReason: String(c.finishReason ?? 'stop'),
88
+ usage: c.usage,
89
+ };
90
+ break;
91
+
92
+ case 'error':
93
+ {
94
+ const err = c.error;
95
+ const msg =
96
+ err instanceof Error
97
+ ? err.message
98
+ : typeof err === 'string'
99
+ ? err
100
+ : 'Unknown error';
101
+ yield {
102
+ type: 'error',
103
+ error: msg,
104
+ };
105
+ }
106
+ break;
107
+ }
108
+ }
109
+ } catch (error) {
110
+ if (options?.abortSignal?.aborted) return;
111
+ yield {
112
+ type: 'error',
113
+ error: error instanceof Error ? error.message : 'Unknown error occurred',
114
+ };
115
+ }
116
+ }
117
+ }