mirror of
https://github.com/ggml-org/llama.vscode.git
synced 2026-05-07 01:15:23 +00:00
Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a2078d470 |
27 changed files with 124 additions and 1431 deletions
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "llama-vscode",
|
||||
"version": "0.0.45",
|
||||
"version": "0.0.39",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "llama-vscode",
|
||||
"version": "0.0.45",
|
||||
"version": "0.0.39",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"axios": "^1.1.2",
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/picomatch": "^4.0.0",
|
||||
"@types/vscode": "^1.109.0",
|
||||
"@types/vscode": "^1.100.0",
|
||||
"@vscode/test-cli": "^0.0.11",
|
||||
"@vscode/test-electron": "^2.5.2",
|
||||
"esbuild": "^0.27.0",
|
||||
|
|
@ -829,9 +829,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/vscode": {
|
||||
"version": "1.109.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.109.0.tgz",
|
||||
"integrity": "sha512-0Pf95rnwEIwDbmXGC08r0B4TQhAbsHQ5UyTIgVgoieDe4cOnf92usuR5dEczb6bTKEp7ziZH4TV1TRGPPCExtw==",
|
||||
"version": "1.103.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.103.0.tgz",
|
||||
"integrity": "sha512-o4hanZAQdNfsKecexq9L3eHICd0AAvdbLk6hA60UzGXbGH/q8b/9xv2RgR7vV3ZcHuyKVq7b37IGd/+gM4Tu+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
|
@ -1182,6 +1182,7 @@
|
|||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -1230,6 +1231,7 @@
|
|||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
|
|
@ -1430,6 +1432,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001669",
|
||||
"electron-to-chromium": "^1.5.41",
|
||||
|
|
@ -5513,6 +5516,7 @@
|
|||
"integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@discoveryjs/json-ext": "^0.5.0",
|
||||
"@webpack-cli/configtest": "^1.2.0",
|
||||
|
|
|
|||
237
package.json
237
package.json
|
|
@ -2,11 +2,11 @@
|
|||
"name": "llama-vscode",
|
||||
"displayName": "llama-vscode",
|
||||
"description": "Local LLM-assisted text completion using llama.cpp",
|
||||
"version": "0.0.47",
|
||||
"version": "0.0.41",
|
||||
"publisher": "ggml-org",
|
||||
"repository": "https://github.com/ggml-org/llama.vscode",
|
||||
"engines": {
|
||||
"vscode": "^1.109.0"
|
||||
"vscode": "^1.100.0"
|
||||
},
|
||||
"icon": "llama.png",
|
||||
"activationEvents": [
|
||||
|
|
@ -17,13 +17,6 @@
|
|||
],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"languageModelChatProviders": [
|
||||
{
|
||||
"vendor": "llama-vscode",
|
||||
"displayName": "llama.vscode",
|
||||
"managementCommand": "extension.showMenu"
|
||||
}
|
||||
],
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
|
|
@ -345,11 +338,7 @@
|
|||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of the agent - for what purposes should be used, what are his strengths, etc."
|
||||
},
|
||||
"subagentEnabled": {
|
||||
"type": "string",
|
||||
"description": "If the agent could be used as subagent of another agent to execute a specific task."
|
||||
"description": "Description of the model - for what purposes should be used, what are his strengths, etc."
|
||||
},
|
||||
"systemInstruction": {
|
||||
"type": "array",
|
||||
|
|
@ -492,210 +481,7 @@
|
|||
"get_diff",
|
||||
"edit_file",
|
||||
"ask_user",
|
||||
"update_todo_list",
|
||||
"delegate_task"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Unite test writer",
|
||||
"description": "Writes the unit tests. The input should provide a path to a source file to be tested.",
|
||||
"systemInstruction": [
|
||||
"You are an expert software engineer specializing in writing unit tests. Your task is to generate high‑quality, reliable, and maintainable unit tests based on the user’s instructions and the provided source code. You must infer the programming language, testing framework, and project conventions from the source file and any accompanying context (such as imports, file extensions, or existing test files).",
|
||||
"Tools & Environment",
|
||||
"",
|
||||
" read_file – to examine the source code and any relevant configuration files (e.g., package.json, pom.xml, requirements.txt, Cargo.toml, etc.).",
|
||||
"",
|
||||
" edit_file – to create or modify test files.",
|
||||
"",
|
||||
" run_terminal_command – to execute tests and report results.",
|
||||
"",
|
||||
"Input & Context",
|
||||
"",
|
||||
"The user will give you the path to a source file that needs unit tests (e.g., src/services/user_service.py, lib/user.dart, internal/user.go). They may also include additional instructions, such as specific scenarios to cover or edge cases to consider.",
|
||||
"Your Thought Process (Internal Reasoning)",
|
||||
"",
|
||||
"Before generating any code, work through these steps in your mind:",
|
||||
"",
|
||||
" Analyze the Source Code",
|
||||
"",
|
||||
" Use read_file to understand the module’s purpose, its exported functions/classes/methods, input parameters, return types, and dependencies.",
|
||||
"",
|
||||
" Determine the programming language (from the file extension, shebang, or import/require statements).",
|
||||
"",
|
||||
" Identify all public APIs that need testing.",
|
||||
"",
|
||||
" Note side effects, asynchronous operations, or interactions with external systems (databases, APIs, file system, etc.).",
|
||||
"",
|
||||
" Infer the Testing Conventions",
|
||||
"",
|
||||
" Look for an existing test directory (e.g., test/, tests/, spec/, __tests__/) and the naming pattern of existing test files (e.g., *.test.js, *_test.py, *_spec.rb).",
|
||||
"",
|
||||
" Detect the testing framework being used:",
|
||||
"",
|
||||
" JavaScript/TypeScript: look for mocha, jest, jasmine in package.json.",
|
||||
"",
|
||||
" Python: look for pytest, unittest in imports or config files.",
|
||||
"",
|
||||
" Java: look for JUnit in pom.xml or build.gradle.",
|
||||
"",
|
||||
" Go: look for testing package imports, etc.",
|
||||
"",
|
||||
" Determine the preferred assertion style (e.g., assert module, expect, should, assertThat).",
|
||||
"",
|
||||
" If no existing tests or configuration are found, use the most common default for that language (e.g., pytest for Python, JUnit 5 for Java, go test for Go, Mocha + assert for Node.js).",
|
||||
"",
|
||||
" Plan the Test Structure",
|
||||
"",
|
||||
" Test file location: For a source file at src/path/to/file.ext, the test file should normally be placed at test/path/to/file_test.ext or follow the project’s convention (mirroring the source directory under a test/ or tests/ root). Ensure the directory structure is created if needed.",
|
||||
"",
|
||||
" Plan the outer test suite (e.g., describe('moduleName', ...) in Mocha, a test class in JUnit, or a module‑level docstring in pytest).",
|
||||
"",
|
||||
" Plan nested suites for each function or method.",
|
||||
"",
|
||||
" List all test cases (happy path, edge cases, error cases) with clear, descriptive names.",
|
||||
"",
|
||||
" Consider Dependencies and Mocking",
|
||||
"",
|
||||
" Identify the module’s dependencies.",
|
||||
"",
|
||||
" Design the module under test to allow dependency injection – your tests should inject simple, manual mocks or stubs to replace real dependencies.",
|
||||
"",
|
||||
" Do not introduce third‑party mocking libraries unless they are already present in the project. Rely on manual mocks (e.g., creating test doubles yourself).",
|
||||
"",
|
||||
" Example: If a function imports an HTTP client, your test should inject a mock client that returns controlled data or throws predictable errors.",
|
||||
"",
|
||||
"Core Principles & Rules",
|
||||
"",
|
||||
"Adhere strictly to these principles in every test you write:",
|
||||
"",
|
||||
" Test Location: Test files must be created in the appropriate test directory (commonly test/, tests/, spec/, etc.) mirroring the source structure. Use the naming convention inferred from the project.",
|
||||
"",
|
||||
" Framework & Style: Use the testing framework and assertion style that the project already uses (or the default you inferred). Write idiomatic tests for that language.",
|
||||
"",
|
||||
" Test Quality:",
|
||||
"",
|
||||
" Tests must be isolated and idempotent – the outcome of one test must not depend on another.",
|
||||
"",
|
||||
" Each test should verify one specific behavior.",
|
||||
"",
|
||||
" Test descriptions must be clear and descriptive, explaining the scenario and expected outcome.",
|
||||
"",
|
||||
" Properly handle asynchronous code using the language’s native async patterns (e.g., async/await, Future, Promise). Ensure the test framework waits for completion.",
|
||||
"",
|
||||
" Reset any module state or mocks in setup/teardown hooks (e.g., beforeEach, setUp, @BeforeEach) to guarantee tests can run in any order.",
|
||||
"",
|
||||
" Code Generation:",
|
||||
"",
|
||||
" Output only the pure code for the test file, properly formatted.",
|
||||
"",
|
||||
" Include all necessary imports/requires for the module under test and the testing/assertion libraries.",
|
||||
"",
|
||||
" Import the actual functions/classes from the source file. Mocking is done inside the test, not by mocking the import itself.",
|
||||
"",
|
||||
" No Source Modification: You cannot modify the source code. If the source is untestable due to poor design (e.g., hard‑coded dependencies), inform the user of the challenges and suggest refactoring the source to allow proper unit testing.",
|
||||
"",
|
||||
"Output Format",
|
||||
"",
|
||||
"Your final response must contain:",
|
||||
"",
|
||||
" A brief, non‑technical confirmation stating the language you inferred and the test file path you will create.",
|
||||
"",
|
||||
"Use the edit_file tool to create the file and the run_terminal_command tool (e.g., npx mocha 'test/services/userService.spec.ts') to verify your work, reporting the results back to the user.",
|
||||
"",
|
||||
"Crucially, you cannot modify the source code itself. If the source code is not testable due to poor design (e.g., hard-to-mock dependencies), you must inform the user of the challenges and suggest refactoring the source to allow for proper unit testing.",
|
||||
""
|
||||
],
|
||||
"tools": [
|
||||
"run_terminal_command",
|
||||
"search_source",
|
||||
"read_file",
|
||||
"list_directory",
|
||||
"regex_search",
|
||||
"delete_file",
|
||||
"edit_file",
|
||||
"update_todo_list"
|
||||
],
|
||||
"subagentEnabled": true
|
||||
},
|
||||
{
|
||||
"name": "Agent creator",
|
||||
"description": "Creates new agent. Assists the user on creating a new agent by asking relevant questions and making suggestions.",
|
||||
"subagentEnabled": true,
|
||||
"systemInstruction": [
|
||||
"You are an AI assistant specialized in helping users create new agents. Your task is to guide the user step by step, asking one question at a time, to collect all the necessary information for creating a new agent. Once you have all the required details, you will use the create_agent tool, passing the information as a JSON string in the format expected by the tool (as described in its documentation). After the agent is successfully created, inform the user that they can edit the newly created agent using the agent editor (Ctrl+Shift+M → Agents… → Edit agent…).",
|
||||
"",
|
||||
"Required Information:",
|
||||
"",
|
||||
" name (string): The name of the new agent.",
|
||||
"",
|
||||
" description (string): A brief description of what the agent does.",
|
||||
"",
|
||||
" systemInstruction (string): The system prompt or instructions that define the agent's behavior.",
|
||||
"",
|
||||
"Optional Information:",
|
||||
"",
|
||||
" subagentEnabled (boolean): Whether the agent can be used as a subagent within other agents. Ask the user for a yes/no answer; convert it to true or false (default to false if not specified).",
|
||||
"",
|
||||
" tools (string): A comma-separated list of tool names that the agent should have access to. If the user says \"none\" or leaves it blank, omit this field or set it to an empty string.",
|
||||
"",
|
||||
"Process:",
|
||||
"",
|
||||
" Begin by greeting the user and explaining that you will ask a series of questions to gather the details for the new agent.",
|
||||
"",
|
||||
" Ask for the name first. Wait for the user's response.",
|
||||
"",
|
||||
" After receiving the name, ask for the description.",
|
||||
"",
|
||||
" Then ask for the systemInstruction.",
|
||||
"",
|
||||
" Next, ask whether the agent should be usable as a subagent (subagentEnabled). Prompt for a yes/no answer. If the answer is ambiguous, ask for clarification.",
|
||||
"",
|
||||
" Finally, ask for any tools the agent should have. Prompt for a comma-separated list or indicate that they can say \"none\".",
|
||||
"The available tools for the new agent are:",
|
||||
"run_terminal_command: runs a terminal command and returns the output",
|
||||
"search_source: searches the code base for the provided query and returns the most relevant chungs (works if RAG is enabled)",
|
||||
"read_file: reads a file",
|
||||
"list_directory: returns the content of a directory/folder",
|
||||
"regex_search: does a regex search in the code base (requires RAG)",
|
||||
"delete_file: deletes the a file",
|
||||
"edit_file: creates are changes a source file",
|
||||
"ask_user: asks user a question without interrupting the tools loop of the agent",
|
||||
"llama_vscode_help: returns the documentation for llama-vscode extension",
|
||||
"update_todo_list: creates or updates a todo list (plan)",
|
||||
"delegate_task: delegates a task to a subagent and returns only the result (the subagent executes in another session, which reduces the context size)",
|
||||
"create_agent: creates a new agent from the provided json string",
|
||||
"",
|
||||
" Once all information is collected, construct a JSON object with the appropriate keys. Ensure that boolean values are represented as true or false (without quotes) and that the tools string is included only if provided.",
|
||||
"",
|
||||
" Example JSON:",
|
||||
" {",
|
||||
" \"name\": \"ExampleAgent\",",
|
||||
" \"description\": \"An agent that helps with example tasks.\",",
|
||||
" \"systemInstruction\": \"You are a helpful assistant specialized in examples.\",",
|
||||
" \"subagentEnabled\": true,",
|
||||
" \"tools\": \"web_search,calculator\"",
|
||||
" }",
|
||||
"",
|
||||
" Call the create_agent tool with this JSON string as the argument.",
|
||||
"",
|
||||
" After the tool executes successfully, inform the user that the agent has been created and remind them that they can edit it later via the agent editor (Ctrl+Shift+M → Agents… → Edit agent…). If the tool returns an error, explain the issue and ask the user to provide corrected information.",
|
||||
"",
|
||||
"Important Guidelines:",
|
||||
"",
|
||||
" Ask only one question at a time and wait for the user's response before proceeding.",
|
||||
"",
|
||||
" If the user provides incomplete or unclear answers, politely ask for clarification or more details.",
|
||||
"",
|
||||
" Do not assume default values without asking; always ask explicitly for optional fields, but you can mention that they can skip them if they want.",
|
||||
"",
|
||||
" Keep your tone friendly and helpful. Make the process feel like a guided conversation.",
|
||||
"",
|
||||
" After the agent is created, do not continue asking for more information unless the user wants to create another agent. If they do, you may restart the process.",
|
||||
"",
|
||||
""
|
||||
],
|
||||
"tools": [
|
||||
"create_agent"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1754,11 +1540,6 @@
|
|||
"default": true,
|
||||
"description": "If code completion should be triggered automatically (true) or only by pressing Ctrl+l."
|
||||
},
|
||||
"llama-vscode.debounce_ms": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Milliseconds to wait after the last keystroke before sending a completion request (0 = disabled). Useful on low-end hardware to avoid triggering inference on every keystroke."
|
||||
},
|
||||
"llama-vscode.api_key": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
|
|
@ -1924,11 +1705,6 @@
|
|||
"default": true,
|
||||
"description": "Enable/disable tool run_terminal_command"
|
||||
},
|
||||
"llama-vscode.tool_create_agent_enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable tool create_agent"
|
||||
},
|
||||
"llama-vscode.tools_custom": {
|
||||
"type": "array",
|
||||
"description": "Array of tool definitions for REST requests to LLM",
|
||||
|
|
@ -2108,11 +1884,6 @@
|
|||
"default": true,
|
||||
"description": "Enable/disable tool update_todo_list"
|
||||
},
|
||||
"llama-vscode.tool_delegate_task_enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Enable/disable tool delegate_task"
|
||||
},
|
||||
"llama-vscode.tool_custom_tool_description": {
|
||||
"type": "string",
|
||||
"default": "Use this tool to get information about ...",
|
||||
|
|
@ -2270,7 +2041,7 @@
|
|||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/picomatch": "^4.0.0",
|
||||
"@types/vscode": "^1.109.0",
|
||||
"@types/vscode": "^1.100.0",
|
||||
"@vscode/test-cli": "^0.0.11",
|
||||
"@vscode/test-electron": "^2.5.2",
|
||||
"esbuild": "^0.27.0",
|
||||
|
|
|
|||
|
|
@ -51,21 +51,7 @@ https://github.com/user-attachments/assets/97bb1418-dcea-4a49-8332-13b2ab4da661
|
|||
|
||||
|
||||
|
||||
## Copilot Chat Model Provider
|
||||
|
||||
### Overview
|
||||
Llama-vscode could be used as a VS Code copilot chat model provider. With other words llama-vscode could provide models for the copilot. The provided models could be from local models or openrouter.com or other appliation, which servers the tools models for llama-vscode. This way you could automatically download and start locally models by llama.cpp and llama-vscode and use them with Copilot for free.
|
||||
|
||||
### How to use it
|
||||
1. Select/Start tools model from llama-vscode (local or external)
|
||||
<img width="485" height="875" alt="copilotSelectToolsModel" src="https://github.com/user-attachments/assets/caa33531-22f4-46dd-b429-7498c45c93e9" />
|
||||
|
||||
2. In VS Code Copilot show the models list -> Other Models -> Manage Models
|
||||
<img width="1404" height="754" alt="CopilotManageModels" src="https://github.com/user-attachments/assets/dc861aa1-db86-46ff-83c1-98c7a435ad06" />
|
||||
|
||||
3. Make the models (all models available by the application serving the tools model are shown) you want to use visible (click on the left of the model name)
|
||||
4. Select the desired model from Copilot and start using it
|
||||
## Custom eval tool
|
||||
## Custom eval tool
|
||||
|
||||
### Overview
|
||||
llama-vscode provides to the users the posibility to partially create their own tool. Custom eval tool is a simple one - has one parameters and and uses the provided by the user javascript function to calculate the result.
|
||||
|
|
@ -212,34 +198,14 @@ Settings:
|
|||
- Health_check_chat_enabled: Enable/disable health check for chat model
|
||||
- Health_check_embs_enabled: Enable/disable health check for embedding model
|
||||
- Health_check_tools_enabled: Enable/disable health check for tools model
|
||||
|
||||
<img width="580" height="779" alt="image" src="https://github.com/user-attachments/assets/dca91333-687e-4856-b187-25df50d17b1c" />
|
||||
|
||||
<img width="580" height="779" alt="image" src="https://github.com/user-attachments/assets/bb29e0c8-85b4-4e7a-a3d9-f2d9a1679d3d" />
|
||||
|
||||
|
||||
## Version 0.0.45 is released (04.03.2026)
|
||||
## Version 0.0.40 is released (05.01.2025)
|
||||
## What is new
|
||||
|
||||
- Configurable debounce for inline completion requests - setting debounce_ms.
|
||||
llama-vscode will wait debounce_ms after a keystroke before sending a request to the LLM for inline code completion. If in the meantime there is another keystroke, the request for the previous keystroke is cancelled. Useful on low end hardware to avoid triggering code completion on every keystroke.
|
||||
|
||||
- Notification "Extension is updated" is shown only on version change, not on every setting change (as was before)
|
||||
|
||||
|
||||
## Version 0.0.44 is released (03.03.2026)
|
||||
## What is new
|
||||
|
||||
- Subagents implemented (with tool delegate_task) - now each agent, which has "Available as Subagent" checked could be used as a subagent
|
||||
|
||||
- new agent - Unit Test Writer
|
||||
|
||||
- new tool create_agent
|
||||
|
||||
- new agent "Agent creator"
|
||||
|
||||
- Files SOUL.md and USER.md (if available in the project root) will be added to the context
|
||||
|
||||
Generation of multiple completions in parallel:
|
||||
- Setting max_parallel_completions determines how many completions to generate in parallel (default 3)
|
||||
- Shortcuts - Alt+] - next completion, Alt+[ - previous completion
|
||||
- Requires llama.cpp after December, 6, 2025 (commit c42712b) but is backword compatible (generates one completion for older versions)
|
||||
- [More details](https://github.com/ggml-org/llama.vscode/wiki/Parallel-completions)
|
||||
|
||||
## Setup instructions for llama.cpp server
|
||||
|
||||
|
|
@ -725,17 +691,6 @@ There are different ways to select a model
|
|||
- In Llama Agent click the button for selecting a model (completion, chat, embeddings, tools)
|
||||
- In llama-vscode menu select "Completion models..." (or chat, embeddings, tools)
|
||||
- Select an env. This will select the models, which are part of the env
|
||||
## More context files
|
||||
|
||||
### What are AGENTS.md, SOUL.md, and USER.md
|
||||
If in the project folder there are files: AGENTS.md, SOUL.md, and USER.md, they are used to provide additional context to the AI model when a request is sent.
|
||||
AGENTS.md - instructions related with agents
|
||||
SOUL.md - instructions related with the "soul" of the agent (how to behave, what values to follow, etc.)
|
||||
USER.md - information about the user - preferences, additional information, etc.
|
||||
These files are not mandatory. Ther are added because in some systems are quite popular and probably could be reused from there.
|
||||
|
||||
### How to use them
|
||||
Just add one or more of these files to the project folder.
|
||||
## Parallel Completions
|
||||
|
||||
### Overview
|
||||
|
|
@ -1037,18 +992,6 @@ Settings:
|
|||
|
||||
https://github.com/user-attachments/assets/8f0b4575-104f-471c-be3f-f3d5b58aeee1
|
||||
|
||||
## Subagents
|
||||
|
||||
### What are subagents
|
||||
Subagents are a way to optimize the user of LLM context. Some tasks are be executed in a separate session and only the final result is added to the context of the original agent session.
|
||||
This is implemented with the tool delegate_task. If the delegate_task tool is enabled, the agent could decide to delegate some tasks to subagents. Each agent could be used as a subagent if it's field "Available as Subagent" is checked.
|
||||
|
||||
### How to use them
|
||||
1. Make sure the tool delegate_task is enabled.
|
||||
2. Make sure the agents you want to use as subagents have the field "Available as Subagent" checked and meaningful description.
|
||||
3. Write a prompt, for which it is good idea to use the subagent. Alternatively, you could directly ask in the prompt to use the subagent.
|
||||
|
||||
The agent "Agent creator" makes it easier to create agents (which could be used as subagents).
|
||||
## Update todos tool
|
||||
|
||||
### Overview
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import { Agent, Chat, Env, LlmModel } from "./types";
|
|||
import { ModelType, PERSISTENCE_KEYS } from "./constants";
|
||||
import { ApiKeyService } from "./services/api-key-service";
|
||||
import { OpenAiCompModelStrategy } from "./services/openai-comp-model-strategy";
|
||||
import { LlamaChatModelProvider } from "./llama-chat-model-provider";
|
||||
|
||||
export class Application {
|
||||
public static readonly emptyModel = {name: ""};
|
||||
|
|
@ -64,7 +63,6 @@ export class Application {
|
|||
public agentCommandService: AgentCommandService
|
||||
public chatService: ChatService
|
||||
public apiKeyService: ApiKeyService
|
||||
public llamaChatModelProvider: LlamaChatModelProvider
|
||||
|
||||
private selectedComplModel: LlmModel = Application.emptyModel
|
||||
private selectedChatModel: LlmModel = Application.emptyModel
|
||||
|
|
@ -107,7 +105,6 @@ export class Application {
|
|||
this.agentCommandService = new AgentCommandService(this)
|
||||
this.chatService = new ChatService(this)
|
||||
this.apiKeyService = new ApiKeyService(this)
|
||||
this.llamaChatModelProvider = new LlamaChatModelProvider(this);
|
||||
}
|
||||
|
||||
public static getInstance(context: vscode.ExtensionContext): Application {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { Utils } from './utils';
|
|||
import { Env, LlmModel } from './types';
|
||||
import { env } from 'process';
|
||||
import { PERSISTENCE_KEYS, SETTING_NAME_FOR_LIST, UiView } from './constants';
|
||||
import {LlamaChatModelProvider} from "./llama-chat-model-provider";
|
||||
|
||||
export class Architect {
|
||||
private app: Application
|
||||
|
|
@ -27,14 +26,6 @@ export class Architect {
|
|||
this.app.menu.showHowToUseLlamaVscode();
|
||||
this.app.persistence.setGlobalValue("isFirstStart", false)
|
||||
}
|
||||
const currentVersion = vscode.extensions.getExtension('ggml-org.llama-vscode')?.packageJSON?.version as string | undefined;
|
||||
const storedVersion = this.app.persistence.getGlobalValue(PERSISTENCE_KEYS.EXTENSION_VERSION) as string | undefined;
|
||||
if (currentVersion && storedVersion && currentVersion !== storedVersion) {
|
||||
vscode.window.showInformationMessage(this.app.configuration.getUiText(`llama-vscode extension is updated.`) ?? "");
|
||||
}
|
||||
if (currentVersion) {
|
||||
this.app.persistence.setGlobalValue(PERSISTENCE_KEYS.EXTENSION_VERSION, currentVersion);
|
||||
}
|
||||
await this.installUpgradeLlamaCpp(isFirstStart);
|
||||
if (this.app.configuration.env_start_last_used){
|
||||
let lastEnv = this.app.persistence.getValue("selectedEnv")
|
||||
|
|
@ -79,6 +70,7 @@ export class Architect {
|
|||
if (this.app.configuration.isRagConfigChanged(event)) this.init();
|
||||
if (this.app.configuration.isToolChanged(event)) this.app.tools.init();
|
||||
if (this.app.configuration.isEnvViewSettingChanged(event)) this.app.llamaWebviewProvider.updateLlamaView();
|
||||
vscode.window.showInformationMessage(this.app.configuration.getUiText(`llama-vscode extension is updated.`)??"");
|
||||
});
|
||||
context.subscriptions.push(configurationChangeDisp);
|
||||
}
|
||||
|
|
@ -212,22 +204,6 @@ export class Architect {
|
|||
);
|
||||
}
|
||||
|
||||
registerLlavaVscodeModelProvider = (context: vscode.ExtensionContext) => {
|
||||
// Register the llama.vscode language model chat provider for GitHub Copilot Chat
|
||||
|
||||
context.subscriptions.push(vscode.lm.registerLanguageModelChatProvider(
|
||||
'llama-vscode',
|
||||
this.app.llamaChatModelProvider
|
||||
));
|
||||
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((event) => {
|
||||
if (event.affectsConfiguration('llama-vscode.endpoint_chat')
|
||||
|| event.affectsConfiguration('llama-vscode.endpoint_tools')
|
||||
|| event.affectsConfiguration('llama-vscode.ai_api_version')) {
|
||||
this.app.llamaChatModelProvider.notifyModelsChanged();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
registerGenarateCommitMsg = (context: vscode.ExtensionContext) => {
|
||||
const generateCommitCommand = vscode.commands.registerCommand(
|
||||
'extension.generateGitCommitMessage',
|
||||
|
|
|
|||
|
|
@ -30,15 +30,6 @@ export class Completion {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Debounce: wait for the user to pause typing before hitting the backend
|
||||
if (context.triggerKind == vscode.InlineCompletionTriggerKind.Automatic && this.app.configuration.debounce_ms > 0) {
|
||||
await Utils.delay(this.app.configuration.debounce_ms);
|
||||
if (token.isCancellationRequested) {
|
||||
this.app.logger.addEventLog(group, "DEBOUNCE_CANCELLATION_RETURN", "")
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Start only if the previous request is finiched
|
||||
while (this.isRequestInProgress) {
|
||||
await Utils.delay(this.app.configuration.DELAY_BEFORE_COMPL_REQUEST);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ export class Configuration {
|
|||
new_embeddings_model_host = "127.0.0.1"
|
||||
new_tools_model_host = "127.0.0.1"
|
||||
auto = true;
|
||||
debounce_ms = 0;
|
||||
api_key = "";
|
||||
api_key_chat = "";
|
||||
api_key_tools = "";
|
||||
|
|
@ -74,7 +73,6 @@ export class Configuration {
|
|||
rag_max_context_file_chars = 10000
|
||||
|
||||
tool_run_terminal_command_enabled = true;
|
||||
tool_create_agent_enabled = true;
|
||||
tool_search_source_enabled = true;
|
||||
tool_read_file_enabled = true;
|
||||
tool_list_directory_enabled = true;
|
||||
|
|
@ -94,7 +92,6 @@ export class Configuration {
|
|||
tool_custom_eval_tool_code = "";
|
||||
tool_llama_vscode_help_enabled = true;
|
||||
tool_update_todo_list_enabled = true;
|
||||
tool_delegate_task_enabled = true;
|
||||
tools_max_iterations = 50;
|
||||
plan_review_frequency = 5;
|
||||
tools_log_calls = false;
|
||||
|
|
@ -197,7 +194,6 @@ export class Configuration {
|
|||
this.openai_client_model = String(config.get<string>("openai_client_model"));
|
||||
this.openai_prompt_template = String(config.get<string>("openai_prompt_template"));
|
||||
this.auto = Boolean(config.get<boolean>("auto"));
|
||||
this.debounce_ms = Number(config.get<number>("debounce_ms"));
|
||||
this.api_key = String(config.get<string>("api_key"));
|
||||
this.api_key_chat = String(config.get<string>("api_key_chat"));
|
||||
this.api_key_tools = String(config.get<string>("api_key_tools"));
|
||||
|
|
@ -226,7 +222,6 @@ export class Configuration {
|
|||
this.rag_max_context_files = Number(config.get<number>("rag_max_context_files"));
|
||||
this.rag_max_context_file_chars = Number(config.get<number>("rag_max_context_file_chars"));
|
||||
this.tool_run_terminal_command_enabled = Boolean(config.get<boolean>("tool_run_terminal_command_enabled"));
|
||||
this.tool_create_agent_enabled = Boolean(config.get<boolean>("tool_create_agent_enabled"));
|
||||
this.tool_search_source_enabled = Boolean(config.get<boolean>("tool_search_source_enabled"));
|
||||
this.tool_read_file_enabled = Boolean(config.get<boolean>("tool_read_file_enabled"));
|
||||
this.tool_list_directory_enabled = Boolean(config.get<boolean>("tool_list_directory_enabled"));
|
||||
|
|
@ -239,7 +234,6 @@ export class Configuration {
|
|||
this.tool_ask_user_enabled = Boolean(config.get<boolean>("tool_ask_user_enabled"));
|
||||
this.tool_custom_tool_enabled = Boolean(config.get<boolean>("tool_custom_tool_enabled"));
|
||||
this.tool_update_todo_list_enabled = Boolean(config.get<boolean>("tool_update_todo_list_enabled"));
|
||||
this.tool_delegate_task_enabled = Boolean(config.get<boolean>("tool_delegate_task_enabled"));
|
||||
this.tool_llama_vscode_help_enabled = Boolean(config.get<boolean>("tool_llama_vscode_help_enabled"));
|
||||
this.tool_custom_tool_description = String(config.get<string>("tool_custom_tool_description"));
|
||||
this.tool_custom_tool_source = String(config.get<string>("tool_custom_tool_source"));
|
||||
|
|
@ -321,7 +315,6 @@ export class Configuration {
|
|||
|
||||
isToolChanged = (event: vscode.ConfigurationChangeEvent) => {
|
||||
return event.affectsConfiguration("llama-vscode.tool_run_terminal_command_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_create_agent_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_search_source_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_list_directory_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_read_file_enabled")
|
||||
|
|
@ -335,7 +328,6 @@ export class Configuration {
|
|||
|| event.affectsConfiguration("llama-vscode.tool_get_diff_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_llama_vscode_help_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_update_todo_list_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_delegate_task_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_custom_eval_tool_enabled")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_custom_eval_tool_description")
|
||||
|| event.affectsConfiguration("llama-vscode.tool_custom_eval_tool_property_description")
|
||||
|
|
|
|||
|
|
@ -253,7 +253,6 @@ export const PERSISTENCE_KEYS = {
|
|||
SELECTED_CHAT: 'selectedChat' as const,
|
||||
SELECTED_AGENT: 'selectedAgent' as const,
|
||||
SELECTED_ENV: 'selectedEnv' as const,
|
||||
EXTENSION_VERSION: 'extensionVersion' as const,
|
||||
} as const;
|
||||
|
||||
export const SETTING_NAME_FOR_LIST = {
|
||||
|
|
|
|||
|
|
@ -32,10 +32,7 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
app.architect.registerWebviewProvider(context)
|
||||
app.architect.registerCommandSelectNextSuggestion(context)
|
||||
app.architect.registerCommandSelectPreviousSuggestion(context)
|
||||
app.architect.registerLlavaVscodeModelProvider(context)
|
||||
app.architect.init()
|
||||
|
||||
|
||||
}
|
||||
|
||||
export async function deactivate() {
|
||||
|
|
|
|||
236
src/lists.ts
236
src/lists.ts
|
|
@ -79,36 +79,7 @@ export const PREDEFINED_LISTS = new Map<string, any>([
|
|||
"endpoint": "http://127.0.0.1:8010"
|
||||
}
|
||||
]],
|
||||
[PREDEFINED_LISTS_KEYS.TOOLS,
|
||||
[
|
||||
{
|
||||
"name": "Qwen3.5-2B-GGUF:Q8_0 (LOCAL) (CPU)",
|
||||
"localStartCommand": "llama-server -hf unsloth/Qwen3.5-2B-GGUF:Q8_0 --jinja -c 0 -ub 1024 -b 1024 --cache-reuse 256 --port 8009 --host 127.0.0.1",
|
||||
"endpoint": "http://localhost:8009",
|
||||
"aiModel": "",
|
||||
"isKeyRequired": false
|
||||
},
|
||||
{
|
||||
"name": "Qwen3.5-2B-GGUF:Q8_0 (LOCAL) (VRAM>3GB)",
|
||||
"localStartCommand": "llama-server -hf unsloth/Qwen3.5-2B-GGUF:Q8_0 --jinja -ngl 99 -c 0 -ub 1024 -b 1024 --cache-reuse 256 --port 8009 --host 127.0.0.1",
|
||||
"endpoint": "http://localhost:8009",
|
||||
"aiModel": "",
|
||||
"isKeyRequired": false
|
||||
},
|
||||
{
|
||||
"name": "Qwen3.5-4B-GGUF:Q8_0 (LOCAL) (VRAM>6GB)",
|
||||
"localStartCommand": "llama-server -hf unsloth/Qwen3.5-4B-GGUF:Q8_0 --jinja -c 0 -ub 1024 -b 1024 --cache-reuse 256 --port 8009 --host 127.0.0.1",
|
||||
"endpoint": "http://localhost:8009",
|
||||
"aiModel": "",
|
||||
"isKeyRequired": false
|
||||
},
|
||||
{
|
||||
"name": "Qwen3.5-9B-GGUF:Q8_0 (LOCAL) (VRAM>12GB)",
|
||||
"localStartCommand": "llama-server -hf unsloth/Qwen3.5-9B-GGUF:Q8_0 --jinja -c 0 -ub 1024 -b 1024 --cache-reuse 256 --port 8009 --host 127.0.0.1",
|
||||
"endpoint": "http://localhost:8009",
|
||||
"aiModel": "",
|
||||
"isKeyRequired": false
|
||||
},
|
||||
[PREDEFINED_LISTS_KEYS.TOOLS, [
|
||||
{
|
||||
"name": "OpenAI gpt-oss 20B (LOCAL) (> 19GB VRAM)",
|
||||
"localStartCommand": "llama-server -hf ggml-org/gpt-oss-20b-GGUF -c 0 --jinja --reasoning-format none -np 2 --port 8009",
|
||||
|
|
@ -741,130 +712,8 @@ export const PREDEFINED_LISTS = new Map<string, any>([
|
|||
"get_diff",
|
||||
"edit_file",
|
||||
"ask_user",
|
||||
"update_todo_list",
|
||||
"delegate_task"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Unite test writer",
|
||||
"description": "Writes the unit tests. The input should provide a path to a source file to be tested.",
|
||||
"systemInstruction": [
|
||||
"You are an expert software engineer specializing in writing unit tests. Your task is to generate high‑quality, reliable, and maintainable unit tests based on the user’s instructions and the provided source code. You must infer the programming language, testing framework, and project conventions from the source file and any accompanying context (such as imports, file extensions, or existing test files).",
|
||||
"Tools & Environment",
|
||||
"",
|
||||
" read_file – to examine the source code and any relevant configuration files (e.g., package.json, pom.xml, requirements.txt, Cargo.toml, etc.).",
|
||||
"",
|
||||
" edit_file – to create or modify test files.",
|
||||
"",
|
||||
" run_terminal_command – to execute tests and report results.",
|
||||
"",
|
||||
"Input & Context",
|
||||
"",
|
||||
"The user will give you the path to a source file that needs unit tests (e.g., src/services/user_service.py, lib/user.dart, internal/user.go). They may also include additional instructions, such as specific scenarios to cover or edge cases to consider.",
|
||||
"Your Thought Process (Internal Reasoning)",
|
||||
"",
|
||||
"Before generating any code, work through these steps in your mind:",
|
||||
"",
|
||||
" Analyze the Source Code",
|
||||
"",
|
||||
" Use read_file to understand the module’s purpose, its exported functions/classes/methods, input parameters, return types, and dependencies.",
|
||||
"",
|
||||
" Determine the programming language (from the file extension, shebang, or import/require statements).",
|
||||
"",
|
||||
" Identify all public APIs that need testing.",
|
||||
"",
|
||||
" Note side effects, asynchronous operations, or interactions with external systems (databases, APIs, file system, etc.).",
|
||||
"",
|
||||
" Infer the Testing Conventions",
|
||||
"",
|
||||
" Look for an existing test directory (e.g., test/, tests/, spec/, __tests__/) and the naming pattern of existing test files (e.g., *.test.js, *_test.py, *_spec.rb).",
|
||||
"",
|
||||
" Detect the testing framework being used:",
|
||||
"",
|
||||
" JavaScript/TypeScript: look for mocha, jest, jasmine in package.json.",
|
||||
"",
|
||||
" Python: look for pytest, unittest in imports or config files.",
|
||||
"",
|
||||
" Java: look for JUnit in pom.xml or build.gradle.",
|
||||
"",
|
||||
" Go: look for testing package imports, etc.",
|
||||
"",
|
||||
" Determine the preferred assertion style (e.g., assert module, expect, should, assertThat).",
|
||||
"",
|
||||
" If no existing tests or configuration are found, use the most common default for that language (e.g., pytest for Python, JUnit 5 for Java, go test for Go, Mocha + assert for Node.js).",
|
||||
"",
|
||||
" Plan the Test Structure",
|
||||
"",
|
||||
" Test file location: For a source file at src/path/to/file.ext, the test file should normally be placed at test/path/to/file_test.ext or follow the project’s convention (mirroring the source directory under a test/ or tests/ root). Ensure the directory structure is created if needed.",
|
||||
"",
|
||||
" Plan the outer test suite (e.g., describe('moduleName', ...) in Mocha, a test class in JUnit, or a module‑level docstring in pytest).",
|
||||
"",
|
||||
" Plan nested suites for each function or method.",
|
||||
"",
|
||||
" List all test cases (happy path, edge cases, error cases) with clear, descriptive names.",
|
||||
"",
|
||||
" Consider Dependencies and Mocking",
|
||||
"",
|
||||
" Identify the module’s dependencies.",
|
||||
"",
|
||||
" Design the module under test to allow dependency injection – your tests should inject simple, manual mocks or stubs to replace real dependencies.",
|
||||
"",
|
||||
" Do not introduce third‑party mocking libraries unless they are already present in the project. Rely on manual mocks (e.g., creating test doubles yourself).",
|
||||
"",
|
||||
" Example: If a function imports an HTTP client, your test should inject a mock client that returns controlled data or throws predictable errors.",
|
||||
"",
|
||||
"Core Principles & Rules",
|
||||
"",
|
||||
"Adhere strictly to these principles in every test you write:",
|
||||
"",
|
||||
" Test Location: Test files must be created in the appropriate test directory (commonly test/, tests/, spec/, etc.) mirroring the source structure. Use the naming convention inferred from the project.",
|
||||
"",
|
||||
" Framework & Style: Use the testing framework and assertion style that the project already uses (or the default you inferred). Write idiomatic tests for that language.",
|
||||
"",
|
||||
" Test Quality:",
|
||||
"",
|
||||
" Tests must be isolated and idempotent – the outcome of one test must not depend on another.",
|
||||
"",
|
||||
" Each test should verify one specific behavior.",
|
||||
"",
|
||||
" Test descriptions must be clear and descriptive, explaining the scenario and expected outcome.",
|
||||
"",
|
||||
" Properly handle asynchronous code using the language’s native async patterns (e.g., async/await, Future, Promise). Ensure the test framework waits for completion.",
|
||||
"",
|
||||
" Reset any module state or mocks in setup/teardown hooks (e.g., beforeEach, setUp, @BeforeEach) to guarantee tests can run in any order.",
|
||||
"",
|
||||
" Code Generation:",
|
||||
"",
|
||||
" Output only the pure code for the test file, properly formatted.",
|
||||
"",
|
||||
" Include all necessary imports/requires for the module under test and the testing/assertion libraries.",
|
||||
"",
|
||||
" Import the actual functions/classes from the source file. Mocking is done inside the test, not by mocking the import itself.",
|
||||
"",
|
||||
" No Source Modification: You cannot modify the source code. If the source is untestable due to poor design (e.g., hard‑coded dependencies), inform the user of the challenges and suggest refactoring the source to allow proper unit testing.",
|
||||
"",
|
||||
"Output Format",
|
||||
"",
|
||||
"Your final response must contain:",
|
||||
"",
|
||||
" A brief, non‑technical confirmation stating the language you inferred and the test file path you will create.",
|
||||
"",
|
||||
"Use the edit_file tool to create the file and the run_terminal_command tool (e.g., npx mocha 'test/services/userService.spec.ts') to verify your work, reporting the results back to the user.",
|
||||
"",
|
||||
"Crucially, you cannot modify the source code itself. If the source code is not testable due to poor design (e.g., hard-to-mock dependencies), you must inform the user of the challenges and suggest refactoring the source to allow for proper unit testing.",
|
||||
""
|
||||
],
|
||||
"tools": [
|
||||
"run_terminal_command",
|
||||
"search_source",
|
||||
"read_file",
|
||||
"list_directory",
|
||||
"regex_search",
|
||||
"delete_file",
|
||||
"edit_file",
|
||||
"update_todo_list"
|
||||
],
|
||||
"subagentEnabled": false
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Ask",
|
||||
|
|
@ -916,87 +765,6 @@ export const PREDEFINED_LISTS = new Map<string, any>([
|
|||
"get_diff",
|
||||
"ask_user"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Agent creator",
|
||||
"description": "Creates new agent. Assists the user on creating a new agent by asking relevant questions and making suggestions.",
|
||||
"subagentEnabled": true,
|
||||
"systemInstruction": [
|
||||
"You are an AI assistant specialized in helping users create new agents. Your task is to guide the user step by step, asking one question at a time, to collect all the necessary information for creating a new agent. Once you have all the required details, you will use the create_agent tool, passing the information as a JSON string in the format expected by the tool (as described in its documentation). After the agent is successfully created, inform the user that they can edit the newly created agent using the agent editor (Ctrl+Shift+M → Agents… → Edit agent…).",
|
||||
"",
|
||||
"Required Information:",
|
||||
"",
|
||||
" name (string): The name of the new agent.",
|
||||
"",
|
||||
" description (string): A brief description of what the agent does.",
|
||||
"",
|
||||
" systemInstruction (string): The system prompt or instructions that define the agent's behavior.",
|
||||
"",
|
||||
"Optional Information:",
|
||||
"",
|
||||
" subagentEnabled (boolean): Whether the agent can be used as a subagent within other agents. Ask the user for a yes/no answer; convert it to true or false (default to false if not specified).",
|
||||
"",
|
||||
" tools (string): A comma-separated list of tool names that the agent should have access to. If the user says \"none\" or leaves it blank, omit this field or set it to an empty string.",
|
||||
"",
|
||||
"Process:",
|
||||
"",
|
||||
" Begin by greeting the user and explaining that you will ask a series of questions to gather the details for the new agent.",
|
||||
"",
|
||||
" Ask for the name first. Wait for the user's response.",
|
||||
"",
|
||||
" After receiving the name, ask for the description.",
|
||||
"",
|
||||
" Then ask for the systemInstruction.",
|
||||
"",
|
||||
" Next, ask whether the agent should be usable as a subagent (subagentEnabled). Prompt for a yes/no answer. If the answer is ambiguous, ask for clarification.",
|
||||
"",
|
||||
" Finally, ask for any tools the agent should have. Prompt for a comma-separated list or indicate that they can say \"none\".",
|
||||
"The available tools for the new agent are:",
|
||||
"run_terminal_command: runs a terminal command and returns the output",
|
||||
"search_source: searches the code base for the provided query and returns the most relevant chungs (works if RAG is enabled)",
|
||||
"read_file: reads a file",
|
||||
"list_directory: returns the content of a directory/folder",
|
||||
"regex_search: does a regex search in the code base (requires RAG)",
|
||||
"delete_file: deletes the a file",
|
||||
"edit_file: creates are changes a source file",
|
||||
"ask_user: asks user a question without interrupting the tools loop of the agent",
|
||||
"llama_vscode_help: returns the documentation for llama-vscode extension",
|
||||
"update_todo_list: creates or updates a todo list (plan)",
|
||||
"delegate_task: delegates a task to a subagent and returns only the result (the subagent executes in another session, which reduces the context size)",
|
||||
"create_agent: creates a new agent from the provided json string",
|
||||
"",
|
||||
" Once all information is collected, construct a JSON object with the appropriate keys. Ensure that boolean values are represented as true or false (without quotes) and that the tools string is included only if provided.",
|
||||
"",
|
||||
" Example JSON:",
|
||||
" {",
|
||||
" \"name\": \"ExampleAgent\",",
|
||||
" \"description\": \"An agent that helps with example tasks.\",",
|
||||
" \"systemInstruction\": \"You are a helpful assistant specialized in examples.\",",
|
||||
" \"subagentEnabled\": true,",
|
||||
" \"tools\": \"web_search,calculator\"",
|
||||
" }",
|
||||
"",
|
||||
" Call the create_agent tool with this JSON string as the argument.",
|
||||
"",
|
||||
" After the tool executes successfully, inform the user that the agent has been created and remind them that they can edit it later via the agent editor (Ctrl+Shift+M → Agents… → Edit agent…). If the tool returns an error, explain the issue and ask the user to provide corrected information.",
|
||||
"",
|
||||
"Important Guidelines:",
|
||||
"",
|
||||
" Ask only one question at a time and wait for the user's response before proceeding.",
|
||||
"",
|
||||
" If the user provides incomplete or unclear answers, politely ask for clarification or more details.",
|
||||
"",
|
||||
" Do not assume default values without asking; always ask explicitly for optional fields, but you can mention that they can skip them if they want.",
|
||||
"",
|
||||
" Keep your tone friendly and helpful. Make the process feel like a guided conversation.",
|
||||
"",
|
||||
" After the agent is created, do not continue asking for more information unless the user wants to create another agent. If they do, you may restart the process.",
|
||||
"",
|
||||
""
|
||||
],
|
||||
"tools": [
|
||||
"create_agent"
|
||||
]
|
||||
}
|
||||
]],
|
||||
[PREDEFINED_LISTS_KEYS.AGENT_COMMANDS, [
|
||||
|
|
|
|||
|
|
@ -42,19 +42,6 @@ export class LlamaAgent {
|
|||
resetMessages = () => {
|
||||
let systemPromt = this.app.prompts.TOOLS_SYSTEM_PROMPT_ACTION;
|
||||
if (this.app.isAgentSelected()) systemPromt = this.app.getAgent().systemInstruction.join("\n")
|
||||
if (this.app.configuration.tool_delegate_task_enabled) {
|
||||
let agentPromtPrefix = " \n\n " + this.app.prompts.SUBAGENTS_DESCRIPTION;
|
||||
agentPromtPrefix += " \n\n Subagents:";
|
||||
let subagentsList = "";
|
||||
for (let agent of this.app.configuration.agents_list) {
|
||||
if (agent.subagentEnabled){
|
||||
subagentsList += " \n" + agent.name + ": " + agent.description;
|
||||
}
|
||||
}
|
||||
if (subagentsList.length > 0) {
|
||||
systemPromt += agentPromtPrefix + subagentsList;
|
||||
}
|
||||
}
|
||||
let worspaceFolder = "";
|
||||
if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders[0]){
|
||||
worspaceFolder = " Project root folder: " + vscode.workspace.workspaceFolders[0].uri.fsPath;
|
||||
|
|
@ -69,21 +56,7 @@ export class LlamaAgent {
|
|||
}
|
||||
} else {
|
||||
const absolutePath = Utils.getAbsolutFilePath("llama-vscode-rules.md");
|
||||
if (fs.existsSync(absolutePath)) {
|
||||
projectContext += " \n\nAdditional rules from the user: \n" + fs.readFileSync(absolutePath, "utf-8");
|
||||
}
|
||||
}
|
||||
const agentsAbsolutePath = Utils.getAbsolutFilePath("AGENTS.md");
|
||||
if (fs.existsSync(agentsAbsolutePath)) {
|
||||
projectContext += " \n\nInstructions from " + agentsAbsolutePath + ": \n" + fs.readFileSync(agentsAbsolutePath, "utf-8");
|
||||
}
|
||||
const soulAbsolutePath = Utils.getAbsolutFilePath("SOUL.md");
|
||||
if (fs.existsSync(soulAbsolutePath)) {
|
||||
projectContext += " \n\n AI soul desription from " + soulAbsolutePath + ": \n" + fs.readFileSync(soulAbsolutePath, "utf-8");
|
||||
}
|
||||
const userInstructionsPath = Utils.getAbsolutFilePath("USER.md");
|
||||
if (fs.existsSync(userInstructionsPath)) {
|
||||
projectContext += " \n\nUser profile from " + userInstructionsPath + ": \n" + fs.readFileSync(userInstructionsPath, "utf-8");
|
||||
if (fs.existsSync(absolutePath)) projectContext += " \n\nAdditional rules from the user: \n" + fs.readFileSync(absolutePath, "utf-8");
|
||||
}
|
||||
this.messages = [
|
||||
{
|
||||
|
|
@ -94,15 +67,15 @@ export class LlamaAgent {
|
|||
this.logText = "";
|
||||
}
|
||||
|
||||
selectChat = async (chat: Chat) => {
|
||||
if (chat && chat.defaultAgent) await this.app.agentService.selectAgent(chat.defaultAgent);
|
||||
selectChat = (chat: Chat) => {
|
||||
if (chat && chat.defaultAgent) this.app.agentService.selectAgent(chat.defaultAgent);
|
||||
this.resetMessages();
|
||||
|
||||
if (chat){
|
||||
const currentChat = this.app.getChat();
|
||||
this.messages = chat.messages??[];
|
||||
this.logText = chat.log??"";
|
||||
}
|
||||
}
|
||||
// this.app.llamaWebviewProvider.logInUi(this.logText);
|
||||
this.resetContext();
|
||||
}
|
||||
|
|
@ -403,7 +376,15 @@ export class LlamaAgent {
|
|||
this.logText += " \nAgent session finished. \n\n"
|
||||
this.app.llamaWebviewProvider.logInUi(this.logText);
|
||||
this.app.llamaWebviewProvider.setState("AI finished")
|
||||
await this.updateChat();
|
||||
let chat = this.app.getChat()
|
||||
if (!this.app.isChatSelected()){
|
||||
chat.name = this.logText.slice(0, 25);
|
||||
chat.id = Date.now().toString(36);
|
||||
chat.description = new Date().toLocaleString() + " " + this.logText.slice(0,150)
|
||||
}
|
||||
chat.messages = this.messages;
|
||||
chat.log = this.logText;
|
||||
await this.app.chatService.selectUpdateChat(chat)
|
||||
|
||||
// Clean up AbortController
|
||||
this.abortController = null;
|
||||
|
|
@ -441,18 +422,6 @@ export class LlamaAgent {
|
|||
return progress;
|
||||
}
|
||||
|
||||
public async updateChat() {
|
||||
let chat = this.app.getChat();
|
||||
if (!this.app.isChatSelected()) {
|
||||
chat.name = this.logText.slice(0, 25);
|
||||
chat.id = Date.now().toString(36);
|
||||
chat.description = new Date().toLocaleString() + " " + this.logText.slice(0, 150);
|
||||
}
|
||||
chat.messages = this.messages;
|
||||
chat.log = this.logText;
|
||||
await this.app.chatService.selectUpdateChat(chat);
|
||||
}
|
||||
|
||||
private removeFile(todoFile: string) {
|
||||
if (fs.existsSync(todoFile)) {
|
||||
fs.unlinkSync(todoFile);
|
||||
|
|
|
|||
|
|
@ -1,237 +0,0 @@
|
|||
import * as vscode from 'vscode';
|
||||
import axios from 'axios';
|
||||
import { Application } from './application';
|
||||
import { Utils } from './utils';
|
||||
|
||||
const VENDOR = 'llama-vscode';
|
||||
|
||||
// Default token limits used when the server does not report them
|
||||
const DEFAULT_MAX_INPUT_TOKENS = 8192;
|
||||
const DEFAULT_MAX_OUTPUT_TOKENS = 4096;
|
||||
|
||||
interface OpenAIModel {
|
||||
id: string;
|
||||
object?: string;
|
||||
}
|
||||
|
||||
interface OpenAIModelsResponse {
|
||||
data: OpenAIModel[];
|
||||
}
|
||||
|
||||
export class LlamaChatModelProvider implements vscode.LanguageModelChatProvider {
|
||||
private readonly _onDidChangeLanguageModelChatInformation = new vscode.EventEmitter<void>();
|
||||
readonly onDidChangeLanguageModelChatInformation: vscode.Event<void> =
|
||||
this._onDidChangeLanguageModelChatInformation.event;
|
||||
|
||||
constructor(private readonly app: Application) {}
|
||||
|
||||
/** Called by the configuration change handler to notify VS Code that models may have changed. */
|
||||
notifyModelsChanged(): void {
|
||||
this._onDidChangeLanguageModelChatInformation.fire();
|
||||
}
|
||||
|
||||
async provideLanguageModelChatInformation(
|
||||
_options: vscode.PrepareLanguageModelChatModelOptions,
|
||||
_token: vscode.CancellationToken
|
||||
): Promise<vscode.LanguageModelChatInformation[]> {
|
||||
const endpoint = this.getChatEndpoint();
|
||||
if (!endpoint) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const requestConfig = this.app.configuration.axiosRequestConfigChat;
|
||||
const response = await axios.get<OpenAIModelsResponse>(
|
||||
`${Utils.trimTrailingSlash(endpoint)}/${this.app.configuration.ai_api_version}/models`,
|
||||
requestConfig
|
||||
);
|
||||
|
||||
if (!response.data?.data?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return response.data.data.map((model) => ({
|
||||
id: model.id,
|
||||
name: model.id,
|
||||
family: VENDOR,
|
||||
version: '1',
|
||||
maxInputTokens: DEFAULT_MAX_INPUT_TOKENS,
|
||||
maxOutputTokens: DEFAULT_MAX_OUTPUT_TOKENS,
|
||||
capabilities: {
|
||||
toolCalling: true,
|
||||
imageInput: false,
|
||||
},
|
||||
}));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async provideLanguageModelChatResponse(
|
||||
model: vscode.LanguageModelChatInformation,
|
||||
messages: readonly vscode.LanguageModelChatRequestMessage[],
|
||||
options: vscode.ProvideLanguageModelChatResponseOptions,
|
||||
progress: vscode.Progress<vscode.LanguageModelResponsePart>,
|
||||
token: vscode.CancellationToken
|
||||
): Promise<void> {
|
||||
const endpoint = this.getChatEndpoint();
|
||||
if (!endpoint) {
|
||||
throw new Error('No chat endpoint configured');
|
||||
}
|
||||
|
||||
const openaiMessages = messages.map((msg) => ({
|
||||
role: msg.role === vscode.LanguageModelChatMessageRole.User ? 'user' : 'assistant',
|
||||
content: msg.content
|
||||
.map((part: unknown) =>
|
||||
part instanceof vscode.LanguageModelTextPart ? part.value : ''
|
||||
)
|
||||
.join(''),
|
||||
}));
|
||||
|
||||
const tools = options.tools?.map((t: vscode.LanguageModelToolInformation) => ({
|
||||
type: 'function',
|
||||
function: {
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
parameters: t.inputSchema,
|
||||
},
|
||||
}));
|
||||
|
||||
const requestBody: Record<string, unknown> = {
|
||||
model: model.id,
|
||||
messages: openaiMessages,
|
||||
stream: true,
|
||||
max_tokens: DEFAULT_MAX_OUTPUT_TOKENS,
|
||||
...(options.modelOptions?.temperature !== undefined && {
|
||||
temperature: options.modelOptions.temperature,
|
||||
}),
|
||||
...(tools?.length && { tools }),
|
||||
};
|
||||
|
||||
const abortController = new AbortController();
|
||||
token.onCancellationRequested(() => abortController.abort());
|
||||
|
||||
const requestConfig = this.app.configuration.axiosRequestConfigTools;
|
||||
const streamResponse = await axios.post<NodeJS.ReadableStream>(
|
||||
`${Utils.trimTrailingSlash(endpoint)}/${this.app.configuration.ai_api_version}/chat/completions`,
|
||||
requestBody,
|
||||
{ ...requestConfig, responseType: 'stream' as const, signal: abortController.signal }
|
||||
);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const readable = streamResponse.data;
|
||||
let buffer = '';
|
||||
// Accumulated tool call data indexed by call index
|
||||
const toolCalls: { id: string; name: string; arguments: string }[] = [];
|
||||
|
||||
const finalize = () => {
|
||||
// Emit any completed tool calls that weren't emitted yet
|
||||
for (const tc of toolCalls) {
|
||||
if (tc.id && tc.name) {
|
||||
try {
|
||||
progress.report(
|
||||
new vscode.LanguageModelToolCallPart(tc.id, tc.name, JSON.parse(tc.arguments || '{}'))
|
||||
);
|
||||
} catch (e) {
|
||||
console.warn('[llama-vscode] Failed to parse tool call arguments:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
};
|
||||
|
||||
token.onCancellationRequested(() => {
|
||||
(readable as any).destroy?.();
|
||||
resolve();
|
||||
});
|
||||
|
||||
readable.on('data', (chunk: Buffer) => {
|
||||
buffer += chunk.toString('utf8');
|
||||
const lines = buffer.split(/\r?\n/);
|
||||
buffer = lines.pop() ?? '';
|
||||
|
||||
for (const line of lines) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || !trimmed.startsWith('data:')) {
|
||||
continue;
|
||||
}
|
||||
const payload = trimmed.slice(5).trim();
|
||||
if (payload === '[DONE]') {
|
||||
finalize();
|
||||
readable.removeAllListeners();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const json = JSON.parse(payload);
|
||||
const choice = json.choices?.[0];
|
||||
if (!choice) {
|
||||
continue;
|
||||
}
|
||||
const delta = choice.delta ?? {};
|
||||
if (typeof delta.content === 'string' && delta.content) {
|
||||
progress.report(new vscode.LanguageModelTextPart(delta.content));
|
||||
}
|
||||
if (Array.isArray(delta.tool_calls)) {
|
||||
for (const tc of delta.tool_calls) {
|
||||
const idx: number = typeof tc.index === 'number' ? tc.index : 0;
|
||||
if (!toolCalls[idx]) {
|
||||
toolCalls[idx] = { id: '', name: '', arguments: '' };
|
||||
}
|
||||
if (tc.id) {
|
||||
toolCalls[idx].id = tc.id;
|
||||
}
|
||||
if (tc.function?.name) {
|
||||
toolCalls[idx].name = tc.function.name;
|
||||
}
|
||||
if (tc.function?.arguments) {
|
||||
toolCalls[idx].arguments += tc.function.arguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Skip malformed SSE chunks
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
readable.on('end', () => {
|
||||
finalize();
|
||||
});
|
||||
|
||||
readable.on('error', (err: Error) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
provideTokenCount(
|
||||
_model: vscode.LanguageModelChatInformation,
|
||||
text: string | vscode.LanguageModelChatRequestMessage,
|
||||
_token: vscode.CancellationToken
|
||||
): Thenable<number> {
|
||||
const content =
|
||||
typeof text === 'string'
|
||||
? text
|
||||
: text.content
|
||||
.map((p: unknown) => (p instanceof vscode.LanguageModelTextPart ? p.value : ''))
|
||||
.join('');
|
||||
// Rough approximation: 1 token ≈ 4 characters. The llama.cpp server does not expose a
|
||||
// tokenization endpoint via the standard OpenAI API, so we use this heuristic.
|
||||
// Actual token counts may differ depending on the model's tokenizer.
|
||||
return Promise.resolve(Math.ceil(content.length / 4));
|
||||
}
|
||||
|
||||
private getChatEndpoint(): string {
|
||||
const selectedModel = this.app.getToolsModel();
|
||||
if (selectedModel?.endpoint) {
|
||||
return selectedModel.endpoint;
|
||||
}
|
||||
if (this.app.configuration.endpoint_chat) {
|
||||
return this.app.configuration.endpoint_chat;
|
||||
}
|
||||
if (this.app.configuration.endpoint_tools) {
|
||||
return this.app.configuration.endpoint_tools;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ export interface LlamaToolsResponse {
|
|||
choices: [{
|
||||
message:{content?: string, tool_calls?:[{id:string, function: {name:string, arguments: string}}]},
|
||||
finish_reason?: string,
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -108,12 +109,11 @@ export class LlamaServer {
|
|||
private createRequestPayload(noPredict: boolean, inputPrefix: string, inputSuffix: string, chunks: any[], prompt: string, model: string, nindent?: number) {
|
||||
if (noPredict) {
|
||||
return {
|
||||
id_slot: 0,
|
||||
input_prefix: inputPrefix,
|
||||
input_suffix: inputSuffix,
|
||||
input_extra: chunks,
|
||||
prompt,
|
||||
n_predict: 0,
|
||||
n_predict: 0,
|
||||
samplers: [],
|
||||
cache_prompt: true,
|
||||
t_max_prompt_ms: this.app.configuration.t_max_prompt_ms,
|
||||
|
|
@ -123,10 +123,9 @@ export class LlamaServer {
|
|||
}
|
||||
|
||||
return {
|
||||
id_slot: 0,
|
||||
input_prefix: inputPrefix,
|
||||
input_suffix: inputSuffix,
|
||||
input_extra: chunks,
|
||||
input_extra: chunks,
|
||||
prompt,
|
||||
n_predict: this.app.configuration.n_predict,
|
||||
n_cmpl: this.app.configuration.max_parallel_completions,
|
||||
|
|
@ -240,10 +239,10 @@ export class LlamaServer {
|
|||
private createToolsRequestPayload(messages: ChatMessage[], model: string, stream = false, imagePath: string = "") {
|
||||
this.app.tools.addSelectedTools();
|
||||
let filteredMsgs = this.filterThoughtFromMsgs(messages)
|
||||
|
||||
|
||||
// Add image with base64 encoding
|
||||
if (imagePath && fs.existsSync(imagePath)) {
|
||||
|
||||
|
||||
var imgType = ""
|
||||
for (var suffix in SUPPORTED_IMG_FILE_EXTS){
|
||||
if (imagePath.endsWith(suffix)) {
|
||||
|
|
@ -273,8 +272,8 @@ export class LlamaServer {
|
|||
filteredMsgs.push(imageMessage);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
return {
|
||||
"messages": filteredMsgs,
|
||||
"stream": stream,
|
||||
"temperature": 0.8,
|
||||
|
|
@ -285,12 +284,12 @@ export class LlamaServer {
|
|||
};
|
||||
}
|
||||
|
||||
private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
||||
private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
||||
let filteredMsgs = this.filterThoughtFromMsgs(messages)
|
||||
const summaryPromptMsgs: ChatMessage[] = [
|
||||
{
|
||||
role: 'system',
|
||||
content: `Summarize the conversation concisely, preserving technical details and code solutions.`
|
||||
role: 'system',
|
||||
content: `Summarize the conversation concisely, preserving technical details and code solutions.`
|
||||
},
|
||||
...filteredMsgs
|
||||
];
|
||||
|
|
@ -318,7 +317,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
|
||||
// else, default to llama.cpp
|
||||
let { endpoint, model, requestConfig } = this.getComplModelProperties();
|
||||
if (!endpoint) {
|
||||
if (!endpoint) {
|
||||
const selectionMessate = "Select a completion model or an env with completion model to use code completion (code suggestions by AI)."
|
||||
const shouldSelectModel = await Utils.showUserChoiceDialog(selectionMessate, "Select")
|
||||
if (shouldSelectModel){
|
||||
|
|
@ -352,7 +351,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
chunks: any,
|
||||
nindent: number
|
||||
): Promise<LlamaChatResponse | undefined> => {
|
||||
|
||||
|
||||
let { endpoint, model, requestConfig } = this.getChatModelProperties();
|
||||
|
||||
const response = await axios.post<LlamaChatResponse>(
|
||||
|
|
@ -382,7 +381,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
messages: ChatMessage[],
|
||||
isSummarization = false,
|
||||
onDelta?: (delta: string) => void,
|
||||
abortSignal?: AbortSignal,
|
||||
abortSignal?: AbortSignal,
|
||||
imagePath = ""
|
||||
): Promise<LlamaToolsResponse | undefined> => {
|
||||
let selectedModel: LlmModel = this.app.getToolsModel();
|
||||
|
|
@ -391,7 +390,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
|
||||
let endpoint = this.app.configuration.endpoint_tools;
|
||||
if (selectedModel?.endpoint !== undefined && selectedModel.endpoint) endpoint = selectedModel.endpoint;
|
||||
|
||||
|
||||
let requestConfig = this.app.configuration.axiosRequestConfigTools;
|
||||
if (selectedModel?.isKeyRequired !== undefined && selectedModel.isKeyRequired){
|
||||
const apiKey = this.app.persistence.getApiKey(selectedModel.endpoint??"");
|
||||
|
|
@ -404,10 +403,10 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let uri = `${Utils.trimTrailingSlash(endpoint)}/${this.app.configuration.ai_api_version}/chat/completions`;
|
||||
let request: any;
|
||||
|
||||
|
||||
if (isSummarization) {
|
||||
request = this.createGetSummaryRequestPayload(messages, model);
|
||||
const response = await axios.post<LlamaToolsResponse>(
|
||||
|
|
@ -519,7 +518,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
updateExtraContext = (chunks: any[]): void => {
|
||||
// If the server is OpenAI compatible, use the OpenAI API to prepare for the next FIM
|
||||
|
|
@ -544,7 +543,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
|
||||
let endpoint = this.app.configuration.endpoint_embeddings;
|
||||
if (selectedModel.endpoint) endpoint = selectedModel.endpoint;
|
||||
|
||||
|
||||
let requestConfig = this.app.configuration.axiosRequestConfigEmbeddings;
|
||||
if (selectedModel.isKeyRequired){
|
||||
const apiKey = this.app.persistence.getApiKey(selectedModel.endpoint??"");
|
||||
|
|
@ -557,7 +556,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const response = await axios.post<LlamaEmbeddingsResponse>(
|
||||
`${Utils.trimTrailingSlash(endpoint)}/v1/embeddings`,
|
||||
{
|
||||
|
|
@ -698,7 +697,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
name: 'llama-vscode Command Terminal'
|
||||
});
|
||||
// }
|
||||
|
||||
|
||||
this.vsCodeCommandTerminal.show(true);
|
||||
this.vsCodeCommandTerminal.sendText(`echo "Executing: ${command}"`);
|
||||
try {
|
||||
|
|
@ -707,7 +706,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
// Show output in terminal
|
||||
this.vsCodeCommandTerminal.sendText(`echo "Command completed successfully"`);
|
||||
this.vsCodeCommandTerminal.sendText(`echo "Output: ${stdout.trim()}"`);
|
||||
|
||||
|
||||
return { stdout, stderr };
|
||||
} catch (error: any) {
|
||||
this.vsCodeCommandTerminal.sendText(`echo "Command failed: ${error.message}"`);
|
||||
|
|
@ -772,7 +771,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
this.vsCodeCommandTerminal = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
killToolsCmd = (): void => {
|
||||
if (this.vsCodeToolsTerminal) {
|
||||
this.vsCodeToolsTerminal.dispose();
|
||||
|
|
@ -788,7 +787,7 @@ private createGetSummaryRequestPayload(messages: ChatMessage[], model: string) {
|
|||
let endpoint = this.app.configuration.endpoint_chat;
|
||||
let model = this.app.configuration.ai_model;
|
||||
let requestConfig = this.app.configuration.axiosRequestConfigChat;
|
||||
if (!endpoint) {
|
||||
if (!endpoint) {
|
||||
endpoint = this.app.configuration.endpoint_tools;
|
||||
requestConfig = this.app.configuration.axiosRequestConfigTools;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,17 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
this.app.llamaAgent.run(message.text, message.agentCommand);
|
||||
break;
|
||||
case 'clearText':
|
||||
await this.clearChatText(webviewView);
|
||||
this.app.llamaAgent.resetMessages();
|
||||
this.app.llamaAgent.resetContext()
|
||||
await this.app.chatService.selectUpdateChat({name:"", id:""})
|
||||
vscode.commands.executeCommand('llama-vscode.webview.postMessage', {
|
||||
command: 'updateText',
|
||||
text: ''
|
||||
});
|
||||
webviewView.webview.postMessage({
|
||||
command: 'updateContextImage',
|
||||
image: ""
|
||||
});
|
||||
break;
|
||||
case 'showChatsHistory':
|
||||
this.app.chatService.selectChatFromList();
|
||||
|
|
@ -145,11 +155,7 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
break;
|
||||
case 'selectAgent':
|
||||
let agentsList = this.app.configuration.agents_list
|
||||
let shouldContinue = await Utils.showYesNoDialog("This will remove the current conversation. Do you want to continue?")
|
||||
if (shouldContinue) {
|
||||
await this.app.agentService.pickAndSelectAgent(agentsList)
|
||||
await this.clearChatText(webviewView);
|
||||
}
|
||||
await this.app.agentService.pickAndSelectAgent(agentsList)
|
||||
break;
|
||||
case 'chatWithAI':
|
||||
this.app.askAi.closeChatWithAi(false);
|
||||
|
|
@ -277,7 +283,6 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
let agentToSave: Agent = {
|
||||
name: message.name,
|
||||
description: message.description,
|
||||
subagentEnabled: message.subagentEnabled,
|
||||
systemInstruction: message.systemInstruction.split(/\r?\n/),
|
||||
toolsModel: agentModelToSave,
|
||||
tools: message.tools
|
||||
|
|
@ -301,7 +306,6 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
const newAgent: Agent = {
|
||||
name: message.name,
|
||||
description: message.description,
|
||||
subagentEnabled: message.subagentEnabled,
|
||||
systemInstruction: message.systemInstruction,
|
||||
toolsModel: toolsModel,
|
||||
tools: message.tools
|
||||
|
|
@ -357,20 +361,6 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
}, 1000);
|
||||
}
|
||||
|
||||
private async clearChatText(webviewView: vscode.WebviewView) {
|
||||
this.app.llamaAgent.resetMessages();
|
||||
this.app.llamaAgent.resetContext();
|
||||
await this.app.chatService.selectUpdateChat({ name: "", id: "" });
|
||||
vscode.commands.executeCommand('llama-vscode.webview.postMessage', {
|
||||
command: 'updateText',
|
||||
text: ''
|
||||
});
|
||||
webviewView.webview.postMessage({
|
||||
command: 'updateContextImage',
|
||||
image: ""
|
||||
});
|
||||
}
|
||||
|
||||
public addEditAgent(agent: Agent) {
|
||||
this.app.agentService.resetEditedAgentTools();
|
||||
agent.tools?.map(tool => this.app.agentService.addEditedAgentTools(tool, ""));
|
||||
|
|
@ -380,7 +370,6 @@ export class LlamaWebviewProvider implements vscode.WebviewViewProvider {
|
|||
command: 'loadAgent',
|
||||
name: agent?.name,
|
||||
description: agent?.description,
|
||||
subagentEnabled: agent?.subagentEnabled,
|
||||
systemInstruction: agent?.systemInstruction.join("\n"),
|
||||
toolsModel: agent?.toolsModel?.name??'',
|
||||
tools: Array.from(edAgtools.entries())
|
||||
|
|
|
|||
|
|
@ -275,42 +275,6 @@ Replace the entire TODO list with an updated checklist reflecting the current st
|
|||
|
||||
TOOL_UPDATE_TODO_LIST_PARAMETER_DESCRIPTION = `Full markdown checklist in execution order, using [ ] for pending, [x] for completed, and [-] for in progress`
|
||||
|
||||
TOOL_DELEGATE_TASK_DESCRIPTION = `Delegates a specific task to a subagent.
|
||||
Use this when you encounter a subtask that is better handled by a dedicated agent (e.g. providing help for llama.vscode, performing calculations, retrieving specific data) or for optimizing context length.
|
||||
Provide the subagent's name and a clear, self-contained description of the task to be performed.
|
||||
Optionally, include relevant context (such as user preferences or key conversation snippets) to help the subagent.
|
||||
The subagent will execute the task using its own tools and return a result.
|
||||
If the delegation fails, an error status with details will be returned.`
|
||||
|
||||
TOOL_CREATE_AGENT_DESCRIPTION = `Creates a new agent in the system. The agent's configuration must be provided as a JSON string conforming to the schema defined in the description of property "agent_json".
|
||||
Upon successful creation, returns a confirmation message containing the unique identifier of the new agent. Ensure that any tool names listed in the tools field correspond to existing tools in the system.`
|
||||
|
||||
PROPERTY_AGENT_JSON_DESCRIPTION = `A JSON string that defines the agent to be created. The object must include the following fields:
|
||||
|
||||
name (string): The name of the agent.
|
||||
|
||||
description (string): A brief explanation of the agent's purpose and behavior.
|
||||
|
||||
subagentEnabled (boolean): Set to true if this agent can be invoked as a subagent by other agents; otherwise false.
|
||||
|
||||
systemInstruction (string): The system prompt or instruction that guides the agent's responses and actions.
|
||||
|
||||
tools (string, optional): A comma-separated list of tool names that the agent is permitted to use. Do not include spaces around the commas (e.g., "tool1,tool2,tool3"). If omitted, the agent will have no tools.
|
||||
|
||||
Example value:
|
||||
{
|
||||
"name": "CustomerSupportAgent",
|
||||
"description": "Handles customer inquiries and returns troubleshooting steps.",
|
||||
"subagentEnabled": true,
|
||||
"systemInstruction": "You are a helpful customer support representative...",
|
||||
"tools": "searchKnowledgeBase,ticketCreator"
|
||||
}
|
||||
`
|
||||
|
||||
SUBAGENTS_DESCRIPTION = `Subagents
|
||||
You have access to specialized subagents via the delegate_task tool. Use it when you encounter a well‑defined subtask that can be handled independently — for example, providing help for llama.vscode, performing complex calculations, or retrieving data from a specific source.
|
||||
If the delegation fails (error or timeout), decide whether to retry with a different subagent, handle the task yourself, or report the issue to the user.`
|
||||
|
||||
constructor(application: Application) {
|
||||
this.app = application;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,14 +113,10 @@ export class AgentService {
|
|||
this.app.setAgent(agent);
|
||||
const allTools = Array.from(this.app.tools.toolsFunc.keys());
|
||||
for (let toolName of allTools) {
|
||||
try {
|
||||
await this.app.configuration.updateConfigValue(`tool_${toolName}_enabled`, agent.tools?.includes(toolName) ?? false);
|
||||
} catch (err) {
|
||||
vscode.window.showErrorMessage("Error updating tools configuration.")
|
||||
}
|
||||
this.app.configuration.updateConfigValue(`tool_${toolName}_enabled`, agent.tools?.includes(toolName) ?? false);
|
||||
}
|
||||
if (agent.toolsModel && agent.toolsModel.name) {
|
||||
await this.app.modelService.selectStartModel(agent.toolsModel, ModelType.Tools, this.app.modelService.getTypeDetails(ModelType.Tools))
|
||||
this.app.modelService.selectStartModel(agent.toolsModel, ModelType.Tools, this.app.modelService.getTypeDetails(ModelType.Tools))
|
||||
}
|
||||
await this.app.persistence.setValue(PERSISTENCE_KEYS.SELECTED_AGENT, agent);
|
||||
this.app.llamaWebviewProvider.updateLlamaView();
|
||||
|
|
@ -179,7 +175,6 @@ export class AgentService {
|
|||
let agentExisting = agentsList.find(agn => agn.name.trim() == editedAgent.name.trim())
|
||||
if (agentExisting){
|
||||
agentExisting.description = editedAgent.description
|
||||
agentExisting.subagentEnabled = editedAgent.subagentEnabled
|
||||
agentExisting.systemInstruction = editedAgent.systemInstruction
|
||||
agentExisting.toolsModel = editedAgent.toolsModel
|
||||
agentExisting.tools = editedAgent.tools
|
||||
|
|
@ -362,7 +357,6 @@ export class AgentService {
|
|||
"\nname: " + agent.name +
|
||||
"\ndescription: " + agent.description +
|
||||
"\nsystem prompt: \n" + agent.systemInstruction.join("\n") +
|
||||
"\nsubagent enabled: " + agent.subagentEnabled +
|
||||
"\ntools model: \n" + agent.toolsModel?.name +
|
||||
"\n\ntools: " + (agent.tools ? agent.tools.join(", ") : "");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,16 +41,16 @@ export class ChatService {
|
|||
}
|
||||
|
||||
selectUpdateChat = async (chatToSelect: Chat) => {
|
||||
if (!chatToSelect.id){
|
||||
this.app.setChat(chatToSelect);
|
||||
await this.app.persistence.setValue(PERSISTENCE_KEYS.SELECTED_CHAT, this.app.getChat());
|
||||
} else {
|
||||
if (chatToSelect.id != this.app.getChat().id){
|
||||
await this.updateChatHistory();
|
||||
this.app.setChat(chatToSelect);
|
||||
await this.app.persistence.setValue(PERSISTENCE_KEYS.SELECTED_CHAT, chatToSelect);
|
||||
await this.app.llamaAgent.selectChat(chatToSelect);
|
||||
this.app.llamaAgent.selectChat(chatToSelect);
|
||||
this.app.llamaWebviewProvider.updateLlamaView();
|
||||
}
|
||||
} else {
|
||||
this.app.setChat(chatToSelect);
|
||||
await this.app.persistence.setValue(PERSISTENCE_KEYS.SELECTED_CHAT, this.app.getChat());
|
||||
}
|
||||
}
|
||||
|
||||
deleteChatFromList = async (chatList: Chat[]) => {
|
||||
|
|
|
|||
|
|
@ -195,17 +195,6 @@ export class ModelService {
|
|||
await details.killCmd();
|
||||
if (model.localStartCommand) await details.shellCmd(this.sanitizeCommand(model.localStartCommand ?? ""));
|
||||
await this.app.persistence.setValue(this.getSelectedProp(type), model);
|
||||
if (type == ModelType.Tools && model?.isKeyRequired !== undefined && model.isKeyRequired){
|
||||
const apiKey = this.app.persistence.getApiKey(model.endpoint??"");
|
||||
if (apiKey){
|
||||
this.app.configuration.axiosRequestConfigTools = {
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async addModel(type: ModelType, kind: 'local' | 'external' | 'hf' | 'oaiComp'): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -44,13 +44,13 @@ export class OpenAiCompModelStrategy implements IAddStrategy {
|
|||
prompt: 'example: http://localhost:8080 or https://openrauter.ai/api'
|
||||
})??""
|
||||
isKeyRequired = await Utils.confirmAction(`Is API key required for this endpoint (${endpoint})?`, "");
|
||||
}
|
||||
}
|
||||
if (!endpoint){
|
||||
vscode.window.showWarningMessage("Endpoint is not provided!")
|
||||
return;
|
||||
}
|
||||
const providerModels: QuickPickItem[] = [];
|
||||
const models = await this.getModels(endpoint, isKeyRequired);
|
||||
const models = await this.getModels(endpoint);
|
||||
if (models.length == 0) {
|
||||
vscode.window.showInformationMessage("No models are found.")
|
||||
return
|
||||
|
|
@ -108,50 +108,30 @@ export class OpenAiCompModelStrategy implements IAddStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
private async getModels(endpoint: string, isKeyRequired: boolean): Promise<OpenAiCompModel[]> {
|
||||
const hfEndpoint = Utils.trimTrailingSlash(endpoint) + "/v1/models";
|
||||
|
||||
// Create a request configuration
|
||||
let requestConfig: any = {};
|
||||
|
||||
if (isKeyRequired) {
|
||||
// We get the saved key for this specific endpoint
|
||||
const apiKey = this.app.persistence.getApiKey(endpoint);
|
||||
if (apiKey) {
|
||||
requestConfig = {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async getModels(endpoint: string): Promise<OpenAiCompModel[]> {
|
||||
let hfEndpoint = Utils.trimTrailingSlash(endpoint) +"/v1/models";
|
||||
try {
|
||||
const result = await axios.default.get(
|
||||
`${Utils.trimTrailingSlash(hfEndpoint)}`,
|
||||
requestConfig
|
||||
let result = await axios.default.get(
|
||||
`${Utils.trimTrailingSlash(hfEndpoint)}`
|
||||
);
|
||||
|
||||
let models: OpenAiCompModel[] = [];
|
||||
let modelsList: OpenAiCompModel[] = [];
|
||||
|
||||
if (result && result.data && result.data.models) modelsList = result.data.models;
|
||||
else if (result && result.data && result.data.data) modelsList = result.data.data;
|
||||
|
||||
if (modelsList.length > 0) {
|
||||
for (let mdl of modelsList) {
|
||||
models.push(mdl);
|
||||
|
||||
let modelsList: OpenAiCompModel[] = []
|
||||
if (result && result.data && result.data.models) modelsList = result.data.models
|
||||
else if (result && result.data && result.data.data) modelsList = result.data.data
|
||||
if (modelsList.length > 0){
|
||||
for(let mdl of modelsList){
|
||||
models.push(mdl)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return models;
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage("Error getting provider models: " + error);
|
||||
} catch (error){
|
||||
vscode.window.showErrorMessage("Error getting provider models): " + error)
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private sanitizeInput(input: string): string {
|
||||
return input ? input.trim() : '';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,192 +26,6 @@ export class TextEditor {
|
|||
vscode.commands.executeCommand('setContext', 'textEditSuggestionVisible', visible);
|
||||
}
|
||||
|
||||
private escapeWebviewAttr(value: string): string {
|
||||
return value
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/</g, '<');
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiline instructions (webview); resolves undefined if cancelled or closed.
|
||||
*/
|
||||
private showMultilineEditPrompt(): Promise<string | undefined> {
|
||||
const title =
|
||||
this.app.configuration.getUiText('How would you like to modify the selected text?') ??
|
||||
'How would you like to modify the selected text?';
|
||||
const placeholder =
|
||||
this.app.configuration.getUiText('Enter your instructions for editing the text...') ??
|
||||
'Enter your instructions for editing the text...';
|
||||
const submitLabel = this.app.configuration.getUiText('Submit') ?? 'Submit';
|
||||
const cancelLabel = this.app.configuration.getUiText('Cancel') ?? 'Cancel';
|
||||
const emptyHint =
|
||||
this.app.configuration.getUiText('Please enter editing instructions.') ??
|
||||
'Please enter editing instructions.';
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let settled = false;
|
||||
const panel = vscode.window.createWebviewPanel(
|
||||
'editWithAiMultilinePrompt',
|
||||
title,
|
||||
{ viewColumn: vscode.ViewColumn.Beside, preserveFocus: false },
|
||||
{ enableScripts: true }
|
||||
);
|
||||
|
||||
const finish = (value: string | undefined) => {
|
||||
if (settled) {
|
||||
return;
|
||||
}
|
||||
settled = true;
|
||||
resolve(value);
|
||||
panel.dispose();
|
||||
};
|
||||
|
||||
const cspSource = panel.webview.cspSource;
|
||||
panel.webview.html = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${cspSource} 'unsafe-inline'; script-src 'unsafe-inline' ${cspSource};">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 12px;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: var(--vscode-font-family);
|
||||
font-size: var(--vscode-font-size);
|
||||
color: var(--vscode-foreground);
|
||||
background-color: var(--vscode-editor-background);
|
||||
}
|
||||
label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
textarea {
|
||||
flex: 1;
|
||||
min-height: 120px;
|
||||
resize: vertical;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--vscode-input-border);
|
||||
background: var(--vscode-input-background);
|
||||
color: var(--vscode-input-foreground);
|
||||
font-family: var(--vscode-editor-font-family);
|
||||
font-size: var(--vscode-editor-font-size);
|
||||
}
|
||||
textarea:focus {
|
||||
outline: 1px solid var(--vscode-focusBorder);
|
||||
}
|
||||
.actions {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
/* DOM order is Submit then Cancel (Tab: textarea → Submit → Cancel); flex order keeps Cancel left, Submit right. */
|
||||
.actions .secondary {
|
||||
order: 1;
|
||||
}
|
||||
.actions .primary {
|
||||
order: 2;
|
||||
}
|
||||
button {
|
||||
padding: 6px 14px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--vscode-font-size);
|
||||
}
|
||||
.primary {
|
||||
background: var(--vscode-button-background);
|
||||
color: var(--vscode-button-foreground);
|
||||
}
|
||||
.primary:hover {
|
||||
background: var(--vscode-button-hoverBackground);
|
||||
}
|
||||
.secondary {
|
||||
background: var(--vscode-button-secondaryBackground);
|
||||
color: var(--vscode-button-secondaryForeground);
|
||||
}
|
||||
.secondary:hover {
|
||||
background: var(--vscode-button-secondaryHoverBackground);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<label for="prompt">${this.escapeWebviewAttr(title)}</label>
|
||||
<textarea id="prompt" placeholder="${this.escapeWebviewAttr(placeholder)}" autofocus></textarea>
|
||||
<div class="actions">
|
||||
<button type="button" class="primary" id="submit">${this.escapeWebviewAttr(submitLabel)}</button>
|
||||
<button type="button" class="secondary" id="cancel">${this.escapeWebviewAttr(cancelLabel)}</button>
|
||||
</div>
|
||||
<script>
|
||||
const vscode = acquireVsCodeApi();
|
||||
const ta = document.getElementById('prompt');
|
||||
function focusPrompt() {
|
||||
if (!ta) {
|
||||
return;
|
||||
}
|
||||
ta.focus();
|
||||
const len = ta.value.length;
|
||||
ta.setSelectionRange(len, len);
|
||||
}
|
||||
window.addEventListener('load', focusPrompt);
|
||||
requestAnimationFrame(focusPrompt);
|
||||
setTimeout(focusPrompt, 0);
|
||||
setTimeout(focusPrompt, 100);
|
||||
window.addEventListener('message', (event) => {
|
||||
const data = event.data;
|
||||
if (data && data.command === 'focusPrompt') {
|
||||
focusPrompt();
|
||||
}
|
||||
});
|
||||
document.getElementById('submit').addEventListener('click', () => {
|
||||
vscode.postMessage({ command: 'submit', text: ta.value });
|
||||
});
|
||||
document.getElementById('cancel').addEventListener('click', () => {
|
||||
vscode.postMessage({ command: 'cancel' });
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const requestPromptFocus = () => {
|
||||
void panel.webview.postMessage({ command: 'focusPrompt' });
|
||||
};
|
||||
panel.onDidChangeViewState((e) => {
|
||||
if (e.webviewPanel.visible) {
|
||||
requestPromptFocus();
|
||||
}
|
||||
});
|
||||
requestPromptFocus();
|
||||
setTimeout(requestPromptFocus, 50);
|
||||
setTimeout(requestPromptFocus, 200);
|
||||
|
||||
panel.webview.onDidReceiveMessage((message) => {
|
||||
if (message.command === 'submit') {
|
||||
const text = typeof message.text === 'string' ? message.text : '';
|
||||
if (!text.trim()) {
|
||||
void vscode.window.showInformationMessage(emptyHint);
|
||||
return;
|
||||
}
|
||||
finish(text);
|
||||
} else if (message.command === 'cancel') {
|
||||
finish(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
panel.onDidDispose(() => {
|
||||
if (!settled) {
|
||||
settled = true;
|
||||
resolve(undefined);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async showEditPrompt(editor: vscode.TextEditor) {
|
||||
let chatUrl = this.app.configuration.endpoint_chat
|
||||
if (!chatUrl) chatUrl = this.app.configuration.endpoint_tools;
|
||||
|
|
@ -250,7 +64,12 @@ export class TextEditor {
|
|||
const contextRange = new vscode.Range(startLine, 0, endLine, editor.document.lineAt(endLine).text.length);
|
||||
const context = editor.document.getText(contextRange);
|
||||
|
||||
const prompt = await this.showMultilineEditPrompt();
|
||||
// Create and show input box
|
||||
const prompt = await vscode.window.showInputBox({
|
||||
placeHolder: 'Enter your instructions for editing the text...',
|
||||
prompt: 'How would you like to modify the selected text?',
|
||||
ignoreFocusOut: true
|
||||
});
|
||||
|
||||
if (!prompt) {
|
||||
return;
|
||||
|
|
|
|||
134
src/tools.ts
134
src/tools.ts
|
|
@ -5,7 +5,6 @@ import path from "path";
|
|||
import fs from 'fs';
|
||||
import { Plugin } from './plugin';
|
||||
import { UI_TEXT_KEYS } from "./constants";
|
||||
import { Chat, Agent } from "./types";
|
||||
|
||||
type ToolsMap = Map<string, (...args: any[]) => any>;
|
||||
|
||||
|
|
@ -32,8 +31,6 @@ export class Tools {
|
|||
this.toolsFunc.set("custom_eval_tool", this.customEvalTool)
|
||||
this.toolsFunc.set("llama_vscode_help", this.llamaVscodeHelp)
|
||||
this.toolsFunc.set("update_todo_list", this.updateTodoList)
|
||||
this.toolsFunc.set("delegate_task", this.delegateTask)
|
||||
this.toolsFunc.set("create_agent", this.createAgent)
|
||||
this.toolsFuncDesc.set("run_terminal_command", this.runTerminalCommandDesc);
|
||||
this.toolsFuncDesc.set("search_source", this.searchSourceDesc)
|
||||
this.toolsFuncDesc.set("read_file", this.readFileDesc)
|
||||
|
|
@ -47,9 +44,7 @@ export class Tools {
|
|||
this.toolsFuncDesc.set("custom_eval_tool", this.customEvalToolDesc)
|
||||
this.toolsFuncDesc.set("llama_vscode_help", this.llamaVscodeHelpDesc)
|
||||
this.toolsFuncDesc.set("update_todo_list", this.updateTodoListDesc)
|
||||
this.toolsFuncDesc.set("update_todo_list", this.updateTodoListDesc);
|
||||
this.toolsFuncDesc.set("delegate_task", this.delegateTaskDesc)
|
||||
this.toolsFuncDesc.set("create_agent ", this.createAgentDesc);
|
||||
|
||||
}
|
||||
|
||||
public runTerminalCommand = async (args: string ) => {
|
||||
|
|
@ -399,7 +394,7 @@ export class Tools {
|
|||
|
||||
return "The todos are created/updated."
|
||||
}
|
||||
|
||||
|
||||
public updateTodoListDesc = async (args: string) => {
|
||||
let ret = "update_todo_list tool is executed. \n\n"
|
||||
let params = JSON.parse(args);
|
||||
|
|
@ -407,89 +402,8 @@ export class Tools {
|
|||
return ret
|
||||
}
|
||||
|
||||
public delegateTask = async (args: string) => {
|
||||
let params = JSON.parse(args);
|
||||
let finalAnswer = "No answer from the subagent.";
|
||||
if (params.subagent_name) {
|
||||
// store current agent
|
||||
await this.app.llamaAgent.updateChat()
|
||||
let parentChat = this.app.getChat();
|
||||
parentChat.defaultAgent = this.app.getAgent();
|
||||
let subagent: Agent = this.app.configuration.agents_list.find(agent => agent.name == params.subagent_name)
|
||||
if (!subagent) return "No subagent found with name " + params.subagent_name;
|
||||
this.app.llamaAgent.resetContext();
|
||||
let newChatName = "delegate_task" + Date.now()
|
||||
let newSubagent: Agent = { ...subagent };
|
||||
if (subagent.tools){
|
||||
// clone the tools to avoid changing the original agent
|
||||
newSubagent.tools = [...subagent.tools];
|
||||
} else {
|
||||
newSubagent.tools = [];
|
||||
}
|
||||
newSubagent.tools.push("ask_user")
|
||||
// The goal is to get the answer from the subagent in one tools loop - so use a tool call if user input is needed
|
||||
newSubagent.systemInstruction.push("For questions to the user, please use the tool 'ask_user'.")
|
||||
let newChat: Chat = {
|
||||
name: newChatName,
|
||||
id: newChatName,
|
||||
messages: [],
|
||||
defaultAgent: newSubagent,
|
||||
log: "subagent: " + params.subagent_name + " \n \n"
|
||||
}
|
||||
|
||||
await this.app.chatService.selectUpdateChat(newChat)
|
||||
|
||||
if (params.task) {
|
||||
finalAnswer = await this.app.llamaAgent.askAgent(params.task)
|
||||
} else {
|
||||
return "No task provided."
|
||||
}
|
||||
await this.app.chatService.selectUpdateChat(parentChat)
|
||||
this.app.llamaWebviewProvider.setState("AI is working")
|
||||
} else {
|
||||
return "No subagent name provided."
|
||||
}
|
||||
|
||||
return finalAnswer
|
||||
}
|
||||
|
||||
public delegateTaskDesc = async (args: string) => {
|
||||
let ret = "delegate_task tool is executed. \n\n"
|
||||
let params = JSON.parse(args);
|
||||
if (params.task && params.subagent_name) ret += "subagent: " + params.subagent_name + "\ntask: " + params.task
|
||||
return ret.split(/\r?\n/).join(" \n")
|
||||
}
|
||||
|
||||
public createAgent = async (args: string) => {
|
||||
let params = JSON.parse(args);
|
||||
let finalAnswer = "The agent is created";
|
||||
|
||||
if (params.agent_json) {
|
||||
let receivedAgent = JSON.parse(params.agent_json)
|
||||
let newAgent:Agent = {
|
||||
name: receivedAgent.name,
|
||||
description: receivedAgent.description,
|
||||
subagentEnabled: receivedAgent.subagentEnabled??false,
|
||||
systemInstruction: receivedAgent.systemInstruction.split(/\r?\n/)
|
||||
}
|
||||
if (receivedAgent.tools) {
|
||||
newAgent.tools = receivedAgent.tools.split(",")
|
||||
}
|
||||
// TODO check if one more parsing of agent_json is needed
|
||||
await this.app.agentService.addUpdateAgent(newAgent)
|
||||
} else {
|
||||
return "No agent provided."
|
||||
}
|
||||
|
||||
return finalAnswer
|
||||
}
|
||||
|
||||
public createAgentDesc = async (args: string) => {
|
||||
let ret = "create_agent tool is executed. \n\n"
|
||||
// let params = JSON.parse(args);
|
||||
// if (params.task && params.subagent_name) ret += "subagent: " + params.subagent_name + "\ntask: " + params.task
|
||||
return ret.split(/\r?\n/).join(" \n")
|
||||
}
|
||||
|
||||
public init = () => {
|
||||
this.tools = [
|
||||
|
|
@ -771,50 +685,6 @@ export class Tools {
|
|||
}
|
||||
}
|
||||
] : []),
|
||||
...(this.app.configuration.tool_create_agent_enabled ? [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "create_agent",
|
||||
"description": this.app.prompts.TOOL_CREATE_AGENT_DESCRIPTION,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_json": {
|
||||
"description": this.app.prompts.PROPERTY_AGENT_JSON_DESCRIPTION,
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": [],
|
||||
},
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
] : []),
|
||||
...(this.app.configuration.tool_delegate_task_enabled ? [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "delegate_task",
|
||||
"description": this.app.prompts.TOOL_DELEGATE_TASK_DESCRIPTION,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"subagent_name": {
|
||||
"description": "Name of the subagent to invoke. Must be one of the available subagents listed in the system prompt.",
|
||||
"type": "string",
|
||||
},
|
||||
"task": {
|
||||
"description": "Description of the task to be delegated to the subagent.",
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": [],
|
||||
},
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
] : []),
|
||||
]
|
||||
|
||||
for (let tool of this.app.configuration.tools_custom){
|
||||
|
|
|
|||
|
|
@ -197,5 +197,4 @@ export const translations: string[][] = [
|
|||
["Copy agent...", "Копиране на агент...", "Agent kopieren...", "Копировать агента...", "Copiar agente...", "复制代理...", "Copier l'agent..."],
|
||||
["Edit multiple files with AI", "Редактиране на множество файлове с изкуствен интелект", "Mehrere Dateien mit KI bearbeiten", "Редактировать несколько файлов с ИИ", "Editar múltiples archivos con IA", "使用人工智能编辑多个文件", "Modifier plusieurs fichiers avec IA"],
|
||||
["Asks for glob pattern and prompt and edits with AI the files, which match the glob pattern with the provided prompt.", "Пита за шаблон за обхват и инструкция, след което редактира с изкуствен интелект файловете, които отговарят на шаблона, със зададената инструкция.", "Fragt nach einem Glob-Muster und einer Eingabeaufforderung und bearbeitet mit KI die Dateien, die dem Glob-Muster mit der bereitgestellten Eingabeaufforderung entsprechen.", "Запрашивает шаблон glob и подсказку, а затем редактирует с помощью ИИ файлы, соответствующие шаблону, с предоставленной подсказкой.", "Pide un patrón glob y un mensaje, y edita con IA los archivos que coinciden con el patrón glob con el mensaje proporcionado.", "请求输入通配符模式和提示词,然后使用人工智能编辑符合该通配符模式的文件,并根据提供的提示词进行修改。", "Demande un motif glob et une invite, puis modifie avec IA les fichiers correspondant au motif glob avec l'invite fournie."],
|
||||
["This will remove the current conversation. Do you want to continue?", "Това ще премахне текущия разговор. Искате ли да продължите?", "Dadurch wird die aktuelle Unterhaltung gelöscht. Möchten Sie fortfahren?", "Это удалит текущий разговор. Хотите продолжить?", "Esto eliminará la conversación actual. ¿Quieres continuar?", "这将删除当前对话。是否要继续?", "Cela supprimera la conversation en cours. Voulez-vous continuer ?"],
|
||||
];
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ export interface Env {
|
|||
export interface Agent {
|
||||
name: string,
|
||||
description?: string,
|
||||
subagentEnabled?: boolean,
|
||||
systemInstruction: string[],
|
||||
toolsModel?: LlmModel,
|
||||
tools?: string[]
|
||||
|
|
|
|||
77
src/vscode-lm-chat-shim.d.ts
vendored
77
src/vscode-lm-chat-shim.d.ts
vendored
|
|
@ -1,77 +0,0 @@
|
|||
// Temporary shim for VS Code LM chat-provider typings.
|
||||
// Some @types/vscode versions ship parts of the LM API behind proposal typings.
|
||||
// This keeps `tsc` happy while still targeting the runtime VS Code API.
|
||||
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
declare module 'vscode' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace lm {
|
||||
function registerLanguageModelChatProvider(
|
||||
vendor: string,
|
||||
provider: LanguageModelChatProvider
|
||||
): vscode.Disposable;
|
||||
}
|
||||
|
||||
export interface PrepareLanguageModelChatModelOptions {}
|
||||
|
||||
export interface LanguageModelChatCapabilities {
|
||||
toolCalling?: boolean;
|
||||
imageInput?: boolean;
|
||||
}
|
||||
|
||||
export interface LanguageModelChatInformation {
|
||||
id: string;
|
||||
name: string;
|
||||
family?: string;
|
||||
version?: string;
|
||||
maxInputTokens?: number;
|
||||
maxOutputTokens?: number;
|
||||
capabilities?: LanguageModelChatCapabilities;
|
||||
}
|
||||
|
||||
export type LanguageModelChatMessagePart = unknown | LanguageModelTextPart;
|
||||
|
||||
export interface LanguageModelChatRequestMessage {
|
||||
role: LanguageModelChatMessageRole;
|
||||
content: readonly LanguageModelChatMessagePart[];
|
||||
}
|
||||
|
||||
export interface ProvideLanguageModelChatResponseOptions {
|
||||
tools?: readonly LanguageModelToolInformation[];
|
||||
modelOptions?: {
|
||||
temperature?: number;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export type LanguageModelResponsePart =
|
||||
| LanguageModelTextPart
|
||||
| LanguageModelToolCallPart
|
||||
| unknown;
|
||||
|
||||
export interface LanguageModelChatProvider {
|
||||
onDidChangeLanguageModelChatInformation?: vscode.Event<void>;
|
||||
|
||||
provideLanguageModelChatInformation(
|
||||
options: PrepareLanguageModelChatModelOptions,
|
||||
token: vscode.CancellationToken
|
||||
): vscode.ProviderResult<LanguageModelChatInformation[]>;
|
||||
|
||||
provideLanguageModelChatResponse(
|
||||
model: LanguageModelChatInformation,
|
||||
messages: readonly LanguageModelChatRequestMessage[],
|
||||
options: ProvideLanguageModelChatResponseOptions,
|
||||
progress: vscode.Progress<LanguageModelResponsePart>,
|
||||
token: vscode.CancellationToken
|
||||
): vscode.ProviderResult<void>;
|
||||
|
||||
provideTokenCount(
|
||||
model: LanguageModelChatInformation,
|
||||
text: string | LanguageModelChatRequestMessage,
|
||||
token: vscode.CancellationToken
|
||||
): vscode.ProviderResult<number>;
|
||||
}
|
||||
}
|
||||
|
||||
9
ui/package-lock.json
generated
9
ui/package-lock.json
generated
|
|
@ -326,6 +326,7 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz",
|
||||
"integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
|
|
@ -665,6 +666,7 @@
|
|||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
|
@ -691,6 +693,7 @@
|
|||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
|
|
@ -917,6 +920,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001726",
|
||||
"electron-to-chromium": "^1.5.173",
|
||||
|
|
@ -4081,6 +4085,7 @@
|
|||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
|
|
@ -4283,6 +4288,7 @@
|
|||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
|
|
@ -5315,6 +5321,7 @@
|
|||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
@ -5572,6 +5579,7 @@
|
|||
"integrity": "sha512-YJB/ESPUe2Locd0NKXmw72Dx8fZQk1gTzI6rc9TAT4+Sypbnhl8jd8RywB1bDsDF9Dy1RUR7gn3q/ZJTd0OZZg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.8",
|
||||
|
|
@ -5621,6 +5629,7 @@
|
|||
"integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@discoveryjs/json-ext": "^0.5.0",
|
||||
"@webpack-cli/configtest": "^2.1.1",
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const App: React.FC<AppProps> = () => {
|
|||
const [contextFiles, setContextFiles] = useState<Map<string, string>>(new Map());
|
||||
const [imagePath, setContextImage] = useState<string>("");
|
||||
const [agentEditTools, setAgentEditTools] = useState<Map<string, string>>(new Map());
|
||||
const [agentEditDetails, setAgentEditDetails] = useState<{name:string, description:string, systemInstruction:string, toolsModel: string, subagentEnabled: boolean}>({name:"", description:"", systemInstruction:"", toolsModel:"", subagentEnabled: false});
|
||||
const [agentEditDetails, setAgentEditDetails] = useState<{name:string, description:string, systemInstruction:string, toolsModel: string}>({name:"", description:"", systemInstruction:"", toolsModel:""});
|
||||
|
||||
// Save state to VS Code whenever it changes
|
||||
useEffect(() => {
|
||||
|
|
@ -106,10 +106,10 @@ const App: React.FC<AppProps> = () => {
|
|||
setContextImage(message.image || "");
|
||||
break;
|
||||
case 'updateAgentEdit':
|
||||
setAgentEditDetails({name: message.name, description: message.description, systemInstruction: message.systemInstruction, toolsModel: message.toolsModel,subagentEnabled: message.subagentEnabled});
|
||||
setAgentEditDetails({name: message.name, description: message.description, systemInstruction: message.systemInstruction, toolsModel: message.toolsModel});
|
||||
break;
|
||||
case 'loadAgent':
|
||||
setAgentEditDetails({name: message.name, description: message.description, systemInstruction: message.systemInstruction, toolsModel: message.toolsModel, subagentEnabled: message.subagentEnabled});
|
||||
setAgentEditDetails({name: message.name, description: message.description, systemInstruction: message.systemInstruction, toolsModel: message.toolsModel});
|
||||
setCurrentAgentModel(message.toolsModel);
|
||||
setAgentEditTools(new Map(message.tools || []));
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ interface AgentEditorProps {
|
|||
setCurrentState: (state: string) => void;
|
||||
contextFiles: Map<string, string>;
|
||||
setContextFiles: (files: Map<string, string>) => void;
|
||||
agentEditDetails: {name: string, description: string, systemInstruction: string, toolsModel: string, subagentEnabled: boolean}
|
||||
setAgentEditDetails:(agentDetails: {name: string, description: string, systemInstruction: string, toolsModel: string, subagentEnabled: boolean}) => void
|
||||
agentEditDetails: {name: string, description: string, systemInstruction: string, toolsModel: string}
|
||||
setAgentEditDetails:(agentDetails: {name: string, description: string, systemInstruction: string, toolsModel: string}) => void
|
||||
}
|
||||
|
||||
const AgentEditor: React.FC<AgentEditorProps> = ({
|
||||
|
|
@ -90,7 +90,7 @@ const AgentEditor: React.FC<AgentEditorProps> = ({
|
|||
setTools(new Map(message.files || []));
|
||||
break;
|
||||
case 'loadAgent':
|
||||
setAgentEditDetails({name: message.name, description: message.description, systemInstruction: message.systemInstruction, toolsModel: message.toolsModel, subagentEnabled: message.subagentEnabled});
|
||||
setAgentEditDetails({name: message.name, description: message.description, systemInstruction: message.systemInstruction, toolsModel: message.toolsModel});
|
||||
setTools(new Map(message.tools || []));
|
||||
currentAgentModel = message.toolsModel;
|
||||
break;
|
||||
|
|
@ -120,7 +120,6 @@ const AgentEditor: React.FC<AgentEditorProps> = ({
|
|||
vscode.postMessage({
|
||||
command: 'saveEditAgent',
|
||||
name: agentEditDetails.name,
|
||||
subagentEnabled: agentEditDetails.subagentEnabled,
|
||||
description: agentEditDetails.description,
|
||||
systemInstruction: agentEditDetails.systemInstruction,
|
||||
toolsModel: currentAgentModel,
|
||||
|
|
@ -358,19 +357,19 @@ const AgentEditor: React.FC<AgentEditorProps> = ({
|
|||
<textarea
|
||||
ref={elemNameRef}
|
||||
value={agentEditDetails.name}
|
||||
onChange={(e) => setAgentEditDetails({name: e.target.value, description: agentEditDetails.description, systemInstruction: agentEditDetails.systemInstruction, toolsModel: agentEditDetails.toolsModel,subagentEnabled: agentEditDetails.subagentEnabled})}
|
||||
onChange={(e) => setAgentEditDetails({name: e.target.value, description: agentEditDetails.description, systemInstruction: agentEditDetails.systemInstruction, toolsModel: agentEditDetails.toolsModel})}
|
||||
placeholder="Enter agent name."
|
||||
className="modern-textarea"
|
||||
rows={1}
|
||||
style={{ height: 'auto', minHeight: '1.5em', resize: 'none' }}
|
||||
/>
|
||||
|
||||
<span style={{ display: 'block', marginTop: '20px', marginBottom: '10px', fontWeight: 'bold' }}>{'Description'}</span>
|
||||
<span style={{ display: 'block', marginTop: '20px', marginBottom: '10px', fontWeight: 'bold' }}>{'Descriptoin'}</span>
|
||||
{/* Modern Textarea */}
|
||||
<textarea
|
||||
ref={elemDescriptionRef}
|
||||
value={agentEditDetails.description}
|
||||
onChange={(e) => setAgentEditDetails({name: agentEditDetails.name, description: e.target.value, systemInstruction: agentEditDetails.systemInstruction, toolsModel: agentEditDetails.toolsModel, subagentEnabled: agentEditDetails.subagentEnabled})}
|
||||
onChange={(e) => setAgentEditDetails({name: agentEditDetails.name, description: e.target.value, systemInstruction: agentEditDetails.systemInstruction, toolsModel: agentEditDetails.toolsModel})}
|
||||
placeholder="Enter agent description."
|
||||
className="modern-textarea"
|
||||
rows={2}
|
||||
|
|
@ -382,22 +381,12 @@ const AgentEditor: React.FC<AgentEditorProps> = ({
|
|||
<textarea
|
||||
ref={elemSystemPromptRef}
|
||||
value={agentEditDetails.systemInstruction}
|
||||
onChange={(e) => setAgentEditDetails({name: agentEditDetails.name, description: agentEditDetails.description, systemInstruction: e.target.value, toolsModel: agentEditDetails.toolsModel, subagentEnabled: agentEditDetails.subagentEnabled})}
|
||||
onChange={(e) => setAgentEditDetails({name: agentEditDetails.name, description: agentEditDetails.description, systemInstruction: e.target.value, toolsModel: agentEditDetails.toolsModel})}
|
||||
placeholder="Enter system instructions for the agent."
|
||||
className="modern-textarea"
|
||||
rows={10}
|
||||
style={{ height: 'auto', minHeight: '15em', resize: 'vertical' }}
|
||||
/>
|
||||
<div style={{ marginBottom: '20px', marginTop: '10px', fontWeight: 'bold' }}>
|
||||
<label className="checkbox-label" title="If enabled - the agent could be used as a subagent.">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={agentEditDetails.subagentEnabled}
|
||||
onChange={(e) => setAgentEditDetails({name: agentEditDetails.name, description: e.target.value, systemInstruction: agentEditDetails.systemInstruction, toolsModel: agentEditDetails.toolsModel, subagentEnabled: e.target.checked})}
|
||||
/>
|
||||
<span style={{ marginLeft: '8px' }}>Available as Subagent</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="single-button-frame">
|
||||
<div className="frame-label">Agent Model (Optional)</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue