Add a new @roo-code/types package and use it everywhere (#3912)

This commit is contained in:
Chris Estreich 2025-05-26 12:06:45 -07:00 committed by GitHub
parent ce6cc6fa97
commit e66136f1aa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
217 changed files with 1609 additions and 5315 deletions

View file

@ -1,82 +0,0 @@
"""
This script updates a specific version's release notes section in CHANGELOG.md with new content
or reformats existing content.
The script:
1. Takes a version number, changelog path, and optionally new content as input from environment variables
2. Finds the section in the changelog for the specified version
3. Either:
a) Replaces the content with new content if provided, or
b) Reformats existing content by:
- Removing the first two lines of the changeset format
- Ensuring version numbers are wrapped in square brackets
4. Writes the updated changelog back to the file
Environment Variables:
CHANGELOG_PATH: Path to the changelog file (defaults to 'CHANGELOG.md')
VERSION: The version number to update/format
PREV_VERSION: The previous version number (used to locate section boundaries)
NEW_CONTENT: Optional new content to insert for this version
"""
#!/usr/bin/env python3
import os
CHANGELOG_PATH = os.environ.get("CHANGELOG_PATH", "CHANGELOG.md")
VERSION = os.environ["VERSION"]
PREV_VERSION = os.environ.get("PREV_VERSION", "")
NEW_CONTENT = os.environ.get("NEW_CONTENT", "")
def overwrite_changelog_section(changelog_text: str, new_content: str):
# Find the section for the specified version
version_pattern = f"## {VERSION}\n"
prev_version_pattern = f"## [{PREV_VERSION}]\n"
print(f"latest version: {VERSION}")
print(f"prev_version: {PREV_VERSION}")
notes_start_index = changelog_text.find(version_pattern) + len(version_pattern)
notes_end_index = (
changelog_text.find(prev_version_pattern, notes_start_index)
if PREV_VERSION and prev_version_pattern in changelog_text
else len(changelog_text)
)
if new_content:
return (
changelog_text[:notes_start_index]
+ f"{new_content}\n"
+ changelog_text[notes_end_index:]
)
else:
changeset_lines = changelog_text[notes_start_index:notes_end_index].split("\n")
# Remove the first two lines from the regular changeset format, ex: \n### Patch Changes
parsed_lines = "\n".join(changeset_lines[2:])
updated_changelog = (
changelog_text[:notes_start_index]
+ parsed_lines
+ changelog_text[notes_end_index:]
)
updated_changelog = updated_changelog.replace(
f"## {VERSION}", f"## [{VERSION}]"
)
return updated_changelog
with open(CHANGELOG_PATH, "r") as f:
changelog_content = f.read()
new_changelog = overwrite_changelog_section(changelog_content, NEW_CONTENT)
print(
"----------------------------------------------------------------------------------"
)
print(new_changelog)
print(
"----------------------------------------------------------------------------------"
)
# Write back to CHANGELOG.md
with open(CHANGELOG_PATH, "w") as f:
f.write(new_changelog)
print(f"{CHANGELOG_PATH} updated successfully!")

View file

@ -13,27 +13,6 @@ env:
PNPM_VERSION: 10.8.1
jobs:
compile:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Check types
run: pnpm check-types
- name: Lint
run: pnpm lint
check-translations:
runs-on: ubuntu-latest
steps:
@ -72,58 +51,48 @@ jobs:
- name: Run knip checks
run: pnpm knip
test-extension:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run unit tests
working-directory: src
run: pnpm test
test-webview:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run unit tests
working-directory: webview-ui
run: pnpm test
unit-test:
needs: [test-extension, test-webview]
compile:
runs-on: ubuntu-latest
steps:
- name: NO-OP
run: echo "All unit tests passed."
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Lint
run: pnpm lint
- name: Check types
run: pnpm check-types
platform-unit-test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run unit tests
run: pnpm test
check-openrouter-api-key:
runs-on: ubuntu-latest
@ -164,3 +133,10 @@ jobs:
- name: Run integration tests
working-directory: apps/vscode-e2e
run: xvfb-run -a pnpm test:ci
unit-test:
needs: [platform-unit-test] # [platform-unit-test, integration-test]
runs-on: ubuntu-latest
steps:
- name: NO-OP
run: echo "All tests passed."

View file

@ -16,14 +16,6 @@ else
fi
fi
$pnpm_cmd --filter roo-cline generate-types
if [ -n "$(git diff --name-only src/exports/roo-code.d.ts)" ]; then
echo "Error: There are unstaged changes to roo-code.d.ts after running 'pnpm --filter roo-cline generate-types'."
echo "Please review and stage the changes before committing."
exit 1
fi
# Detect if running on Windows and use npx.cmd, otherwise use npx.
if [ "$OS" = "Windows_NT" ]; then
npx_cmd="npx.cmd"

View file

@ -3,16 +3,16 @@
"private": true,
"scripts": {
"lint": "eslint src --ext=ts --max-warnings=0",
"check-types": "tsc --noEmit",
"check-types": "tsc -p tsconfig.esm.json --noEmit",
"format": "prettier --write src",
"test:ci": "pnpm --filter roo-cline build:development && pnpm test:run",
"test:ci": "pnpm -w bundle && pnpm --filter @roo-code/vscode-webview build && pnpm test:run",
"test:run": "rimraf out && tsc -p tsconfig.json && npx dotenvx run -f .env.local -- node ./out/runTest.js",
"clean": "rimraf out .turbo"
},
"devDependencies": {
"@roo-code/config-eslint": "workspace:^",
"@roo-code/config-typescript": "workspace:^",
"@roo-code/types": "^1.12.0",
"@roo-code/types": "workspace:^",
"@types/mocha": "^10.0.10",
"@types/node": "^22.14.1",
"@types/vscode": "^1.95.0",

View file

@ -1,8 +1,6 @@
import * as assert from "assert"
import * as vscode from "vscode"
import { Package } from "@roo-code/types"
suite("Roo Code Extension", () => {
test("Commands should be registered", async () => {
const expectedCommands = [
@ -36,12 +34,10 @@ suite("Roo Code Extension", () => {
"terminalExplainCommand",
]
const commands = new Set(
(await vscode.commands.getCommands(true)).filter((cmd) => cmd.startsWith(Package.name)),
)
const commands = new Set((await vscode.commands.getCommands(true)).filter((cmd) => cmd.startsWith("roo-cline")))
for (const command of expectedCommands) {
assert.ok(commands.has(`${Package.name}.${command}`), `Command ${command} should be registered`)
assert.ok(commands.has(`roo-cline.${command}`), `Command ${command} should be registered`)
}
})
})

View file

@ -3,16 +3,12 @@ import Mocha from "mocha"
import { glob } from "glob"
import * as vscode from "vscode"
import { type RooCodeAPI, Package } from "@roo-code/types"
import type { RooCodeAPI } from "@roo-code/types"
import { waitFor } from "./utils"
declare global {
let api: RooCodeAPI
}
export async function run() {
const extension = vscode.extensions.getExtension<RooCodeAPI>(`${Package.publisher}.${Package.name}`)
const extension = vscode.extensions.getExtension<RooCodeAPI>("RooVeterinaryInc.roo-cline")
if (!extension) {
throw new Error("Extension not found")
@ -23,13 +19,12 @@ export async function run() {
await api.setConfiguration({
apiProvider: "openrouter" as const,
openRouterApiKey: process.env.OPENROUTER_API_KEY!,
openRouterModelId: "google/gemini-2.0-flash-001",
openRouterModelId: "openai/gpt-4.1",
})
await vscode.commands.executeCommand(`${Package.name}.SidebarProvider.focus`)
await vscode.commands.executeCommand("roo-cline.SidebarProvider.focus")
await waitFor(() => api.isReady())
// @ts-expect-error - Expose the API to the tests.
globalThis.api = api
// Add all the tests to the runner.

View file

@ -1,23 +1,17 @@
import * as assert from "assert"
import type { RooCodeAPI, ClineMessage } from "@roo-code/types"
import type { ClineMessage } from "@roo-code/types"
import { waitUntilCompleted } from "./utils"
suite("Roo Code Modes", () => {
test("Should handle switching modes correctly", async () => {
// @ts-expect-error - Expose the API to the tests.
const api = globalThis.api as RooCodeAPI
/**
* Switch modes.
*/
const api = globalThis.api
const switchModesPrompt =
"For each mode (Architect, Ask, Debug) respond with the mode name and what it specializes in after switching to that mode."
const messages: ClineMessage[] = []
const modeSwitches: string[] = []
api.on("taskModeSwitched", (_taskId, mode) => {

View file

@ -1,13 +1,12 @@
import * as assert from "assert"
import type { RooCodeAPI, ClineMessage } from "@roo-code/types"
import type { ClineMessage } from "@roo-code/types"
import { sleep, waitFor, waitUntilCompleted } from "./utils"
suite.skip("Roo Code Subtasks", () => {
test("Should handle subtask cancellation and resumption correctly", async () => {
// @ts-expect-error - Expose the API to the tests.
const api = globalThis.api as RooCodeAPI
const api = globalThis.api
const messages: Record<string, ClineMessage[]> = {}
@ -49,7 +48,7 @@ suite.skip("Roo Code Subtasks", () => {
// The parent task should not have resumed yet, so we shouldn't see
// "Parent task resumed".
assert.ok(
messages[parentTaskId].find(({ type, text }) => type === "say" && text === "Parent task resumed") ===
messages[parentTaskId]?.find(({ type, text }) => type === "say" && text === "Parent task resumed") ===
undefined,
"Parent task should not have resumed after subtask cancellation",
)
@ -63,7 +62,7 @@ suite.skip("Roo Code Subtasks", () => {
// The parent task should still not have resumed.
assert.ok(
messages[parentTaskId].find(({ type, text }) => type === "say" && text === "Parent task resumed") ===
messages[parentTaskId]?.find(({ type, text }) => type === "say" && text === "Parent task resumed") ===
undefined,
"Parent task should not have resumed after subtask cancellation",
)

View file

@ -1,13 +1,12 @@
import * as assert from "assert"
import type { RooCodeAPI, ClineMessage } from "@roo-code/types"
import type { ClineMessage } from "@roo-code/types"
import { waitUntilCompleted } from "./utils"
suite("Roo Code Task", () => {
test("Should handle prompt and response correctly", async () => {
// @ts-expect-error - Expose the API to the tests.
const api = globalThis.api as RooCodeAPI
const api = globalThis.api
const messages: ClineMessage[] = []

8
apps/vscode-e2e/src/types/global.d.ts vendored Normal file
View file

@ -0,0 +1,8 @@
import type { RooCodeAPI } from "@roo-code/types"
declare global {
// eslint-disable-next-line no-var
var api: RooCodeAPI
}
export {}

View file

@ -0,0 +1,8 @@
{
"extends": "@roo-code/config-typescript/base.json",
"compilerOptions": {
"outDir": "out"
},
"include": ["src"],
"exclude": ["node_modules"]
}

View file

@ -11,6 +11,6 @@
"useUnknownInCatchVariables": false,
"outDir": "out"
},
"include": ["src", "../src/exports/roo-code.d.ts"],
"include": ["src"],
"exclude": [".vscode-test", "**/node_modules/**", "out"]
}

View file

@ -9,16 +9,17 @@ const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
async function main() {
const name = "extension-nightly"
const production = process.argv.includes("--production")
const minify = production
const sourcemap = !production
const overrideJson = JSON.parse(fs.readFileSync(path.join(__dirname, "package.nightly.json"), "utf8"))
console.log(`[main] name: ${overrideJson.name}`)
console.log(`[main] version: ${overrideJson.version}`)
console.log(`[${name}] name: ${overrideJson.name}`)
console.log(`[${name}] version: ${overrideJson.version}`)
const gitSha = getGitSha()
console.log(`[main] gitSha: ${gitSha}`)
console.log(`[${name}] gitSha: ${gitSha}`)
/**
* @type {import('esbuild').BuildOptions}
@ -43,12 +44,22 @@ async function main() {
const buildDir = path.join(__dirname, "build")
const distDir = path.join(buildDir, "dist")
console.log(`[${name}] srcDir: ${srcDir}`)
console.log(`[${name}] buildDir: ${buildDir}`)
console.log(`[${name}] distDir: ${distDir}`)
// Clean build directory before starting new build
if (fs.existsSync(buildDir)) {
console.log(`[${name}] Cleaning build directory: ${buildDir}`)
fs.rmSync(buildDir, { recursive: true, force: true })
}
/**
* @type {import('esbuild').Plugin[]}
*/
const plugins = [
{
name: "copy-files",
name: "copyPaths",
setup(build) {
build.onEnd(() => {
copyPaths(
@ -69,7 +80,7 @@ async function main() {
},
},
{
name: "generate-package-json",
name: "generatePackageJson",
setup(build) {
build.onEnd(() => {
const packageJson = JSON.parse(fs.readFileSync(path.join(srcDir, "package.json"), "utf8"))
@ -81,7 +92,7 @@ async function main() {
})
fs.writeFileSync(path.join(buildDir, "package.json"), JSON.stringify(generatedPackageJson, null, 2))
console.log(`[generate-package-json] Generated package.json`)
console.log(`[generatePackageJson] Generated package.json`)
let count = 0
@ -92,7 +103,7 @@ async function main() {
}
})
console.log(`[copy-src] Copied ${count} package.nls*.json files to ${buildDir}`)
console.log(`[generatePackageJson] Copied ${count} package.nls*.json files to ${buildDir}`)
const nlsPkg = JSON.parse(fs.readFileSync(path.join(srcDir, "package.nls.json"), "utf8"))
@ -105,18 +116,18 @@ async function main() {
JSON.stringify({ ...nlsPkg, ...nlsNightlyPkg }, null, 2),
)
console.log(`[copy-src] Generated package.nls.json`)
console.log(`[generatePackageJson] Generated package.nls.json`)
})
},
},
{
name: "copy-wasms",
name: "copyWasms",
setup(build) {
build.onEnd(() => copyWasms(srcDir, distDir))
},
},
{
name: "copy-locales",
name: "copyLocales",
setup(build) {
build.onEnd(() => copyLocales(srcDir, distDir))
},

View file

@ -4,9 +4,8 @@
"private": true,
"packageManager": "pnpm@10.8.1",
"scripts": {
"bundle": "pnpm clean && pnpm --filter @roo-code/build build && node esbuild.mjs",
"build": "pnpm bundle --production && pnpm --filter @roo-code/vscode-webview build --mode nightly",
"vsix": "pnpm build && cd build && mkdirp ../../../bin && npx vsce package --no-dependencies --out ../../../bin",
"bundle:nightly": "node esbuild.mjs",
"vsix:nightly": "cd build && mkdirp ../../../bin && npx vsce package --no-dependencies --out ../../../bin",
"clean": "rimraf build .turbo"
},
"devDependencies": {

View file

@ -1,243 +0,0 @@
import { suite, test, before, after } from "mocha"
import * as assert from "assert"
import { type RooCodeAPI } from "@roo-code/types"
import { waitFor, sleep } from "./utils" // Assuming utils.ts is in the same directory or path is adjusted
// Define an interface for globalThis that includes the 'api' property
interface GlobalWithApi extends NodeJS.Global {
api: RooCodeAPI
}
// Cast globalThis to our new interface
const g = globalThis as unknown as GlobalWithApi
// Define a minimal interface for task messages for type safety in callbacks
interface TestTaskMessage {
role: string
content: string | unknown // Content can be complex
isSummary?: boolean
// Allow other properties
[key: string]: unknown
}
suite("Context Condensing Integration Tests", () => {
let initialConfig: ReturnType<RooCodeAPI["getConfiguration"]>
before(async () => {
// Ensure API is ready before starting tests
await waitFor(() => g.api && g.api.isReady())
initialConfig = g.api.getConfiguration()
})
after(async () => {
// Restore initial configuration after tests
if (initialConfig) {
// Type issue: RooCodeSettings might not include new props.
// This will cause a type error if initialConfig contains new props not in RooCodeSettings.
// For now, we assume initialConfig is a valid RooCodeSettings or types need update.
await g.api.setConfiguration(initialConfig)
}
})
suite("Settings Persistence", () => {
test("should persist condensingApiConfigId when set", async () => {
const testConfigId = "test-condensing-api-config"
// @ts-expect-error - Argument of type '{ condensingApiConfigId: string; }' is not assignable to parameter of type 'RooCodeSettings'.
await g.api.setConfiguration({ condensingApiConfigId: testConfigId })
await sleep(100)
const updatedConfig = g.api.getConfiguration()
assert.strictEqual(
// @ts-expect-error - Property 'condensingApiConfigId' does not exist on type 'RooCodeSettings'.
updatedConfig.condensingApiConfigId,
testConfigId,
"condensingApiConfigId did not persist",
)
})
test("should persist customCondensingPrompt when set", async () => {
const testPrompt = "This is a custom condensing prompt for testing."
// @ts-expect-error - Argument of type '{ customCondensingPrompt: string; }' is not assignable to parameter of type 'RooCodeSettings'.
await g.api.setConfiguration({ customCondensingPrompt: testPrompt })
await sleep(100)
const updatedConfig = g.api.getConfiguration()
assert.strictEqual(
// @ts-expect-error - Property 'customCondensingPrompt' does not exist on type 'RooCodeSettings'.
updatedConfig.customCondensingPrompt,
testPrompt,
"customCondensingPrompt did not persist",
)
})
test("should clear customCondensingPrompt when set to empty string", async () => {
const initialPrompt = "A prompt to be cleared."
// @ts-expect-error - Argument of type '{ customCondensingPrompt: string; }' is not assignable to parameter of type 'RooCodeSettings'.
await g.api.setConfiguration({ customCondensingPrompt: initialPrompt })
await sleep(100)
let updatedConfig = g.api.getConfiguration()
// @ts-expect-error - Property 'customCondensingPrompt' does not exist on type 'RooCodeSettings'.
assert.strictEqual(updatedConfig.customCondensingPrompt, initialPrompt, "Initial prompt was not set")
// @ts-expect-error - Argument of type '{ customCondensingPrompt: string; }' is not assignable to parameter of type 'RooCodeSettings'.
await g.api.setConfiguration({ customCondensingPrompt: "" })
await sleep(100)
updatedConfig = g.api.getConfiguration()
// @ts-expect-error - Property 'customCondensingPrompt' does not exist on type 'RooCodeSettings'.
assert.strictEqual(updatedConfig.customCondensingPrompt, "", "customCondensingPrompt was not cleared")
})
test("should clear customCondensingPrompt when set to undefined", async () => {
const initialPrompt = "Another prompt to be cleared."
// @ts-expect-error - Argument of type '{ customCondensingPrompt: string; }' is not assignable to parameter of type 'RooCodeSettings'.
await g.api.setConfiguration({ customCondensingPrompt: initialPrompt })
await sleep(100)
let updatedConfig = g.api.getConfiguration()
assert.strictEqual(
// @ts-expect-error - Property 'customCondensingPrompt' does not exist on type 'RooCodeSettings'.
updatedConfig.customCondensingPrompt,
initialPrompt,
"Initial prompt for undefined test was not set",
)
// @ts-expect-error - Argument of type '{ customCondensingPrompt: undefined; }' is not assignable to parameter of type 'RooCodeSettings'.
await g.api.setConfiguration({ customCondensingPrompt: undefined })
await sleep(100)
updatedConfig = g.api.getConfiguration()
// @ts-expect-error - Property 'customCondensingPrompt' does not exist on type 'RooCodeSettings'.
const currentPrompt = updatedConfig.customCondensingPrompt
assert.ok(
currentPrompt === "" || currentPrompt === undefined || currentPrompt === null,
"customCondensingPrompt was not cleared by undefined",
)
})
})
suite("Message Handling (Conceptual - Covered by Settings Persistence)", () => {
test.skip("should correctly update backend state from webview messages", () => {
assert.ok(true, "Skipping direct webview message test, covered by settings persistence.")
})
})
suite("API Configuration Resolution and Prompt Customization", () => {
let taskId: string | undefined
beforeEach(async () => {
// @ts-expect-error - Property 'tasks' does not exist on type 'RooCodeAPI'.
const taskResponse = await g.api.tasks.createTask({
initialMessage: "This is the first message for a new task.",
})
taskId = taskResponse.taskId
assert.ok(taskId, "Task ID should be created")
await sleep(500)
})
afterEach(async () => {
if (taskId) {
taskId = undefined
}
// This directive was unused, meaning setConfiguration(initialConfig) is fine.
await g.api.setConfiguration(initialConfig)
await sleep(100)
})
test("should trigger condensation with default settings", async function () {
this.timeout(60000)
assert.ok(taskId, "Task ID must be defined for this test")
for (let i = 0; i < 5; i++) {
// @ts-expect-error - Property 'tasks' does not exist on type 'RooCodeAPI'.
await g.api.tasks.sendMessage({
taskId: taskId!,
message: `This is message number ${i + 2} in the conversation.`,
messageType: "user",
})
await sleep(2000)
}
// @ts-expect-error - Property 'tasks' does not exist on type 'RooCodeAPI'.
const task = await g.api.tasks.getTask(taskId!)
assert.ok(task, "Task should be retrievable")
const hasSummary = task.messages.some((msg: TestTaskMessage) => msg.isSummary === true)
console.log(
`Task messages for default settings test (taskId: ${taskId}):`,
JSON.stringify(task.messages, null, 2),
)
console.log(`Has summary (default settings): ${hasSummary}`)
assert.ok(
true,
"Condensation process completed with default settings (actual summary check is complex for e2e).",
)
})
test("should trigger condensation with custom condensing API config", async function () {
this.timeout(60000)
assert.ok(taskId, "Task ID must be defined for this test")
const customCondensingConfigId = "condensing-test-provider"
// This directive was unused. The error is on the property itself.
await g.api.setConfiguration({
// @ts-expect-error - condensingApiConfigId is not a known property in RooCodeSettings.
condensingApiConfigId: customCondensingConfigId,
})
await sleep(100)
for (let i = 0; i < 5; i++) {
// @ts-expect-error - Property 'tasks' does not exist on type 'RooCodeAPI'.
await g.api.tasks.sendMessage({
taskId: taskId!,
message: `Message ${i + 2} with custom API config.`,
messageType: "user",
})
await sleep(2000)
}
// @ts-expect-error - Property 'tasks' does not exist on type 'RooCodeAPI'.
const task = await g.api.tasks.getTask(taskId!)
assert.ok(task, "Task should be retrievable with custom API config")
const hasSummary = task.messages.some((msg: TestTaskMessage) => msg.isSummary === true)
console.log(
`Task messages for custom API config test (taskId: ${taskId}):`,
JSON.stringify(task.messages, null, 2),
)
console.log(`Has summary (custom API config): ${hasSummary}`)
assert.ok(
true,
"Condensation process completed with custom API config (specific handler verification is complex for e2e).",
)
})
test("should trigger condensation with custom condensing prompt", async function () {
this.timeout(60000)
assert.ok(taskId, "Task ID must be defined for this test")
const customPrompt = "E2E Test: Summarize this conversation very briefly."
// @ts-expect-error - Argument of type '{ customCondensingPrompt: string; }' is not assignable to parameter of type 'RooCodeSettings'.
await g.api.setConfiguration({ customCondensingPrompt: customPrompt })
await sleep(100)
for (let i = 0; i < 5; i++) {
// @ts-expect-error - Property 'tasks' does not exist on type 'RooCodeAPI'.
await g.api.tasks.sendMessage({
taskId: taskId!,
message: `Message ${i + 2} with custom prompt.`,
messageType: "user",
})
await sleep(2000)
}
// @ts-expect-error - Property 'tasks' does not exist on type 'RooCodeAPI'.
const task = await g.api.tasks.getTask(taskId!)
assert.ok(task, "Task should be retrievable with custom prompt")
const summaryMessage = task.messages.find((msg: TestTaskMessage) => msg.isSummary === true)
console.log(
`Task messages for custom prompt test (taskId: ${taskId}):`,
JSON.stringify(task.messages, null, 2),
)
if (summaryMessage) {
console.log("Summary content with custom prompt:", summaryMessage.content)
}
assert.ok(
true,
"Condensation process completed with custom prompt (prompt content verification is complex for e2e).",
)
})
})
})

View file

@ -12,8 +12,8 @@
"bin/**",
"apps/vscode-e2e/**",
"evals/**",
"src/extension/**",
"src/activate/**",
"src/exports/**",
"src/workers/**",
"src/schemas/ipc.ts",
"src/extension.ts",

View file

@ -13,14 +13,13 @@
"check-types": "turbo check-types --log-order grouped --output-logs new-only",
"test": "turbo test --log-order grouped --output-logs new-only",
"format": "turbo format --log-order grouped --output-logs new-only",
"bundle": "turbo bundle --log-order grouped --output-logs new-only",
"bundle:nightly": "turbo bundle:nightly --log-order grouped --output-logs new-only",
"build": "turbo vsix --log-order grouped --output-logs new-only",
"build:nightly": "turbo vsix:nightly --log-order grouped --output-logs new-only",
"clean": "turbo clean --log-order grouped --output-logs new-only && rimraf dist out bin .vite-port .turbo",
"build": "pnpm --filter roo-cline vsix",
"compile": "pnpm --filter roo-cline bundle",
"vsix": "pnpm --filter roo-cline vsix",
"build:nightly": "pnpm --filter @roo-code/vscode-nightly vsix",
"generate-types": "pnpm --filter roo-cline generate-types",
"changeset:version": "cp CHANGELOG.md src/CHANGELOG.md && changeset version && cp -vf src/CHANGELOG.md .",
"knip": "pnpm --filter @roo-code/build build && knip --include files",
"knip": "knip --include files",
"update-contributors": "node scripts/update-contributors.js"
},
"devDependencies": {

View file

@ -3,27 +3,7 @@ import * as path from "path"
import { ViewsContainer, Views, Menus, Configuration, contributesSchema } from "./types.js"
export function copyPaths(copyPaths: [string, string][], srcDir: string, dstDir: string) {
copyPaths.forEach(([srcRelPath, dstRelPath]) => {
const stats = fs.lstatSync(path.join(srcDir, srcRelPath))
if (stats.isDirectory()) {
if (fs.existsSync(path.join(dstDir, dstRelPath))) {
fs.rmSync(path.join(dstDir, dstRelPath), { recursive: true })
}
fs.mkdirSync(path.join(dstDir, dstRelPath), { recursive: true })
const count = copyDir(path.join(srcDir, srcRelPath), path.join(dstDir, dstRelPath), 0)
console.log(`[copyPaths] Copied ${count} files from ${srcRelPath} to ${dstRelPath}`)
} else {
fs.copyFileSync(path.join(srcDir, srcRelPath), path.join(dstDir, dstRelPath))
console.log(`[copyPaths] Copied ${srcRelPath} to ${dstRelPath}`)
}
})
}
export function copyDir(srcDir: string, dstDir: string, count: number): number {
function copyDir(srcDir: string, dstDir: string, count: number): number {
const entries = fs.readdirSync(srcDir, { withFileTypes: true })
for (const entry of entries) {
@ -42,6 +22,50 @@ export function copyDir(srcDir: string, dstDir: string, count: number): number {
return count
}
function rmDir(dirPath: string, maxRetries: number = 3): void {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
fs.rmSync(dirPath, { recursive: true, force: true })
return
} catch (error) {
const isLastAttempt = attempt === maxRetries
const isEnotemptyError = error instanceof Error && "code" in error && (error.code === 'ENOTEMPTY' || error.code === 'EBUSY')
if (isLastAttempt || !isEnotemptyError) {
throw error // Re-throw if it's the last attempt or not a locking error.
}
// Wait with exponential backoff before retrying.
const delay = Math.min(100 * Math.pow(2, attempt - 1), 1000) // Cap at 1s.
console.warn(`[rmDir] Attempt ${attempt} failed for ${dirPath}, retrying in ${delay}ms...`)
// Synchronous sleep for simplicity in build scripts.
const start = Date.now()
while (Date.now() - start < delay) { /* Busy wait */ }
}
}
}
export function copyPaths(copyPaths: [string, string][], srcDir: string, dstDir: string) {
copyPaths.forEach(([srcRelPath, dstRelPath]) => {
const stats = fs.lstatSync(path.join(srcDir, srcRelPath))
if (stats.isDirectory()) {
if (fs.existsSync(path.join(dstDir, dstRelPath))) {
rmDir(path.join(dstDir, dstRelPath))
}
fs.mkdirSync(path.join(dstDir, dstRelPath), { recursive: true })
const count = copyDir(path.join(srcDir, srcRelPath), path.join(dstDir, dstRelPath), 0)
console.log(`[copyPaths] Copied ${count} files from ${srcRelPath} to ${dstRelPath}`)
} else {
fs.copyFileSync(path.join(srcDir, srcRelPath), path.join(dstDir, dstRelPath))
console.log(`[copyPaths] Copied ${srcRelPath} to ${dstRelPath}`)
}
})
}
export function copyWasms(srcDir: string, distDir: string): void {
const nodeModulesDir = path.join(srcDir, "node_modules")

View file

@ -1,2 +1,2 @@
export { getGitSha } from "./git.js"
export { copyPaths, copyDir, copyWasms, copyLocales, setupLocaleWatcher, generatePackageJson } from "./esbuild.js"
export { copyPaths, copyWasms, copyLocales, setupLocaleWatcher, generatePackageJson } from "./esbuild.js"

View file

@ -1,15 +1,16 @@
# Roo Code API
The Roo Code extension exposes an API that can be used by other extensions. To use this API in your extension:
The Roo Code extension exposes an API that can be used by other extensions.
To use this API in your extension:
1. Copy `src/extension-api/roo-code.d.ts` to your extension's source directory.
2. Include `roo-code.d.ts` in your extension's compilation.
3. Get access to the API with the following code:
1. Install `@roo-code/types` with npm, pnpm, or yarn.
2. Import the `RooCodeAPI` type.
3. Load the extension API.
```typescript
import { RooCodeAPI, Package } from "path/to/roo-code"
import { RooCodeAPI } from "@roo-code/types"
const extension = vscode.extensions.getExtension<RooCodeAPI>(`${Package.publisher}.${Package.name}`)
const extension = vscode.extensions.getExtension<RooCodeAPI>("RooVeterinaryInc.roo-cline")
if (!extension?.isActive) {
throw new Error("Extension is not activated")

View file

@ -0,0 +1,4 @@
import { config } from "@roo-code/config-eslint/base"
/** @type {import("eslint").Linter.Config} */
export default [...config]

View file

@ -0,0 +1,37 @@
{
"name": "@roo-code/types",
"description": "Roo Code foundational types and schemas.",
"private": true,
"type": "module",
"main": "./dist/index.cjs",
"exports": {
".": {
"types": "./src/index.ts",
"import": "./src/index.ts",
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"files": [
"dist"
],
"scripts": {
"lint": "eslint src --ext=ts --max-warnings=0",
"check-types": "tsc --noEmit",
"test": "vitest --globals --run",
"build": "tsup",
"clean": "rimraf dist .turbo"
},
"dependencies": {
"zod": "^3.24.2"
},
"devDependencies": {
"@roo-code/config-eslint": "workspace:^",
"@roo-code/config-typescript": "workspace:^",
"@types/node": "^22.15.20",
"tsup": "^8.3.5",
"vitest": "^3.1.3"
}
}

View file

@ -0,0 +1,17 @@
// npx vitest run src/__tests__/index.test.ts
import { GLOBAL_STATE_KEYS } from "../index.js"
describe("GLOBAL_STATE_KEYS", () => {
it("should contain provider settings keys", () => {
expect(GLOBAL_STATE_KEYS).toContain("autoApprovalEnabled")
})
it("should contain provider settings keys", () => {
expect(GLOBAL_STATE_KEYS).toContain("anthropicBaseUrl")
})
it("should not contain secret state keys", () => {
expect(GLOBAL_STATE_KEYS).not.toContain("openRouterApiKey")
})
})

View file

@ -1,59 +1,37 @@
import { EventEmitter } from "events"
import { Socket } from "node:net"
/**
* Types
*/
import type { EventEmitter } from "events"
import type { Socket } from "net"
import type {
GlobalSettings,
ProviderName,
ProviderSettings,
RooCodeSettings,
ProviderSettingsEntry,
ProviderSettings,
ClineMessage,
TokenUsage,
RooCodeEvents,
IpcMessage,
ToolUsage,
ToolName,
TaskCommand,
TaskEvent,
} from "./types"
IpcMessage,
} from "./index.js"
import { IpcMessageType } from "./index.js"
export type {
GlobalSettings,
ProviderName,
ProviderSettings,
ProviderSettingsEntry,
ClineMessage,
TokenUsage,
RooCodeEvents,
IpcMessage,
TaskCommand,
TaskEvent,
// TODO: Make sure this matches `RooCodeEvents` from `@roo-code/types`.
export interface RooCodeAPIEvents {
message: [data: { taskId: string; action: "created" | "updated"; message: ClineMessage }]
taskCreated: [taskId: string]
taskStarted: [taskId: string]
taskModeSwitched: [taskId: string, mode: string]
taskPaused: [taskId: string]
taskUnpaused: [taskId: string]
taskAskResponded: [taskId: string]
taskAborted: [taskId: string]
taskSpawned: [parentTaskId: string, childTaskId: string]
taskCompleted: [taskId: string, tokenUsage: TokenUsage, toolUsage: ToolUsage]
taskTokenUsageUpdated: [taskId: string, tokenUsage: TokenUsage]
taskToolFailed: [taskId: string, toolName: ToolName, error: string]
}
/**
* Enums
*/
import { RooCodeEventName, IpcOrigin, IpcMessageType } from "../schemas"
export { RooCodeEventName, IpcOrigin, IpcMessageType }
/**
* Constants
*/
import { providerNames, Package } from "../schemas"
export { providerNames, Package }
/**
* RooCodeAPI
*/
export type RooCodeSettings = GlobalSettings & ProviderSettings
export interface RooCodeAPI extends EventEmitter<RooCodeEvents> {
export interface RooCodeAPI extends EventEmitter<RooCodeAPIEvents> {
/**
* Starts a new task with an optional initial message and images.
* @param task Optional initial task message.
@ -71,84 +49,70 @@ export interface RooCodeAPI extends EventEmitter<RooCodeEvents> {
images?: string[]
newTab?: boolean
}): Promise<string>
/**
* Resumes a task with the given ID.
* @param taskId The ID of the task to resume.
* @throws Error if the task is not found in the task history.
*/
resumeTask(taskId: string): Promise<void>
/**
* Checks if a task with the given ID is in the task history.
* @param taskId The ID of the task to check.
* @returns True if the task is in the task history, false otherwise.
*/
isTaskInHistory(taskId: string): Promise<boolean>
/**
* Returns the current task stack.
* @returns An array of task IDs.
*/
getCurrentTaskStack(): string[]
/**
* Clears the current task.
*/
clearCurrentTask(lastMessage?: string): Promise<void>
/**
* Cancels the current task.
*/
cancelCurrentTask(): Promise<void>
/**
* Sends a message to the current task.
* @param message Optional message to send.
* @param images Optional array of image data URIs (e.g., "data:image/webp;base64,...").
*/
sendMessage(message?: string, images?: string[]): Promise<void>
/**
* Simulates pressing the primary button in the chat interface.
*/
pressPrimaryButton(): Promise<void>
/**
* Simulates pressing the secondary button in the chat interface.
*/
pressSecondaryButton(): Promise<void>
/**
* Returns true if the API is ready to use.
*/
isReady(): boolean
/**
* Returns the current configuration.
* @returns The current configuration.
*/
getConfiguration(): RooCodeSettings
/**
* Sets the configuration for the current task.
* @param values An object containing key-value pairs to set.
*/
setConfiguration(values: RooCodeSettings): Promise<void>
/**
* Returns a list of all configured profile names
* @returns Array of profile names
*/
getProfiles(): string[]
/**
* Returns the profile entry for a given name
* @param name The name of the profile
* @returns The profile entry, or undefined if the profile does not exist
*/
getProfileEntry(name: string): ProviderSettingsEntry | undefined
/**
* Creates a new API configuration profile
* @param name The name of the profile
@ -158,7 +122,6 @@ export interface RooCodeAPI extends EventEmitter<RooCodeEvents> {
* @throws Error if the profile already exists
*/
createProfile(name: string, profile?: ProviderSettings, activate?: boolean): Promise<string>
/**
* Updates an existing API configuration profile
* @param name The name of the profile
@ -168,7 +131,6 @@ export interface RooCodeAPI extends EventEmitter<RooCodeEvents> {
* @throws Error if the profile does not exist
*/
updateProfile(name: string, profile: ProviderSettings, activate?: boolean): Promise<string | undefined>
/**
* Creates a new API configuration profile or updates an existing one
* @param name The name of the profile
@ -177,20 +139,17 @@ export interface RooCodeAPI extends EventEmitter<RooCodeEvents> {
* @returns The ID of the upserted profile
*/
upsertProfile(name: string, profile: ProviderSettings, activate?: boolean): Promise<string | undefined>
/**
* Deletes a profile by name
* @param name The name of the profile to delete
* @throws Error if the profile does not exist
*/
deleteProfile(name: string): Promise<void>
/**
* Returns the name of the currently active profile
* @returns The profile name, or undefined if no profile is active
*/
getActiveProfile(): string | undefined
/**
* Changes the active API configuration profile
* @param name The name of the profile to activate
@ -199,10 +158,6 @@ export interface RooCodeAPI extends EventEmitter<RooCodeEvents> {
setActiveProfile(name: string): Promise<string | undefined>
}
/**
* RooCodeIpcServer
*/
export type IpcServerEvents = {
[IpcMessageType.Connect]: [clientId: string]
[IpcMessageType.Disconnect]: [clientId: string]
@ -212,12 +167,8 @@ export type IpcServerEvents = {
export interface RooCodeIpcServer extends EventEmitter<IpcServerEvents> {
listen(): void
broadcast(message: IpcMessage): void
send(client: string | Socket, message: IpcMessage): void
get socketPath(): string
get isListening(): boolean
}

View file

@ -0,0 +1,2 @@
export * from "./types.js"
export * from "./api.js"

View file

@ -1,30 +1,16 @@
// Updates to this file will automatically propgate to src/exports/types.ts
// via a pre-commit hook. If you want to update the types before committing you
// can run `pnpm generate-types`.
import { z } from "zod"
import { Equals, Keys, AssertEqual } from "../utils/type-fu"
/**
* Extension
* TS
*/
import { publisher, name, version } from "../package.json"
export type Keys<T> = keyof T
// These ENV variables can be defined by ESBuild when building the extension
// in order to override the values in package.json. This allows us to build
// different extension variants with the same package.json file.
// The build process still needs to emit a modified package.json for consumption
// by VSCode, but that build artifact is not used during the transpile step of
// the build, so we still need this override mechanism.
export const Package = {
publisher,
name: process.env.PKG_NAME || name,
version: process.env.PKG_VERSION || version,
outputChannel: process.env.PKG_OUTPUT_CHANNEL || "Roo-Code",
sha: process.env.PKG_SHA,
} as const
export type Values<T> = T[keyof T]
export type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false
export type AssertEqual<T extends true> = T
/**
* CodeAction
@ -244,7 +230,7 @@ export const codebaseIndexModelsSchema = z.object({
export type CodebaseIndexModels = z.infer<typeof codebaseIndexModelsSchema>
export const codebaseIndexProviderSchema = z.object({
codeIndexOpenAiKey: z.string().optional(),
codeIndexOpenAiKey: z.string().optional(),
codeIndexQdrantApiKey: z.string().optional(),
})
@ -661,7 +647,7 @@ export const providerSettingsSchema = z.object({
...groqSchema.shape,
...chutesSchema.shape,
...litellmSchema.shape,
...codebaseIndexProviderSchema.shape
...codebaseIndexProviderSchema.shape,
})
export type ProviderSettings = z.infer<typeof providerSettingsSchema>
@ -1356,28 +1342,3 @@ export const ipcMessageSchema = z.discriminatedUnion("type", [
])
export type IpcMessage = z.infer<typeof ipcMessageSchema>
/**
* TypeDefinition
*/
export type TypeDefinition = {
schema: z.ZodTypeAny
identifier: string
}
export const typeDefinitions: TypeDefinition[] = [
{ schema: globalSettingsSchema, identifier: "GlobalSettings" },
{ schema: providerNamesSchema, identifier: "ProviderName" },
{ schema: providerSettingsSchema, identifier: "ProviderSettings" },
{ schema: providerSettingsEntrySchema, identifier: "ProviderSettingsEntry" },
{ schema: clineMessageSchema, identifier: "ClineMessage" },
{ schema: tokenUsageSchema, identifier: "TokenUsage" },
{ schema: rooCodeEventsSchema, identifier: "RooCodeEvents" },
{ schema: ipcMessageSchema, identifier: "IpcMessage" },
{ schema: taskCommandSchema, identifier: "TaskCommand" },
{ schema: taskEventSchema, identifier: "TaskEvent" },
]
// Also export as default for ESM compatibility.
export default { typeDefinitions }

View file

@ -0,0 +1,9 @@
{
"extends": "@roo-code/config-typescript/base.json",
"compilerOptions": {
"types": ["vitest/globals"],
"outDir": "dist"
},
"include": ["src"],
"exclude": ["node_modules"]
}

View file

@ -0,0 +1,11 @@
import { defineConfig } from "tsup"
export default defineConfig({
entry: ["src/index.ts"],
format: ["cjs", "esm"],
dts: true,
clean: false,
splitting: false,
sourcemap: true,
outDir: "dist",
})

1097
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,7 @@
import * as vscode from "vscode"
import { CodeActionName, CodeActionId } from "../schemas"
import { CodeActionName, CodeActionId } from "@roo-code/types"
import { getCodeActionCommand } from "../utils/commands"
import { EditorUtils } from "../integrations/editor/EditorUtils"

View file

@ -1,6 +1,6 @@
import * as vscode from "vscode"
import { Package } from "../schemas"
import { Package } from "../shared/package"
import { ClineProvider } from "../core/webview/ClineProvider"
import { t } from "../i18n"

View file

@ -1,6 +1,7 @@
import * as vscode from "vscode"
import { CodeActionId, CodeActionName } from "../schemas"
import { CodeActionId, CodeActionName } from "@roo-code/types"
import { getCodeActionCommand } from "../utils/commands"
import { EditorUtils } from "../integrations/editor/EditorUtils"
import { ClineProvider } from "../core/webview/ClineProvider"

View file

@ -1,7 +1,9 @@
import * as vscode from "vscode"
import delay from "delay"
import { CommandId, Package } from "../schemas"
import type { CommandId } from "@roo-code/types"
import { Package } from "../shared/package"
import { getCommand } from "../utils/commands"
import { ClineProvider } from "../core/webview/ClineProvider"
import { ContextProxy } from "../core/config/ContextProxy"

View file

@ -1,6 +1,7 @@
import * as vscode from "vscode"
import { TerminalActionId, TerminalActionPromptType } from "../schemas"
import { TerminalActionId, TerminalActionPromptType } from "@roo-code/types"
import { getTerminalCommand } from "../utils/commands"
import { ClineProvider } from "../core/webview/ClineProvider"
import { Terminal } from "../integrations/terminal/Terminal"

View file

@ -1,29 +1,33 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ProviderSettings, ModelInfo } from "../shared/api"
import { GlamaHandler } from "./providers/glama"
import { AnthropicHandler } from "./providers/anthropic"
import { AwsBedrockHandler } from "./providers/bedrock"
import { OpenRouterHandler } from "./providers/openrouter"
import { VertexHandler } from "./providers/vertex"
import { AnthropicVertexHandler } from "./providers/anthropic-vertex"
import { OpenAiHandler } from "./providers/openai"
import { OllamaHandler } from "./providers/ollama"
import { LmStudioHandler } from "./providers/lmstudio"
import { GeminiHandler } from "./providers/gemini"
import { OpenAiNativeHandler } from "./providers/openai-native"
import { DeepSeekHandler } from "./providers/deepseek"
import { MistralHandler } from "./providers/mistral"
import { VsCodeLmHandler } from "./providers/vscode-lm"
import type { ProviderSettings, ModelInfo } from "@roo-code/types"
import { ApiStream } from "./transform/stream"
import { UnboundHandler } from "./providers/unbound"
import { RequestyHandler } from "./providers/requesty"
import { HumanRelayHandler } from "./providers/human-relay"
import { FakeAIHandler } from "./providers/fake-ai"
import { XAIHandler } from "./providers/xai"
import { GroqHandler } from "./providers/groq"
import { ChutesHandler } from "./providers/chutes"
import { LiteLLMHandler } from "./providers/litellm"
import {
GlamaHandler,
AnthropicHandler,
AwsBedrockHandler,
OpenRouterHandler,
VertexHandler,
AnthropicVertexHandler,
OpenAiHandler,
OllamaHandler,
LmStudioHandler,
GeminiHandler,
OpenAiNativeHandler,
DeepSeekHandler,
MistralHandler,
VsCodeLmHandler,
UnboundHandler,
RequestyHandler,
HumanRelayHandler,
FakeAIHandler,
XAIHandler,
GroqHandler,
ChutesHandler,
LiteLLMHandler,
} from "./providers"
export interface SingleCompletionHandler {
completePrompt(prompt: string): Promise<string>
@ -67,11 +71,9 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
case "bedrock":
return new AwsBedrockHandler(options)
case "vertex":
if (options.apiModelId?.startsWith("claude")) {
return new AnthropicVertexHandler(options)
} else {
return new VertexHandler(options)
}
return options.apiModelId?.startsWith("claude")
? new AnthropicVertexHandler(options)
: new VertexHandler(options)
case "openai":
return new OpenAiHandler(options)
case "ollama":

View file

@ -2,8 +2,10 @@
import { Anthropic } from "@anthropic-ai/sdk"
import type { ModelInfo } from "@roo-code/types"
import { geminiDefaultModelId } from "../../../shared/api"
import { GeminiHandler } from "../gemini"
import { geminiDefaultModelId, type ModelInfo } from "../../../shared/api"
const GEMINI_20_FLASH_THINKING_NAME = "gemini-2.0-flash-thinking-exp-1219"

View file

@ -2,7 +2,9 @@ import { Anthropic } from "@anthropic-ai/sdk"
import { AnthropicVertex } from "@anthropic-ai/vertex-sdk"
import { GoogleAuth, JWTInput } from "google-auth-library"
import { ApiHandlerOptions, ModelInfo, vertexDefaultModelId, VertexModelId, vertexModels } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, vertexDefaultModelId, VertexModelId, vertexModels } from "../../shared/api"
import { safeJsonParse } from "../../shared/safeJsonParse"
import { ApiStream } from "../transform/stream"

View file

@ -2,13 +2,9 @@ import { Anthropic } from "@anthropic-ai/sdk"
import { Stream as AnthropicStream } from "@anthropic-ai/sdk/streaming"
import { CacheControlEphemeral } from "@anthropic-ai/sdk/resources"
import {
anthropicDefaultModelId,
AnthropicModelId,
anthropicModels,
ApiHandlerOptions,
ModelInfo,
} from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { anthropicDefaultModelId, AnthropicModelId, anthropicModels, ApiHandlerOptions } from "../../shared/api"
import { ApiStream } from "../transform/stream"
import { getModelParams } from "../transform/model-params"

View file

@ -1,7 +1,9 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
import { ApiHandlerOptions, ModelInfo } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import type { ApiHandlerOptions } from "../../shared/api"
import { ApiStream } from "../transform/stream"
import { convertToOpenAiMessages } from "../transform/openai-format"

View file

@ -1,6 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ModelInfo } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import type { ApiHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { ApiStream } from "../transform/stream"

View file

@ -9,18 +9,18 @@ import {
} from "@aws-sdk/client-bedrock-runtime"
import { fromIni } from "@aws-sdk/credential-providers"
import { Anthropic } from "@anthropic-ai/sdk"
import type { ModelInfo, ProviderSettings } from "@roo-code/types"
import {
BedrockModelId,
ModelInfo as SharedModelInfo,
bedrockDefaultModelId,
bedrockModels,
bedrockDefaultPromptRouterModelId,
} from "../../shared/api"
import { ProviderSettings } from "../../schemas"
import { ApiStream } from "../transform/stream"
import { BaseProvider } from "./base-provider"
import { logger } from "../../utils/logging"
// New cache-related imports
import { MultiPointStrategy } from "../transform/cache-strategy/multi-point-strategy"
import { ModelInfo as CacheModelInfo } from "../transform/cache-strategy/types"
import { AMAZON_BEDROCK_REGION_INFO } from "../../shared/aws_regions"
@ -514,7 +514,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
*
*************************************************************************************/
private costModelConfig: { id: BedrockModelId | string; info: SharedModelInfo } = {
private costModelConfig: { id: BedrockModelId | string; info: ModelInfo } = {
id: "",
info: { maxTokens: 0, contextWindow: 0, supportsPromptCache: false, supportsImages: false },
}
@ -621,7 +621,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
}
//Prompt Router responses come back in a different sequence and the model used is in the response and must be fetched by name
getModelById(modelId: string, modelType?: string): { id: BedrockModelId | string; info: SharedModelInfo } {
getModelById(modelId: string, modelType?: string): { id: BedrockModelId | string; info: ModelInfo } {
// Try to find the model in bedrockModels
const baseModelId = this.parseBaseModelId(modelId) as BedrockModelId
@ -651,7 +651,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
return model
}
override getModel(): { id: BedrockModelId | string; info: SharedModelInfo } {
override getModel(): { id: BedrockModelId | string; info: ModelInfo } {
if (this.costModelConfig?.id?.trim().length > 0) {
return this.costModelConfig
}
@ -683,7 +683,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
modelConfig.info.maxTokens = modelConfig.info.maxTokens || BEDROCK_MAX_TOKENS
return modelConfig as { id: BedrockModelId | string; info: SharedModelInfo }
return modelConfig as { id: BedrockModelId | string; info: ModelInfo }
}
/************************************************************************************
@ -695,10 +695,7 @@ export class AwsBedrockHandler extends BaseProvider implements SingleCompletionH
// Store previous cache point placements for maintaining consistency across consecutive messages
private previousCachePointPlacements: { [conversationId: string]: any[] } = {}
private supportsAwsPromptCache(modelConfig: {
id: BedrockModelId | string
info: SharedModelInfo
}): boolean | undefined {
private supportsAwsPromptCache(modelConfig: { id: BedrockModelId | string; info: ModelInfo }): boolean | undefined {
// Check if the model supports prompt cache
// The cachableFields property is not part of the ModelInfo type in schemas
// but it's used in the bedrockModels object in shared/api.ts

View file

@ -1,7 +1,10 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ApiHandlerOptions, ModelInfo } from "../../shared/api"
import { ApiStream } from "../transform/stream"
import type { ModelInfo } from "@roo-code/types"
import type { ApiHandler, SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import type { ApiHandlerOptions } from "../../shared/api"
import { ApiStream } from "../transform/stream"
interface FakeAI {
/**

View file

@ -1,7 +1,8 @@
import axios from "axios"
import { ModelInfo } from "../../../shared/api"
import { parseApiPrice } from "../../../utils/cost"
import type { ModelInfo } from "@roo-code/types"
import { parseApiPrice } from "../../../shared/cost"
export async function getGlamaModels(): Promise<Record<string, ModelInfo>> {
const models: Record<string, ModelInfo> = {}

View file

@ -1,4 +1,5 @@
import axios from "axios"
import { OPEN_ROUTER_COMPUTER_USE_MODELS, ModelRecord } from "../../../shared/api"
/**

View file

@ -1,16 +1,16 @@
import axios from "axios"
import { z } from "zod"
import { isModelParameter } from "../../../schemas"
import { type ModelInfo, isModelParameter } from "@roo-code/types"
import {
ApiHandlerOptions,
ModelInfo,
OPEN_ROUTER_COMPUTER_USE_MODELS,
OPEN_ROUTER_REASONING_BUDGET_MODELS,
OPEN_ROUTER_REQUIRED_REASONING_BUDGET_MODELS,
anthropicModels,
} from "../../../shared/api"
import { parseApiPrice } from "../../../utils/cost"
import { parseApiPrice } from "../../../shared/cost"
/**
* OpenRouterBaseModel

View file

@ -1,7 +1,8 @@
import axios from "axios"
import { ModelInfo } from "../../../shared/api"
import { parseApiPrice } from "../../../utils/cost"
import type { ModelInfo } from "@roo-code/types"
import { parseApiPrice } from "../../../shared/cost"
export async function getRequestyModels(apiKey?: string): Promise<Record<string, ModelInfo>> {
const models: Record<string, ModelInfo> = {}

View file

@ -1,6 +1,6 @@
import axios from "axios"
import { ModelInfo } from "../../../shared/api"
import type { ModelInfo } from "@roo-code/types"
export async function getUnboundModels(apiKey?: string | null): Promise<Record<string, ModelInfo>> {
const models: Record<string, ModelInfo> = {}

View file

@ -7,12 +7,15 @@ import {
} from "@google/genai"
import type { JWTInput } from "google-auth-library"
import { ApiHandlerOptions, ModelInfo, GeminiModelId, geminiDefaultModelId, geminiModels } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, GeminiModelId, geminiDefaultModelId, geminiModels } from "../../shared/api"
import { safeJsonParse } from "../../shared/safeJsonParse"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { convertAnthropicContentToGemini, convertAnthropicMessageToGemini } from "../transform/gemini-format"
import type { ApiStream } from "../transform/stream"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { BaseProvider } from "./base-provider"
type GeminiHandlerOptions = ApiHandlerOptions & {

View file

@ -2,7 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
import axios from "axios"
import OpenAI from "openai"
import { Package } from "../../schemas"
import { Package } from "../../shared/package"
import { ApiHandlerOptions, glamaDefaultModelId, glamaDefaultModelInfo } from "../../shared/api"
import { ApiStream } from "../transform/stream"

View file

@ -1,10 +1,13 @@
import { Anthropic } from "@anthropic-ai/sdk"
import * as vscode from "vscode"
import { ModelInfo } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { getCommand } from "../../utils/commands"
import { ApiStream } from "../transform/stream"
import type { ApiHandler, SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
/**
* Human Relay API processor
* This processor does not directly call the API, but interacts with the model through human operations copy and paste.

View file

@ -0,0 +1,22 @@
export { GlamaHandler } from "./glama"
export { AnthropicHandler } from "./anthropic"
export { AwsBedrockHandler } from "./bedrock"
export { OpenRouterHandler } from "./openrouter"
export { VertexHandler } from "./vertex"
export { AnthropicVertexHandler } from "./anthropic-vertex"
export { OpenAiHandler } from "./openai"
export { OllamaHandler } from "./ollama"
export { LmStudioHandler } from "./lmstudio"
export { GeminiHandler } from "./gemini"
export { OpenAiNativeHandler } from "./openai-native"
export { DeepSeekHandler } from "./deepseek"
export { MistralHandler } from "./mistral"
export { VsCodeLmHandler } from "./vscode-lm"
export { UnboundHandler } from "./unbound"
export { RequestyHandler } from "./requesty"
export { HumanRelayHandler } from "./human-relay"
export { FakeAIHandler } from "./fake-ai"
export { XAIHandler } from "./xai"
export { GroqHandler } from "./groq"
export { ChutesHandler } from "./chutes"
export { LiteLLMHandler } from "./litellm"

View file

@ -2,11 +2,15 @@ import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
import axios from "axios"
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, openAiModelInfoSaneDefaults } from "../../shared/api"
import { XmlMatcher } from "../../utils/xml-matcher"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"
import { BaseProvider } from "./base-provider"
import { XmlMatcher } from "../../utils/xml-matcher"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
const LMSTUDIO_DEFAULT_TEMPERATURE = 0

View file

@ -1,8 +1,12 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { Mistral } from "@mistralai/mistralai"
import { ApiHandlerOptions, mistralDefaultModelId, MistralModelId, mistralModels, ModelInfo } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, mistralDefaultModelId, MistralModelId, mistralModels } from "../../shared/api"
import { convertToMistralMessages } from "../transform/mistral-format"
import { ApiStream } from "../transform/stream"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"

View file

@ -2,14 +2,18 @@ import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
import axios from "axios"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, openAiModelInfoSaneDefaults } from "../../shared/api"
import { XmlMatcher } from "../../utils/xml-matcher"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { convertToR1Format } from "../transform/r1-format"
import { ApiStream } from "../transform/stream"
import { DEEP_SEEK_DEFAULT_TEMPERATURE } from "./constants"
import { XmlMatcher } from "../../utils/xml-matcher"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
// Alias for the usage object returned in streaming chunks
type CompletionUsage = OpenAI.Chat.Completions.ChatCompletionChunk["usage"]

View file

@ -1,22 +1,23 @@
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
import type { ModelInfo } from "@roo-code/types"
import {
ApiHandlerOptions,
ModelInfo,
openAiNativeDefaultModelId,
OpenAiNativeModelId,
openAiNativeModels,
} from "../../shared/api"
import { calculateApiCostOpenAI } from "../../utils/cost"
import { calculateApiCostOpenAI } from "../../shared/cost"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"
import { getModelParams } from "../transform/model-params"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
const OPENAI_NATIVE_DEFAULT_TEMPERATURE = 0

View file

@ -2,12 +2,9 @@ import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI, { AzureOpenAI } from "openai"
import axios from "axios"
import {
ApiHandlerOptions,
azureOpenAiDefaultApiVersion,
ModelInfo,
openAiModelInfoSaneDefaults,
} from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, azureOpenAiDefaultApiVersion, openAiModelInfoSaneDefaults } from "../../shared/api"
import { XmlMatcher } from "../../utils/xml-matcher"
@ -18,8 +15,8 @@ import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
import { getModelParams } from "../transform/model-params"
import { DEFAULT_HEADERS, DEEP_SEEK_DEFAULT_TEMPERATURE } from "./constants"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
export const AZURE_AI_INFERENCE_PATH = "/models/chat/completions"

View file

@ -1,19 +1,18 @@
import { Anthropic } from "@anthropic-ai/sdk"
import {
ApiHandlerOptions,
ModelInfo,
ModelRecord,
requestyDefaultModelId,
requestyDefaultModelInfo,
} from "../../shared/api"
import OpenAI from "openai"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, ModelRecord, requestyDefaultModelId, requestyDefaultModelInfo } from "../../shared/api"
import { calculateApiCostOpenAI } from "../../shared/cost"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { calculateApiCostOpenAI } from "../../utils/cost"
import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../"
import { BaseProvider } from "./base-provider"
import { DEFAULT_HEADERS } from "./constants"
import { getModels } from "./fetchers/modelCache"
import OpenAI from "openai"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../"
// Requesty usage includes an extra field for Anthropic use cases.
// Safely cast the prompt token details section to the appropriate structure.

View file

@ -1,6 +1,9 @@
import OpenAI from "openai"
import { ApiHandlerOptions, RouterName, ModelRecord, ModelInfo } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, RouterName, ModelRecord } from "../../shared/api"
import { BaseProvider } from "./base-provider"
import { getModels } from "./fetchers/modelCache"

View file

@ -1,7 +1,9 @@
import { ApiHandlerOptions, ModelInfo, VertexModelId, vertexDefaultModelId, vertexModels } from "../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { ApiHandlerOptions, VertexModelId, vertexDefaultModelId, vertexModels } from "../../shared/api"
import { SingleCompletionHandler } from "../index"
import { GeminiHandler } from "./gemini"
import { SingleCompletionHandler } from "../index"
export class VertexHandler extends GeminiHandler implements SingleCompletionHandler {
constructor(options: ApiHandlerOptions) {

View file

@ -1,12 +1,16 @@
import { Anthropic } from "@anthropic-ai/sdk"
import * as vscode from "vscode"
import type { ModelInfo } from "@roo-code/types"
import { SELECTOR_SEPARATOR, stringifyVsCodeLmModelSelector } from "../../shared/vsCodeSelectorUtils"
import { ApiHandlerOptions, openAiModelInfoSaneDefaults } from "../../shared/api"
import { ApiStream } from "../transform/stream"
import { convertToVsCodeLmMessages } from "../transform/vscode-lm-format"
import { SELECTOR_SEPARATOR, stringifyVsCodeLmModelSelector } from "../../shared/vsCodeSelectorUtils"
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
import { BaseProvider } from "./base-provider"
import type { SingleCompletionHandler, ApiHandler, ApiHandlerCreateMessageMetadata } from "../index"
import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from "../index"
/**
* Handles interaction with VS Code's Language Model API for chat-based operations.

View file

@ -1,7 +1,8 @@
import { ApiHandler } from "../.."
import type { ModelInfo } from "@roo-code/types"
import { ApiHandler } from "../../index"
import { ApiMessage } from "../../../core/task-persistence/apiMessages"
import { maybeRemoveImageBlocks } from "../image-cleaning"
import { ModelInfo } from "../../../shared/api"
describe("maybeRemoveImageBlocks", () => {
// Mock ApiHandler factory function

View file

@ -1,6 +1,7 @@
// npx jest src/api/transform/__tests__/model-params.test.ts
import { ModelInfo } from "../../../schemas"
import type { ModelInfo } from "@roo-code/types"
import { ANTHROPIC_DEFAULT_MAX_TOKENS } from "../../providers/constants"
import { getModelParams } from "../model-params"

View file

@ -1,6 +1,7 @@
// npx jest src/api/transform/__tests__/reasoning.test.ts
import { ModelInfo, ProviderSettings } from "../../../schemas"
import type { ModelInfo, ProviderSettings } from "@roo-code/types"
import {
getOpenRouterReasoning,
getAnthropicReasoning,

View file

@ -1,6 +1,7 @@
import { ApiHandler } from ".."
import { ApiMessage } from "../../core/task-persistence/apiMessages"
import { ApiHandler } from "../index"
/* Removes image blocks from messages if they are not supported by the Api Handler */
export function maybeRemoveImageBlocks(messages: ApiMessage[], apiHandler: ApiHandler): ApiMessage[] {
return messages.map((message) => {

View file

@ -1,10 +1,7 @@
import type { ModelInfo, ProviderSettings } from "@roo-code/types"
import { ANTHROPIC_DEFAULT_MAX_TOKENS } from "../providers/constants"
import {
shouldUseReasoningBudget,
shouldUseReasoningEffort,
type ModelInfo,
type ProviderSettings,
} from "../../shared/api"
import { shouldUseReasoningBudget, shouldUseReasoningEffort } from "../../shared/api"
import {
type AnthropicReasoningParams,

View file

@ -1,7 +1,8 @@
import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta"
import OpenAI from "openai"
import { ModelInfo, ProviderSettings } from "../../schemas"
import type { ModelInfo, ProviderSettings } from "@roo-code/types"
import { shouldUseReasoningBudget, shouldUseReasoningEffort } from "../../shared/api"
type ReasoningEffort = "low" | "medium" | "high"

View file

@ -1,5 +1,6 @@
import { type ToolName, toolNames } from "@roo-code/types"
import { TextContent, ToolUse, ToolParamName, toolParamNames } from "../../shared/tools"
import { toolNames, ToolName } from "../../schemas"
export type AssistantMessageContent = TextContent | ToolUse

View file

@ -1,5 +1,6 @@
import { type ToolName, toolNames } from "@roo-code/types"
import { TextContent, ToolUse, ToolParamName, toolParamNames } from "../../shared/tools"
import { toolNames, ToolName } from "../../schemas"
export type AssistantMessageContent = TextContent | ToolUse

View file

@ -1,11 +1,10 @@
import cloneDeep from "clone-deep"
import { serializeError } from "serialize-error"
import type { ToolName } from "../../schemas"
import type { ToolName, ClineAsk, ToolProgressStatus } from "@roo-code/types"
import { defaultModeSlug, getModeBySlug } from "../../shared/modes"
import type { ToolParamName, ToolResponse } from "../../shared/tools"
import type { ClineAsk, ToolProgressStatus } from "../../shared/ExtensionMessage"
import { telemetryService } from "../../services/telemetry/TelemetryService"

View file

@ -6,15 +6,16 @@ import {
GLOBAL_SETTINGS_KEYS,
SECRET_STATE_KEYS,
GLOBAL_STATE_KEYS,
ProviderSettings,
GlobalSettings,
SecretState,
GlobalState,
RooCodeSettings,
type ProviderSettings,
type GlobalSettings,
type SecretState,
type GlobalState,
type RooCodeSettings,
providerSettingsSchema,
globalSettingsSchema,
isSecretStateKey,
} from "../../schemas"
} from "@roo-code/types"
import { logger } from "../../utils/logging"
import { telemetryService } from "../../services/telemetry/TelemetryService"

View file

@ -1,13 +1,15 @@
import * as vscode from "vscode"
import * as path from "path"
import * as fs from "fs/promises"
import { customModesSettingsSchema } from "../../schemas"
import { ModeConfig } from "../../shared/modes"
import * as yaml from "yaml"
import { type ModeConfig, customModesSettingsSchema } from "@roo-code/types"
import { fileExistsAtPath } from "../../utils/fs"
import { arePathsEqual, getWorkspacePath } from "../../utils/path"
import { logger } from "../../utils/logging"
import { GlobalFileNames } from "../../shared/globalFileNames"
import * as yaml from "yaml"
const ROOMODES_FILENAME = ".roomodes"

View file

@ -1,7 +1,12 @@
import { ExtensionContext } from "vscode"
import { z, ZodError } from "zod"
import { providerSettingsSchema, ProviderSettingsEntry, providerSettingsSchemaDiscriminated } from "../../schemas"
import {
type ProviderSettingsEntry,
providerSettingsSchema,
providerSettingsSchemaDiscriminated,
} from "@roo-code/types"
import { Mode, modes } from "../../shared/modes"
import { telemetryService } from "../../services/telemetry/TelemetryService"

View file

@ -1,9 +1,10 @@
// npx jest src/core/config/__tests__/ContextProxy.test.ts
import * as vscode from "vscode"
import { ContextProxy } from "../ContextProxy"
import { GLOBAL_STATE_KEYS, SECRET_STATE_KEYS } from "../../../schemas"
import { GLOBAL_STATE_KEYS, SECRET_STATE_KEYS } from "@roo-code/types"
import { ContextProxy } from "../ContextProxy"
jest.mock("vscode", () => ({
Uri: {

View file

@ -3,12 +3,16 @@
import * as vscode from "vscode"
import * as path from "path"
import * as fs from "fs/promises"
import { CustomModesManager } from "../CustomModesManager"
import { ModeConfig } from "../../../shared/modes"
import * as yaml from "yaml"
import type { ModeConfig } from "@roo-code/types"
import { fileExistsAtPath } from "../../../utils/fs"
import { getWorkspacePath, arePathsEqual } from "../../../utils/path"
import { GlobalFileNames } from "../../../shared/globalFileNames"
import * as yaml from "yaml"
import { CustomModesManager } from "../CustomModesManager"
jest.mock("vscode")
jest.mock("fs/promises")

View file

@ -1,9 +1,9 @@
// npx jest src/core/config/__tests__/CustomModesSettings.test.ts
import { customModesSettingsSchema } from "../../../schemas"
import { ModeConfig } from "../../../shared/modes"
import { ZodError } from "zod"
import { type ModeConfig, customModesSettingsSchema } from "@roo-code/types"
describe("CustomModesSettings", () => {
const validMode = {
slug: "123e4567-e89b-12d3-a456-426614174000",

View file

@ -2,8 +2,7 @@
import { ZodError } from "zod"
import { modeConfigSchema } from "../../../schemas"
import { ModeConfig } from "../../../shared/modes"
import { type ModeConfig, modeConfigSchema } from "@roo-code/types"
function validateCustomMode(mode: unknown): asserts mode is ModeConfig {
modeConfigSchema.parse(mode)

View file

@ -2,7 +2,8 @@
import { ExtensionContext } from "vscode"
import { ProviderSettings } from "../../../schemas"
import type { ProviderSettings } from "@roo-code/types"
import { ProviderSettingsManager, ProviderProfiles } from "../ProviderSettingsManager"
// Mock VSCode ExtensionContext

View file

@ -5,7 +5,8 @@ import * as path from "path"
import * as vscode from "vscode"
import { ProviderName } from "../../../schemas"
import type { ProviderName } from "@roo-code/types"
import { importSettings, exportSettings } from "../importExport"
import { ProviderSettingsManager } from "../ProviderSettingsManager"
import { ContextProxy } from "../ContextProxy"

View file

@ -5,12 +5,13 @@ import fs from "fs/promises"
import * as vscode from "vscode"
import { z, ZodError } from "zod"
import { globalSettingsSchema } from "../../schemas"
import { globalSettingsSchema } from "@roo-code/types"
import { telemetryService } from "../../services/telemetry/TelemetryService"
import { ProviderSettingsManager, providerProfilesSchema } from "./ProviderSettingsManager"
import { ContextProxy } from "./ContextProxy"
import { CustomModesManager } from "./CustomModesManager"
import { telemetryService } from "../../services/telemetry/TelemetryService"
type ImportOptions = {
providerSettingsManager: ProviderSettingsManager

View file

@ -2,8 +2,9 @@
import { distance } from "fastest-levenshtein"
import { ToolProgressStatus } from "@roo-code/types"
import { addLineNumbers, everyLineHasLineNumbers, stripLineNumbers } from "../../../integrations/misc/extract-text"
import { ToolProgressStatus } from "../../../shared/ExtensionMessage"
import { ToolUse, DiffStrategy, DiffResult } from "../../../shared/tools"
import { normalizeString } from "../../../utils/text-normalization"

View file

@ -5,7 +5,9 @@ import * as vscode from "vscode"
import pWaitFor from "p-wait-for"
import delay from "delay"
import { EXPERIMENT_IDS, experiments as Experiments, ExperimentId } from "../../shared/experiments"
import type { ExperimentId } from "@roo-code/types"
import { EXPERIMENT_IDS, experiments as Experiments } from "../../shared/experiments"
import { formatLanguage } from "../../shared/language"
import { defaultModeSlug, getFullModeDetails, getModeBySlug, isToolAllowedForMode } from "../../shared/modes"
import { getApiMetrics } from "../../shared/getApiMetrics"

View file

@ -1,9 +1,13 @@
// npx jest src/core/prompts/__tests__/system.test.ts
import * as vscode from "vscode"
import { ModeConfig } from "@roo-code/types"
import { SYSTEM_PROMPT } from "../system"
import { McpHub } from "../../../services/mcp/McpHub"
import { defaultModeSlug, modes, Mode, ModeConfig } from "../../../shared/modes"
import "../../../utils/path" // Import path utils to get access to toPosix string extension.
import { defaultModeSlug, modes, Mode } from "../../../shared/modes"
import "../../../utils/path"
import { addCustomInstructions } from "../sections/custom-instructions"
import { MultiSearchReplaceDiffStrategy } from "../../diff/strategies/multi-search-replace"

View file

@ -1,9 +1,11 @@
import fs from "fs/promises"
import path from "path"
import { LANGUAGES, isLanguage } from "../../../shared/language"
import { Dirent } from "fs"
import { isLanguage } from "@roo-code/types"
import { LANGUAGES } from "../../../shared/language"
/**
* Safely read a file and return its trimmed content
*/

View file

@ -2,7 +2,9 @@ import * as path from "path"
import * as vscode from "vscode"
import { promises as fs } from "fs"
import { ModeConfig, getAllModesWithPrompts } from "../../../shared/modes"
import type { ModeConfig } from "@roo-code/types"
import { getAllModesWithPrompts } from "../../../shared/modes"
export async function getModesSection(context: vscode.ExtensionContext): Promise<string> {
const settingsDir = path.join(context.globalStorageUri.fsPath, "settings")

View file

@ -1,19 +1,18 @@
import {
Mode,
modes,
CustomModePrompts,
PromptComponent,
defaultModeSlug,
ModeConfig,
getModeBySlug,
getGroupName,
} from "../../shared/modes"
import { PromptVariables, loadSystemPromptFile } from "./sections/custom-system-prompt"
import { DiffStrategy } from "../../shared/tools"
import { McpHub } from "../../services/mcp/McpHub"
import { getToolDescriptionsForMode } from "./tools"
import * as vscode from "vscode"
import * as os from "os"
import type { ModeConfig, PromptComponent, CustomModePrompts } from "@roo-code/types"
import { Mode, modes, defaultModeSlug, getModeBySlug, getGroupName } from "../../shared/modes"
import { DiffStrategy } from "../../shared/tools"
import { formatLanguage } from "../../shared/language"
import { McpHub } from "../../services/mcp/McpHub"
import { CodeIndexManager } from "../../services/code-index/manager"
import { PromptVariables, loadSystemPromptFile } from "./sections/custom-system-prompt"
import { getToolDescriptionsForMode } from "./tools"
import {
getRulesSection,
getSystemInfoSection,
@ -26,8 +25,6 @@ import {
addCustomInstructions,
markdownFormattingSection,
} from "./sections"
import { formatLanguage } from "../../shared/language"
import { CodeIndexManager } from "../../services/code-index/manager"
async function generatePrompt(
context: vscode.ExtensionContext,

View file

@ -1,7 +1,8 @@
import { ToolName } from "../../../schemas"
import type { ToolName, ModeConfig } from "@roo-code/types"
import { TOOL_GROUPS, ALWAYS_AVAILABLE_TOOLS, DiffStrategy } from "../../../shared/tools"
import { McpHub } from "../../../services/mcp/McpHub"
import { Mode, ModeConfig, getModeConfig, isToolAllowedForMode, getGroupName } from "../../../shared/modes"
import { Mode, getModeConfig, isToolAllowedForMode, getGroupName } from "../../../shared/modes"
import { ToolArgs } from "./types"
import { getExecuteCommandDescription } from "./execute-command"

View file

@ -2,16 +2,18 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { ModelInfo } from "../../../shared/api"
import type { ModelInfo } from "@roo-code/types"
import { BaseProvider } from "../../../api/providers/base-provider"
import { ApiMessage } from "../../task-persistence/apiMessages"
import * as condenseModule from "../../condense"
import {
TOKEN_BUFFER_PERCENTAGE,
estimateTokenCount,
truncateConversation,
truncateConversationIfNeeded,
} from "../index"
import { ApiMessage } from "../../task-persistence/apiMessages"
import * as condenseModule from "../../condense"
// Create a mock ApiHandler for testing
class MockApiHandler extends BaseProvider {

View file

@ -1,10 +1,11 @@
import * as path from "path"
import * as fs from "fs/promises"
import type { ClineMessage } from "@roo-code/types"
import { fileExistsAtPath } from "../../utils/fs"
import { GlobalFileNames } from "../../shared/globalFileNames"
import { ClineMessage } from "../../shared/ExtensionMessage"
import { getTaskDirectoryPath } from "../../utils/storage"
export type ReadTaskMessagesOptions = {

View file

@ -1,12 +1,12 @@
import NodeCache from "node-cache"
import getFolderSize from "get-folder-size"
import { ClineMessage } from "../../shared/ExtensionMessage"
import type { ClineMessage, HistoryItem } from "@roo-code/types"
import { combineApiRequests } from "../../shared/combineApiRequests"
import { combineCommandSequences } from "../../shared/combineCommandSequences"
import { getApiMetrics } from "../../shared/getApiMetrics"
import { findLastIndex } from "../../shared/array"
import { HistoryItem } from "../../shared/HistoryItem"
import { getTaskDirectoryPath } from "../../utils/storage"
const taskSizeCache = new NodeCache({ stdTTL: 30, checkperiod: 5 * 60 })

View file

@ -8,29 +8,30 @@ import delay from "delay"
import pWaitFor from "p-wait-for"
import { serializeError } from "serialize-error"
// schemas
import { TokenUsage, ToolUsage, ToolName, ContextCondense } from "../../schemas"
import type {
ProviderSettings,
TokenUsage,
ToolUsage,
ToolName,
ContextCondense,
ClineAsk,
ClineMessage,
ClineSay,
ToolProgressStatus,
HistoryItem,
} from "@roo-code/types"
// api
import { ApiHandler, ApiHandlerCreateMessageMetadata, buildApiHandler } from "../../api"
import { ApiStream } from "../../api/transform/stream"
// shared
import { ProviderSettings } from "../../shared/api"
import { findLastIndex } from "../../shared/array"
import { combineApiRequests } from "../../shared/combineApiRequests"
import { combineCommandSequences } from "../../shared/combineCommandSequences"
import { t } from "../../i18n"
import {
ClineApiReqCancelReason,
ClineApiReqInfo,
ClineAsk,
ClineMessage,
ClineSay,
ToolProgressStatus,
} from "../../shared/ExtensionMessage"
import { ClineApiReqCancelReason, ClineApiReqInfo } from "../../shared/ExtensionMessage"
import { getApiMetrics } from "../../shared/getApiMetrics"
import { HistoryItem } from "../../shared/HistoryItem"
import { ClineAskResponse } from "../../shared/WebviewMessage"
import { defaultModeSlug } from "../../shared/modes"
import { DiffStrategy } from "../../shared/tools"
@ -50,7 +51,7 @@ import { RooTerminalProcess } from "../../integrations/terminal/types"
import { TerminalRegistry } from "../../integrations/terminal/TerminalRegistry"
// utils
import { calculateApiCostAnthropic } from "../../utils/cost"
import { calculateApiCostAnthropic } from "../../shared/cost"
import { getWorkspacePath } from "../../utils/path"
// prompts

View file

@ -6,10 +6,10 @@ import * as path from "path"
import * as vscode from "vscode"
import { Anthropic } from "@anthropic-ai/sdk"
import { GlobalState } from "../../../schemas"
import type { GlobalState, ProviderSettings, ModelInfo } from "@roo-code/types"
import { Task } from "../Task"
import { ClineProvider } from "../../webview/ClineProvider"
import { ProviderSettings, ModelInfo } from "../../../shared/api"
import { ApiStreamChunk } from "../../../api/transform/stream"
import { ContextProxy } from "../../config/ContextProxy"
import { processUserContentMentions } from "../../mentions/processUserContentMentions"

View file

@ -1,6 +1,7 @@
// npx jest src/core/tools/__tests__/ToolRepetitionDetector.test.ts
import type { ToolName } from "../../../schemas"
import type { ToolName } from "@roo-code/types"
import type { ToolUse } from "../../../shared/tools"
import { ToolRepetitionDetector } from "../ToolRepetitionDetector"

View file

@ -2,10 +2,11 @@
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
import type { ToolUsage } from "@roo-code/types"
import { Task } from "../../task/Task"
import { formatResponse } from "../../prompts/responses"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../../shared/tools"
import { ToolUsage } from "../../../schemas"
import { unescapeHtmlEntities } from "../../../utils/text-normalization"
// Mock dependencies

View file

@ -1,7 +1,10 @@
// npx jest src/core/tools/__tests__/validateToolUse.test.ts
import { isToolAllowedForMode, modes, ModeConfig } from "../../../shared/modes"
import type { ModeConfig } from "@roo-code/types"
import { isToolAllowedForMode, modes } from "../../../shared/modes"
import { TOOL_GROUPS } from "../../../shared/tools"
import { validateToolUse } from "../validateToolUse"
const [codeMode, architectMode, askMode] = modes.map((mode) => mode.slug)

View file

@ -3,8 +3,10 @@ import * as path from "path"
import delay from "delay"
import { CommandExecutionStatus } from "@roo-code/types"
import { Task } from "../task/Task"
import { CommandExecutionStatus } from "../../schemas"
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolResponse } from "../../shared/tools"
import { formatResponse } from "../prompts/responses"
import { unescapeHtmlEntities } from "../../utils/text-normalization"

View file

@ -1,5 +1,6 @@
import { ToolName } from "../../schemas"
import { Mode, isToolAllowedForMode, ModeConfig } from "../../shared/modes"
import type { ToolName, ModeConfig } from "@roo-code/types"
import { Mode, isToolAllowedForMode } from "../../shared/modes"
export function validateToolUse(
toolName: ToolName,

View file

@ -9,25 +9,26 @@ import axios from "axios"
import pWaitFor from "p-wait-for"
import * as vscode from "vscode"
import {
import type {
GlobalState,
ProviderName,
ProviderSettings,
RooCodeSettings,
ProviderSettingsEntry,
Package,
CodeActionId,
CodeActionName,
TerminalActionId,
TerminalActionPromptType,
} from "../../schemas"
HistoryItem,
} from "@roo-code/types"
import { t } from "../../i18n"
import { setPanel } from "../../activate/registerCommands"
import { Package } from "../../shared/package"
import { requestyDefaultModelId, openRouterDefaultModelId, glamaDefaultModelId } from "../../shared/api"
import { findLast } from "../../shared/array"
import { supportPrompt } from "../../shared/support-prompt"
import { GlobalFileNames } from "../../shared/globalFileNames"
import { HistoryItem } from "../../shared/HistoryItem"
import { ExtensionMessage } from "../../shared/ExtensionMessage"
import { Mode, defaultModeSlug } from "../../shared/modes"
import { experimentDefault } from "../../shared/experiments"

View file

@ -4,14 +4,17 @@ import Anthropic from "@anthropic-ai/sdk"
import * as vscode from "vscode"
import axios from "axios"
import { ClineProvider } from "../ClineProvider"
import { ProviderSettingsEntry, ClineMessage, ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
import { setTtsEnabled } from "../../../utils/tts"
import type { ProviderSettingsEntry, ClineMessage } from "@roo-code/types"
import { ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
import { defaultModeSlug } from "../../../shared/modes"
import { experimentDefault } from "../../../shared/experiments"
import { setTtsEnabled } from "../../../utils/tts"
import { ContextProxy } from "../../config/ContextProxy"
import { Task, TaskOptions } from "../../task/Task"
import { ClineProvider } from "../ClineProvider"
// Mock setup must come before imports
jest.mock("../../prompts/sections/custom-instructions")

View file

@ -3,9 +3,11 @@ import fs from "fs/promises"
import pWaitFor from "p-wait-for"
import * as vscode from "vscode"
import type { Language, ProviderSettings, GlobalState } from "@roo-code/types"
import { ClineProvider } from "./ClineProvider"
import { Language, ProviderSettings, GlobalState, Package } from "../../schemas"
import { changeLanguage, t } from "../../i18n"
import { Package } from "../../shared/package"
import { RouterName, toRouterName, ModelRecord } from "../../shared/api"
import { supportPrompt } from "../../shared/support-prompt"
import { checkoutDiffPayloadSchema, checkoutRestorePayloadSchema, WebviewMessage } from "../../shared/WebviewMessage"

View file

@ -1,4 +1,5 @@
import * as esbuild from "esbuild"
import * as fs from "fs"
import * as path from "path"
import { fileURLToPath } from "url"
import process from "node:process"
@ -10,6 +11,7 @@ const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
async function main() {
const name = "extension"
const production = process.argv.includes("--production")
const watch = process.argv.includes("--watch")
const minify = production
@ -32,12 +34,17 @@ async function main() {
const buildDir = __dirname
const distDir = path.join(buildDir, "dist")
if (fs.existsSync(distDir)) {
console.log(`[${name}] Cleaning dist directory: ${distDir}`)
fs.rmSync(distDir, { recursive: true, force: true })
}
/**
* @type {import('esbuild').Plugin[]}
*/
const plugins = [
{
name: "copy-files",
name: "copyFiles",
setup(build) {
build.onEnd(() => {
copyPaths(
@ -55,13 +62,13 @@ async function main() {
},
},
{
name: "copy-wasms",
name: "copyWasms",
setup(build) {
build.onEnd(() => copyWasms(srcDir, distDir))
},
},
{
name: "copy-locales",
name: "copyLocales",
setup(build) {
build.onEnd(() => copyLocales(srcDir, distDir))
},
@ -91,6 +98,9 @@ async function main() {
entryPoints: ["extension.ts"],
outfile: "dist/extension.js",
external: ["vscode"],
alias: {
"@roo-code/types": path.resolve(__dirname, "../packages/types/dist/index.js"),
},
}
/**
@ -100,6 +110,9 @@ async function main() {
...buildOptions,
entryPoints: ["workers/countTokens.ts"],
outdir: "dist/workers",
alias: {
"@roo-code/types": path.resolve(__dirname, "../packages/types/dist/index.js"),
},
}
const [extensionCtx, workerCtx] = await Promise.all([

Some files were not shown because too many files have changed in this diff Show more