From 081656eb5bb2a1bd6049a15f12fe20f0d8d28938 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Wed, 14 Jan 2026 12:14:35 +0530 Subject: [PATCH 1/5] release axon-code-2 model out of preview + default mdoel --- README.md | 10 +++++----- .../__tests__/persistence-provider-merge.test.ts | 2 +- cli/src/config/defaults.ts | 2 +- cli/src/constants/providers/settings.ts | 2 +- cli/src/utils/browserAuth.ts | 2 +- src/api/providers/kilocode-models.ts | 6 +++--- src/core/kilocode/api/codeReviewService.ts | 1 - src/package.json | 2 +- .../components/ui/hooks/useOpenRouterModelProviders.ts | 6 +++--- webview-ui/src/utils/prettyModelName.ts | 6 ++---- 10 files changed, 18 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index f4ca65fc9c..62765c2a32 100644 --- a/README.md +++ b/README.md @@ -82,11 +82,11 @@ Axon Code provides a comprehensive suite of intelligent tools: Choose the right model for your workflow: -| Model | Use Case | Capabilities | -| ------------------------- | --------------------- | -------------------------------------------- | -| **`axon-code`** | Daily coding tasks | High intelligence, balanced performance | -| **`axon-code-2-preview`** | Complex agentic tasks | Maximum intelligence, long-running workflows | -| **`axon-mini`** | Quick tasks | Lightweight, low-effort operations | +| Model | Use Case | Capabilities | +| ----------------- | --------------------- | -------------------------------------------- | +| **`axon-code`** | Daily coding tasks | High intelligence, balanced performance | +| **`axon-code-2`** | Complex agentic tasks | Maximum intelligence, long-running workflows | +| **`axon-mini`** | Quick tasks | Lightweight, low-effort operations | ## 📦 Installation diff --git a/cli/src/config/__tests__/persistence-provider-merge.test.ts b/cli/src/config/__tests__/persistence-provider-merge.test.ts index bd9f993c3f..aed5e67e62 100644 --- a/cli/src/config/__tests__/persistence-provider-merge.test.ts +++ b/cli/src/config/__tests__/persistence-provider-merge.test.ts @@ -67,7 +67,7 @@ describe("Provider Merging", () => { id: "default", provider: "kilocode", kilocodeToken: "test-token-1234567890", - kilocodeModel: "axon-code", + kilocodeModel: "axon-code-2", }, ], theme: "dark", diff --git a/cli/src/config/defaults.ts b/cli/src/config/defaults.ts index 5ad9198892..fca8a3475d 100644 --- a/cli/src/config/defaults.ts +++ b/cli/src/config/defaults.ts @@ -55,7 +55,7 @@ export const DEFAULT_CONFIG = { id: "default", provider: "kilocode", kilocodeToken: "", - kilocodeModel: "axon-code", + kilocodeModel: "axon-code-2", }, ], autoApproval: DEFAULT_AUTO_APPROVAL, diff --git a/cli/src/constants/providers/settings.ts b/cli/src/constants/providers/settings.ts index 8745a4ff9f..31f25613bf 100644 --- a/cli/src/constants/providers/settings.ts +++ b/cli/src/constants/providers/settings.ts @@ -558,7 +558,7 @@ export const getProviderSettings = (provider: ProviderName, config: ProviderSett return [ createFieldConfig("kilocodeToken", config), createFieldConfig("kilocodeOrganizationId", config, "personal"), - createFieldConfig("kilocodeModel", config, "axon-code"), + createFieldConfig("kilocodeModel", config, "axon-code-2"), ] default: diff --git a/cli/src/utils/browserAuth.ts b/cli/src/utils/browserAuth.ts index 68fcdac606..d456ee1148 100644 --- a/cli/src/utils/browserAuth.ts +++ b/cli/src/utils/browserAuth.ts @@ -203,7 +203,7 @@ export async function performBrowserAuth(source: string = "axon-code-cli"): Prom id: "default", provider: "kilocode", kilocodeToken: token, - kilocodeModel: config.providers?.[0]?.kilocodeModel || "axon-code", + kilocodeModel: config.providers?.[0]?.kilocodeModel || "axon-code-2", ...config.providers?.[0], // Preserve other existing fields }, ], diff --git a/src/api/providers/kilocode-models.ts b/src/api/providers/kilocode-models.ts index 2dbca07741..5596c208ed 100644 --- a/src/api/providers/kilocode-models.ts +++ b/src/api/providers/kilocode-models.ts @@ -96,9 +96,9 @@ export const KILO_CODE_MODELS: Record = { input_cache_writes: "0", }, }, - "axon-code-2-preview": { - id: "axon-code-2-preview", - name: "Axon Code 2 (Preview)", + "axon-code-2": { + id: "axon-code-2", + name: "Axon Code 2", description: "Axon Code 2 is the next-generation of Axon Code for coding tasks, currently in experimental stage.", input_modalities: ["text"], diff --git a/src/core/kilocode/api/codeReviewService.ts b/src/core/kilocode/api/codeReviewService.ts index 0deeac3d67..3c16e4f3b0 100644 --- a/src/core/kilocode/api/codeReviewService.ts +++ b/src/core/kilocode/api/codeReviewService.ts @@ -79,7 +79,6 @@ export class CodeReviewService { let url: string if (this.enterpriseHost && this.enterpriseApiKey) { - console.log("this.enterpriseApiKey", this.enterpriseApiKey) // Use enterprise host and API key url = `${this.enterpriseHost.replace(/\/$/, "")}/codereview` headers["Authorization"] = `Bearer ${this.enterpriseApiKey}` diff --git a/src/package.json b/src/package.json index b0bd2fd032..b3df5047b4 100644 --- a/src/package.json +++ b/src/package.json @@ -3,7 +3,7 @@ "displayName": "%extension.displayName%", "description": "%extension.description%", "publisher": "matterai", - "version": "5.1.0", + "version": "5.2.0", "icon": "assets/icons/matterai-ic.png", "galleryBanner": { "color": "#FFFFFF", diff --git a/webview-ui/src/components/ui/hooks/useOpenRouterModelProviders.ts b/webview-ui/src/components/ui/hooks/useOpenRouterModelProviders.ts index c6b45b457f..384eefc75e 100644 --- a/webview-ui/src/components/ui/hooks/useOpenRouterModelProviders.ts +++ b/webview-ui/src/components/ui/hooks/useOpenRouterModelProviders.ts @@ -72,9 +72,9 @@ const KILO_CODE_MODELS: Record = { input_cache_writes: "0", }, }, - "axon-code-2-preview": { - id: "axon-code-2-preview", - name: "Axon Code 2 (Preview)", + "axon-code-2": { + id: "axon-code-2", + name: "Axon Code 2", description: "Axon Code 2 is the next-generation of Axon Code for coding tasks, currently in experimental stage.", input_modalities: ["text"], diff --git a/webview-ui/src/utils/prettyModelName.ts b/webview-ui/src/utils/prettyModelName.ts index a1b801ff33..be18a2db3d 100644 --- a/webview-ui/src/utils/prettyModelName.ts +++ b/webview-ui/src/utils/prettyModelName.ts @@ -1,10 +1,8 @@ // Hardcoded credits information for Axon models const AXON_MODEL_CREDITS: Record = { "axon-mini": "(0.5x)", - "axon-code": "(1x)", - "axon-code-2-preview": "(0.5x)", - // "gemini-3-flash-preview": "(1x)", - // "gemini-3-pro-preview": "(2x)", + "axon-code": "(0.8x)", + "axon-code-2": "(1x)", } export const prettyModelName = (modelId: string): string => { From a18a574546629db16ab9784b3bc496a5915db6a1 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Wed, 14 Jan 2026 17:36:52 +0530 Subject: [PATCH 2/5] fixes to default model --- apps/web-evals/src/lib/schemas.ts | 2 +- cli/docs/PROVIDER_CONFIGURATION.md | 2 +- cli/src/constants/providers/settings.ts | 2 +- packages/types/src/providers/openrouter.ts | 4 ++-- src/api/providers/openrouter.ts | 2 +- .../assistant-message/AssistantMessageParser.ts | 17 +++++++++++++++++ src/core/task/Task.ts | 9 +++++++++ 7 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apps/web-evals/src/lib/schemas.ts b/apps/web-evals/src/lib/schemas.ts index 987bbd3b57..f9679d523a 100644 --- a/apps/web-evals/src/lib/schemas.ts +++ b/apps/web-evals/src/lib/schemas.ts @@ -6,7 +6,7 @@ import { rooCodeSettingsSchema } from "@roo-code/types" * CreateRun */ -export const MODEL_DEFAULT = "axon-code" +export const MODEL_DEFAULT = "axon-code-2" export const CONCURRENCY_MIN = 1 export const CONCURRENCY_MAX = 25 diff --git a/cli/docs/PROVIDER_CONFIGURATION.md b/cli/docs/PROVIDER_CONFIGURATION.md index 73922ec0db..5cefe9d121 100644 --- a/cli/docs/PROVIDER_CONFIGURATION.md +++ b/cli/docs/PROVIDER_CONFIGURATION.md @@ -71,7 +71,7 @@ The official Axon Code provider for accessing Axon Code's managed AI services. **Required Fields**: - `kilocodeToken` (password): Your Axon Code authentication token -- `kilocodeModel` (text): The model to use (default: `axon-code`) +- `kilocodeModel` (text): The model to use (default: `axon-code-2`) **Optional Fields**: diff --git a/cli/src/constants/providers/settings.ts b/cli/src/constants/providers/settings.ts index 31f25613bf..63d6d499a0 100644 --- a/cli/src/constants/providers/settings.ts +++ b/cli/src/constants/providers/settings.ts @@ -570,7 +570,7 @@ export const getProviderSettings = (provider: ProviderName, config: ProviderSett * Provider-specific default models */ export const PROVIDER_DEFAULT_MODELS: Record = { - kilocode: "axon-code", + kilocode: "axon-code-2", anthropic: "claude-3-5-sonnet-20241022", "openai-native": "gpt-4o", openrouter: "anthropic/claude-3-5-sonnet", diff --git a/packages/types/src/providers/openrouter.ts b/packages/types/src/providers/openrouter.ts index 0114a33af8..fee7dc7fcf 100644 --- a/packages/types/src/providers/openrouter.ts +++ b/packages/types/src/providers/openrouter.ts @@ -1,7 +1,7 @@ import type { ModelInfo } from "../model.js" // https://openrouter.ai/models?order=newest&supported_parameters=tools -export const openRouterDefaultModelId = "axon-code" +export const openRouterDefaultModelId = "axon-code-2" export const openRouterDefaultModelInfo: ModelInfo = { maxTokens: 32000, @@ -13,7 +13,7 @@ export const openRouterDefaultModelInfo: ModelInfo = { outputPrice: 4.0, cacheWritesPrice: 0.0, cacheReadsPrice: 0.0, - description: "Axon Code is super intelligent LLM model for coding tasks", + description: "Axon Code 2 is the next-generation of Axon Code for coding tasks, currently in experimental stage.", } export const OPENROUTER_DEFAULT_PROVIDER_NAME = "[default]" diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts index d5448e040c..37e603537e 100644 --- a/src/api/providers/openrouter.ts +++ b/src/api/providers/openrouter.ts @@ -140,7 +140,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH super() this.options = options - const baseURL = this.options.openRouterBaseUrl || "https://api.matterai.so/v1/web" + const baseURL = this.options.openRouterBaseUrl || "https://api2.matterai.so/v1/web" const apiKey = this.options.openRouterApiKey ?? "not-provided" this.client = new OpenAI({ baseURL, apiKey, defaultHeaders: DEFAULT_HEADERS }) diff --git a/src/core/assistant-message/AssistantMessageParser.ts b/src/core/assistant-message/AssistantMessageParser.ts index 1160a1b45e..aebfb40a46 100644 --- a/src/core/assistant-message/AssistantMessageParser.ts +++ b/src/core/assistant-message/AssistantMessageParser.ts @@ -77,6 +77,15 @@ export class AssistantMessageParser { * currently set parallel_tool_calls to false, so in theory there should only be 1 call. */ public *processNativeToolCalls(toolCalls: NativeToolCall[]): Generator { + console.log( + `[AssistantMessageParser] Processing ${toolCalls.length} native tool call(s):`, + toolCalls.map((tc) => ({ + id: tc.id, + index: tc.index, + name: tc.function?.name, + argsLength: tc.function?.arguments?.length, + })), + ) for (const toolCall of toolCalls) { // Determine the tracking key // If we have an index, use that to look up or store the id @@ -177,11 +186,19 @@ export class AssistantMessageParser { } } catch (error) { // Arguments are not yet complete valid JSON, continue accumulating + // Log to help diagnose parsing issues + console.log( + `[AssistantMessageParser] JSON parsing incomplete/failed for tool "${accumulatedCall.function!.name}" (id: ${toolCallId}). Args length: ${accumulatedCall.function!.arguments.length}. Error:`, + error, + ) continue } // Tool call is complete - convert it to ToolUse format if (isComplete) { + console.log( + `[AssistantMessageParser] Successfully processed native tool call "${accumulatedCall.function!.name}" (id: ${toolCallId})`, + ) const toolName = accumulatedCall.function!.name // Finalize any current text content before adding tool use if (this.currentTextContent) { diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 5510565538..53ad39aac0 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2263,6 +2263,9 @@ export class Task extends EventEmitter implements TaskLike { case "native_tool_calls": { // Handle native OpenAI-format tool calls // Process native tool calls through the parser + console.log( + `[Task] Received native_tool_calls chunk with ${chunk.toolCalls.length} tool call(s)`, + ) let yieldedCount = 0 for (const toolUse of this.assistantMessageParser.processNativeToolCalls( chunk.toolCalls, @@ -2270,10 +2273,16 @@ export class Task extends EventEmitter implements TaskLike { assistantToolUses.push(toolUse) yieldedCount++ } + console.log( + `[Task] After processing: yielded ${yieldedCount} tool uses, contentBlocks before: ${this.assistantMessageContent.length}`, + ) // Update content blocks after processing native tool calls const prevLength = this.assistantMessageContent.length this.assistantMessageContent = this.assistantMessageParser.getContentBlocks() + console.log( + `[Task] contentBlocks after: ${this.assistantMessageContent.length}, prevLength: ${prevLength}`, + ) if (this.assistantMessageContent.length > prevLength) { // New content we need to present From 7545bbae3b5d02df8adbffb0c5fe5535b892c404 Mon Sep 17 00:00:00 2001 From: code-crusher Date: Wed, 14 Jan 2026 23:07:59 +0530 Subject: [PATCH 3/5] complete memories feature --- CHANGELOG.md | 11 + packages/types/src/tool.ts | 1 + packages/types/src/vscode.ts | 1 + src/activate/registerCommands.ts | 5 + src/assets/codicons/codicon.css | 573 ++++++++++++++++++ .../AssistantMessageParser.ts | 3 - .../presentAssistantMessage.ts | 4 + src/core/prompts/system.ts | 37 +- .../prompts/tools/check-past-chat-memories.ts | 34 ++ src/core/prompts/tools/index.ts | 3 + .../native-tools/check_past_chat_memories.ts | 26 + src/core/prompts/tools/native-tools/index.ts | 2 + src/core/task/Task.ts | 12 +- src/core/tools/attemptCompletionTool.ts | 44 +- src/core/tools/checkPastChatMemoriesTool.ts | 89 +++ src/core/webview/generateSystemPrompt.ts | 4 + src/core/webview/webviewMessageHandler.ts | 15 + src/package.json | 32 +- src/package.nls.json | 1 + src/services/chat-memory/MemoryManager.ts | 188 ++++++ src/services/chat-memory/index.ts | 2 + src/services/chat-memory/types.ts | 24 + src/shared/ExtensionMessage.ts | 8 +- src/shared/WebviewMessage.ts | 15 + src/shared/tools.ts | 11 +- webview-ui/src/App.tsx | 48 +- .../src/components/chat/ChatTextArea.tsx | 1 + .../src/components/history/HistoryView.tsx | 2 +- .../src/components/memories/MemoriesView.tsx | 166 +++++ webview-ui/src/components/memories/index.ts | 1 + webview-ui/src/i18n/locales/en/memories.json | 12 + 31 files changed, 1331 insertions(+), 44 deletions(-) create mode 100644 src/core/prompts/tools/check-past-chat-memories.ts create mode 100644 src/core/prompts/tools/native-tools/check_past_chat_memories.ts create mode 100644 src/core/tools/checkPastChatMemoriesTool.ts create mode 100644 src/services/chat-memory/MemoryManager.ts create mode 100644 src/services/chat-memory/index.ts create mode 100644 src/services/chat-memory/types.ts create mode 100644 webview-ui/src/components/memories/MemoriesView.tsx create mode 100644 webview-ui/src/components/memories/index.ts create mode 100644 webview-ui/src/i18n/locales/en/memories.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 30769eb18b..4139468c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [v5.2.0] - 2026-01-14 + +### Added + +- New Auto-Generated memories for past chats: Axon Code can now generate and reference memories in chats when building or updating codebase to ensure any previously used context can be quickly remembered. + +### Changed + +- Removed marketplace +- Minor fixes to stream tool calling in cases where tools got stuck + ## [v5.1.0] - 2026-01-12 ### Added diff --git a/packages/types/src/tool.ts b/packages/types/src/tool.ts index 80f1e3c58a..49c92f20b9 100644 --- a/packages/types/src/tool.ts +++ b/packages/types/src/tool.ts @@ -44,6 +44,7 @@ export const toolNames = [ "update_todo_list", "run_slash_command", "generate_image", + "check_past_chat_memories", ] as const export const toolNamesSchema = z.enum(toolNames) diff --git a/packages/types/src/vscode.ts b/packages/types/src/vscode.ts index ed92c46185..8161070f62 100644 --- a/packages/types/src/vscode.ts +++ b/packages/types/src/vscode.ts @@ -64,6 +64,7 @@ export const commandIds = [ "acceptInput", "profileButtonClicked", // kilocode_change "helpButtonClicked", // kilocode_change + "memoriesButtonClicked", // kilocode_change: Chat memories "focusChatInput", // kilocode_change "importSettings", // kilocode_change "exportSettings", // kilocode_change diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index 5c0a913c2c..6e74eb36e1 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -103,6 +103,11 @@ const getCommandsMap = ({ context, outputChannel }: RegisterCommandOptions): Rec // This ensures the focus happens after the view has switched await visibleProvider.postMessageToWebview({ type: "action", action: "focusInput" }) }, + memoriesButtonClicked: () => { + const visibleProvider = getVisibleProviderOrLog(outputChannel) + if (!visibleProvider) return + visibleProvider.postMessageToWebview({ type: "action", action: "memoriesButtonClicked" }) + }, mcpButtonClicked: () => { const visibleProvider = getVisibleProviderOrLog(outputChannel) diff --git a/src/assets/codicons/codicon.css b/src/assets/codicons/codicon.css index c0c150bce3..f98c79753c 100644 --- a/src/assets/codicons/codicon.css +++ b/src/assets/codicons/codicon.css @@ -60,1710 +60,2283 @@ .codicon-add:before { content: "\ea60"; } + .codicon-plus:before { content: "\ea60"; } + .codicon-gist-new:before { content: "\ea60"; } + .codicon-repo-create:before { content: "\ea60"; } + .codicon-lightbulb:before { content: "\ea61"; } + .codicon-light-bulb:before { content: "\ea61"; } + .codicon-repo:before { content: "\ea62"; } + .codicon-repo-delete:before { content: "\ea62"; } + .codicon-gist-fork:before { content: "\ea63"; } + .codicon-repo-forked:before { content: "\ea63"; } + .codicon-git-pull-request:before { content: "\ea64"; } + .codicon-git-pull-request-abandoned:before { content: "\ea64"; } + .codicon-record-keys:before { content: "\ea65"; } + .codicon-keyboard:before { content: "\ea65"; } + .codicon-tag:before { content: "\ea66"; } + .codicon-git-pull-request-label:before { content: "\ea66"; } + .codicon-tag-add:before { content: "\ea66"; } + .codicon-tag-remove:before { content: "\ea66"; } + .codicon-person:before { content: "\ea67"; } + .codicon-person-follow:before { content: "\ea67"; } + .codicon-person-outline:before { content: "\ea67"; } + .codicon-person-filled:before { content: "\ea67"; } + .codicon-git-branch:before { content: "\ea68"; } + .codicon-git-branch-create:before { content: "\ea68"; } + .codicon-git-branch-delete:before { content: "\ea68"; } + .codicon-source-control:before { content: "\ea68"; } + .codicon-mirror:before { content: "\ea69"; } + .codicon-mirror-public:before { content: "\ea69"; } + .codicon-star:before { content: "\ea6a"; } + .codicon-star-add:before { content: "\ea6a"; } + .codicon-star-delete:before { content: "\ea6a"; } + .codicon-star-empty:before { content: "\ea6a"; } + .codicon-comment:before { content: "\ea6b"; } + .codicon-comment-add:before { content: "\ea6b"; } + .codicon-alert:before { content: "\ea6c"; } + .codicon-warning:before { content: "\ea6c"; } + .codicon-search:before { content: "\ea6d"; } + .codicon-search-save:before { content: "\ea6d"; } + .codicon-log-out:before { content: "\ea6e"; } + .codicon-sign-out:before { content: "\ea6e"; } + .codicon-log-in:before { content: "\ea6f"; } + .codicon-sign-in:before { content: "\ea6f"; } + .codicon-eye:before { content: "\ea70"; } + .codicon-eye-unwatch:before { content: "\ea70"; } + .codicon-eye-watch:before { content: "\ea70"; } + .codicon-circle-filled:before { content: "\ea71"; } + .codicon-primitive-dot:before { content: "\ea71"; } + .codicon-close-dirty:before { content: "\ea71"; } + .codicon-debug-breakpoint:before { content: "\ea71"; } + .codicon-debug-breakpoint-disabled:before { content: "\ea71"; } + .codicon-debug-hint:before { content: "\ea71"; } + .codicon-terminal-decoration-success:before { content: "\ea71"; } + .codicon-primitive-square:before { content: "\ea72"; } + .codicon-edit:before { content: "\ea73"; } + .codicon-pencil:before { content: "\ea73"; } + .codicon-info:before { content: "\ea74"; } + .codicon-issue-opened:before { content: "\ea74"; } + .codicon-gist-private:before { content: "\ea75"; } + .codicon-git-fork-private:before { content: "\ea75"; } + .codicon-lock:before { content: "\ea75"; } + .codicon-mirror-private:before { content: "\ea75"; } + .codicon-close:before { content: "\ea76"; } + .codicon-remove-close:before { content: "\ea76"; } + .codicon-x:before { content: "\ea76"; } + .codicon-repo-sync:before { content: "\ea77"; } + .codicon-sync:before { content: "\ea77"; } + .codicon-clone:before { content: "\ea78"; } + .codicon-desktop-download:before { content: "\ea78"; } + .codicon-beaker:before { content: "\ea79"; } + .codicon-microscope:before { content: "\ea79"; } + .codicon-vm:before { content: "\ea7a"; } + .codicon-device-desktop:before { content: "\ea7a"; } + .codicon-file:before { content: "\ea7b"; } + .codicon-file-text:before { content: "\ea7b"; } + .codicon-more:before { content: "\ea7c"; } + .codicon-ellipsis:before { content: "\ea7c"; } + .codicon-kebab-horizontal:before { content: "\ea7c"; } + .codicon-mail-reply:before { content: "\ea7d"; } + .codicon-reply:before { content: "\ea7d"; } + .codicon-organization:before { content: "\ea7e"; } + .codicon-organization-filled:before { content: "\ea7e"; } + .codicon-organization-outline:before { content: "\ea7e"; } + .codicon-new-file:before { content: "\ea7f"; } + .codicon-file-add:before { content: "\ea7f"; } + .codicon-new-folder:before { content: "\ea80"; } + .codicon-file-directory-create:before { content: "\ea80"; } + .codicon-trash:before { content: "\ea81"; } + .codicon-trashcan:before { content: "\ea81"; } + .codicon-history:before { content: "\ea82"; } + .codicon-clock:before { content: "\ea82"; } + .codicon-folder:before { content: "\ea83"; } + .codicon-file-directory:before { content: "\ea83"; } + .codicon-symbol-folder:before { content: "\ea83"; } + .codicon-logo-github:before { content: "\ea84"; } + .codicon-mark-github:before { content: "\ea84"; } + .codicon-github:before { content: "\ea84"; } + .codicon-terminal:before { content: "\ea85"; } + .codicon-console:before { content: "\ea85"; } + .codicon-repl:before { content: "\ea85"; } + .codicon-zap:before { content: "\ea86"; } + .codicon-symbol-event:before { content: "\ea86"; } + .codicon-error:before { content: "\ea87"; } + .codicon-stop:before { content: "\ea87"; } + .codicon-variable:before { content: "\ea88"; } + .codicon-symbol-variable:before { content: "\ea88"; } + .codicon-array:before { content: "\ea8a"; } + .codicon-symbol-array:before { content: "\ea8a"; } + .codicon-symbol-module:before { content: "\ea8b"; } + .codicon-symbol-package:before { content: "\ea8b"; } + .codicon-symbol-namespace:before { content: "\ea8b"; } + .codicon-symbol-object:before { content: "\ea8b"; } + .codicon-symbol-method:before { content: "\ea8c"; } + .codicon-symbol-function:before { content: "\ea8c"; } + .codicon-symbol-constructor:before { content: "\ea8c"; } + .codicon-symbol-boolean:before { content: "\ea8f"; } + .codicon-symbol-null:before { content: "\ea8f"; } + .codicon-symbol-numeric:before { content: "\ea90"; } + .codicon-symbol-number:before { content: "\ea90"; } + .codicon-symbol-structure:before { content: "\ea91"; } + .codicon-symbol-struct:before { content: "\ea91"; } + .codicon-symbol-parameter:before { content: "\ea92"; } + .codicon-symbol-type-parameter:before { content: "\ea92"; } + .codicon-symbol-key:before { content: "\ea93"; } + .codicon-symbol-text:before { content: "\ea93"; } + .codicon-symbol-reference:before { content: "\ea94"; } + .codicon-go-to-file:before { content: "\ea94"; } + .codicon-symbol-enum:before { content: "\ea95"; } + .codicon-symbol-value:before { content: "\ea95"; } + .codicon-symbol-ruler:before { content: "\ea96"; } + .codicon-symbol-unit:before { content: "\ea96"; } + .codicon-activate-breakpoints:before { content: "\ea97"; } + .codicon-archive:before { content: "\ea98"; } + .codicon-arrow-both:before { content: "\ea99"; } + .codicon-arrow-down:before { content: "\ea9a"; } + .codicon-arrow-left:before { content: "\ea9b"; } + .codicon-arrow-right:before { content: "\ea9c"; } + .codicon-arrow-small-down:before { content: "\ea9d"; } + .codicon-arrow-small-left:before { content: "\ea9e"; } + .codicon-arrow-small-right:before { content: "\ea9f"; } + .codicon-arrow-small-up:before { content: "\eaa0"; } + .codicon-arrow-up:before { content: "\eaa1"; } + .codicon-bell:before { content: "\eaa2"; } + .codicon-bold:before { content: "\eaa3"; } + .codicon-book:before { content: "\eaa4"; } + .codicon-bookmark:before { content: "\eaa5"; } + .codicon-debug-breakpoint-conditional-unverified:before { content: "\eaa6"; } + .codicon-debug-breakpoint-conditional:before { content: "\eaa7"; } + .codicon-debug-breakpoint-conditional-disabled:before { content: "\eaa7"; } + .codicon-debug-breakpoint-data-unverified:before { content: "\eaa8"; } + .codicon-debug-breakpoint-data:before { content: "\eaa9"; } + .codicon-debug-breakpoint-data-disabled:before { content: "\eaa9"; } + .codicon-debug-breakpoint-log-unverified:before { content: "\eaaa"; } + .codicon-debug-breakpoint-log:before { content: "\eaab"; } + .codicon-debug-breakpoint-log-disabled:before { content: "\eaab"; } + .codicon-briefcase:before { content: "\eaac"; } + .codicon-broadcast:before { content: "\eaad"; } + .codicon-browser:before { content: "\eaae"; } + .codicon-bug:before { content: "\eaaf"; } + .codicon-calendar:before { content: "\eab0"; } + .codicon-case-sensitive:before { content: "\eab1"; } + .codicon-check:before { content: "\eab2"; } + .codicon-checklist:before { content: "\eab3"; } + .codicon-chevron-down:before { content: "\eab4"; } + .codicon-chevron-left:before { content: "\eab5"; } + .codicon-chevron-right:before { content: "\eab6"; } + .codicon-chevron-up:before { content: "\eab7"; } + .codicon-chrome-close:before { content: "\eab8"; } + .codicon-chrome-maximize:before { content: "\eab9"; } + .codicon-chrome-minimize:before { content: "\eaba"; } + .codicon-chrome-restore:before { content: "\eabb"; } + .codicon-circle-outline:before { content: "\eabc"; } + .codicon-circle:before { content: "\eabc"; } + .codicon-debug-breakpoint-unverified:before { content: "\eabc"; } + .codicon-terminal-decoration-incomplete:before { content: "\eabc"; } + .codicon-circle-slash:before { content: "\eabd"; } + .codicon-circuit-board:before { content: "\eabe"; } + .codicon-clear-all:before { content: "\eabf"; } + .codicon-clippy:before { content: "\eac0"; } + .codicon-close-all:before { content: "\eac1"; } + .codicon-cloud-download:before { content: "\eac2"; } + .codicon-cloud-upload:before { content: "\eac3"; } + .codicon-code:before { content: "\eac4"; } + .codicon-collapse-all:before { content: "\eac5"; } + .codicon-color-mode:before { content: "\eac6"; } + .codicon-comment-discussion:before { content: "\eac7"; } + .codicon-credit-card:before { content: "\eac9"; } + .codicon-dash:before { content: "\eacc"; } + .codicon-dashboard:before { content: "\eacd"; } + .codicon-database:before { content: "\eace"; } + .codicon-debug-continue:before { content: "\eacf"; } + .codicon-debug-disconnect:before { content: "\ead0"; } + .codicon-debug-pause:before { content: "\ead1"; } + .codicon-debug-restart:before { content: "\ead2"; } + .codicon-debug-start:before { content: "\ead3"; } + .codicon-debug-step-into:before { content: "\ead4"; } + .codicon-debug-step-out:before { content: "\ead5"; } + .codicon-debug-step-over:before { content: "\ead6"; } + .codicon-debug-stop:before { content: "\ead7"; } + .codicon-debug:before { content: "\ead8"; } + .codicon-device-camera-video:before { content: "\ead9"; } + .codicon-device-camera:before { content: "\eada"; } + .codicon-device-mobile:before { content: "\eadb"; } + .codicon-diff-added:before { content: "\eadc"; } + .codicon-diff-ignored:before { content: "\eadd"; } + .codicon-diff-modified:before { content: "\eade"; } + .codicon-diff-removed:before { content: "\eadf"; } + .codicon-diff-renamed:before { content: "\eae0"; } + .codicon-diff:before { content: "\eae1"; } + .codicon-diff-sidebyside:before { content: "\eae1"; } + .codicon-discard:before { content: "\eae2"; } + .codicon-editor-layout:before { content: "\eae3"; } + .codicon-empty-window:before { content: "\eae4"; } + .codicon-exclude:before { content: "\eae5"; } + .codicon-extensions:before { content: "\eae6"; } + +.codicon-brain:before { + content: "\eae6"; +} + .codicon-eye-closed:before { content: "\eae7"; } + .codicon-file-binary:before { content: "\eae8"; } + .codicon-file-code:before { content: "\eae9"; } + .codicon-file-media:before { content: "\eaea"; } + .codicon-file-pdf:before { content: "\eaeb"; } + .codicon-file-submodule:before { content: "\eaec"; } + .codicon-file-symlink-directory:before { content: "\eaed"; } + .codicon-file-symlink-file:before { content: "\eaee"; } + .codicon-file-zip:before { content: "\eaef"; } + .codicon-files:before { content: "\eaf0"; } + .codicon-filter:before { content: "\eaf1"; } + .codicon-flame:before { content: "\eaf2"; } + .codicon-fold-down:before { content: "\eaf3"; } + .codicon-fold-up:before { content: "\eaf4"; } + .codicon-fold:before { content: "\eaf5"; } + .codicon-folder-active:before { content: "\eaf6"; } + .codicon-folder-opened:before { content: "\eaf7"; } + .codicon-gear:before { content: "\eaf8"; } + .codicon-gift:before { content: "\eaf9"; } + .codicon-gist-secret:before { content: "\eafa"; } + .codicon-gist:before { content: "\eafb"; } + .codicon-git-commit:before { content: "\eafc"; } + .codicon-git-compare:before { content: "\eafd"; } + .codicon-compare-changes:before { content: "\eafd"; } + .codicon-git-merge:before { content: "\eafe"; } + .codicon-github-action:before { content: "\eaff"; } + .codicon-github-alt:before { content: "\eb00"; } + .codicon-globe:before { content: "\eb01"; } + .codicon-grabber:before { content: "\eb02"; } + .codicon-graph:before { content: "\eb03"; } + .codicon-gripper:before { content: "\eb04"; } + .codicon-heart:before { content: "\eb05"; } + .codicon-home:before { content: "\eb06"; } + .codicon-horizontal-rule:before { content: "\eb07"; } + .codicon-hubot:before { content: "\eb08"; } + .codicon-inbox:before { content: "\eb09"; } + .codicon-issue-reopened:before { content: "\eb0b"; } + .codicon-issues:before { content: "\eb0c"; } + .codicon-italic:before { content: "\eb0d"; } + .codicon-jersey:before { content: "\eb0e"; } + .codicon-json:before { content: "\eb0f"; } + .codicon-kebab-vertical:before { content: "\eb10"; } + .codicon-key:before { content: "\eb11"; } + .codicon-law:before { content: "\eb12"; } + .codicon-lightbulb-autofix:before { content: "\eb13"; } + .codicon-link-external:before { content: "\eb14"; } + .codicon-link:before { content: "\eb15"; } + .codicon-list-ordered:before { content: "\eb16"; } + .codicon-list-unordered:before { content: "\eb17"; } + .codicon-live-share:before { content: "\eb18"; } + .codicon-loading:before { content: "\eb19"; } + .codicon-location:before { content: "\eb1a"; } + .codicon-mail-read:before { content: "\eb1b"; } + .codicon-mail:before { content: "\eb1c"; } + .codicon-markdown:before { content: "\eb1d"; } + .codicon-megaphone:before { content: "\eb1e"; } + .codicon-mention:before { content: "\eb1f"; } + .codicon-milestone:before { content: "\eb20"; } + .codicon-git-pull-request-milestone:before { content: "\eb20"; } + .codicon-mortar-board:before { content: "\eb21"; } + .codicon-move:before { content: "\eb22"; } + .codicon-multiple-windows:before { content: "\eb23"; } + .codicon-mute:before { content: "\eb24"; } + .codicon-no-newline:before { content: "\eb25"; } + .codicon-note:before { content: "\eb26"; } + .codicon-octoface:before { content: "\eb27"; } + .codicon-open-preview:before { content: "\eb28"; } + .codicon-package:before { content: "\eb29"; } + .codicon-paintcan:before { content: "\eb2a"; } + .codicon-pin:before { content: "\eb2b"; } + .codicon-play:before { content: "\eb2c"; } + .codicon-run:before { content: "\eb2c"; } + .codicon-plug:before { content: "\eb2d"; } + .codicon-preserve-case:before { content: "\eb2e"; } + .codicon-preview:before { content: "\eb2f"; } + .codicon-project:before { content: "\eb30"; } + .codicon-pulse:before { content: "\eb31"; } + .codicon-question:before { content: "\eb32"; } + .codicon-quote:before { content: "\eb33"; } + .codicon-radio-tower:before { content: "\eb34"; } + .codicon-reactions:before { content: "\eb35"; } + .codicon-references:before { content: "\eb36"; } + .codicon-refresh:before { content: "\eb37"; } + .codicon-regex:before { content: "\eb38"; } + .codicon-remote-explorer:before { content: "\eb39"; } + .codicon-remote:before { content: "\eb3a"; } + .codicon-remove:before { content: "\eb3b"; } + .codicon-replace-all:before { content: "\eb3c"; } + .codicon-replace:before { content: "\eb3d"; } + .codicon-repo-clone:before { content: "\eb3e"; } + .codicon-repo-force-push:before { content: "\eb3f"; } + .codicon-repo-pull:before { content: "\eb40"; } + .codicon-repo-push:before { content: "\eb41"; } + .codicon-report:before { content: "\eb42"; } + .codicon-request-changes:before { content: "\eb43"; } + .codicon-rocket:before { content: "\eb44"; } + .codicon-root-folder-opened:before { content: "\eb45"; } + .codicon-root-folder:before { content: "\eb46"; } + .codicon-rss:before { content: "\eb47"; } + .codicon-ruby:before { content: "\eb48"; } + .codicon-save-all:before { content: "\eb49"; } + .codicon-save-as:before { content: "\eb4a"; } + .codicon-save:before { content: "\eb4b"; } + .codicon-screen-full:before { content: "\eb4c"; } + .codicon-screen-normal:before { content: "\eb4d"; } + .codicon-search-stop:before { content: "\eb4e"; } + .codicon-server:before { content: "\eb50"; } + .codicon-settings-gear:before { content: "\eb51"; } + .codicon-settings:before { content: "\eb52"; } + .codicon-shield:before { content: "\eb53"; } + .codicon-smiley:before { content: "\eb54"; } + .codicon-sort-precedence:before { content: "\eb55"; } + .codicon-split-horizontal:before { content: "\eb56"; } + .codicon-split-vertical:before { content: "\eb57"; } + .codicon-squirrel:before { content: "\eb58"; } + .codicon-star-full:before { content: "\eb59"; } + .codicon-star-half:before { content: "\eb5a"; } + .codicon-symbol-class:before { content: "\eb5b"; } + .codicon-symbol-color:before { content: "\eb5c"; } + .codicon-symbol-constant:before { content: "\eb5d"; } + .codicon-symbol-enum-member:before { content: "\eb5e"; } + .codicon-symbol-field:before { content: "\eb5f"; } + .codicon-symbol-file:before { content: "\eb60"; } + .codicon-symbol-interface:before { content: "\eb61"; } + .codicon-symbol-keyword:before { content: "\eb62"; } + .codicon-symbol-misc:before { content: "\eb63"; } + .codicon-symbol-operator:before { content: "\eb64"; } + .codicon-symbol-property:before { content: "\eb65"; } + .codicon-wrench:before { content: "\eb65"; } + .codicon-wrench-subaction:before { content: "\eb65"; } + .codicon-symbol-snippet:before { content: "\eb66"; } + .codicon-tasklist:before { content: "\eb67"; } + .codicon-telescope:before { content: "\eb68"; } + .codicon-text-size:before { content: "\eb69"; } + .codicon-three-bars:before { content: "\eb6a"; } + .codicon-thumbsdown:before { content: "\eb6b"; } + .codicon-thumbsup:before { content: "\eb6c"; } + .codicon-tools:before { content: "\eb6d"; } + .codicon-triangle-down:before { content: "\eb6e"; } + .codicon-triangle-left:before { content: "\eb6f"; } + .codicon-triangle-right:before { content: "\eb70"; } + .codicon-triangle-up:before { content: "\eb71"; } + .codicon-twitter:before { content: "\eb72"; } + .codicon-unfold:before { content: "\eb73"; } + .codicon-unlock:before { content: "\eb74"; } + .codicon-unmute:before { content: "\eb75"; } + .codicon-unverified:before { content: "\eb76"; } + .codicon-verified:before { content: "\eb77"; } + .codicon-versions:before { content: "\eb78"; } + .codicon-vm-active:before { content: "\eb79"; } + .codicon-vm-outline:before { content: "\eb7a"; } + .codicon-vm-running:before { content: "\eb7b"; } + .codicon-watch:before { content: "\eb7c"; } + .codicon-whitespace:before { content: "\eb7d"; } + .codicon-whole-word:before { content: "\eb7e"; } + .codicon-window:before { content: "\eb7f"; } + .codicon-word-wrap:before { content: "\eb80"; } + .codicon-zoom-in:before { content: "\eb81"; } + .codicon-zoom-out:before { content: "\eb82"; } + .codicon-list-filter:before { content: "\eb83"; } + .codicon-list-flat:before { content: "\eb84"; } + .codicon-list-selection:before { content: "\eb85"; } + .codicon-selection:before { content: "\eb85"; } + .codicon-list-tree:before { content: "\eb86"; } + .codicon-debug-breakpoint-function-unverified:before { content: "\eb87"; } + .codicon-debug-breakpoint-function:before { content: "\eb88"; } + .codicon-debug-breakpoint-function-disabled:before { content: "\eb88"; } + .codicon-debug-stackframe-active:before { content: "\eb89"; } + .codicon-circle-small-filled:before { content: "\eb8a"; } + .codicon-debug-stackframe-dot:before { content: "\eb8a"; } + .codicon-terminal-decoration-mark:before { content: "\eb8a"; } + .codicon-debug-stackframe:before { content: "\eb8b"; } + .codicon-debug-stackframe-focused:before { content: "\eb8b"; } + .codicon-debug-breakpoint-unsupported:before { content: "\eb8c"; } + .codicon-symbol-string:before { content: "\eb8d"; } + .codicon-debug-reverse-continue:before { content: "\eb8e"; } + .codicon-debug-step-back:before { content: "\eb8f"; } + .codicon-debug-restart-frame:before { content: "\eb90"; } + .codicon-debug-alt:before { content: "\eb91"; } + .codicon-call-incoming:before { content: "\eb92"; } + .codicon-call-outgoing:before { content: "\eb93"; } + .codicon-menu:before { content: "\eb94"; } + .codicon-expand-all:before { content: "\eb95"; } + .codicon-feedback:before { content: "\eb96"; } + .codicon-git-pull-request-reviewer:before { content: "\eb96"; } + .codicon-group-by-ref-type:before { content: "\eb97"; } + .codicon-ungroup-by-ref-type:before { content: "\eb98"; } + .codicon-account:before { content: "\eb99"; } + .codicon-git-pull-request-assignee:before { content: "\eb99"; } + .codicon-bell-dot:before { content: "\eb9a"; } + .codicon-debug-console:before { content: "\eb9b"; } + .codicon-library:before { content: "\eb9c"; } + .codicon-output:before { content: "\eb9d"; } + .codicon-run-all:before { content: "\eb9e"; } + .codicon-sync-ignored:before { content: "\eb9f"; } + .codicon-pinned:before { content: "\eba0"; } + .codicon-github-inverted:before { content: "\eba1"; } + .codicon-server-process:before { content: "\eba2"; } + .codicon-server-environment:before { content: "\eba3"; } + .codicon-pass:before { content: "\eba4"; } + .codicon-issue-closed:before { content: "\eba4"; } + .codicon-stop-circle:before { content: "\eba5"; } + .codicon-play-circle:before { content: "\eba6"; } + .codicon-record:before { content: "\eba7"; } + .codicon-debug-alt-small:before { content: "\eba8"; } + .codicon-vm-connect:before { content: "\eba9"; } + .codicon-cloud:before { content: "\ebaa"; } + .codicon-merge:before { content: "\ebab"; } + .codicon-export:before { content: "\ebac"; } + .codicon-graph-left:before { content: "\ebad"; } + .codicon-magnet:before { content: "\ebae"; } + .codicon-notebook:before { content: "\ebaf"; } + .codicon-redo:before { content: "\ebb0"; } + .codicon-check-all:before { content: "\ebb1"; } + .codicon-pinned-dirty:before { content: "\ebb2"; } + .codicon-pass-filled:before { content: "\ebb3"; } + .codicon-circle-large-filled:before { content: "\ebb4"; } + .codicon-circle-large:before { content: "\ebb5"; } + .codicon-circle-large-outline:before { content: "\ebb5"; } + .codicon-combine:before { content: "\ebb6"; } + .codicon-gather:before { content: "\ebb6"; } + .codicon-table:before { content: "\ebb7"; } + .codicon-variable-group:before { content: "\ebb8"; } + .codicon-type-hierarchy:before { content: "\ebb9"; } + .codicon-type-hierarchy-sub:before { content: "\ebba"; } + .codicon-type-hierarchy-super:before { content: "\ebbb"; } + .codicon-git-pull-request-create:before { content: "\ebbc"; } + .codicon-run-above:before { content: "\ebbd"; } + .codicon-run-below:before { content: "\ebbe"; } + .codicon-notebook-template:before { content: "\ebbf"; } + .codicon-debug-rerun:before { content: "\ebc0"; } + .codicon-workspace-trusted:before { content: "\ebc1"; } + .codicon-workspace-untrusted:before { content: "\ebc2"; } + .codicon-workspace-unknown:before { content: "\ebc3"; } + .codicon-terminal-cmd:before { content: "\ebc4"; } + .codicon-terminal-debian:before { content: "\ebc5"; } + .codicon-terminal-linux:before { content: "\ebc6"; } + .codicon-terminal-powershell:before { content: "\ebc7"; } + .codicon-terminal-tmux:before { content: "\ebc8"; } + .codicon-terminal-ubuntu:before { content: "\ebc9"; } + .codicon-terminal-bash:before { content: "\ebca"; } + .codicon-arrow-swap:before { content: "\ebcb"; } + .codicon-copy:before { content: "\ebcc"; } + .codicon-person-add:before { content: "\ebcd"; } + .codicon-filter-filled:before { content: "\ebce"; } + .codicon-wand:before { content: "\ebcf"; } + .codicon-debug-line-by-line:before { content: "\ebd0"; } + .codicon-inspect:before { content: "\ebd1"; } + .codicon-layers:before { content: "\ebd2"; } + .codicon-layers-dot:before { content: "\ebd3"; } + .codicon-layers-active:before { content: "\ebd4"; } + .codicon-compass:before { content: "\ebd5"; } + .codicon-compass-dot:before { content: "\ebd6"; } + .codicon-compass-active:before { content: "\ebd7"; } + .codicon-azure:before { content: "\ebd8"; } + .codicon-issue-draft:before { content: "\ebd9"; } + .codicon-git-pull-request-closed:before { content: "\ebda"; } + .codicon-git-pull-request-draft:before { content: "\ebdb"; } + .codicon-debug-all:before { content: "\ebdc"; } + .codicon-debug-coverage:before { content: "\ebdd"; } + .codicon-run-errors:before { content: "\ebde"; } + .codicon-folder-library:before { content: "\ebdf"; } + .codicon-debug-continue-small:before { content: "\ebe0"; } + .codicon-beaker-stop:before { content: "\ebe1"; } + .codicon-graph-line:before { content: "\ebe2"; } + .codicon-graph-scatter:before { content: "\ebe3"; } + .codicon-pie-chart:before { content: "\ebe4"; } + .codicon-bracket:before { content: "\eb0f"; } + .codicon-bracket-dot:before { content: "\ebe5"; } + .codicon-bracket-error:before { content: "\ebe6"; } + .codicon-lock-small:before { content: "\ebe7"; } + .codicon-azure-devops:before { content: "\ebe8"; } + .codicon-verified-filled:before { content: "\ebe9"; } + .codicon-newline:before { content: "\ebea"; } + .codicon-layout:before { content: "\ebeb"; } + .codicon-layout-activitybar-left:before { content: "\ebec"; } + .codicon-layout-activitybar-right:before { content: "\ebed"; } + .codicon-layout-panel-left:before { content: "\ebee"; } + .codicon-layout-panel-center:before { content: "\ebef"; } + .codicon-layout-panel-justify:before { content: "\ebf0"; } + .codicon-layout-panel-right:before { content: "\ebf1"; } + .codicon-layout-panel:before { content: "\ebf2"; } + .codicon-layout-sidebar-left:before { content: "\ebf3"; } + .codicon-layout-sidebar-right:before { content: "\ebf4"; } + .codicon-layout-statusbar:before { content: "\ebf5"; } + .codicon-layout-menubar:before { content: "\ebf6"; } + .codicon-layout-centered:before { content: "\ebf7"; } + .codicon-target:before { content: "\ebf8"; } + .codicon-indent:before { content: "\ebf9"; } + .codicon-record-small:before { content: "\ebfa"; } + .codicon-error-small:before { content: "\ebfb"; } + .codicon-terminal-decoration-error:before { content: "\ebfb"; } + .codicon-arrow-circle-down:before { content: "\ebfc"; } + .codicon-arrow-circle-left:before { content: "\ebfd"; } + .codicon-arrow-circle-right:before { content: "\ebfe"; } + .codicon-arrow-circle-up:before { content: "\ebff"; } + .codicon-layout-sidebar-right-off:before { content: "\ec00"; } + .codicon-layout-panel-off:before { content: "\ec01"; } + .codicon-layout-sidebar-left-off:before { content: "\ec02"; } + .codicon-blank:before { content: "\ec03"; } + .codicon-heart-filled:before { content: "\ec04"; } + .codicon-map:before { content: "\ec05"; } + .codicon-map-horizontal:before { content: "\ec05"; } + .codicon-fold-horizontal:before { content: "\ec05"; } + .codicon-map-filled:before { content: "\ec06"; } + .codicon-map-horizontal-filled:before { content: "\ec06"; } + .codicon-fold-horizontal-filled:before { content: "\ec06"; } + .codicon-circle-small:before { content: "\ec07"; } + .codicon-bell-slash:before { content: "\ec08"; } + .codicon-bell-slash-dot:before { content: "\ec09"; } + .codicon-comment-unresolved:before { content: "\ec0a"; } + .codicon-git-pull-request-go-to-changes:before { content: "\ec0b"; } + .codicon-git-pull-request-new-changes:before { content: "\ec0c"; } + .codicon-search-fuzzy:before { content: "\ec0d"; } + .codicon-comment-draft:before { content: "\ec0e"; } + .codicon-send:before { content: "\ec0f"; } + .codicon-sparkle:before { content: "\ec10"; } + .codicon-insert:before { content: "\ec11"; } + .codicon-mic:before { content: "\ec12"; } + .codicon-thumbsdown-filled:before { content: "\ec13"; } + .codicon-thumbsup-filled:before { content: "\ec14"; } + .codicon-coffee:before { content: "\ec15"; } + .codicon-snake:before { content: "\ec16"; } + .codicon-game:before { content: "\ec17"; } + .codicon-vr:before { content: "\ec18"; } + .codicon-chip:before { content: "\ec19"; } + .codicon-piano:before { content: "\ec1a"; } + .codicon-music:before { content: "\ec1b"; } + .codicon-mic-filled:before { content: "\ec1c"; } + .codicon-repo-fetch:before { content: "\ec1d"; } + .codicon-copilot:before { content: "\ec1e"; } + .codicon-lightbulb-sparkle:before { content: "\ec1f"; } + .codicon-robot:before { content: "\ec20"; } + .codicon-sparkle-filled:before { content: "\ec21"; } + .codicon-diff-single:before { content: "\ec22"; } + .codicon-diff-multiple:before { content: "\ec23"; } + .codicon-surround-with:before { content: "\ec24"; } + .codicon-share:before { content: "\ec25"; } + .codicon-git-stash:before { content: "\ec26"; } + .codicon-git-stash-apply:before { content: "\ec27"; } + .codicon-git-stash-pop:before { content: "\ec28"; } + .codicon-vscode:before { content: "\ec29"; } + .codicon-vscode-insiders:before { content: "\ec2a"; } + .codicon-code-oss:before { content: "\ec2b"; } + .codicon-run-coverage:before { content: "\ec2c"; } + .codicon-run-all-coverage:before { content: "\ec2d"; } + .codicon-coverage:before { content: "\ec2e"; } + .codicon-github-project:before { content: "\ec2f"; } + .codicon-map-vertical:before { content: "\ec30"; } + .codicon-fold-vertical:before { content: "\ec30"; } + .codicon-map-vertical-filled:before { content: "\ec31"; } + .codicon-fold-vertical-filled:before { content: "\ec31"; } + .codicon-go-to-search:before { content: "\ec32"; } + .codicon-percentage:before { content: "\ec33"; } + .codicon-sort-percentage:before { content: "\ec33"; } + .codicon-git-fetch:before { content: "\f101"; } diff --git a/src/core/assistant-message/AssistantMessageParser.ts b/src/core/assistant-message/AssistantMessageParser.ts index aebfb40a46..6f8fa438c8 100644 --- a/src/core/assistant-message/AssistantMessageParser.ts +++ b/src/core/assistant-message/AssistantMessageParser.ts @@ -196,9 +196,6 @@ export class AssistantMessageParser { // Tool call is complete - convert it to ToolUse format if (isComplete) { - console.log( - `[AssistantMessageParser] Successfully processed native tool call "${accumulatedCall.function!.name}" (id: ${toolCallId})`, - ) const toolName = accumulatedCall.function!.name // Finalize any current text content before adding tool use if (this.currentTextContent) { diff --git a/src/core/assistant-message/presentAssistantMessage.ts b/src/core/assistant-message/presentAssistantMessage.ts index 334702748c..3851ff333e 100644 --- a/src/core/assistant-message/presentAssistantMessage.ts +++ b/src/core/assistant-message/presentAssistantMessage.ts @@ -251,6 +251,10 @@ export async function presentAssistantMessage(cline: Task) { return `[${block.name} for '${block.params.path}']` case "plan_file_edit": return `[${block.name} for '${block.params.filename}']` + case "check_past_chat_memories": + return `[${block.name} for '${block.params.regex}']` + default: + return `[${block.name}]` } } diff --git a/src/core/prompts/system.ts b/src/core/prompts/system.ts index 83460cd976..2938280320 100644 --- a/src/core/prompts/system.ts +++ b/src/core/prompts/system.ts @@ -1,7 +1,14 @@ import * as os from "os" import * as vscode from "vscode" -import type { CustomModePrompts, Experiments, ModeConfig, PromptComponent, TodoItem } from "@roo-code/types" +import type { + CustomModePrompts, + Experiments, + ModeConfig, + PromptComponent, + TodoItem, + HistoryItem, +} from "@roo-code/types" import type { SystemPromptSettings } from "./types" @@ -32,6 +39,27 @@ export function getPromptComponent( return component } +/** + * Get previous chat titles section for system prompt + */ +function getPreviousChatTitlesSection(history?: HistoryItem[]): string { + if (!history || history.length === 0) { + return "" + } + + // Get titles from history, filter out empty ones, and take last 20 + const titles = history + .filter((item) => item.title && item.title.trim() !== "") + .map((item) => item.title) + .slice(-20) + + if (titles.length === 0) { + return "" + } + + return `Previous Chat Titles: ${titles.join(", ")}` +} + const applyDiffToolDescription = ` Common tool calls and explanations @@ -416,6 +444,7 @@ async function generatePrompt( modelId?: string, toolUseStyle?: ToolUseStyle, // kilocode_change clineProviderState?: ClineProviderState, // kilocode_change + taskHistory?: HistoryItem[], // kilocode_change: Chat memories ): Promise { if (!context) { throw new Error("Extension context is required for generating system prompt") @@ -442,6 +471,8 @@ async function generatePrompt( const codeIndexManager = CodeIndexManager.getInstance(context, cwd) + const previousChatTitlesSection = getPreviousChatTitlesSection(taskHistory) + const basePrompt = `${roleDefinition} ${ @@ -469,6 +500,8 @@ ${applyDiffToolDescription} ${mcpServersSection} +${previousChatTitlesSection} + ${getSystemInfoSection(cwd)} ` @@ -497,6 +530,7 @@ export const SYSTEM_PROMPT = async ( modelId?: string, toolUseStyle?: ToolUseStyle, // kilocode_change clineProviderState?: ClineProviderState, // kilocode_change + taskHistory?: HistoryItem[], // kilocode_change: Chat memories ): Promise => { if (!context) { throw new Error("Extension context is required for generating system prompt") @@ -574,5 +608,6 @@ ${customInstructions}` modelId, toolUseStyle, // kilocode_change clineProviderState, // kilocode_change + taskHistory, // kilocode_change: Chat memories ) } diff --git a/src/core/prompts/tools/check-past-chat-memories.ts b/src/core/prompts/tools/check-past-chat-memories.ts new file mode 100644 index 0000000000..ee2a1fa70e --- /dev/null +++ b/src/core/prompts/tools/check-past-chat-memories.ts @@ -0,0 +1,34 @@ +import { ToolArgs } from "./types" + +export function getCheckPastChatMemoriesDescription(args: ToolArgs): string { + return `## check_past_chat_memories +Description: Search through previous chat completion results to find relevant context from past tasks. Use this when you need to recall what was implemented or fixed in previous chats. This tool performs a regex search across stored memories from completed tasks. + +Parameters: +- regex: (required) Regular expression pattern to search memory contents. Uses JavaScript regex syntax. +- workspace: (optional) Filter by workspace directory. If not provided, defaults to current workspace (${args.cwd}). + +Usage: + +Your regex pattern here +workspace path (optional) + + +Example: Searching for memories about authentication + +authentication|auth|login|token + + +Example: Searching for memories about a specific feature + +user.*profile|profile.*update + + +The tool returns matching memories with: +- Task title or ID +- Date of completion +- Mode used +- Content of the completion result + +Use this tool when you encounter a task that seems related to previous work, or when you need to understand what has been implemented before.` +} diff --git a/src/core/prompts/tools/index.ts b/src/core/prompts/tools/index.ts index f68d9609e8..9cc0ec8bc8 100644 --- a/src/core/prompts/tools/index.ts +++ b/src/core/prompts/tools/index.ts @@ -32,6 +32,7 @@ import { getCodebaseSearchDescription } from "./codebase-search" import { getUpdateTodoListDescription } from "./update-todo-list" import { getRunSlashCommandDescription } from "./run-slash-command" import { getGenerateImageDescription } from "./generate-image" +import { getCheckPastChatMemoriesDescription } from "./check-past-chat-memories" import { CodeIndexManager } from "../../../services/code-index/manager" // kilocode_change start: Morph fast apply @@ -73,6 +74,7 @@ const toolDescriptionMap: Record string | undefined> update_todo_list: (args) => getUpdateTodoListDescription(args), run_slash_command: () => getRunSlashCommandDescription(), generate_image: (args) => getGenerateImageDescription(args), + check_past_chat_memories: (args) => getCheckPastChatMemoriesDescription(args), } export function getToolDescriptionsForMode( @@ -212,4 +214,5 @@ export { getCodebaseSearchDescription, getRunSlashCommandDescription, getGenerateImageDescription, + getCheckPastChatMemoriesDescription, } diff --git a/src/core/prompts/tools/native-tools/check_past_chat_memories.ts b/src/core/prompts/tools/native-tools/check_past_chat_memories.ts new file mode 100644 index 0000000000..6b17d8a65b --- /dev/null +++ b/src/core/prompts/tools/native-tools/check_past_chat_memories.ts @@ -0,0 +1,26 @@ +import type OpenAI from "openai" + +export default { + type: "function", + function: { + name: "check_past_chat_memories", + description: + "Search through previous chat completion results to find relevant context from past tasks. Use this when you need to recall what was implemented or fixed in previous chats.", + strict: true, + parameters: { + type: "object", + properties: { + regex: { + type: "string", + description: "Regular expression pattern to search memory contents", + }, + workspace: { + type: "string", + description: "Filter by workspace directory (optional, defaults to current workspace)", + }, + }, + required: ["regex"], + additionalProperties: false, + }, + }, +} satisfies OpenAI.Chat.ChatCompletionTool diff --git a/src/core/prompts/tools/native-tools/index.ts b/src/core/prompts/tools/native-tools/index.ts index 6d8c75964d..18d23c0b92 100644 --- a/src/core/prompts/tools/native-tools/index.ts +++ b/src/core/prompts/tools/native-tools/index.ts @@ -1,6 +1,7 @@ import { OpenAI } from "openai/client" import askFollowupQuestion from "./ask_followup_question" import attemptCompletion from "./attempt_completion" +import checkPastChatMemories from "./check_past_chat_memories" import executeCommand from "./execute_command" import fetchInstructions from "./fetch_instructions" import listCodeDefinitionNames from "./list_code_definition_names" @@ -22,6 +23,7 @@ export const nativeTools = [ fileEdit, askFollowupQuestion, attemptCompletion, + checkPastChatMemories, // browserAction, codebaseSearch, // editFile, diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 53ad39aac0..6fb3d4857a 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2621,14 +2621,22 @@ export class Task extends EventEmitter implements TaskLike { } // kilocode_change end - if (partialBlocks.length > 0) { + // kilocode_change start: Fix native tool calls not being executed + // Native tool calls are added with partial: false, so partialBlocks.length + // may be 0 even when there are unprocessed content blocks (especially tool uses). + // We need to call presentAssistantMessage if: + // 1. There were partial blocks that we just marked as complete, OR + // 2. There are content blocks that haven't been processed yet (currentStreamingContentIndex < content length) + const hasUnprocessedContent = this.currentStreamingContentIndex < this.assistantMessageContent.length + if (partialBlocks.length > 0 || hasUnprocessedContent) { // If there is content to update then it will complete and // update `this.userMessageContentReady` to true, which we // `pWaitFor` before making the next request. All this is really // doing is presenting the last partial message that we just set - // to complete. + // to complete, or executing any unprocessed tool calls. presentAssistantMessage(this) } + // kilocode_change end // Note: updateApiReqMsg() is now called from within drainStreamInBackgroundToFindAllUsage // to ensure usage data is captured even when the stream is interrupted. The background task diff --git a/src/core/tools/attemptCompletionTool.ts b/src/core/tools/attemptCompletionTool.ts index 7f3544a11b..0f7a3b5720 100644 --- a/src/core/tools/attemptCompletionTool.ts +++ b/src/core/tools/attemptCompletionTool.ts @@ -18,6 +18,7 @@ import { import { formatResponse } from "../prompts/responses" import { Package } from "../../shared/package" import { getCommitRangeForNewCompletion } from "../checkpoints/kilocode/seeNewChanges" +import { MemoryManager } from "../../services/chat-memory" // kilocode_change start async function getClineMessageOptions(task: Task) { @@ -30,7 +31,40 @@ async function getClineMessageOptions(task: Task) { } ) } -// kilocode_change end + +/** + * Save completion result as a chat memory + * This is non-critical - errors are logged but don't block completion + */ +async function saveCompletionMemory(cline: Task, result: string): Promise { + try { + const provider = cline.providerRef.deref() + const globalStoragePath = provider?.contextProxy.globalStorageUri.fsPath + + if (!globalStoragePath) { + return + } + + // Get task title from the first message + const taskTitle = cline.clineMessages[0]?.text + + // Get current mode from provider state + const mode = (await provider?.getState())?.mode ?? "default" + + // Save memory + const memoryManager = new MemoryManager(globalStoragePath) + await memoryManager.saveMemory({ + taskId: cline.taskId, + content: result, + taskTitle, + workspace: cline.workspacePath, + mode, + }) + } catch (error) { + // Don't block completion if memory saving fails + console.error("Failed to save chat memory:", error) + } +} export async function attemptCompletionTool( cline: Task, @@ -94,6 +128,11 @@ export async function attemptCompletionTool( TelemetryService.instance.captureTaskCompleted(cline.taskId) cline.emit(RooCodeEventName.TaskCompleted, cline.taskId, cline.getTokenUsage(), cline.toolUsage) + // Save completion as chat memory + if (result) { + await saveCompletionMemory(cline, result) + } + await cline.ask("command", removeClosingTag("command", command), block.partial).catch(() => {}) } } else { @@ -125,6 +164,9 @@ export async function attemptCompletionTool( TelemetryService.instance.captureTaskCompleted(cline.taskId) cline.emit(RooCodeEventName.TaskCompleted, cline.taskId, cline.getTokenUsage(), cline.toolUsage) + // Save completion as chat memory + await saveCompletionMemory(cline, result) + if (cline.parentTask) { const didApprove = await askFinishSubTaskApproval() diff --git a/src/core/tools/checkPastChatMemoriesTool.ts b/src/core/tools/checkPastChatMemoriesTool.ts new file mode 100644 index 0000000000..2754ab0a33 --- /dev/null +++ b/src/core/tools/checkPastChatMemoriesTool.ts @@ -0,0 +1,89 @@ +import { Task } from "../task/Task" +import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools" +import { ClineSayTool } from "../../shared/ExtensionMessage" +import { MemoryManager } from "../../services/chat-memory" + +export async function checkPastChatMemoriesTool( + cline: Task, + block: ToolUse, + askApproval: AskApproval, + handleError: HandleError, + pushToolResult: PushToolResult, + removeClosingTag: RemoveClosingTag, +) { + const regex: string | undefined = block.params.regex + const workspace: string | undefined = block.params.workspace + + const sharedMessageProps: ClineSayTool = { + tool: "checkPastChatMemories", + regex: removeClosingTag("regex", regex), + workspace: removeClosingTag("workspace", workspace), + } + + try { + if (block.partial) { + const partialMessage = JSON.stringify({ ...sharedMessageProps, content: "" } satisfies ClineSayTool) + await cline.ask("tool", partialMessage, block.partial).catch(() => {}) + return + } else { + if (!regex) { + cline.consecutiveMistakeCount++ + cline.recordToolError("check_past_chat_memories") + pushToolResult(await cline.sayAndCreateMissingParamError("check_past_chat_memories", "regex")) + return + } + + cline.consecutiveMistakeCount = 0 + + // Get global storage path from provider + const provider = cline.providerRef.deref() + const globalStoragePath = provider?.contextProxy.globalStorageUri.fsPath + + if (!globalStoragePath) { + pushToolResult("Unable to access global storage path.") + return + } + + // Get memory manager instance + const memoryManager = new MemoryManager(globalStoragePath) + + // Search memories + const memories = await memoryManager.searchMemories({ + regex, + workspace: workspace || cline.cwd, + }) + + // Format results + let formattedResults = "" + if (memories.length === 0) { + formattedResults = "No matching memories found." + } else { + formattedResults = `Found ${memories.length} matching memories:\n\n` + memories.forEach((memory, index) => { + const date = new Date(memory.timestamp).toLocaleDateString() + formattedResults += `${index + 1}. Task: ${memory.taskTitle || memory.taskId}\n` + formattedResults += ` Date: ${date}\n` + formattedResults += ` Mode: ${memory.mode || "N/A"}\n` + formattedResults += ` Content:\n${memory.content}\n\n` + }) + } + + const completeMessage = JSON.stringify({ + ...sharedMessageProps, + content: formattedResults, + } satisfies ClineSayTool) + const didApprove = await askApproval("tool", completeMessage) + + if (!didApprove) { + return + } + + pushToolResult(formattedResults) + + return + } + } catch (error) { + await handleError("searching chat memories", error) + return + } +} diff --git a/src/core/webview/generateSystemPrompt.ts b/src/core/webview/generateSystemPrompt.ts index 2f2f936412..363a85bc14 100644 --- a/src/core/webview/generateSystemPrompt.ts +++ b/src/core/webview/generateSystemPrompt.ts @@ -67,6 +67,9 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web // and browser tools are enabled in settings const canUseBrowserTool = modelSupportsComputerUse && modeSupportsBrowser && (browserToolEnabled ?? true) + // Get task history for chat memories + const taskHistory = provider.getTaskHistory() + const systemPrompt = await SYSTEM_PROMPT( provider.context, cwd, @@ -97,6 +100,7 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web undefined, getActiveToolUseStyle(apiConfiguration), state, + taskHistory, // kilocode_change: Chat memories // kilocode_change end ) diff --git a/src/core/webview/webviewMessageHandler.ts b/src/core/webview/webviewMessageHandler.ts index 1f703eafe2..10367020ed 100644 --- a/src/core/webview/webviewMessageHandler.ts +++ b/src/core/webview/webviewMessageHandler.ts @@ -11,6 +11,7 @@ import { codeReviewSettingsSchema, CodeReviewSettings, getKiloUrlFromToken, isGl import { getAppUrl } from "@roo-code/types" import { MaybeTypedWebviewMessage, + MemoryItem, ProfileData, SeeNewChangesPayload, TaskHistoryRequestPayload, @@ -1609,6 +1610,20 @@ ${comment.suggestion} }) break } + case "get_memories": { + const { MemoryManager } = await import("../../services/chat-memory/MemoryManager") + const memoryManager = new MemoryManager(provider.context.globalStorageUri.fsPath) + const memories = await memoryManager.getAllMemories(message.showAllWorkspaces ? undefined : provider.cwd) + const memoryItems: MemoryItem[] = memories.map((memory) => ({ + ...memory, + timestamp: memory.timestamp.toString(), + })) + await provider.postMessageToWebview({ + type: "memories_response", + memories: memoryItems, + }) + break + } // kilocode_change end case "checkpointRestore": { const result = checkoutRestorePayloadSchema.safeParse(message.payload) diff --git a/src/package.json b/src/package.json index b3df5047b4..16f7800b83 100644 --- a/src/package.json +++ b/src/package.json @@ -147,6 +147,11 @@ "title": "%command.marketplace.title%", "icon": "$(extensions)" }, + { + "command": "axon-code.memoriesButtonClicked", + "title": "%command.memories.title%", + "icon": "$(book)" + }, { "command": "axon-code.popoutButtonClicked", "title": "%command.openInEditor.title%", @@ -345,33 +350,33 @@ "when": "view == axon-code.SidebarProvider" }, { - "command": "axon-code.marketplaceButtonClicked", - "group": "navigation@3", + "command": "axon-code.historyButtonClicked", + "group": "navigation@4", "when": "view == axon-code.SidebarProvider" }, { - "command": "axon-code.historyButtonClicked", - "group": "navigation@4", + "command": "axon-code.memoriesButtonClicked", + "group": "navigation@5", "when": "view == axon-code.SidebarProvider" }, { "command": "axon-code.profileButtonClicked", - "group": "navigation@5", + "group": "navigation@6", "when": "view == axon-code.SidebarProvider" }, { "command": "axon-code.settingsButtonClicked", - "group": "navigation@6", + "group": "navigation@7", "when": "view == axon-code.SidebarProvider" }, { "command": "axon-code.popoutButtonClicked", - "group": "navigation@7", + "group": "navigation@8", "when": "view == axon-code.SidebarProvider" }, { "command": "axon-code.helpButtonClicked", - "group": "navigation@8", + "group": "navigation@9", "when": "false && view == axon-code.SidebarProvider" } ], @@ -392,19 +397,24 @@ "when": "activeWebviewPanelId == axon-code.TabPanelProvider" }, { - "command": "axon-code.popoutButtonClicked", + "command": "axon-code.memoriesButtonClicked", "group": "navigation@4", "when": "activeWebviewPanelId == axon-code.TabPanelProvider" }, { - "command": "axon-code.settingsButtonClicked", + "command": "axon-code.popoutButtonClicked", "group": "navigation@5", "when": "activeWebviewPanelId == axon-code.TabPanelProvider" }, { - "command": "axon-code.helpButtonClicked", + "command": "axon-code.settingsButtonClicked", "group": "navigation@6", "when": "activeWebviewPanelId == axon-code.TabPanelProvider" + }, + { + "command": "axon-code.helpButtonClicked", + "group": "navigation@7", + "when": "activeWebviewPanelId == axon-code.TabPanelProvider" } ], "scm/input": [ diff --git a/src/package.nls.json b/src/package.nls.json index 71b2e246a3..2ab89e72b5 100644 --- a/src/package.nls.json +++ b/src/package.nls.json @@ -29,6 +29,7 @@ "command.acceptInput.title": "Accept Input/Suggestion", "command.generateCommitMessage.title": "Generate Commit Message with Kilo", "command.profile.title": "Profile", + "command.memories.title": "Memories", "configuration.title": "Axon Code", "command.toggleAutoApprove.title": "Toggle Auto-Approve", "commands.allowedCommands.description": "Commands that can be auto-executed when 'Always approve execute operations' is enabled", diff --git a/src/services/chat-memory/MemoryManager.ts b/src/services/chat-memory/MemoryManager.ts new file mode 100644 index 0000000000..22aaadf39d --- /dev/null +++ b/src/services/chat-memory/MemoryManager.ts @@ -0,0 +1,188 @@ +import * as fs from "fs/promises" +import * as path from "path" + +import type { ChatMemory, MemorySaveOptions, MemorySearchOptions } from "./types" + +const MEMORY_FILE = "chat-memories.json" +const MAX_CONTENT_LENGTH = 10000 +const DEFAULT_SEARCH_LIMIT = 20 + +export class MemoryManager { + private memories: ChatMemory[] = [] + private filePath: string + private loaded: boolean = false + + constructor(private globalStoragePath: string) { + this.filePath = path.join(globalStoragePath, MEMORY_FILE) + } + + /** + * Load memories from disk (lazy loading) + */ + private async loadMemories(): Promise { + if (this.loaded) { + return + } + + try { + const data = await fs.readFile(this.filePath, "utf-8") + this.memories = JSON.parse(data) + this.loaded = true + } catch (error) { + // File doesn't exist or is corrupted, start with empty array + this.memories = [] + this.loaded = true + } + } + + /** + * Save memories to disk + */ + private async saveMemories(): Promise { + try { + await fs.mkdir(path.dirname(this.filePath), { recursive: true }) + await fs.writeFile(this.filePath, JSON.stringify(this.memories, null, 2), "utf-8") + } catch (error) { + console.error("Failed to save chat memories:", error) + } + } + + /** + * Save a new memory + */ + async saveMemory(options: MemorySaveOptions): Promise { + await this.loadMemories() + + const { taskId, content, taskTitle, workspace, mode, maxContentLength = MAX_CONTENT_LENGTH } = options + + // Truncate content if too long + const truncatedContent = + content.length > maxContentLength ? content.substring(0, maxContentLength) + "... (truncated)" : content + + const memory: ChatMemory = { + id: `${taskId}-${Date.now()}`, + taskId, + taskTitle, + content: truncatedContent, + timestamp: Date.now(), + workspace, + mode, + } + + this.memories.push(memory) + await this.saveMemories() + } + + /** + * Search memories by regex pattern + */ + async searchMemories(options: MemorySearchOptions): Promise { + await this.loadMemories() + + const { regex, workspace, limit = DEFAULT_SEARCH_LIMIT } = options + + try { + const regexPattern = new RegExp(regex, "gi") + + const filtered = this.memories.filter((memory) => { + // Filter by workspace if specified + if (workspace && memory.workspace !== workspace) { + return false + } + + // Check if content matches regex + return regexPattern.test(memory.content) + }) + + // Sort by timestamp (most recent first) and limit results + return filtered.sort((a, b) => b.timestamp - a.timestamp).slice(0, limit) + } catch (error) { + console.error("Invalid regex pattern:", error) + return [] + } + } + + /** + * Get all memories, optionally filtered by workspace + */ + async getAllMemories(workspace?: string): Promise { + await this.loadMemories() + + if (workspace) { + return this.memories.filter((memory) => memory.workspace === workspace) + } + + return [...this.memories] + } + + /** + * Delete a specific memory by ID + */ + async deleteMemory(memoryId: string): Promise { + await this.loadMemories() + + this.memories = this.memories.filter((memory) => memory.id !== memoryId) + await this.saveMemories() + } + + /** + * Delete all memories for a specific task + */ + async deleteMemoriesForTask(taskId: string): Promise { + await this.loadMemories() + + this.memories = this.memories.filter((memory) => memory.taskId !== taskId) + await this.saveMemories() + } + + /** + * Delete all memories for a specific workspace + */ + async deleteMemoriesForWorkspace(workspace: string): Promise { + await this.loadMemories() + + this.memories = this.memories.filter((memory) => memory.workspace !== workspace) + await this.saveMemories() + } + + /** + * Clear all memories (use with caution) + */ + async clearAllMemories(): Promise { + this.memories = [] + await this.saveMemories() + } + + /** + * Get memory count + */ + async getMemoryCount(workspace?: string): Promise { + await this.loadMemories() + + if (workspace) { + return this.memories.filter((memory) => memory.workspace === workspace).length + } + + return this.memories.length + } + + /** + * Clean up old memories (older than specified days) + */ + async cleanupOldMemories(daysOld: number = 30): Promise { + await this.loadMemories() + + const cutoffTime = Date.now() - daysOld * 24 * 60 * 60 * 1000 + const initialCount = this.memories.length + + this.memories = this.memories.filter((memory) => memory.timestamp > cutoffTime) + + const deletedCount = initialCount - this.memories.length + + if (deletedCount > 0) { + await this.saveMemories() + } + + return deletedCount + } +} diff --git a/src/services/chat-memory/index.ts b/src/services/chat-memory/index.ts new file mode 100644 index 0000000000..3cdd6a1895 --- /dev/null +++ b/src/services/chat-memory/index.ts @@ -0,0 +1,2 @@ +export { MemoryManager } from "./MemoryManager" +export type { ChatMemory, MemorySaveOptions, MemorySearchOptions } from "./types" diff --git a/src/services/chat-memory/types.ts b/src/services/chat-memory/types.ts new file mode 100644 index 0000000000..263383343f --- /dev/null +++ b/src/services/chat-memory/types.ts @@ -0,0 +1,24 @@ +export interface ChatMemory { + id: string + taskId: string + taskTitle?: string + content: string + timestamp: number + workspace: string + mode?: string +} + +export interface MemorySearchOptions { + regex: string + workspace?: string + limit?: number +} + +export interface MemorySaveOptions { + taskId: string + content: string + taskTitle?: string + workspace: string + mode?: string + maxContentLength?: number +} diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index cd09ae35a7..b5b4bc13dc 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -28,6 +28,7 @@ import { ProfileDataResponsePayload, TaskHistoryResponsePayload, TasksByIdResponsePayload, + MemoryItem, } from "./WebviewMessage" import { ClineRulesToggles } from "./cline-rules" import { KiloCodeWrapperProperties } from "./kilocode/wrapper" @@ -157,6 +158,7 @@ export interface ExtensionMessage { | "organizationSwitchResult" | "implementPlan" // kilocode_change: Plan mode implementation | "showToast" // kilocode_change + | "memories_response" // kilocode_change: Chat memories response text?: string // kilocode_change start payload?: @@ -170,10 +172,11 @@ export interface ExtensionMessage { | "chatButtonClicked" | "mcpButtonClicked" | "settingsButtonClicked" - | "historyButtonClicked" | "promptsButtonClicked" + | "historyButtonClicked" | "profileButtonClicked" // kilocode_change | "marketplaceButtonClicked" + | "memoriesButtonClicked" | "cloudButtonClicked" | "didBecomeVisible" | "focusInput" @@ -273,6 +276,7 @@ export interface ExtensionMessage { queuedMessages?: QueuedMessage[] list?: string[] // For dismissedUpsells organizationId?: string | null // For organizationSwitchResult + memories?: MemoryItem[] // kilocode_change: For memories_response } export type ExtensionState = Pick< @@ -485,6 +489,7 @@ export interface ClineSayTool { | "runSlashCommand" | "planFileEdit" // kilocode_change: Plan mode file editing | "codeReview" // kilocode_change: AI Code Review + | "checkPastChatMemories" // Chat memories feature path?: string diff?: string content?: string @@ -494,6 +499,7 @@ export interface ClineSayTool { reason?: string isOutsideWorkspace?: boolean isProtected?: boolean + workspace?: string additionalFileCount?: number // Number of additional files in same read_file request search?: string replace?: string diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index b81bdd2db4..e6b09530b3 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -323,6 +323,8 @@ export interface WebviewMessage { | "gitChangesForReview" | "codeReviewSettings" // kilocode_change | "showToast" // kilocode_change + | "get_memories" // kilocode_change: Chat memories + | "memories_response" // kilocode_change: Chat memories response // kilocode_change end text?: string editedMessageContent?: string @@ -392,6 +394,8 @@ export interface WebviewMessage { upsellId?: string // For dismissUpsell list?: string[] // For dismissedUpsells response organizationId?: string | null // For organization switching + showAllWorkspaces?: boolean // kilocode_change: For get_memories + memories?: MemoryItem[] // kilocode_change: For memories_response codeIndexSettings?: { // Global state settings codebaseIndexEnabled: boolean @@ -494,6 +498,17 @@ export interface TaskHistoryResponsePayload { pageIndex: number pageCount: number } + +// kilocode_change: Chat memories +export interface MemoryItem { + id: string + workspace: string + taskId: string + taskTitle?: string + content: string + timestamp: string + mode?: string +} // kilocode_change end export const checkoutDiffPayloadSchema = z.object({ diff --git a/src/shared/tools.ts b/src/shared/tools.ts index 7b82cd09f0..b718e9bb16 100644 --- a/src/shared/tools.ts +++ b/src/shared/tools.ts @@ -80,6 +80,7 @@ export const toolParamNames = [ "todos", "prompt", "image", + "workspace", ] as const export type ToolParamName = (typeof toolParamNames)[number] @@ -204,6 +205,12 @@ export interface EditFileToolUse extends ToolUse { } // kilocode_change end +export interface CheckPastChatMemoriesToolUse extends ToolUse { + name: "check_past_chat_memories" + params: Required, "regex">> & + Partial, "workspace">> +} + export interface GenerateImageToolUse extends ToolUse { name: "generate_image" params: Partial, "prompt" | "path" | "image">> @@ -237,12 +244,13 @@ export const TOOL_DISPLAY_NAMES: Record = { search_and_replace: "search and replace", new_rule: "create new rule", report_bug: "report bug", // kilocode_change - condense: "condense the current context window", // kilicode_change + condense: "condense the current context window", // kilocode_change codebase_search: "codebase search", update_todo_list: "update todo list", run_slash_command: "run slash command", generate_image: "generate images", plan_file_edit: "edit plan files", // kilocode_change: Plan mode file editing + check_past_chat_memories: "check past chat memories", } as const // Define available tool groups. @@ -255,6 +263,7 @@ export const TOOL_GROUPS: Record = { "list_files", "list_code_definition_names", "codebase_search", + "check_past_chat_memories", ], }, edit: { diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index a87a5602a8..ab8c070330 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -1,40 +1,40 @@ -import React, { useCallback, useEffect, useRef, useState, useMemo } from "react" -import { useEvent } from "react-use" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" +import React, { useCallback, useEffect, useRef, useState } from "react" +import { useEvent } from "react-use" import { ExtensionMessage } from "@roo/ExtensionMessage" import TranslationProvider from "./i18n/TranslationContext" -import { MarketplaceViewStateManager } from "./components/marketplace/MarketplaceViewStateManager" -import { vscode } from "./utils/vscode" -import { telemetryClient } from "./utils/TelemetryClient" import { TelemetryEventName } from "@roo-code/types" -import { initializeSourceMaps, exposeSourceMapsForDebugging } from "./utils/sourceMapInitializer" -import { ExtensionStateContextProvider, useExtensionState } from "./context/ExtensionStateContext" import ChatView, { ChatViewRef } from "./components/chat/ChatView" import HistoryView from "./components/history/HistoryView" -import SettingsView, { SettingsViewRef } from "./components/settings/SettingsView" -import WelcomeView from "./components/kilocode/welcome/WelcomeView" // kilocode_change import ProfileView from "./components/kilocode/profile/ProfileView" // kilocode_change +import WelcomeView from "./components/kilocode/welcome/WelcomeView" // kilocode_change import McpView from "./components/mcp/McpView" -import { MarketplaceView } from "./components/marketplace/MarketplaceView" -import ModesView from "./components/modes/ModesView" -import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog" -import BottomControls from "./components/kilocode/BottomControls" // kilocode_change -import { MemoryService } from "./services/MemoryService" // kilocode_change +import MemoriesView from "./components/memories/MemoriesView" +import SettingsView, { SettingsViewRef } from "./components/settings/SettingsView" +import { ExtensionStateContextProvider, useExtensionState } from "./context/ExtensionStateContext" +import { exposeSourceMapsForDebugging, initializeSourceMaps } from "./utils/sourceMapInitializer" +import { telemetryClient } from "./utils/TelemetryClient" +import { vscode } from "./utils/vscode" +// import { MarketplaceView } from "./components/marketplace/MarketplaceView" import { CheckpointRestoreDialog } from "./components/chat/CheckpointRestoreDialog" import { DeleteMessageDialog, EditMessageDialog } from "./components/chat/MessageModificationConfirmationDialog" import ErrorBoundary from "./components/ErrorBoundary" +import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog" +import BottomControls from "./components/kilocode/BottomControls" // kilocode_change +import ModesView from "./components/modes/ModesView" +import { MemoryService } from "./services/MemoryService" // kilocode_change // import { AccountView } from "./components/account/AccountView" // kilocode_change: we have our own profile view // import { CloudView } from "./components/cloud/CloudView" // kilocode_change: not rendering this import { useAddNonInteractiveClickListener } from "./components/ui/hooks/useNonInteractiveClick" -import { TooltipProvider } from "./components/ui/tooltip" import { STANDARD_TOOLTIP_DELAY } from "./components/ui/standard-tooltip" -import { useKiloIdentity } from "./utils/kilocode/useKiloIdentity" -import { MemoryWarningBanner } from "./kilocode/MemoryWarningBanner" import { ToastProvider, useToast } from "./components/ui/toast" +import { TooltipProvider } from "./components/ui/tooltip" +import { MemoryWarningBanner } from "./kilocode/MemoryWarningBanner" +import { useKiloIdentity } from "./utils/kilocode/useKiloIdentity" -type Tab = "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account" | "cloud" | "profile" // kilocode_change: add "profile" +type Tab = "settings" | "history" | "mcp" | "modes" | "chat" | "account" | "profile" | "memories" | "marketplace" interface HumanRelayDialogState { isOpen: boolean @@ -69,7 +69,8 @@ const tabsByMessageAction: Partial { const { showToast } = useToast() // Create a persistent state manager - const marketplaceStateManager = useMemo(() => new MarketplaceViewStateManager(), []) + // const marketplaceStateManager = useMemo(() => new MarketplaceViewStateManager(), []) const [showAnnouncement, setShowAnnouncement] = useState(false) const [tab, setTab] = useState("chat") @@ -127,7 +128,7 @@ const App = () => { (newTab: Tab) => { // Only check MDM compliance if mdmCompliant is explicitly false (meaning there's an MDM policy and user is non-compliant) // If mdmCompliant is undefined or true, allow tab switching - if (mdmCompliant === false && newTab !== "cloud") { + if (mdmCompliant === false) { // Notify the user that authentication is required by their organization vscode.postMessage({ type: "showMdmAuthRequiredNotification" }) return @@ -302,19 +303,20 @@ const App = () => { {tab === "modes" && switchTab("chat")} />} {tab === "mcp" && switchTab("chat")} />} {tab === "history" && switchTab("chat")} />} + {tab === "memories" && switchTab("chat")} />} {tab === "settings" && ( switchTab("chat")} targetSection={currentSection} /> // kilocode_change )} {/* kilocode_change: add profileview */} {tab === "profile" && switchTab("chat")} />} - {tab === "marketplace" && ( + {/* {tab === "marketplace" && ( switchTab("chat")} // kilocode_change: targetTab="mode" targetTab="mode" /> - )} + )} */} {/* kilocode_change: no cloud view */} {/* {tab === "cloud" && ( ( "transition-background-color duration-150 ease-in-out", "will-change-background-color", "min-h-[110px]", + "max-h-[calc(100vh/2.5)]", "box-border", "rounded-xl", "overflow-x-hidden", diff --git a/webview-ui/src/components/history/HistoryView.tsx b/webview-ui/src/components/history/HistoryView.tsx index 2bdeb478db..fef1c8a792 100644 --- a/webview-ui/src/components/history/HistoryView.tsx +++ b/webview-ui/src/components/history/HistoryView.tsx @@ -129,7 +129,7 @@ const HistoryView = ({ onDone }: HistoryViewProps) => { setSortOption("mostRelevant") } }}> -
+
{searchQuery && (
void +} + +const MemoriesView = ({ onDone }: MemoriesViewProps) => { + const { t } = useAppTranslation() + + const [memories, setMemories] = useState([]) + const [searchQuery, setSearchQuery] = useState("") + const [loading, setLoading] = useState(true) + const [showAllWorkspaces, setShowAllWorkspaces] = useState(false) + + // Fetch memories on mount + useEffect(() => { + vscode.postMessage({ + type: "get_memories", + showAllWorkspaces, + }) + }, [showAllWorkspaces]) + + // Listen for memories response + useEffect(() => { + const handleMessage = (event: MessageEvent) => { + const message = event.data + if (message.type === "memories_response") { + setMemories(message.memories || []) + setLoading(false) + } + } + + window.addEventListener("message", handleMessage) + return () => window.removeEventListener("message", handleMessage) + }, []) + + // Filter memories by search query + const filteredMemories = memories.filter((memory) => { + if (!searchQuery) return true + const query = searchQuery.toLowerCase() + return ( + memory.taskTitle.toLowerCase().includes(query) || + memory.content.toLowerCase().includes(query) || + memory.workspace.toLowerCase().includes(query) + ) + }) + + // Format timestamp + const formatTimestamp = (timestamp: string) => { + const date = new Date(timestamp) + return date.toLocaleString() + } + + // Truncate content for preview + const truncateContent = (content: string, maxLength = 200) => { + if (content.length <= maxLength) return content + return content.substring(0, maxLength) + "..." + } + + return ( + + +
+

+ + {t("memories:title")} +

+ +
+
+ { + setSearchQuery((e.target as HTMLInputElement)?.value) + }}> +
+ {searchQuery && ( +
setSearchQuery("")} + slot="end" + /> + )} + +
+ +
+
+ {t("memories:count", { count: filteredMemories.length })} +
+
+ + + + {loading ? ( +
+ {t("memories:loading")} +
+ ) : filteredMemories.length === 0 ? ( +
+ +

{searchQuery ? t("memories:noResults") : t("memories:noMemories")}

+
+ ) : ( +
), + }} + itemContent={(_index, memory) => ( +
+
+

+ {memory.taskTitle || t("memories:untitled")} +

+ {memory.mode && ( + + {memory.mode} + + )} +
+
+
+ + {memory.workspace} +
+
+ + {formatTimestamp(memory.timestamp)} +
+
+
+ {truncateContent(memory.content)} +
+
+ )} + /> + )} + + + ) +} + +export default memo(MemoriesView) diff --git a/webview-ui/src/components/memories/index.ts b/webview-ui/src/components/memories/index.ts new file mode 100644 index 0000000000..ff5e4000f9 --- /dev/null +++ b/webview-ui/src/components/memories/index.ts @@ -0,0 +1 @@ +export { default as MemoriesView } from "./MemoriesView" diff --git a/webview-ui/src/i18n/locales/en/memories.json b/webview-ui/src/i18n/locales/en/memories.json new file mode 100644 index 0000000000..12db13e365 --- /dev/null +++ b/webview-ui/src/i18n/locales/en/memories.json @@ -0,0 +1,12 @@ +{ + "title": "Memories", + "done": "Done", + "searchPlaceholder": "Search memories...", + "loading": "Loading memories...", + "noMemories": "No memories found. Memories are saved when you complete tasks.", + "noResults": "No memories match your search.", + "count": "{{count}} memories", + "currentWorkspace": "Current Workspace", + "allWorkspaces": "All Workspaces", + "untitled": "Untitled" +} From b662bf6515c7f74aa8f0dcc1f4eb9079d42bdc8e Mon Sep 17 00:00:00 2001 From: code-crusher Date: Wed, 14 Jan 2026 23:09:18 +0530 Subject: [PATCH 4/5] complete memories feature --- webview-ui/src/components/memories/MemoriesView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webview-ui/src/components/memories/MemoriesView.tsx b/webview-ui/src/components/memories/MemoriesView.tsx index 18f5bd1805..1d37786eab 100644 --- a/webview-ui/src/components/memories/MemoriesView.tsx +++ b/webview-ui/src/components/memories/MemoriesView.tsx @@ -46,9 +46,9 @@ const MemoriesView = ({ onDone }: MemoriesViewProps) => { if (!searchQuery) return true const query = searchQuery.toLowerCase() return ( - memory.taskTitle.toLowerCase().includes(query) || - memory.content.toLowerCase().includes(query) || - memory.workspace.toLowerCase().includes(query) + memory?.taskTitle?.toLowerCase().includes(query) || + memory?.content?.toLowerCase().includes(query) || + memory?.workspace?.toLowerCase().includes(query) ) }) From 501c7b1aa7e75d24373de762e62b0ca7907666af Mon Sep 17 00:00:00 2001 From: code-crusher Date: Thu, 15 Jan 2026 07:51:18 +0530 Subject: [PATCH 5/5] cleanup console logs --- .../assistant-message/AssistantMessageParser.ts | 14 -------------- src/core/task/Task.ts | 11 ----------- 2 files changed, 25 deletions(-) diff --git a/src/core/assistant-message/AssistantMessageParser.ts b/src/core/assistant-message/AssistantMessageParser.ts index 6f8fa438c8..1160a1b45e 100644 --- a/src/core/assistant-message/AssistantMessageParser.ts +++ b/src/core/assistant-message/AssistantMessageParser.ts @@ -77,15 +77,6 @@ export class AssistantMessageParser { * currently set parallel_tool_calls to false, so in theory there should only be 1 call. */ public *processNativeToolCalls(toolCalls: NativeToolCall[]): Generator { - console.log( - `[AssistantMessageParser] Processing ${toolCalls.length} native tool call(s):`, - toolCalls.map((tc) => ({ - id: tc.id, - index: tc.index, - name: tc.function?.name, - argsLength: tc.function?.arguments?.length, - })), - ) for (const toolCall of toolCalls) { // Determine the tracking key // If we have an index, use that to look up or store the id @@ -186,11 +177,6 @@ export class AssistantMessageParser { } } catch (error) { // Arguments are not yet complete valid JSON, continue accumulating - // Log to help diagnose parsing issues - console.log( - `[AssistantMessageParser] JSON parsing incomplete/failed for tool "${accumulatedCall.function!.name}" (id: ${toolCallId}). Args length: ${accumulatedCall.function!.arguments.length}. Error:`, - error, - ) continue } diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 6fb3d4857a..c105832a82 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -2263,9 +2263,6 @@ export class Task extends EventEmitter implements TaskLike { case "native_tool_calls": { // Handle native OpenAI-format tool calls // Process native tool calls through the parser - console.log( - `[Task] Received native_tool_calls chunk with ${chunk.toolCalls.length} tool call(s)`, - ) let yieldedCount = 0 for (const toolUse of this.assistantMessageParser.processNativeToolCalls( chunk.toolCalls, @@ -2273,17 +2270,9 @@ export class Task extends EventEmitter implements TaskLike { assistantToolUses.push(toolUse) yieldedCount++ } - console.log( - `[Task] After processing: yielded ${yieldedCount} tool uses, contentBlocks before: ${this.assistantMessageContent.length}`, - ) - // Update content blocks after processing native tool calls const prevLength = this.assistantMessageContent.length this.assistantMessageContent = this.assistantMessageParser.getContentBlocks() - console.log( - `[Task] contentBlocks after: ${this.assistantMessageContent.length}, prevLength: ${prevLength}`, - ) - if (this.assistantMessageContent.length > prevLength) { // New content we need to present this.userMessageContentReady = false