mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
Merge main to ollama_improvements: resolve conflicts in Ollama i18n implementation
This commit is contained in:
commit
8a6b4b58ad
619 changed files with 27836 additions and 27165 deletions
15
.github/workflows/website-deploy.yml
vendored
15
.github/workflows/website-deploy.yml
vendored
|
|
@ -8,6 +8,10 @@ on:
|
|||
- 'apps/web-roo-code/**'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-roocode-com
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
|
|
@ -36,8 +40,17 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js and pnpm
|
||||
uses: ./.github/actions/setup-node-pnpm
|
||||
- name: Run lint
|
||||
run: pnpm lint
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run type check
|
||||
run: pnpm check-types
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run build
|
||||
run: pnpm build
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Install Vercel CLI
|
||||
run: npm install --global vercel@canary
|
||||
run: npm install --global vercel@latest
|
||||
- name: Pull Vercel Environment Information
|
||||
run: npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
|
||||
- name: Build Project Artifacts
|
||||
|
|
|
|||
40
.github/workflows/website-preview.yml
vendored
40
.github/workflows/website-preview.yml
vendored
|
|
@ -11,6 +11,10 @@ on:
|
|||
- "apps/web-roo-code/**"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: preview-roocode-com-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
|
||||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
|
|
@ -39,8 +43,17 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js and pnpm
|
||||
uses: ./.github/actions/setup-node-pnpm
|
||||
- name: Run lint
|
||||
run: pnpm lint
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run type check
|
||||
run: pnpm check-types
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Run build
|
||||
run: pnpm build
|
||||
working-directory: apps/web-roo-code
|
||||
- name: Install Vercel CLI
|
||||
run: npm install --global vercel@canary
|
||||
run: npm install --global vercel@latest
|
||||
- name: Pull Vercel Environment Information
|
||||
run: npx vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
|
||||
- name: Build Project Artifacts
|
||||
|
|
@ -70,15 +83,20 @@ jobs:
|
|||
comment.body.includes(commentIdentifier)
|
||||
);
|
||||
|
||||
if (existingComment) {
|
||||
return;
|
||||
}
|
||||
|
||||
const comment = commentIdentifier + '\n🚀 **Preview deployed!**\n\nYour changes have been deployed to Vercel:\n\n**Preview URL:** ' + deploymentUrl + '\n\nThis preview will be updated automatically when you push new commits to this PR.';
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: comment
|
||||
});
|
||||
if (existingComment) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existingComment.id,
|
||||
body: comment
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: comment
|
||||
});
|
||||
}
|
||||
|
|
|
|||
5
AGENTS.md
Normal file
5
AGENTS.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# AGENTS.md
|
||||
|
||||
This file provides guidance to agents when working with code in this repository.
|
||||
|
||||
- Settings View Pattern: When working on `SettingsView`, inputs must bind to the local `cachedState`, NOT the live `useExtensionState()`. The `cachedState` acts as a buffer for user edits, isolating them from the `ContextProxy` source-of-truth until the user explicitly clicks "Save". Wiring inputs directly to the live state causes race conditions.
|
||||
93
CHANGELOG.md
93
CHANGELOG.md
|
|
@ -1,5 +1,98 @@
|
|||
# Roo Code Changelog
|
||||
|
||||
## [3.45.0] - 2026-01-27
|
||||
|
||||

|
||||
|
||||
- Smart Code Folding: Context condensation now intelligently preserves a lightweight map of files you worked on—function signatures, class declarations, and type definitions—so Roo can continue referencing them accurately after condensing. Files are prioritized by most recent access, with a ~50k character budget ensuring your latest work is always preserved. (Idea by @shariqriazz, PR #10942 by @hannesrudolph)
|
||||
|
||||
## [3.44.2] - 2026-01-27
|
||||
|
||||
- Re-enable parallel tool calling with new_task isolation safeguards (PR #11006 by @mrubens)
|
||||
- Fix worktree indexing by using relative paths in isPathInIgnoredDirectory (PR #11009 by @daniel-lxs)
|
||||
- Fix local model validation error for Ollama models (PR #10893 by @roomote)
|
||||
- Fix duplicate tool_call emission from Responses API providers (PR #11008 by @daniel-lxs)
|
||||
|
||||
## [3.44.1] - 2026-01-27
|
||||
|
||||
- Fix LiteLLM tool ID validation errors for Bedrock proxy (PR #10990 by @daniel-lxs)
|
||||
- Add temperature=0.9 and top_p=0.95 to zai-glm-4.7 model for better generation quality (PR #10945 by @sebastiand-cerebras)
|
||||
- Add quality checks to marketing site deployment workflows (PR #10959 by @mp-roocode)
|
||||
|
||||
## [3.44.0] - 2026-01-26
|
||||
|
||||

|
||||
|
||||
- Add worktree selector and creation UX (PR #10940 by @brunobergher, thanks Cline!)
|
||||
- Improve subtask visibility and navigation in history and chat views (PR #10864 by @brunobergher)
|
||||
- Add wildcard support for MCP alwaysAllow configuration (PR #10948 by @app/roomote)
|
||||
- Fix: Prevent nested condensing from including previously-condensed content (PR #10985 by @hannesrudolph)
|
||||
- Fix: VS Code LM token counting returns 0 outside requests, breaking context condensing (#10968 by @srulyt, PR #10983 by @daniel-lxs)
|
||||
- Fix: Record truncation event when condensation fails but truncation succeeds (PR #10984 by @hannesrudolph)
|
||||
- Replace hyphen encoding with fuzzy matching for MCP tool names (PR #10775 by @daniel-lxs)
|
||||
- Remove MCP SERVERS section from system prompt for cleaner prompts (PR #10895 by @daniel-lxs)
|
||||
- new_task tool creates checkpoint the same way write_to_file does (PR #10982 by @daniel-lxs)
|
||||
- Update Fireworks provider with new models (#10674 by @hannesrudolph, PR #10679 by @ThanhNguyxn)
|
||||
- Fix: Truncate AWS Bedrock toolUseId to 64 characters (PR #10902 by @daniel-lxs)
|
||||
- Fix: Restore opaque background to settings section headers (PR #10951 by @app/roomote)
|
||||
- Fix: Remove unsupported Fireworks model tool fields (PR #10937 by @app/roomote)
|
||||
- Update and improve zh-TW Traditional Chinese locale and docs (PR #10953 by @PeterDaveHello)
|
||||
- Chore: Remove POWER_STEERING experiment remnants (PR #10980 by @hannesrudolph)
|
||||
|
||||
## [3.43.0] - 2026-01-23
|
||||
|
||||

|
||||
|
||||
- Intelligent Context Condensation v2: New context condensation system that intelligently summarizes conversation history when approaching context limits, preserving important information while reducing token usage (PR #10873 by @hannesrudolph)
|
||||
- Improved context condensation with environment details, accurate token counts, and lazy evaluation for better performance (PR #10920 by @hannesrudolph)
|
||||
- Move condense prompt editor to Context Management tab for better discoverability and organization (PR #10909 by @hannesrudolph)
|
||||
- Update Z.AI models with new variants and pricing (#10859 by @ErdemGKSL, PR #10860 by @ErdemGKSL)
|
||||
- Add pnpm install:vsix:nightly command for easier nightly build installation (PR #10912 by @hannesrudolph)
|
||||
- Fix: Convert orphaned tool_results to text blocks after condensing to prevent API errors (PR #10927 by @daniel-lxs)
|
||||
- Fix: Auto-migrate v1 condensing prompt and handle invalid providers on import (PR #10931 by @hannesrudolph)
|
||||
- Fix: Use json-stream-stringify for pretty-printing MCP config files to prevent memory issues with large configs (#9862 by @Michaelzag, PR #9864 by @Michaelzag)
|
||||
- Fix: Correct Gemini 3 pricing for Flash and Pro models (#10432 by @rossdonald, PR #10487 by @roomote)
|
||||
- Fix: Skip thoughtSignature blocks during markdown export for cleaner output (#10199 by @rossdonald, PR #10932 by @rossdonald)
|
||||
- Fix: Duplicate model display for OpenAI Codex provider (PR #10930 by @roomote)
|
||||
- Remove diffEnabled and fuzzyMatchThreshold settings as they are no longer needed (#10648 by @hannesrudolph, PR #10298 by @hannesrudolph)
|
||||
- Remove MULTI_FILE_APPLY_DIFF experiment (PR #10925 by @hannesrudolph)
|
||||
- Remove POWER_STEERING experimental feature (PR #10926 by @hannesrudolph)
|
||||
- Remove legacy XML tool calling code (getToolDescription) for cleaner codebase (PR #10929 by @hannesrudolph)
|
||||
|
||||
## [3.42.0] - 2026-01-22
|
||||
|
||||

|
||||
|
||||
- Added UI to track your ChatGPT usage limits in the OpenAI Codex provider (PR #10813 by @hannesrudolph)
|
||||
- Removed deprecated Claude Code provider (PR #10883 by @daniel-lxs)
|
||||
- Streamlined codebase by removing legacy XML tool calling functionality (#10848 by @hannesrudolph, PR #10841 by @hannesrudolph)
|
||||
- Standardize model selectors across all providers: Improved consistency of model selection UI (#10650 by @hannesrudolph, PR #10294 by @hannesrudolph)
|
||||
- Enable prompt caching for Cerebras zai-glm-4.7 model (#10601 by @jahanson, PR #10670 by @app/roomote)
|
||||
- Add Kimi K2 thinking model to VertexAI provider (#9268 by @diwakar-s-maurya, PR #9269 by @app/roomote)
|
||||
- Warn users when too many MCP tools are enabled (PR #10772 by @app/roomote)
|
||||
- Migrate context condensing prompt to customSupportPrompts (PR #10881 by @hannesrudolph)
|
||||
- Unify export path logic and default to Downloads folder (PR #10882 by @hannesrudolph)
|
||||
- Performance improvements for webview state synchronization (PR #10842 by @hannesrudolph)
|
||||
- Fix: Handle mode selector empty state on workspace switch (#10660 by @hannesrudolph, PR #9674 by @app/roomote)
|
||||
- Fix: Resolve race condition in context condensing prompt input (PR #10876 by @hannesrudolph)
|
||||
- Fix: Prevent double emission of text/reasoning in OpenAI native and codex handlers (PR #10888 by @hannesrudolph)
|
||||
- Fix: Prevent task abortion when resuming via IPC/bridge (PR #10892 by @cte)
|
||||
- Fix: Enforce file restrictions for all editing tools (PR #10896 by @app/roomote)
|
||||
- Fix: Remove custom condensing model option (PR #10901 by @hannesrudolph)
|
||||
- Unify user content tags to <user_message> for consistent prompt formatting (#10658 by @hannesrudolph, PR #10723 by @app/roomote)
|
||||
- Clarify linked SKILL.md file handling in prompts (PR #10907 by @hannesrudolph)
|
||||
- Fix: Padding on Roo Code Cloud teaser (PR #10889 by @app/roomote)
|
||||
|
||||
## [3.41.3] - 2026-01-18
|
||||
|
||||
- Fix: Thinking block word-breaking to prevent horizontal scroll in the chat UI (PR #10806 by @roomote)
|
||||
- Add Claude-like CLI flags and authentication fixes for the Roo Code CLI (PR #10797 by @cte)
|
||||
- Improve CLI authentication by using a redirect instead of a fetch (PR #10799 by @cte)
|
||||
- Fix: Roo Code Router fixes for the CLI (PR #10789 by @cte)
|
||||
- Release CLI v0.0.48 with latest improvements (PR #10800 by @cte)
|
||||
- Release CLI v0.0.47 (PR #10798 by @cte)
|
||||
- Revert E2E tests enablement to address stability issues (PR #10794 by @cte)
|
||||
|
||||
## [3.41.2] - 2026-01-16
|
||||
|
||||
- Add button to open markdown in VSCode preview for easier reading of formatted content (PR #10773 by @brunobergher)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,17 @@ All notable changes to the `@roo-code/cli` package will be documented in this fi
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.0.49] - 2026-01-18
|
||||
|
||||
### Added
|
||||
|
||||
- **Output Format Options**: New `--output-format` flag to control CLI output format for scripting and automation:
|
||||
- `text` (default) - Human-readable interactive output
|
||||
- `json` - Single JSON object with all events and final result at task completion
|
||||
- `stream-json` - NDJSON (newline-delimited JSON) for real-time streaming of events
|
||||
- See [`json-events.ts`](src/types/json-events.ts) for the complete event schema
|
||||
- New [`JsonEventEmitter`](src/agent/json-event-emitter.ts) for structured output generation
|
||||
|
||||
## [0.0.48] - 2026-01-17
|
||||
|
||||
### Changed
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ By default, the CLI prompts for approval before executing actions:
|
|||
```bash
|
||||
export OPENROUTER_API_KEY=sk-or-v1-...
|
||||
|
||||
roo ~/Documents/my-project -P "What is this project?"
|
||||
roo "What is this project?" -w ~/Documents/my-project
|
||||
```
|
||||
|
||||
You can also run without a prompt and enter it interactively in TUI mode:
|
||||
|
|
@ -92,7 +92,7 @@ In interactive mode:
|
|||
For automation and scripts, use `-y` to auto-approve all actions:
|
||||
|
||||
```bash
|
||||
roo ~/Documents/my-project -y -P "Refactor the utils.ts file"
|
||||
roo "Refactor the utils.ts file" -y -w ~/Documents/my-project
|
||||
```
|
||||
|
||||
In non-interactive mode:
|
||||
|
|
@ -149,8 +149,8 @@ Tokens are valid for 90 days. The CLI will prompt you to re-authenticate when yo
|
|||
|
||||
| Option | Description | Default |
|
||||
| --------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------- |
|
||||
| `[workspace]` | Workspace path to operate in (positional argument) | Current directory |
|
||||
| `-P, --prompt <prompt>` | The prompt/task to execute (optional in TUI mode) | None |
|
||||
| `[prompt]` | Your prompt (positional argument, optional) | None |
|
||||
| `-w, --workspace <path>` | Workspace path to operate in | Current directory |
|
||||
| `-e, --extension <path>` | Path to the extension bundle directory | Auto-detected |
|
||||
| `-d, --debug` | Enable debug output (includes detailed debug information, prompts, paths, etc) | `false` |
|
||||
| `-x, --exit-on-complete` | Exit the process when task completes (useful for testing) | `false` |
|
||||
|
|
@ -249,7 +249,7 @@ pnpm lint
|
|||
To create a new release, execute the /cli-release slash command:
|
||||
|
||||
```bash
|
||||
roo ~/Documents/Roo-Code -P "/cli-release" -y
|
||||
roo "/cli-release" -w ~/Documents/Roo-Code -y
|
||||
```
|
||||
|
||||
The workflow will:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@roo-code/cli",
|
||||
"version": "0.0.48",
|
||||
"version": "0.0.49",
|
||||
"description": "Roo Code CLI - Run the Roo Code agent from the command line",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
|
@ -30,6 +30,8 @@
|
|||
"@trpc/client": "^11.8.1",
|
||||
"@vscode/ripgrep": "^1.15.9",
|
||||
"commander": "^12.1.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"execa": "^9.5.2",
|
||||
"fuzzysort": "^3.1.0",
|
||||
"ink": "^6.6.0",
|
||||
"p-wait-for": "^5.0.2",
|
||||
|
|
|
|||
|
|
@ -100,16 +100,17 @@ describe("ExtensionHost", () => {
|
|||
ephemeral: false,
|
||||
debug: false,
|
||||
exitOnComplete: false,
|
||||
integrationTest: true, // Set explicitly for testing
|
||||
}
|
||||
|
||||
const host = new ExtensionHost(options)
|
||||
|
||||
// Options are stored but integrationTest is set to true
|
||||
// Options are stored as-is
|
||||
const storedOptions = getPrivate<ExtensionHostOptions>(host, "options")
|
||||
expect(storedOptions.mode).toBe(options.mode)
|
||||
expect(storedOptions.workspacePath).toBe(options.workspacePath)
|
||||
expect(storedOptions.extensionPath).toBe(options.extensionPath)
|
||||
expect(storedOptions.integrationTest).toBe(true) // Always set to true in constructor
|
||||
expect(storedOptions.integrationTest).toBe(true)
|
||||
})
|
||||
|
||||
it("should be an EventEmitter instance", () => {
|
||||
|
|
@ -298,16 +299,19 @@ describe("ExtensionHost", () => {
|
|||
})
|
||||
|
||||
it("should suppress console when integrationTest is false", () => {
|
||||
const host = createTestHost()
|
||||
// Capture the real console.log before any host is created
|
||||
const originalLog = console.log
|
||||
|
||||
// Override integrationTest to false
|
||||
// Create host with integrationTest: true to prevent constructor from suppressing
|
||||
const host = createTestHost({ integrationTest: true })
|
||||
|
||||
// Override integrationTest to false to test suppression
|
||||
const options = getPrivate<ExtensionHostOptions>(host, "options")
|
||||
options.integrationTest = false
|
||||
|
||||
callPrivate(host, "setupQuietMode")
|
||||
|
||||
// Console should be modified
|
||||
// Console should be modified (suppressed)
|
||||
expect(console.log).not.toBe(originalLog)
|
||||
|
||||
// Restore for other tests
|
||||
|
|
@ -332,9 +336,12 @@ describe("ExtensionHost", () => {
|
|||
|
||||
describe("restoreConsole", () => {
|
||||
it("should restore original console methods when suppressed", () => {
|
||||
const host = createTestHost()
|
||||
// Capture the real console.log before any host is created
|
||||
const originalLog = console.log
|
||||
|
||||
// Create host with integrationTest: true to prevent constructor from suppressing
|
||||
const host = createTestHost({ integrationTest: true })
|
||||
|
||||
// Override integrationTest to false to actually suppress
|
||||
const options = getPrivate<ExtensionHostOptions>(host, "options")
|
||||
options.integrationTest = false
|
||||
|
|
|
|||
|
|
@ -153,7 +153,10 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
|
|||
super()
|
||||
|
||||
this.options = options
|
||||
this.options.integrationTest = true
|
||||
|
||||
// Set up quiet mode early, before any extension code runs.
|
||||
// This suppresses console output from the extension during load.
|
||||
this.setupQuietMode()
|
||||
|
||||
// Initialize client - single source of truth for agent state (including mode).
|
||||
this.client = new ExtensionClient({
|
||||
|
|
@ -162,9 +165,7 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
|
|||
})
|
||||
|
||||
// Initialize output manager.
|
||||
this.outputManager = new OutputManager({
|
||||
disabled: options.disableOutput,
|
||||
})
|
||||
this.outputManager = new OutputManager({ disabled: options.disableOutput })
|
||||
|
||||
// Initialize prompt manager with console mode callbacks.
|
||||
this.promptManager = new PromptManager({
|
||||
|
|
@ -222,8 +223,6 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
|
|||
this.initialSettings.reasoningEffort = this.options.reasoningEffort
|
||||
}
|
||||
}
|
||||
|
||||
this.setupQuietMode()
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
|
@ -267,7 +266,8 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
|
|||
// ==========================================================================
|
||||
|
||||
private setupQuietMode(): void {
|
||||
if (this.options.integrationTest) {
|
||||
// Skip if already set up or if integrationTest mode
|
||||
if (this.originalConsole || this.options.integrationTest) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -292,18 +292,16 @@ export class ExtensionHost extends EventEmitter implements ExtensionHostInterfac
|
|||
}
|
||||
|
||||
private restoreConsole(): void {
|
||||
if (this.options.integrationTest) {
|
||||
if (!this.originalConsole) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.originalConsole) {
|
||||
console.log = this.originalConsole.log
|
||||
console.warn = this.originalConsole.warn
|
||||
console.error = this.originalConsole.error
|
||||
console.debug = this.originalConsole.debug
|
||||
console.info = this.originalConsole.info
|
||||
this.originalConsole = null
|
||||
}
|
||||
console.log = this.originalConsole.log
|
||||
console.warn = this.originalConsole.warn
|
||||
console.error = this.originalConsole.error
|
||||
console.debug = this.originalConsole.debug
|
||||
console.info = this.originalConsole.info
|
||||
this.originalConsole = null
|
||||
|
||||
if (this.originalProcessEmitWarning) {
|
||||
process.emitWarning = this.originalProcessEmitWarning
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export * from "./extension-host.js"
|
||||
export * from "./json-event-emitter.js"
|
||||
|
|
|
|||
464
apps/cli/src/agent/json-event-emitter.ts
Normal file
464
apps/cli/src/agent/json-event-emitter.ts
Normal file
|
|
@ -0,0 +1,464 @@
|
|||
/**
|
||||
* JsonEventEmitter - Handles structured JSON output for the CLI
|
||||
*
|
||||
* This class transforms internal CLI events (ClineMessage, state changes, etc.)
|
||||
* into structured JSON events and outputs them to stdout.
|
||||
*
|
||||
* Supports two output modes:
|
||||
* - "stream-json": NDJSON format (one JSON object per line) for real-time streaming
|
||||
* - "json": Single JSON object at the end with accumulated events
|
||||
*
|
||||
* Schema is optimized for efficiency with high message volume:
|
||||
* - Minimal fields per event
|
||||
* - No redundant wrappers
|
||||
* - `done` flag instead of partial:false
|
||||
*/
|
||||
|
||||
import type { ClineMessage } from "@roo-code/types"
|
||||
|
||||
import type { JsonEvent, JsonEventCost, JsonFinalOutput } from "@/types/json-events.js"
|
||||
|
||||
import type { ExtensionClient } from "./extension-client.js"
|
||||
import type { TaskCompletedEvent } from "./events.js"
|
||||
|
||||
/**
|
||||
* Options for JsonEventEmitter.
|
||||
*/
|
||||
export interface JsonEventEmitterOptions {
|
||||
/** Output mode: "json" or "stream-json" */
|
||||
mode: "json" | "stream-json"
|
||||
/** Output stream (defaults to process.stdout) */
|
||||
stdout?: NodeJS.WriteStream
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tool information from a ClineMessage text field.
|
||||
* Tool messages are JSON with a `tool` field containing the tool name.
|
||||
*/
|
||||
function parseToolInfo(text: string | undefined): { name: string; input: Record<string, unknown> } | null {
|
||||
if (!text) return null
|
||||
try {
|
||||
const parsed = JSON.parse(text)
|
||||
return parsed.tool ? { name: parsed.tool, input: parsed } : null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse API request cost information from api_req_started message text.
|
||||
*/
|
||||
function parseApiReqCost(text: string | undefined): JsonEventCost | undefined {
|
||||
if (!text) return undefined
|
||||
try {
|
||||
const parsed = JSON.parse(text)
|
||||
return parsed.cost !== undefined
|
||||
? {
|
||||
totalCost: parsed.cost,
|
||||
inputTokens: parsed.tokensIn,
|
||||
outputTokens: parsed.tokensOut,
|
||||
cacheWrites: parsed.cacheWrites,
|
||||
cacheReads: parsed.cacheReads,
|
||||
}
|
||||
: undefined
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
/** Internal events that should not be emitted */
|
||||
const SKIP_SAY_TYPES = new Set([
|
||||
"api_req_finished",
|
||||
"api_req_retried",
|
||||
"api_req_retry_delayed",
|
||||
"api_req_rate_limit_wait",
|
||||
"api_req_deleted",
|
||||
"checkpoint_saved",
|
||||
"condense_context",
|
||||
"condense_context_error",
|
||||
"sliding_window_truncation",
|
||||
])
|
||||
|
||||
/** Key offset for reasoning content to avoid collision with text content delta tracking */
|
||||
const REASONING_KEY_OFFSET = 1_000_000_000
|
||||
|
||||
export class JsonEventEmitter {
|
||||
private mode: "json" | "stream-json"
|
||||
private stdout: NodeJS.WriteStream
|
||||
private events: JsonEvent[] = []
|
||||
private unsubscribers: (() => void)[] = []
|
||||
private lastCost: JsonEventCost | undefined
|
||||
private seenMessageIds = new Set<number>()
|
||||
// Track previous content for delta computation
|
||||
private previousContent = new Map<number, string>()
|
||||
// Track the completion result content
|
||||
private completionResultContent: string | undefined
|
||||
|
||||
constructor(options: JsonEventEmitterOptions) {
|
||||
this.mode = options.mode
|
||||
this.stdout = options.stdout ?? process.stdout
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach to an ExtensionClient and subscribe to its events.
|
||||
*/
|
||||
attachToClient(client: ExtensionClient): void {
|
||||
// Subscribe to message events
|
||||
const unsubMessage = client.on("message", (msg) => this.handleMessage(msg, false))
|
||||
const unsubMessageUpdated = client.on("messageUpdated", (msg) => this.handleMessage(msg, true))
|
||||
const unsubTaskCompleted = client.on("taskCompleted", (event) => this.handleTaskCompleted(event))
|
||||
const unsubError = client.on("error", (error) => this.handleError(error))
|
||||
|
||||
this.unsubscribers.push(unsubMessage, unsubMessageUpdated, unsubTaskCompleted, unsubError)
|
||||
|
||||
// Emit init event
|
||||
this.emitEvent({
|
||||
type: "system",
|
||||
subtype: "init",
|
||||
content: "Task started",
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach from the client and clean up subscriptions.
|
||||
*/
|
||||
detach(): void {
|
||||
for (const unsub of this.unsubscribers) {
|
||||
unsub()
|
||||
}
|
||||
this.unsubscribers = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the delta (new content) for a streaming message.
|
||||
* Returns null if there's no new content.
|
||||
*/
|
||||
private computeDelta(msgId: number, fullContent: string | undefined): string | null {
|
||||
if (!fullContent) return null
|
||||
|
||||
const previous = this.previousContent.get(msgId) || ""
|
||||
if (fullContent === previous) return null
|
||||
|
||||
this.previousContent.set(msgId, fullContent)
|
||||
// If content is appended, return only the new part
|
||||
return fullContent.startsWith(previous) ? fullContent.slice(previous.length) : fullContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a streaming partial message with no new content.
|
||||
*/
|
||||
private isEmptyStreamingDelta(content: string | null): boolean {
|
||||
return this.mode === "stream-json" && content === null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content to send for a message (delta for streaming, full for json mode).
|
||||
*/
|
||||
private getContentToSend(msgId: number, text: string | undefined, isPartial: boolean): string | null {
|
||||
if (this.mode === "stream-json" && isPartial) {
|
||||
return this.computeDelta(msgId, text)
|
||||
}
|
||||
return text ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a base event with optional done flag.
|
||||
*/
|
||||
private buildTextEvent(
|
||||
type: "assistant" | "thinking" | "user",
|
||||
id: number,
|
||||
content: string | null,
|
||||
isDone: boolean,
|
||||
subtype?: string,
|
||||
): JsonEvent {
|
||||
const event: JsonEvent = { type, id }
|
||||
if (content !== null) {
|
||||
event.content = content
|
||||
}
|
||||
if (subtype) {
|
||||
event.subtype = subtype
|
||||
}
|
||||
if (isDone) {
|
||||
event.done = true
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a ClineMessage and emit the appropriate JSON event.
|
||||
*/
|
||||
private handleMessage(msg: ClineMessage, _isUpdate: boolean): void {
|
||||
const isDone = !msg.partial
|
||||
|
||||
// In json mode, only emit complete (non-partial) messages
|
||||
if (this.mode === "json" && msg.partial) {
|
||||
return
|
||||
}
|
||||
|
||||
// Skip duplicate complete messages
|
||||
if (isDone && this.seenMessageIds.has(msg.ts)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (isDone) {
|
||||
this.seenMessageIds.add(msg.ts)
|
||||
this.previousContent.delete(msg.ts)
|
||||
}
|
||||
|
||||
const contentToSend = this.getContentToSend(msg.ts, msg.text, msg.partial ?? false)
|
||||
|
||||
// Skip if no new content for streaming partial messages
|
||||
if (msg.partial && this.isEmptyStreamingDelta(contentToSend)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (msg.type === "say" && msg.say) {
|
||||
this.handleSayMessage(msg, contentToSend, isDone)
|
||||
}
|
||||
|
||||
if (msg.type === "ask" && msg.ask) {
|
||||
this.handleAskMessage(msg, contentToSend, isDone)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "say" type messages.
|
||||
*/
|
||||
private handleSayMessage(msg: ClineMessage, contentToSend: string | null, isDone: boolean): void {
|
||||
switch (msg.say) {
|
||||
case "text":
|
||||
this.emitEvent(this.buildTextEvent("assistant", msg.ts, contentToSend, isDone))
|
||||
break
|
||||
|
||||
case "reasoning":
|
||||
this.handleReasoningMessage(msg, isDone)
|
||||
break
|
||||
|
||||
case "error":
|
||||
this.emitEvent({ type: "error", id: msg.ts, content: contentToSend ?? undefined })
|
||||
break
|
||||
|
||||
case "command_output":
|
||||
this.emitEvent({
|
||||
type: "tool_result",
|
||||
tool_result: { name: "execute_command", output: msg.text },
|
||||
})
|
||||
break
|
||||
|
||||
case "user_feedback":
|
||||
case "user_feedback_diff":
|
||||
this.emitEvent(this.buildTextEvent("user", msg.ts, contentToSend, isDone))
|
||||
break
|
||||
|
||||
case "api_req_started": {
|
||||
const cost = parseApiReqCost(msg.text)
|
||||
if (cost) {
|
||||
this.lastCost = cost
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case "browser_action":
|
||||
case "browser_action_result":
|
||||
this.emitEvent({
|
||||
type: "tool_result",
|
||||
subtype: "browser",
|
||||
tool_result: { name: "browser_action", output: msg.text },
|
||||
})
|
||||
break
|
||||
|
||||
case "mcp_server_response":
|
||||
this.emitEvent({
|
||||
type: "tool_result",
|
||||
subtype: "mcp",
|
||||
tool_result: { name: "mcp_server", output: msg.text },
|
||||
})
|
||||
break
|
||||
|
||||
case "completion_result":
|
||||
if (msg.text && !msg.partial) {
|
||||
this.completionResultContent = msg.text
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
if (SKIP_SAY_TYPES.has(msg.say!)) {
|
||||
break
|
||||
}
|
||||
if (msg.text) {
|
||||
this.emitEvent(this.buildTextEvent("assistant", msg.ts, contentToSend, isDone, msg.say))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle reasoning/thinking messages with separate delta tracking.
|
||||
*/
|
||||
private handleReasoningMessage(msg: ClineMessage, isDone: boolean): void {
|
||||
const reasoningContent = msg.reasoning || msg.text
|
||||
const reasoningKey = msg.ts + REASONING_KEY_OFFSET
|
||||
const reasoningDelta = this.getContentToSend(reasoningKey, reasoningContent, msg.partial ?? false)
|
||||
|
||||
if (msg.partial && this.isEmptyStreamingDelta(reasoningDelta)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!msg.partial) {
|
||||
this.previousContent.delete(reasoningKey)
|
||||
}
|
||||
|
||||
this.emitEvent(this.buildTextEvent("thinking", msg.ts, reasoningDelta, isDone))
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "ask" type messages.
|
||||
*/
|
||||
private handleAskMessage(msg: ClineMessage, contentToSend: string | null, isDone: boolean): void {
|
||||
switch (msg.ask) {
|
||||
case "tool": {
|
||||
const toolInfo = parseToolInfo(msg.text)
|
||||
this.emitEvent({
|
||||
type: "tool_use",
|
||||
id: msg.ts,
|
||||
subtype: "tool",
|
||||
tool_use: toolInfo ?? { name: "unknown_tool", input: { raw: msg.text } },
|
||||
})
|
||||
break
|
||||
}
|
||||
|
||||
case "command":
|
||||
this.emitEvent({
|
||||
type: "tool_use",
|
||||
id: msg.ts,
|
||||
subtype: "command",
|
||||
tool_use: { name: "execute_command", input: { command: msg.text } },
|
||||
})
|
||||
break
|
||||
|
||||
case "browser_action_launch":
|
||||
this.emitEvent({
|
||||
type: "tool_use",
|
||||
id: msg.ts,
|
||||
subtype: "browser",
|
||||
tool_use: { name: "browser_action", input: { raw: msg.text } },
|
||||
})
|
||||
break
|
||||
|
||||
case "use_mcp_server":
|
||||
this.emitEvent({
|
||||
type: "tool_use",
|
||||
id: msg.ts,
|
||||
subtype: "mcp",
|
||||
tool_use: { name: "mcp_server", input: { raw: msg.text } },
|
||||
})
|
||||
break
|
||||
|
||||
case "followup":
|
||||
this.emitEvent(this.buildTextEvent("assistant", msg.ts, contentToSend, isDone, "followup"))
|
||||
break
|
||||
|
||||
case "command_output":
|
||||
// Handled in say type
|
||||
break
|
||||
|
||||
case "completion_result":
|
||||
if (msg.text && !msg.partial) {
|
||||
this.completionResultContent = msg.text
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
if (msg.text) {
|
||||
this.emitEvent(this.buildTextEvent("assistant", msg.ts, contentToSend, isDone, msg.ask))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle task completion and emit result event.
|
||||
*/
|
||||
private handleTaskCompleted(event: TaskCompletedEvent): void {
|
||||
// Use tracked completion result content, falling back to event message
|
||||
const resultContent = this.completionResultContent || event.message?.text
|
||||
|
||||
this.emitEvent({
|
||||
type: "result",
|
||||
id: event.message?.ts ?? Date.now(),
|
||||
content: resultContent,
|
||||
done: true,
|
||||
success: event.success,
|
||||
cost: this.lastCost,
|
||||
})
|
||||
|
||||
// For "json" mode, output the final accumulated result
|
||||
if (this.mode === "json") {
|
||||
this.outputFinalResult(event.success, resultContent)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle errors and emit error event.
|
||||
*/
|
||||
private handleError(error: Error): void {
|
||||
this.emitEvent({
|
||||
type: "error",
|
||||
id: Date.now(),
|
||||
content: error.message,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a JSON event.
|
||||
* For stream-json mode: immediately output to stdout
|
||||
* For json mode: accumulate for final output
|
||||
*/
|
||||
private emitEvent(event: JsonEvent): void {
|
||||
this.events.push(event)
|
||||
|
||||
if (this.mode === "stream-json") {
|
||||
this.outputLine(event)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a single JSON line (NDJSON format).
|
||||
*/
|
||||
private outputLine(data: unknown): void {
|
||||
this.stdout.write(JSON.stringify(data) + "\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the final accumulated result (for "json" mode).
|
||||
*/
|
||||
private outputFinalResult(success: boolean, content?: string): void {
|
||||
const output: JsonFinalOutput = {
|
||||
type: "result",
|
||||
success,
|
||||
content,
|
||||
cost: this.lastCost,
|
||||
events: this.events.filter((e) => e.type !== "result"), // Exclude the result event itself
|
||||
}
|
||||
|
||||
this.stdout.write(JSON.stringify(output, null, 2) + "\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Get accumulated events (for testing or external use).
|
||||
*/
|
||||
getEvents(): JsonEvent[] {
|
||||
return [...this.events]
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear accumulated events and state.
|
||||
*/
|
||||
clear(): void {
|
||||
this.events = []
|
||||
this.lastCost = undefined
|
||||
this.seenMessageIds.clear()
|
||||
this.previousContent.clear()
|
||||
this.completionResultContent = undefined
|
||||
}
|
||||
}
|
||||
|
|
@ -11,11 +11,13 @@ import {
|
|||
isSupportedProvider,
|
||||
OnboardingProviderChoice,
|
||||
supportedProviders,
|
||||
ASCII_ROO,
|
||||
DEFAULT_FLAGS,
|
||||
REASONING_EFFORTS,
|
||||
SDK_BASE_URL,
|
||||
OutputFormat,
|
||||
} from "@/types/index.js"
|
||||
import { isValidOutputFormat } from "@/types/json-events.js"
|
||||
import { JsonEventEmitter } from "@/agent/json-event-emitter.js"
|
||||
|
||||
import { createClient } from "@/lib/sdk/index.js"
|
||||
import { loadToken, loadSettings } from "@/lib/storage/index.js"
|
||||
|
|
@ -164,6 +166,23 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption
|
|||
process.exit(1)
|
||||
}
|
||||
|
||||
// Validate output format
|
||||
const outputFormat: OutputFormat = (flagOptions.outputFormat as OutputFormat) || "text"
|
||||
|
||||
if (!isValidOutputFormat(outputFormat)) {
|
||||
console.error(
|
||||
`[CLI] Error: Invalid output format: ${flagOptions.outputFormat}; must be one of: text, json, stream-json`,
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Output format only works with --print mode
|
||||
if (outputFormat !== "text" && !flagOptions.print && isTuiSupported) {
|
||||
console.error("[CLI] Error: --output-format requires --print mode")
|
||||
console.error("[CLI] Usage: roo <prompt> --print --output-format json")
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (!isTuiEnabled) {
|
||||
if (!prompt) {
|
||||
console.error("[CLI] Error: prompt is required in print mode")
|
||||
|
|
@ -204,38 +223,53 @@ export async function run(promptArg: string | undefined, flagOptions: FlagOption
|
|||
process.exit(1)
|
||||
}
|
||||
} else {
|
||||
console.log(ASCII_ROO)
|
||||
console.log()
|
||||
console.log(
|
||||
`[roo] Running ${extensionHostOptions.model || "default"} (${extensionHostOptions.reasoningEffort || "default"}) on ${extensionHostOptions.provider} in ${extensionHostOptions.mode || "default"} mode in ${extensionHostOptions.workspacePath} [debug = ${extensionHostOptions.debug}]`,
|
||||
)
|
||||
const useJsonOutput = outputFormat === "json" || outputFormat === "stream-json"
|
||||
|
||||
extensionHostOptions.disableOutput = useJsonOutput
|
||||
|
||||
const host = new ExtensionHost(extensionHostOptions)
|
||||
|
||||
process.on("SIGINT", async () => {
|
||||
console.log("\n[CLI] Received SIGINT, shutting down...")
|
||||
await host.dispose()
|
||||
process.exit(130)
|
||||
})
|
||||
const jsonEmitter = useJsonOutput
|
||||
? new JsonEventEmitter({ mode: outputFormat as "json" | "stream-json" })
|
||||
: null
|
||||
|
||||
process.on("SIGTERM", async () => {
|
||||
console.log("\n[CLI] Received SIGTERM, shutting down...")
|
||||
async function shutdown(signal: string, exitCode: number): Promise<void> {
|
||||
if (!useJsonOutput) {
|
||||
console.log(`\n[CLI] Received ${signal}, shutting down...`)
|
||||
}
|
||||
jsonEmitter?.detach()
|
||||
await host.dispose()
|
||||
process.exit(143)
|
||||
})
|
||||
process.exit(exitCode)
|
||||
}
|
||||
|
||||
process.on("SIGINT", () => shutdown("SIGINT", 130))
|
||||
process.on("SIGTERM", () => shutdown("SIGTERM", 143))
|
||||
|
||||
try {
|
||||
await host.activate()
|
||||
|
||||
if (jsonEmitter) {
|
||||
jsonEmitter.attachToClient(host.client)
|
||||
}
|
||||
|
||||
await host.runTask(prompt!)
|
||||
jsonEmitter?.detach()
|
||||
await host.dispose()
|
||||
process.exit(0)
|
||||
} catch (error) {
|
||||
console.error("[CLI] Error:", error instanceof Error ? error.message : String(error))
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
|
||||
if (error instanceof Error) {
|
||||
console.error(error.stack)
|
||||
if (useJsonOutput) {
|
||||
const errorEvent = { type: "error", id: Date.now(), content: errorMessage }
|
||||
process.stdout.write(JSON.stringify(errorEvent) + "\n")
|
||||
} else {
|
||||
console.error("[CLI] Error:", errorMessage)
|
||||
if (error instanceof Error) {
|
||||
console.error(error.stack)
|
||||
}
|
||||
}
|
||||
|
||||
jsonEmitter?.detach()
|
||||
await host.dispose()
|
||||
process.exit(1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,11 @@ program
|
|||
)
|
||||
.option("--ephemeral", "Run without persisting state (uses temporary storage)", false)
|
||||
.option("--oneshot", "Exit upon task completion", false)
|
||||
.option(
|
||||
"--output-format <format>",
|
||||
'Output format (only works with --print): "text" (default), "json" (single result), or "stream-json" (realtime streaming)',
|
||||
"text",
|
||||
)
|
||||
.action(run)
|
||||
|
||||
const authCommand = program.command("auth").description("Manage authentication for Roo Code Cloud")
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
export * from "./types.js"
|
||||
export * from "./constants.js"
|
||||
export * from "./json-events.js"
|
||||
|
|
|
|||
120
apps/cli/src/types/json-events.ts
Normal file
120
apps/cli/src/types/json-events.ts
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/**
|
||||
* JSON Event Types for Structured CLI Output
|
||||
*
|
||||
* This module defines the types for structured JSON output from the CLI.
|
||||
* The output format is NDJSON (newline-delimited JSON) for stream-json mode,
|
||||
* or a single JSON object for json mode.
|
||||
*
|
||||
* Schema is optimized for efficiency with high message volume:
|
||||
* - Minimal fields per event
|
||||
* - No redundant wrappers
|
||||
* - `done` flag instead of partial:false
|
||||
*/
|
||||
|
||||
/**
|
||||
* Output format options for the CLI.
|
||||
*/
|
||||
export const OUTPUT_FORMATS = ["text", "json", "stream-json"] as const
|
||||
|
||||
export type OutputFormat = (typeof OUTPUT_FORMATS)[number]
|
||||
|
||||
export function isValidOutputFormat(format: string): format is OutputFormat {
|
||||
return (OUTPUT_FORMATS as readonly string[]).includes(format)
|
||||
}
|
||||
|
||||
/**
|
||||
* Event type discriminators for JSON output.
|
||||
*/
|
||||
export type JsonEventType =
|
||||
| "system" // System messages (init, ready, shutdown)
|
||||
| "assistant" // Assistant text messages
|
||||
| "user" // User messages (echoed input)
|
||||
| "tool_use" // Tool invocations (file ops, commands, browser, MCP)
|
||||
| "tool_result" // Results from tool execution
|
||||
| "thinking" // Reasoning/thinking content
|
||||
| "error" // Errors
|
||||
| "result" // Final task result
|
||||
|
||||
/**
|
||||
* Tool use information for tool_use events.
|
||||
*/
|
||||
export interface JsonEventToolUse {
|
||||
/** Tool name (e.g., "read_file", "write_to_file", "execute_command") */
|
||||
name: string
|
||||
/** Tool input parameters */
|
||||
input?: Record<string, unknown>
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool result information for tool_result events.
|
||||
*/
|
||||
export interface JsonEventToolResult {
|
||||
/** Tool name that produced this result */
|
||||
name: string
|
||||
/** Tool output (for successful execution) */
|
||||
output?: string
|
||||
/** Error message (for failed execution) */
|
||||
error?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Cost and token usage information.
|
||||
*/
|
||||
export interface JsonEventCost {
|
||||
/** Total cost in USD */
|
||||
totalCost?: number
|
||||
/** Input tokens used */
|
||||
inputTokens?: number
|
||||
/** Output tokens generated */
|
||||
outputTokens?: number
|
||||
/** Cache write tokens */
|
||||
cacheWrites?: number
|
||||
/** Cache read tokens */
|
||||
cacheReads?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Base JSON event structure.
|
||||
* Optimized for minimal payload size.
|
||||
*
|
||||
* For streaming deltas:
|
||||
* - Each delta includes `id` for easy correlation
|
||||
* - Final message has `done: true`
|
||||
*/
|
||||
export interface JsonEvent {
|
||||
/** Event type discriminator */
|
||||
type: JsonEventType
|
||||
/** Message ID - included on first delta and final message */
|
||||
id?: number
|
||||
/** Content text (for text-based events) */
|
||||
content?: string
|
||||
/** True when this is the final message (stream complete) */
|
||||
done?: boolean
|
||||
/** Optional subtype for more specific categorization */
|
||||
subtype?: string
|
||||
/** Tool use information (for tool_use events) */
|
||||
tool_use?: JsonEventToolUse
|
||||
/** Tool result information (for tool_result events) */
|
||||
tool_result?: JsonEventToolResult
|
||||
/** Whether the task succeeded (for result events) */
|
||||
success?: boolean
|
||||
/** Cost and token usage (for result events) */
|
||||
cost?: JsonEventCost
|
||||
}
|
||||
|
||||
/**
|
||||
* Final JSON output for "json" mode (single object at end).
|
||||
* Contains the result and accumulated messages.
|
||||
*/
|
||||
export interface JsonFinalOutput {
|
||||
/** Final result type */
|
||||
type: "result"
|
||||
/** Whether the task succeeded */
|
||||
success: boolean
|
||||
/** Result content/message */
|
||||
content?: string
|
||||
/** Cost and token usage */
|
||||
cost?: JsonEventCost
|
||||
/** All events that occurred during the task */
|
||||
events: JsonEvent[]
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import type { ProviderName, ReasoningEffortExtended } from "@roo-code/types"
|
||||
import type { OutputFormat } from "./json-events.js"
|
||||
|
||||
export const supportedProviders = [
|
||||
"anthropic",
|
||||
|
|
@ -32,6 +33,7 @@ export type FlagOptions = {
|
|||
reasoningEffort?: ReasoningEffortFlagOptions
|
||||
ephemeral: boolean
|
||||
oneshot: boolean
|
||||
outputFormat?: OutputFormat
|
||||
}
|
||||
|
||||
export enum OnboardingProviderChoice {
|
||||
|
|
|
|||
|
|
@ -16,15 +16,7 @@ export type ToolCategory =
|
|||
| "other"
|
||||
|
||||
export function getToolCategory(toolName: string): ToolCategory {
|
||||
const fileReadTools = [
|
||||
"readFile",
|
||||
"read_file",
|
||||
"fetchInstructions",
|
||||
"fetch_instructions",
|
||||
"listFilesTopLevel",
|
||||
"listFilesRecursive",
|
||||
"list_files",
|
||||
]
|
||||
const fileReadTools = ["readFile", "read_file", "skill", "listFilesTopLevel", "listFilesRecursive", "list_files"]
|
||||
|
||||
const fileWriteTools = [
|
||||
"editedExistingFile",
|
||||
|
|
|
|||
|
|
@ -50,8 +50,7 @@ export function getToolDisplayName(toolName: string): string {
|
|||
// File read operations
|
||||
readFile: "Read",
|
||||
read_file: "Read",
|
||||
fetchInstructions: "Fetch Instructions",
|
||||
fetch_instructions: "Fetch Instructions",
|
||||
skill: "Load Skill",
|
||||
listFilesTopLevel: "List Files",
|
||||
listFilesRecursive: "List Files (Recursive)",
|
||||
list_files: "List Files",
|
||||
|
|
@ -107,8 +106,7 @@ export function getToolIconName(toolName: string): IconName {
|
|||
// File read operations
|
||||
readFile: "file",
|
||||
read_file: "file",
|
||||
fetchInstructions: "file",
|
||||
fetch_instructions: "file",
|
||||
skill: "file",
|
||||
listFilesTopLevel: "folder",
|
||||
listFilesRecursive: "folder",
|
||||
list_files: "folder",
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ import { useRooCodeCloudModels } from "@/hooks/use-roo-code-cloud-models"
|
|||
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
FormControl,
|
||||
FormField,
|
||||
FormItem,
|
||||
|
|
@ -111,7 +110,6 @@ export function NewRun() {
|
|||
|
||||
const [provider, setModelSource] = useState<"roo" | "openrouter" | "other">("other")
|
||||
const [executionMethod, setExecutionMethod] = useState<ExecutionMethod>("vscode")
|
||||
const [useNativeToolProtocol, setUseNativeToolProtocol] = useState(true)
|
||||
const [commandExecutionTimeout, setCommandExecutionTimeout] = useState(20)
|
||||
const [terminalShellIntegrationTimeout, setTerminalShellIntegrationTimeout] = useState(30) // seconds
|
||||
|
||||
|
|
@ -464,7 +462,6 @@ export function NewRun() {
|
|||
...(runValues.settings || {}),
|
||||
apiProvider: "openrouter",
|
||||
openRouterModelId: selection.model,
|
||||
toolProtocol: useNativeToolProtocol ? "native" : "xml",
|
||||
commandExecutionTimeout,
|
||||
terminalShellIntegrationTimeout: terminalShellIntegrationTimeout * 1000,
|
||||
}
|
||||
|
|
@ -474,7 +471,6 @@ export function NewRun() {
|
|||
...(runValues.settings || {}),
|
||||
apiProvider: "roo",
|
||||
apiModelId: selection.model,
|
||||
toolProtocol: useNativeToolProtocol ? "native" : "xml",
|
||||
commandExecutionTimeout,
|
||||
terminalShellIntegrationTimeout: terminalShellIntegrationTimeout * 1000,
|
||||
}
|
||||
|
|
@ -485,7 +481,6 @@ export function NewRun() {
|
|||
...EVALS_SETTINGS,
|
||||
...providerSettings,
|
||||
...importedSettings.globalSettings,
|
||||
toolProtocol: useNativeToolProtocol ? "native" : "xml",
|
||||
commandExecutionTimeout,
|
||||
terminalShellIntegrationTimeout: terminalShellIntegrationTimeout * 1000,
|
||||
}
|
||||
|
|
@ -512,7 +507,6 @@ export function NewRun() {
|
|||
configSelections,
|
||||
importedSettings,
|
||||
router,
|
||||
useNativeToolProtocol,
|
||||
commandExecutionTimeout,
|
||||
terminalShellIntegrationTimeout,
|
||||
],
|
||||
|
|
@ -688,26 +682,6 @@ export function NewRun() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-4 p-4 rounded-md bg-muted/30 border border-border space-y-3">
|
||||
<Label className="text-sm font-medium text-muted-foreground">
|
||||
Tool Protocol Options
|
||||
</Label>
|
||||
<div className="flex flex-col gap-2.5 pl-1">
|
||||
<label
|
||||
htmlFor="native-other"
|
||||
className="flex items-center gap-2 cursor-pointer">
|
||||
<Checkbox
|
||||
id="native-other"
|
||||
checked={useNativeToolProtocol}
|
||||
onCheckedChange={(checked: boolean) =>
|
||||
setUseNativeToolProtocol(checked)
|
||||
}
|
||||
/>
|
||||
<span className="text-sm">Use Native Tool Calls</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{settings && (
|
||||
<SettingsDiff defaultSettings={EVALS_SETTINGS} customSettings={settings} />
|
||||
)}
|
||||
|
|
@ -792,26 +766,6 @@ export function NewRun() {
|
|||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 p-4 rounded-md bg-muted/30 border border-border space-y-3">
|
||||
<Label className="text-sm font-medium text-muted-foreground">
|
||||
Tool Protocol Options
|
||||
</Label>
|
||||
<div className="flex flex-col gap-2.5 pl-1">
|
||||
<label
|
||||
htmlFor="native"
|
||||
className="flex items-center gap-2 cursor-pointer">
|
||||
<Checkbox
|
||||
id="native"
|
||||
checked={useNativeToolProtocol}
|
||||
onCheckedChange={(checked: boolean) =>
|
||||
setUseNativeToolProtocol(checked)
|
||||
}
|
||||
/>
|
||||
<span className="text-sm">Use Native Tool Calls</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,19 @@ export default function CookiePolicy() {
|
|||
<td className="border border-border px-4 py-3">1 year</td>
|
||||
<td className="border border-border px-4 py-3 font-mono text-sm">ph_*</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="border border-border px-4 py-3 font-medium">HubSpot</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Marketing automation and visitor tracking
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">
|
||||
Analytics (only with your consent)
|
||||
</td>
|
||||
<td className="border border-border px-4 py-3">13 months</td>
|
||||
<td className="border border-border px-4 py-3 font-mono text-sm">
|
||||
hubspotutk, __hstc, __hssrc, __hssc
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
|
@ -122,6 +135,15 @@ export default function CookiePolicy() {
|
|||
PostHog Privacy Policy
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<a
|
||||
href="https://legal.hubspot.com/privacy-policy"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline">
|
||||
HubSpot Privacy Policy
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Essential cookies</h2>
|
||||
<p>
|
||||
|
|
@ -133,10 +155,10 @@ export default function CookiePolicy() {
|
|||
|
||||
<h2 className="mt-12 text-2xl font-bold">Analytics cookies</h2>
|
||||
<p>
|
||||
We use PostHog analytics cookies to understand how visitors interact with our website. This
|
||||
helps us improve our services and user experience. Analytics cookies are placed only if you give
|
||||
consent through our cookie banner. The lawful basis for processing these cookies is your
|
||||
consent, which you can withdraw at any time.
|
||||
We use PostHog and HubSpot analytics cookies to understand how visitors interact with our
|
||||
website. This helps us improve our services, user experience, and marketing efforts. Analytics
|
||||
cookies are placed only if you give consent through our cookie banner. The lawful basis for
|
||||
processing these cookies is your consent, which you can withdraw at any time.
|
||||
</p>
|
||||
|
||||
<h2 className="mt-12 text-2xl font-bold">Third-party services</h2>
|
||||
|
|
|
|||
|
|
@ -291,11 +291,7 @@ export default function PricingPage() {
|
|||
<li>To pay for Cloud Agents running time (${PRICE_CREDITS}/hour)</li>
|
||||
<li>
|
||||
To pay for AI model inference costs (
|
||||
<a
|
||||
href="https://app.roocode.com/provider/pricing"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline">
|
||||
<a href="/provider" target="_blank" rel="noopener noreferrer" className="underline">
|
||||
varies by model
|
||||
</a>
|
||||
)
|
||||
|
|
|
|||
401
apps/web-roo-code/src/app/slack/page.tsx
Normal file
401
apps/web-roo-code/src/app/slack/page.tsx
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
import {
|
||||
ArrowRight,
|
||||
Brain,
|
||||
CreditCard,
|
||||
GitBranch,
|
||||
GraduationCap,
|
||||
Link2,
|
||||
MessageSquare,
|
||||
Settings,
|
||||
Shield,
|
||||
Slack,
|
||||
Users,
|
||||
Zap,
|
||||
} from "lucide-react"
|
||||
import type { LucideIcon } from "lucide-react"
|
||||
import type { Metadata } from "next"
|
||||
|
||||
import { AnimatedBackground } from "@/components/homepage"
|
||||
import { SlackThreadDemo } from "@/components/slack/slack-thread-demo"
|
||||
import { Button } from "@/components/ui"
|
||||
import { EXTERNAL_LINKS } from "@/lib/constants"
|
||||
import { SEO } from "@/lib/seo"
|
||||
import { ogImageUrl } from "@/lib/og"
|
||||
|
||||
const TITLE = "Roo Code for Slack"
|
||||
const DESCRIPTION =
|
||||
"Mention @Roomote in any channel to explain code, plan features, or ship a PR, all without leaving the conversation."
|
||||
const OG_DESCRIPTION = "Your AI Team in Slack"
|
||||
const PATH = "/slack"
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
alternates: {
|
||||
canonical: `${SEO.url}${PATH}`,
|
||||
},
|
||||
openGraph: {
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
url: `${SEO.url}${PATH}`,
|
||||
siteName: SEO.name,
|
||||
images: [
|
||||
{
|
||||
url: ogImageUrl(TITLE, OG_DESCRIPTION),
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: TITLE,
|
||||
},
|
||||
],
|
||||
locale: SEO.locale,
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: SEO.twitterCard,
|
||||
title: TITLE,
|
||||
description: DESCRIPTION,
|
||||
images: [ogImageUrl(TITLE, OG_DESCRIPTION)],
|
||||
},
|
||||
keywords: [
|
||||
...SEO.keywords,
|
||||
"slack integration",
|
||||
"slack bot",
|
||||
"AI in slack",
|
||||
"code assistant slack",
|
||||
"@Roomote",
|
||||
"team collaboration",
|
||||
],
|
||||
}
|
||||
|
||||
// Invalidate cache when a request comes in, at most once every hour.
|
||||
export const revalidate = 3600
|
||||
|
||||
type ValueProp = {
|
||||
icon: LucideIcon
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const VALUE_PROPS: ValueProp[] = [
|
||||
{
|
||||
icon: GitBranch,
|
||||
title: "Discussion to PR.",
|
||||
description:
|
||||
"Your team discusses a feature in Slack. @Roomote turns the discussion into a plan. Then builds it. All without leaving the conversation.",
|
||||
},
|
||||
{
|
||||
icon: Brain,
|
||||
title: "Thread-aware.",
|
||||
description:
|
||||
'@Roomote reads the full thread before responding. Ask "Can we add caching here?" and it knows exactly what code you mean.',
|
||||
},
|
||||
{
|
||||
icon: Link2,
|
||||
title: "Chain agents.",
|
||||
description:
|
||||
"Start with a Planner to spec it out. Then call the Coder to build it. Multi-step workflows, one Slack thread.",
|
||||
},
|
||||
{
|
||||
icon: Users,
|
||||
title: "Open to all.",
|
||||
description:
|
||||
"Anyone on your team can ask @Roomote to fix bugs, build features, or investigate issues. Engineering gets looped in only when needed.",
|
||||
},
|
||||
{
|
||||
icon: GraduationCap,
|
||||
title: "Built-in learning.",
|
||||
description: "Public channel mentions show everyone how to leverage agents. Learn by watching.",
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: "Safe by design.",
|
||||
description: "Agents never touch main/master directly. They produce branches and PRs. You approve.",
|
||||
},
|
||||
]
|
||||
|
||||
type WorkflowStep = {
|
||||
step: number
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const WORKFLOW_STEPS: WorkflowStep[] = [
|
||||
{
|
||||
step: 1,
|
||||
title: "Turn the discussion into a plan",
|
||||
description: "Your team discusses a feature. When it gets complex, summon the Planner agent.",
|
||||
},
|
||||
{
|
||||
step: 2,
|
||||
title: "Refine the plan in the thread",
|
||||
description:
|
||||
"The team reviews the spec in the thread, suggests changes, asks questions. Mention @Roomote again to refine.",
|
||||
},
|
||||
{
|
||||
step: 3,
|
||||
title: "Build the plan",
|
||||
description: "Once the plan looks good, hand it off to the Coder agent to implement.",
|
||||
},
|
||||
{
|
||||
step: 4,
|
||||
title: "Review and ship",
|
||||
description: "The Coder creates a branch and opens a PR. The team reviews, and the feature ships.",
|
||||
},
|
||||
]
|
||||
|
||||
type OnboardingStep = {
|
||||
icon: LucideIcon
|
||||
title: string
|
||||
description: string
|
||||
link?: {
|
||||
href: string
|
||||
text: string
|
||||
}
|
||||
}
|
||||
|
||||
const ONBOARDING_STEPS: OnboardingStep[] = [
|
||||
{
|
||||
icon: CreditCard,
|
||||
title: "1. Team Plan",
|
||||
description: "Slack requires a Team plan.",
|
||||
link: {
|
||||
href: EXTERNAL_LINKS.CLOUD_APP_TEAM_TRIAL,
|
||||
text: "Start a free trial",
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: Settings,
|
||||
title: "2. Connect",
|
||||
description: 'Sign in to Roo Code Cloud and go to Settings. Click "Connect" next to Slack.',
|
||||
},
|
||||
{
|
||||
icon: Slack,
|
||||
title: "3. Authorize",
|
||||
description: "Authorize the Roo Code app to access your Slack workspace.",
|
||||
},
|
||||
{
|
||||
icon: MessageSquare,
|
||||
title: "4. Add to channels",
|
||||
description: "Add @Roomote to the channels where you want it available.",
|
||||
},
|
||||
]
|
||||
|
||||
export default function SlackPage(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
{/* Hero Section */}
|
||||
<section className="relative flex pt-32 pb-20 items-center overflow-hidden">
|
||||
<AnimatedBackground />
|
||||
<div className="container relative flex flex-col items-center h-full z-10 mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid w-full max-w-6xl grid-cols-1 items-center gap-10 lg:grid-cols-2 lg:gap-12">
|
||||
<div className="text-center lg:text-left">
|
||||
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-violet-100 dark:bg-violet-900/30 text-violet-700 dark:text-violet-300 text-sm font-medium mb-6">
|
||||
<Slack className="size-4" />
|
||||
Powered by Roo Code Cloud
|
||||
</div>
|
||||
<h1 className="text-4xl font-bold tracking-tight mb-6 md:text-5xl lg:text-6xl">
|
||||
<span className="text-violet-500">@Roomote:</span> Your AI Team in Slack
|
||||
</h1>
|
||||
<p className="text-xl text-muted-foreground mb-8 max-w-2xl mx-auto lg:mx-0">
|
||||
Mention @Roomote in any channel to explain code, plan features, or ship a PR, all
|
||||
without leaving the conversation.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
|
||||
<Button
|
||||
size="xl"
|
||||
className="bg-violet-600 hover:bg-violet-700 text-white transition-all duration-300 shadow-lg hover:shadow-violet-500/25"
|
||||
asChild>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.CLOUD_APP_SIGNUP}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-center">
|
||||
Get Started
|
||||
<ArrowRight className="ml-2 size-5" />
|
||||
</a>
|
||||
</Button>
|
||||
<Button variant="outline" size="xl" className="backdrop-blur-sm" asChild>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.SLACK_DOCS}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-center">
|
||||
Read the Docs
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center lg:justify-end">
|
||||
<SlackThreadDemo />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Value Props Section */}
|
||||
<section className="py-24 bg-muted/30">
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8 relative">
|
||||
<div className="absolute inset-y-0 left-1/2 h-full w-full max-w-[1200px] -translate-x-1/2 z-1">
|
||||
<div className="absolute left-1/2 top-1/2 h-[800px] w-full -translate-x-1/2 -translate-y-1/2 rounded-full bg-violet-500/10 dark:bg-violet-700/20 blur-[140px]" />
|
||||
</div>
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl mb-4">
|
||||
Why your team will love using Roo Code in Slack
|
||||
</h2>
|
||||
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
|
||||
AI agents that understand context, chain together for complex work, and keep your team in
|
||||
control.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto relative">
|
||||
{VALUE_PROPS.map((prop, index) => {
|
||||
const Icon = prop.icon
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-background p-8 rounded-2xl border border-border hover:shadow-lg transition-all duration-300">
|
||||
<div className="bg-violet-100 dark:bg-violet-900/20 w-12 h-12 rounded-lg flex items-center justify-center mb-6">
|
||||
<Icon className="size-6 text-violet-600 dark:text-violet-400" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold mb-3">{prop.title}</h3>
|
||||
<p className="text-muted-foreground leading-relaxed">{prop.description}</p>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Featured Workflow Section */}
|
||||
<section className="relative overflow-hidden border-t border-border py-24 lg:py-32">
|
||||
<div className="container relative z-10 mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="absolute inset-y-0 left-1/2 h-full w-full max-w-[1200px] -translate-x-1/2 z-1">
|
||||
<div className="absolute left-1/2 top-1/2 h-[400px] w-full -translate-x-1/2 -translate-y-1/2 rounded-full bg-blue-500/10 dark:bg-blue-700/20 blur-[140px]" />
|
||||
</div>
|
||||
|
||||
<div className="mx-auto mb-12 max-w-5xl text-center">
|
||||
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 text-sm font-medium mb-6">
|
||||
<Zap className="size-4" />
|
||||
Featured Workflow
|
||||
</div>
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-5xl mb-4">
|
||||
Thread to Shipped Feature
|
||||
</h2>
|
||||
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
|
||||
Turn Slack discussions into working code. No context lost, no meetings needed.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative mx-auto max-w-6xl">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-5 gap-8 lg:gap-10 items-center">
|
||||
{/* YouTube Video Embed */}
|
||||
<div className="lg:col-span-3 overflow-hidden rounded-2xl border border-border bg-background shadow-lg">
|
||||
<iframe
|
||||
className="aspect-video w-full"
|
||||
src="https://www.youtube-nocookie.com/embed/dJM_8HHGe1E?rel=0"
|
||||
title="Roo Code Slack Integration Demo"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
|
||||
referrerPolicy="strict-origin-when-cross-origin"
|
||||
allowFullScreen
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Workflow Steps */}
|
||||
<div className="lg:col-span-2 space-y-3">
|
||||
{WORKFLOW_STEPS.map((step) => (
|
||||
<div
|
||||
key={step.step}
|
||||
className="relative border border-border rounded-xl bg-background p-4 transition-all duration-300 hover:shadow-md hover:border-blue-500/30">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="bg-blue-100 dark:bg-blue-900/30 w-7 h-7 rounded-full flex items-center justify-center text-blue-700 dark:text-blue-300 font-bold text-xs shrink-0 mt-0.5">
|
||||
{step.step}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<h3 className="text-base font-semibold text-foreground mb-0.5">
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="text-sm leading-snug text-muted-foreground">
|
||||
{step.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Onboarding Section */}
|
||||
<section className="py-24 bg-muted/30">
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl mb-4">Get started in minutes</h2>
|
||||
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
|
||||
Connect your Slack workspace and start working with AI agents.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 max-w-5xl mx-auto">
|
||||
{ONBOARDING_STEPS.map((step, index) => {
|
||||
const Icon = step.icon
|
||||
return (
|
||||
<div key={index} className="text-center">
|
||||
<div className="bg-violet-100 dark:bg-violet-900/20 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||
<Icon className="size-8 text-violet-600 dark:text-violet-400" />
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold mb-2">{step.title}</h3>
|
||||
<p className="text-muted-foreground">
|
||||
{step.description}
|
||||
{step.link && (
|
||||
<>
|
||||
{" "}
|
||||
<a
|
||||
href={step.link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-violet-600 dark:text-violet-400 hover:underline">
|
||||
{step.link.text} →
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* CTA Section */}
|
||||
<section className="py-24">
|
||||
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="mx-auto max-w-4xl rounded-3xl border border-border/50 bg-gradient-to-br from-violet-500/10 via-purple-500/5 to-blue-500/5 p-8 text-center shadow-2xl backdrop-blur-xl dark:border-white/10 sm:p-16">
|
||||
<h2 className="mb-6 text-3xl font-bold tracking-tight sm:text-4xl">
|
||||
Start using Roo Code in Slack
|
||||
</h2>
|
||||
<p className="mx-auto mb-10 max-w-2xl text-lg text-muted-foreground">
|
||||
Start a free 14 day Team trial.
|
||||
</p>
|
||||
<div className="flex flex-col justify-center space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0">
|
||||
<Button
|
||||
size="lg"
|
||||
className="bg-foreground text-background hover:bg-foreground/90 transition-all duration-300"
|
||||
asChild>
|
||||
<a
|
||||
href={EXTERNAL_LINKS.CLOUD_APP_TEAM_TRIAL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-center">
|
||||
Start free trial
|
||||
<ArrowRight className="ml-2 h-4 w-4" />
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ import { EXTERNAL_LINKS } from "@/lib/constants"
|
|||
import { useLogoSrc } from "@/lib/hooks/use-logo-src"
|
||||
import { ScrollButton } from "@/components/ui"
|
||||
import ThemeToggle from "@/components/chromes/theme-toggle"
|
||||
import { Brain, ChevronDown, Cloud, Puzzle, X } from "lucide-react"
|
||||
import { Brain, ChevronDown, Cloud, Puzzle, Slack, X } from "lucide-react"
|
||||
|
||||
interface NavBarProps {
|
||||
stars: string | null
|
||||
|
|
@ -54,6 +54,12 @@ export function NavBar({ stars, downloads }: NavBarProps) {
|
|||
<Cloud className="size-3 inline mr-2 -mt-0.5" />
|
||||
Roo Code Cloud
|
||||
</Link>
|
||||
<Link
|
||||
href="/slack"
|
||||
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground">
|
||||
<Slack className="size-3 inline mr-2 -mt-0.5" />
|
||||
Roo Code for Slack
|
||||
</Link>
|
||||
<Link
|
||||
href="/provider"
|
||||
className="block px-4 py-2 text-sm transition-colors hover:bg-accent hover:text-foreground">
|
||||
|
|
@ -190,6 +196,12 @@ export function NavBar({ stars, downloads }: NavBarProps) {
|
|||
onClick={() => setIsMenuOpen(false)}>
|
||||
Roo Code Cloud
|
||||
</Link>
|
||||
<Link
|
||||
href="/slack"
|
||||
className="block w-full p-5 py-3 text-left text-foreground active:opacity-50"
|
||||
onClick={() => setIsMenuOpen(false)}>
|
||||
Roo Code for Slack
|
||||
</Link>
|
||||
<Link
|
||||
href="/provider"
|
||||
className="block w-full p-5 py-3 text-left text-foreground active:opacity-50"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
"use client"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
import Script from "next/script"
|
||||
import { hasConsent, onConsentChange } from "@/lib/analytics/consent-manager"
|
||||
|
||||
// HubSpot Account ID
|
||||
const HUBSPOT_ID = "243714031"
|
||||
|
||||
/**
|
||||
* HubSpot Tracking Provider
|
||||
* Loads HubSpot tracking script only after user consent is given, following GDPR requirements
|
||||
*/
|
||||
export function HubSpotProvider({ children }: { children: React.ReactNode }) {
|
||||
const [shouldLoad, setShouldLoad] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
// Check initial consent status
|
||||
if (hasConsent()) {
|
||||
setShouldLoad(true)
|
||||
}
|
||||
|
||||
// Listen for consent changes
|
||||
const unsubscribe = onConsentChange((consented) => {
|
||||
if (consented) {
|
||||
setShouldLoad(true)
|
||||
}
|
||||
})
|
||||
|
||||
return unsubscribe
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
{shouldLoad && (
|
||||
<>
|
||||
{/* HubSpot Embed Code */}
|
||||
<Script
|
||||
id="hs-script-loader"
|
||||
src={`//js-na2.hs-scripts.com/${HUBSPOT_ID}.js`}
|
||||
strategy="afterInteractive"
|
||||
async
|
||||
defer
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
|||
import { ThemeProvider } from "next-themes"
|
||||
|
||||
import { GoogleTagManagerProvider } from "./google-tag-manager-provider"
|
||||
import { HubSpotProvider } from "./hubspot-provider"
|
||||
import { PostHogProvider } from "./posthog-provider"
|
||||
|
||||
const queryClient = new QueryClient()
|
||||
|
|
@ -12,11 +13,13 @@ export const Providers = ({ children }: { children: React.ReactNode }) => {
|
|||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<GoogleTagManagerProvider>
|
||||
<PostHogProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem={false}>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</PostHogProvider>
|
||||
<HubSpotProvider>
|
||||
<PostHogProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem={false}>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</PostHogProvider>
|
||||
</HubSpotProvider>
|
||||
</GoogleTagManagerProvider>
|
||||
</QueryClientProvider>
|
||||
)
|
||||
|
|
|
|||
548
apps/web-roo-code/src/components/slack/slack-thread-demo.tsx
Normal file
548
apps/web-roo-code/src/components/slack/slack-thread-demo.tsx
Normal file
|
|
@ -0,0 +1,548 @@
|
|||
"use client"
|
||||
|
||||
import type { ReactNode } from "react"
|
||||
import { useEffect, useMemo, useRef, useState } from "react"
|
||||
import { CheckCircle2, Paperclip } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
type SlackMessage = {
|
||||
id: string
|
||||
author: string
|
||||
timeLabel: string
|
||||
body: ReactNode
|
||||
avatarText: string
|
||||
avatarClassName: string
|
||||
kind: "human" | "bot"
|
||||
}
|
||||
|
||||
function usePrefersReducedMotion(): boolean {
|
||||
const [reduced, setReduced] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
const media = window.matchMedia("(prefers-reduced-motion: reduce)")
|
||||
const onChange = () => setReduced(media.matches)
|
||||
onChange()
|
||||
|
||||
if (typeof media.addEventListener === "function") {
|
||||
media.addEventListener("change", onChange)
|
||||
return () => media.removeEventListener("change", onChange)
|
||||
}
|
||||
|
||||
media.addListener?.(onChange)
|
||||
return () => media.removeListener?.(onChange)
|
||||
}, [])
|
||||
|
||||
return reduced
|
||||
}
|
||||
|
||||
type TypingDotsProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
function TypingDots({ className }: TypingDotsProps): JSX.Element {
|
||||
return (
|
||||
<span className={cn("inline-flex items-center gap-1", className)} aria-hidden="true">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-[#8B8D91] animate-pulse [animation-delay:0ms]" />
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-[#8B8D91] animate-pulse [animation-delay:180ms]" />
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-[#8B8D91] animate-pulse [animation-delay:360ms]" />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
type FakeLinkProps = {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
function FakeLink({ children, className }: FakeLinkProps): JSX.Element {
|
||||
return (
|
||||
<span className={cn("text-violet-300 underline underline-offset-2", "cursor-default", className)}>
|
||||
{children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
type SlackMessageRowProps = {
|
||||
message: SlackMessage
|
||||
isNew: boolean
|
||||
reduceMotion: boolean
|
||||
}
|
||||
|
||||
function SlackMessageRow({ message, isNew, reduceMotion }: SlackMessageRowProps): JSX.Element {
|
||||
let animation = ""
|
||||
if (!reduceMotion && isNew) {
|
||||
animation = "animate-in fade-in slide-in-from-bottom-2 duration-500"
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn("flex gap-3", animation)}>
|
||||
<div
|
||||
className={cn(
|
||||
"mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-xs font-semibold",
|
||||
message.avatarClassName,
|
||||
)}>
|
||||
{message.avatarText}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="flex flex-wrap items-baseline gap-x-2 gap-y-1">
|
||||
<span className="text-[13px] font-semibold text-[#F8F8F9]">{message.author}</span>
|
||||
<span className="text-[11px] text-[#8B8D91]">{message.timeLabel}</span>
|
||||
{message.kind === "bot" && (
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-violet-500/20 px-2 py-0.5 text-[10px] font-medium text-violet-200">
|
||||
<CheckCircle2 className="h-3 w-3" />
|
||||
App
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-1 text-[13px] leading-relaxed text-[#D1D2D3]">{message.body}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export type SlackThreadDemoProps = {
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function SlackThreadDemo({ className }: SlackThreadDemoProps): JSX.Element {
|
||||
const reduceMotion = usePrefersReducedMotion()
|
||||
const [stepIndex, setStepIndex] = useState(0)
|
||||
const scrollViewportRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const messages: SlackMessage[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: "m1",
|
||||
author: "Avery Lee",
|
||||
timeLabel: "Monday at 2:56 PM",
|
||||
avatarText: "AL",
|
||||
avatarClassName: "bg-[#2B2D31] text-[#F8F8F9] ring-1 ring-white/10",
|
||||
kind: "human",
|
||||
body: (
|
||||
<span>We need to add a page to our Marketing site that highlights using Roo Code from Slack.</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m2",
|
||||
author: "Avery Lee",
|
||||
timeLabel: "Monday at 2:58 PM",
|
||||
avatarText: "AL",
|
||||
avatarClassName: "bg-[#2B2D31] text-[#F8F8F9] ring-1 ring-white/10",
|
||||
kind: "human",
|
||||
body: (
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
The documentation for using Roo Code from Slack is here:{" "}
|
||||
<FakeLink className="hover:text-violet-200">
|
||||
https://docs.roocode.com/roo-code-cloud/slack-integration
|
||||
</FakeLink>
|
||||
</div>
|
||||
<div className="text-[#B8BBC0]">Here are some pages from our site we can use for guidance:</div>
|
||||
<ol className="list-decimal pl-5 text-[#D1D2D3]">
|
||||
<li>
|
||||
<FakeLink className="hover:text-violet-200">https://roocode.com</FakeLink>
|
||||
</li>
|
||||
<li>
|
||||
<FakeLink className="hover:text-violet-200">https://roocode.com/extension</FakeLink>
|
||||
</li>
|
||||
<li>
|
||||
<FakeLink className="hover:text-violet-200">https://roocode.com/cloud</FakeLink>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m3",
|
||||
author: "Avery Lee",
|
||||
timeLabel: "Monday at 3:08 PM",
|
||||
avatarText: "AL",
|
||||
avatarClassName: "bg-[#2B2D31] text-[#F8F8F9] ring-1 ring-white/10",
|
||||
kind: "human",
|
||||
body: (
|
||||
<div className="space-y-3">
|
||||
<div>This is the start of a wireframe I have in mind for this page</div>
|
||||
<div className="w-full max-w-[420px] rounded-lg border border-white/10 bg-black/20 p-3">
|
||||
<div className="flex items-center gap-2 text-[12px] text-[#B8BBC0]">
|
||||
<Paperclip className="h-4 w-4" />
|
||||
IMG_9721.heic
|
||||
</div>
|
||||
<div className="mt-3 h-24 w-full rounded-md bg-gradient-to-br from-white/10 via-white/5 to-white/0" />
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m4",
|
||||
author: "Avery Lee",
|
||||
timeLabel: "Monday at 3:09 PM",
|
||||
avatarText: "AL",
|
||||
avatarClassName: "bg-[#2B2D31] text-[#F8F8F9] ring-1 ring-white/10",
|
||||
kind: "human",
|
||||
body: (
|
||||
<span>
|
||||
<FakeLink className="no-underline hover:text-violet-200">@Roomote</FakeLink> let's create
|
||||
the plan to deliver this
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m5",
|
||||
author: "Roomote",
|
||||
timeLabel: "Monday at 3:09 PM",
|
||||
avatarText: "R",
|
||||
avatarClassName: "bg-violet-500/20 text-violet-200 ring-1 ring-violet-500/30",
|
||||
kind: "bot",
|
||||
body: (
|
||||
<div className="space-y-3">
|
||||
<div className="rounded-lg border border-white/10 bg-black/20 px-3 py-2 text-[#D1D2D3]">
|
||||
Calling <span className="font-semibold text-[#F8F8F9]">Planneroo</span> to get started on
|
||||
your task on{" "}
|
||||
<code className="rounded bg-white/10 px-1.5 py-0.5 text-[12px] text-[#F8F8F9]">
|
||||
RooCodeInc/Roo-Code
|
||||
</code>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center rounded-md border border-white/10 bg-transparent px-2 py-1 text-[12px] font-medium text-[#D1D2D3] hover:bg-white/5">
|
||||
Cancel ✕
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m6",
|
||||
author: "Roomote",
|
||||
timeLabel: "Monday at 3:10 PM",
|
||||
avatarText: "R",
|
||||
avatarClassName: "bg-violet-500/20 text-violet-200 ring-1 ring-violet-500/30",
|
||||
kind: "bot",
|
||||
body: (
|
||||
<div className="space-x-2">
|
||||
<span>Cool, I'll knock this out real quick.</span>
|
||||
<FakeLink className="hover:text-violet-200">Follow along</FakeLink>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m7",
|
||||
author: "Roomote",
|
||||
timeLabel: "Monday at 3:12 PM",
|
||||
avatarText: "R",
|
||||
avatarClassName: "bg-violet-500/20 text-violet-200 ring-1 ring-violet-500/30",
|
||||
kind: "bot",
|
||||
body: (
|
||||
<div className="space-y-2">
|
||||
<div className="font-semibold text-[#F8F8F9]">Todo List:</div>
|
||||
<div className="rounded-lg border border-white/10 bg-black/20 px-3 py-2">
|
||||
<ul className="space-y-1">
|
||||
{[
|
||||
"Analyze existing page structures and component patterns",
|
||||
"Review marketing content requirements and wireframe details",
|
||||
"Create detailed component architecture plan",
|
||||
"Design page structure and section breakdown",
|
||||
"Plan navigation updates and integration points",
|
||||
"Test the page and verify all sections work",
|
||||
].map((item) => (
|
||||
<li key={item} className="text-[#D1D2D3]">
|
||||
<span className="mr-2">•</span>
|
||||
<span className="line-through opacity-80">{item}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="text-[12px] text-[#8B8D91]">(edited)</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m8",
|
||||
author: "Roomote",
|
||||
timeLabel: "Monday at 3:16 PM",
|
||||
avatarText: "R",
|
||||
avatarClassName: "bg-violet-500/20 text-violet-200 ring-1 ring-violet-500/30",
|
||||
kind: "bot",
|
||||
body: (
|
||||
<div className="space-y-3">
|
||||
<p>
|
||||
I've created a comprehensive implementation plan for the Roo Code Slack integration
|
||||
marketing page at{" "}
|
||||
<code className="rounded bg-white/10 px-1.5 py-0.5 text-[12px] text-[#F8F8F9]">
|
||||
plans/slack-marketing-page-plan.md
|
||||
</code>
|
||||
.
|
||||
</p>
|
||||
<div className="rounded-lg border border-white/10 bg-black/20 px-3 py-2">
|
||||
<div className="text-[12px] font-semibold text-[#F8F8F9]">Plan Overview</div>
|
||||
<ul className="mt-2 space-y-1 text-[#D1D2D3]">
|
||||
<li>
|
||||
<span className="mr-2">•</span>Hero + dual CTAs
|
||||
</li>
|
||||
<li>
|
||||
<span className="mr-2">•</span>Value props grid
|
||||
</li>
|
||||
<li>
|
||||
<span className="mr-2">•</span>“Thread to Shipped Feature” workflow
|
||||
</li>
|
||||
<li>
|
||||
<span className="mr-2">•</span>Onboarding steps + CTA
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="space-x-2">
|
||||
<span className="text-[#B8BBC0]">Full document:</span>
|
||||
<FakeLink className="hover:text-violet-200">View artifact</FakeLink>
|
||||
</div>
|
||||
<div className="text-[12px] italic text-[#8B8D91]">
|
||||
Want to follow up? Just @-mention me in your response.
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m9",
|
||||
author: "Avery Lee",
|
||||
timeLabel: "Monday at 3:17 PM",
|
||||
avatarText: "AL",
|
||||
avatarClassName: "bg-[#2B2D31] text-[#F8F8F9] ring-1 ring-white/10",
|
||||
kind: "human",
|
||||
body: (
|
||||
<div className="space-x-2">
|
||||
<FakeLink className="no-underline hover:text-violet-200">@Roomote</FakeLink>
|
||||
<span>this looks great, let's use Coderoo to build this</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "m10",
|
||||
author: "Roomote",
|
||||
timeLabel: "Monday at 3:23 PM",
|
||||
avatarText: "R",
|
||||
avatarClassName: "bg-violet-500/20 text-violet-200 ring-1 ring-violet-500/30",
|
||||
kind: "bot",
|
||||
body: (
|
||||
<div className="space-y-3">
|
||||
<p>
|
||||
I've built the Roo Code Slack integration marketing page. Here's what was
|
||||
implemented:
|
||||
</p>
|
||||
|
||||
<div className="rounded-lg border border-white/10 bg-black/20 px-3 py-2">
|
||||
<div className="text-[12px] font-semibold text-[#F8F8F9]">Files</div>
|
||||
<ul className="mt-2 space-y-1 text-[#D1D2D3]">
|
||||
<li>
|
||||
<span className="mr-2">•</span>
|
||||
<code className="rounded bg-white/10 px-1.5 py-0.5 text-[12px] text-[#F8F8F9]">
|
||||
apps/web-roo-code/src/app/slack/page.tsx
|
||||
</code>{" "}
|
||||
— Slack marketing page
|
||||
</li>
|
||||
<li>
|
||||
<span className="mr-2">•</span>
|
||||
<code className="rounded bg-white/10 px-1.5 py-0.5 text-[12px] text-[#F8F8F9]">
|
||||
apps/web-roo-code/src/lib/constants.ts
|
||||
</code>{" "}
|
||||
— added{" "}
|
||||
<code className="rounded bg-white/10 px-1.5 py-0.5 text-[12px] text-[#F8F8F9]">
|
||||
SLACK_DOCS
|
||||
</code>
|
||||
</li>
|
||||
<li>
|
||||
<span className="mr-2">•</span>
|
||||
<code className="rounded bg-white/10 px-1.5 py-0.5 text-[12px] text-[#F8F8F9]">
|
||||
apps/web-roo-code/src/components/chromes/nav-bar.tsx
|
||||
</code>{" "}
|
||||
— added Slack to Product dropdown
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="rounded-lg border border-white/10 bg-black/20 px-3 py-2">
|
||||
<div className="text-[12px] font-semibold text-[#F8F8F9]">Pull Request</div>
|
||||
<div className="mt-2">
|
||||
<span className="font-semibold text-[#F8F8F9]">PR #10853</span>:{" "}
|
||||
<FakeLink className="hover:text-violet-200">
|
||||
https://github.com/RooCodeInc/Roo-Code/pull/10853
|
||||
</FakeLink>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-[#B8BBC0]">
|
||||
The page is accessible at{" "}
|
||||
<code className="rounded bg-white/10 px-1.5 py-0.5 text-[12px] text-[#F8F8F9]">/slack</code>{" "}
|
||||
and includes navigation links in desktop and mobile.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
],
|
||||
[],
|
||||
)
|
||||
|
||||
type DemoPhase =
|
||||
| { kind: "show"; messageIndex: number }
|
||||
| { kind: "typing"; messageIndex: number }
|
||||
| { kind: "reset" }
|
||||
|
||||
const phases: DemoPhase[] = useMemo(() => {
|
||||
const next: DemoPhase[] = []
|
||||
if (messages.length === 0) return [{ kind: "reset" }]
|
||||
|
||||
next.push({ kind: "typing", messageIndex: 0 })
|
||||
next.push({ kind: "show", messageIndex: 0 })
|
||||
for (let messageIndex = 1; messageIndex < messages.length; messageIndex += 1) {
|
||||
next.push({ kind: "typing", messageIndex })
|
||||
next.push({ kind: "show", messageIndex })
|
||||
}
|
||||
next.push({ kind: "reset" })
|
||||
return next
|
||||
}, [messages])
|
||||
|
||||
const lastShowPhaseIndex = useMemo(() => {
|
||||
let lastIndex = -1
|
||||
for (let idx = 0; idx < phases.length; idx += 1) {
|
||||
if (phases[idx]?.kind === "show") lastIndex = idx
|
||||
}
|
||||
return lastIndex
|
||||
}, [phases])
|
||||
|
||||
useEffect(() => {
|
||||
if (reduceMotion) {
|
||||
setStepIndex(lastShowPhaseIndex >= 0 ? lastShowPhaseIndex : 0)
|
||||
return
|
||||
}
|
||||
|
||||
const active = phases[stepIndex] ?? phases.at(0)
|
||||
const isLastMessageShow = active?.kind === "show" && stepIndex === lastShowPhaseIndex
|
||||
const durationMs = (() => {
|
||||
const base = 2200
|
||||
if (active?.kind === "reset") return 500
|
||||
if (active?.kind === "typing") return 900
|
||||
return isLastMessageShow ? base * 2 : base
|
||||
})()
|
||||
|
||||
const timer = window.setTimeout(() => {
|
||||
setStepIndex((prev) => (prev + 1) % phases.length)
|
||||
}, durationMs)
|
||||
|
||||
return () => window.clearTimeout(timer)
|
||||
}, [lastShowPhaseIndex, phases, reduceMotion, stepIndex])
|
||||
|
||||
const activePhase = phases[stepIndex] ?? phases.at(0) ?? { kind: "reset" }
|
||||
|
||||
function getVisibleCount(phase: DemoPhase): number {
|
||||
if (phase.kind === "reset") return 0
|
||||
if (phase.kind === "typing") return phase.messageIndex
|
||||
return phase.messageIndex + 1
|
||||
}
|
||||
|
||||
const visibleCount = getVisibleCount(activePhase)
|
||||
const visibleMessages = messages.slice(0, visibleCount)
|
||||
const typingTarget = activePhase.kind === "typing" ? messages[activePhase.messageIndex] : undefined
|
||||
|
||||
useEffect(() => {
|
||||
const viewport = scrollViewportRef.current
|
||||
if (!viewport) return
|
||||
|
||||
if (activePhase.kind === "reset" || visibleCount <= 1) {
|
||||
viewport.scrollTo({ top: 0, behavior: "auto" })
|
||||
return
|
||||
}
|
||||
|
||||
viewport.scrollTo({
|
||||
top: viewport.scrollHeight,
|
||||
behavior: reduceMotion ? "auto" : "smooth",
|
||||
})
|
||||
}, [activePhase.kind, reduceMotion, visibleCount])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn("w-full max-w-[620px] h-[520px] sm:h-[560px]", className)}
|
||||
role="img"
|
||||
aria-label="Animated Slack thread showing Roo Code responding as @Roomote">
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="relative flex h-full flex-col overflow-hidden rounded-2xl border border-white/10 bg-[#1A1D21] shadow-2xl shadow-black/30">
|
||||
<div className="flex items-center justify-between border-b border-white/10 px-4 py-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#F24A4A]" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#F2C94C]" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#27AE60]" />
|
||||
<div className="ml-3 text-sm font-semibold text-[#F8F8F9]">Thread</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-[11px] text-[#8B8D91]">
|
||||
<span className="h-2 w-2 rounded-full bg-[#27AE60]" />
|
||||
Live demo
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
ref={scrollViewportRef}
|
||||
className="flex-1 overflow-y-auto px-4 py-5 [scrollbar-width:thin] [scrollbar-color:rgba(255,255,255,0.18)_transparent]">
|
||||
<div
|
||||
className={cn(
|
||||
"space-y-5 transition-opacity duration-300 will-change-opacity",
|
||||
activePhase.kind === "reset" ? "opacity-0" : "opacity-100",
|
||||
)}>
|
||||
{visibleMessages.map((message) => (
|
||||
<SlackMessageRow
|
||||
key={message.id}
|
||||
message={message}
|
||||
reduceMotion={reduceMotion}
|
||||
isNew={
|
||||
activePhase.kind === "show" && messages[activePhase.messageIndex]?.id === message.id
|
||||
}
|
||||
/>
|
||||
))}
|
||||
|
||||
{typingTarget && (
|
||||
<div className={cn(reduceMotion ? "" : "animate-in fade-in duration-300", "flex gap-3")}>
|
||||
<div
|
||||
className={cn(
|
||||
"mt-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-md text-xs font-semibold",
|
||||
typingTarget.avatarClassName,
|
||||
)}>
|
||||
{typingTarget.avatarText}
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-baseline gap-x-2">
|
||||
<span className="text-[13px] font-semibold text-[#F8F8F9]">
|
||||
{typingTarget.author}
|
||||
</span>
|
||||
{typingTarget.kind === "bot" && (
|
||||
<span className="inline-flex items-center gap-1 rounded-full bg-violet-500/20 px-2 py-0.5 text-[10px] font-medium text-violet-200">
|
||||
<CheckCircle2 className="h-3 w-3" />
|
||||
App
|
||||
</span>
|
||||
)}
|
||||
<span className="text-[11px] text-[#8B8D91]">typing…</span>
|
||||
</div>
|
||||
<div className="mt-2">
|
||||
<TypingDots />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between border-t border-white/10 px-4 py-3">
|
||||
<div className="flex items-center gap-1.5">
|
||||
{messages.map((message, idx) => (
|
||||
<span
|
||||
key={message.id}
|
||||
className={cn(
|
||||
"h-1.5 w-5 rounded-full transition-colors duration-300",
|
||||
Math.max(0, visibleCount - 1) === idx ? "bg-violet-300" : "bg-white/10",
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ export const EXTERNAL_LINKS = {
|
|||
BLUESKY: "https://bsky.app/profile/roocode.bsky.social",
|
||||
YOUTUBE: "https://www.youtube.com/@RooCodeYT",
|
||||
DOCUMENTATION: "https://docs.roocode.com",
|
||||
SLACK_DOCS: "https://docs.roocode.com/roo-code-cloud/slack-integration",
|
||||
CAREERS: "https://careers.roocode.com",
|
||||
ISSUES: "https://github.com/RooCodeInc/Roo-Code/issues",
|
||||
FEATURE_REQUESTS: "https://github.com/RooCodeInc/Roo-Code/discussions/categories/feature-requests",
|
||||
|
|
@ -28,6 +29,7 @@ export const EXTERNAL_LINKS = {
|
|||
CLOUD_APP_SIGNUP: "https://app.roocode.com/sign-up",
|
||||
CLOUD_APP_SIGNUP_HOME: "https://app.roocode.com/sign-up?redirect_url=/cloud-agents/setup",
|
||||
CLOUD_APP_SIGNUP_PRO: "https://app.roocode.com/sign-up?redirect_url=/cloud-agents/setup",
|
||||
CLOUD_APP_TEAM_TRIAL: "https://app.roocode.com/checkout/team",
|
||||
SUPPORT: "mailto:support@roocode.com",
|
||||
}
|
||||
|
||||
|
|
|
|||
10
locales/zh-TW/CODE_OF_CONDUCT.md
generated
10
locales/zh-TW/CODE_OF_CONDUCT.md
generated
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
## 我們的承諾
|
||||
|
||||
為了營造開放且友善的環境,我們身為貢獻者與維護者,承諾讓參與本專案及社群的體驗,對每個人都不帶有騷擾,不論其年齡、體型、身心障礙、族裔、性徵、性別認同與表現、經驗程度、教育程度、社經地位、國籍、個人外表、種族、宗教信仰、或性傾向。
|
||||
為了營造開放且友善的環境,我們身為貢獻者與維護者,承諾讓參與本專案及社群的體驗,對每個人都不帶有騷擾,不論其年齡、體型、身心障礙、族裔、性徵、性別認同與氣質、經驗程度、教育程度、社經地位、國籍、個人外表、種族、宗教信仰、或性傾向。
|
||||
|
||||
## 我們的準則
|
||||
|
||||
|
|
@ -32,14 +32,14 @@
|
|||
- 使用帶有性暗示的言語或影像,以及不受歡迎的性關注或騷擾
|
||||
- 挑釁、羞辱/貶低他人的評論,以及人身或政治攻擊
|
||||
- 公開或私下的騷擾行為
|
||||
- 未經他人明確許可,公開他人的私人資料,如實體或電子郵件地址
|
||||
- 未經他人明確許可,公開他人的私人資訊,如實體地址或電子郵件信箱
|
||||
- 其他在專業環境中可被合理認定為不恰當的行為
|
||||
|
||||
## 我們的責任
|
||||
|
||||
專案維護者有責任釐清可接受行為的標準,並應對任何不可接受的行為採取適當且公平的糾正措施。
|
||||
專案維護者有責任釐清可接受行為的標準,並應對任何不可接受的行為採取適當且公平的處置措施。
|
||||
|
||||
專案維護者有權利和責任移除、編輯或拒絕不符合本行為準則的評論、提交、程式碼、維基編輯、議題和其他貢獻,或暫時或永久封鎖任何他們認為有不當、威脅、冒犯或有害行為的貢獻者。
|
||||
專案維護者有權利和責任移除、編輯或拒絕不符合本行為準則的留言、Commit、程式碼、Wiki 編輯、Issue 和其他貢獻,或暫時或永久封鎖任何他們認為有不當、威脅、冒犯或有害行為的貢獻者。
|
||||
|
||||
## 範疇
|
||||
|
||||
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
如發生辱罵、騷擾或其他不可接受的行為,請透過 support@roocode.com 聯絡專案團隊回報。所有申訴都將被審查和調查,並做出必要且合適的回應。專案團隊有義務為事件回報者保密。具體執行政策的更多細節可能另行公佈。
|
||||
|
||||
未遵守或未切實執行本行為準則的專案維護者,可能會面臨由專案領導團隊其他成員所決定的暫時或永久的處置。
|
||||
未遵守或未切實執行本行為準則的專案維護者,可能會面臨由專案領導團隊其他成員所決定的暫時或永久處分。
|
||||
|
||||
## 來源說明
|
||||
|
||||
|
|
|
|||
92
locales/zh-TW/CONTRIBUTING.md
generated
92
locales/zh-TW/CONTRIBUTING.md
generated
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
# 為 Roo Code 做出貢獻
|
||||
|
||||
Roo Code 是一個由社群驅動的專案,我們非常重視每一份貢獻。為了簡化協作,我們採用 [「問題優先」的方法](#問題優先方法),這意味著所有的 [拉取請求 (PR)](#提交拉取請求) 都必須先連結到一個 GitHub 問題。請仔細閱讀本指南。
|
||||
Roo Code 是一個由社群驅動的專案,我們非常重視每一份貢獻。為了簡化協作流程,我們採用 [「Issue 優先」的方法](#issue-優先方法),這意味著所有的 [Pull Request (PR)](#提交-pull-request) 都必須先連結到一個 GitHub Issue。請仔細閱讀本指南。
|
||||
|
||||
## 目錄
|
||||
|
||||
|
|
@ -30,32 +30,32 @@ Roo Code 是一個由社群驅動的專案,我們非常重視每一份貢獻
|
|||
|
||||
### 2. 專案路線圖
|
||||
|
||||
我們的路線圖指導著專案的方向。請將您的貢獻與這些關鍵目標保持一致:
|
||||
我們的路線圖指引著專案的方向。請將您的貢獻與這些關鍵目標保持一致:
|
||||
|
||||
### 可靠性第一
|
||||
### 可靠性第一 (Reliability First)
|
||||
|
||||
- 確保差異編輯和命令執行始終可靠。
|
||||
- 減少阻礙常規使用的摩擦點。
|
||||
- 保證在所有地區和平台上的流暢操作。
|
||||
- 擴大對各種人工智慧提供商和模型的強大支援。
|
||||
- 減少阻礙常規使用的摩擦。
|
||||
- 保證在所有語系和平台上的操作流暢。
|
||||
- 擴大對各種 AI 供應商和模型的強大支援。
|
||||
|
||||
### 增強的使用者體驗
|
||||
### 增強的使用者體驗 (Enhanced User Experience)
|
||||
|
||||
- 簡化使用者介面/使用者體驗,以提高清晰度和直觀性。
|
||||
- 不斷改進工作流程,以滿足開發人員對日常使用工具的高期望。
|
||||
- 簡化 UI/UX,提高清晰度和直覺性。
|
||||
- 持續改進工作流程,以滿足開發者對日常使用工具的高期望。
|
||||
|
||||
### 在代理效能上領先
|
||||
### 在 Agent 效能上領先 (Leading on Agent Performance)
|
||||
|
||||
- 建立全面的評估基準 (evals) 來衡量真實世界的生產力。
|
||||
- 讓每個人都能輕鬆執行和解釋這些評估。
|
||||
- 發布能顯示評估分數明顯提高的改進。
|
||||
- 建立全面的評估基準 (Evals) 來衡量實際應用的生產力。
|
||||
- 讓每個人都能輕鬆執行和解讀這些評估結果。
|
||||
- 發布能顯示評估分數有明顯提升的改進。
|
||||
|
||||
在您的 PR 中提及與這些領域的一致性。
|
||||
|
||||
### 3. 加入 Roo Code 社群
|
||||
|
||||
- **主要方式:** 加入我們的 [Discord](https://discord.gg/roocode) 並私訊 **Hannes Rudolph (`hrudolph`)**。
|
||||
- **替代方式:** 經驗豐富的貢獻者可以透過 [GitHub 專案](https://github.com/orgs/RooCodeInc/projects/1) 直接參與。
|
||||
- **替代方式:** 經驗豐富的貢獻者可以透過 [GitHub Project](https://github.com/orgs/RooCodeInc/projects/1) 直接參與。
|
||||
|
||||
## 尋找和規劃您的貢獻
|
||||
|
||||
|
|
@ -65,42 +65,42 @@ Roo Code 是一個由社群驅動的專案,我們非常重視每一份貢獻
|
|||
- **新功能:** 新增功能。
|
||||
- **文件:** 改進指南和清晰度。
|
||||
|
||||
### 問題優先方法
|
||||
### Issue 優先方法
|
||||
|
||||
所有貢獻都始於使用我們精簡範本的 GitHub 問題。
|
||||
所有貢獻都始於使用我們精簡範本的 GitHub Issue。
|
||||
|
||||
- **檢查現有問題**:在 [GitHub 問題](https://github.com/RooCodeInc/Roo-Code/issues) 中搜尋。
|
||||
- **使用以下範本建立問題**:
|
||||
- **增強功能:** 「增強請求」範本(著重於使用者利益的簡單語言)。
|
||||
- **錯誤:** 「錯誤報告」範本(最少的重現步驟 + 預期與實際 + 版本)。
|
||||
- **想參與其中嗎?** 在問題上評論“領取”,並在[Discord](https://discord.gg/roocode)上私訊 **Hannes Rudolph (`hrudolph`)** 以獲得分配。分配將在帖子中確認。
|
||||
- **PR 必須連結到問題。** 未連結的 PR 可能會被關閉。
|
||||
- **檢查現有 Issue**:在 [GitHub Issues](https://github.com/RooCodeInc/Roo-Code/issues) 中搜尋。
|
||||
- **使用以下範本建立 Issue**:
|
||||
- **增強功能:** 「Enhancement Request」範本(著重於使用者利益的淺顯描述)。
|
||||
- **錯誤** 「Bug Report」範本(最少的重現步驟 + 預期與實際結果 + 版本)。
|
||||
- **想參與其中嗎?** 在 Issue 上留言「Claiming」,並在 [Discord](https://discord.gg/roocode) 上私訊 **Hannes Rudolph (`hrudolph`)** 以獲得分配。分配結果將在討論串中確認。
|
||||
- **PR 必須連結到 Issue。** 未連結的 PR 可能會被關閉。
|
||||
|
||||
### 決定做什麼
|
||||
|
||||
- 查看 [GitHub 專案](https://github.com/orgs/RooCodeInc/projects/1) 中的「問題 [未分配]」問題。
|
||||
- 如需文件,請造訪 [Roo Code 文件](https://github.com/RooCodeInc/Roo-Code-Docs)。
|
||||
- 查看 [GitHub 專案](https://github.com/orgs/RooCodeInc/projects/1) 中的「Issue [Unassigned]」。
|
||||
- 如需文件,請造訪 [Roo Code Docs](https://github.com/RooCodeInc/Roo-Code-Docs)。
|
||||
|
||||
### 報告錯誤
|
||||
### 回報錯誤
|
||||
|
||||
- 首先檢查現有的報告。
|
||||
- 使用 [「錯誤報告」範本](https://github.com/RooCodeInc/Roo-Code/issues/new/choose) 建立一個新錯誤,並提供:
|
||||
- 使用 [「Bug Report」範本](https://github.com/RooCodeInc/Roo-Code/issues/new/choose) 建立一個新的錯誤回報,並提供:
|
||||
- 清晰、編號的重現步驟
|
||||
- 預期與實際結果
|
||||
- Roo Code 版本(必需);如果相關,還需提供 API 提供商/模型
|
||||
- **安全問題**:透過 [安全公告](https://github.com/RooCodeInc/Roo-Code/security/advisories/new) 私下報告。
|
||||
- Roo Code 版本(必填);如果相關,還需提供 API 供應商/模型
|
||||
- **安全問題**:透過 [安全公告 (Security Advisories)](https://github.com/RooCodeInc/Roo-Code/security/advisories/new) 私下回報。
|
||||
|
||||
## 開發和提交流程
|
||||
|
||||
### 開發設定
|
||||
|
||||
1. **複製和克隆:**
|
||||
1. **Fork 與 Clone:**
|
||||
|
||||
```
|
||||
git clone https://github.com/您的使用者名稱/Roo-Code.git
|
||||
git clone https://github.com/YOUR_USERNAME/Roo-Code.git
|
||||
```
|
||||
|
||||
2. **安裝依賴項:**
|
||||
2. **安裝相依套件:**
|
||||
|
||||
```
|
||||
pnpm install
|
||||
|
|
@ -108,34 +108,34 @@ pnpm install
|
|||
|
||||
3. **偵錯:** 使用 VS Code 開啟(`F5`)。
|
||||
|
||||
### 編碼指南
|
||||
### 程式碼撰寫指南
|
||||
|
||||
- 每個功能或修復一個集中的 PR。
|
||||
- 遵循 ESLint 和 TypeScript 的最佳實踐。
|
||||
- 編寫清晰、描述性的提交,並引用問題(例如,`修復 #123`)。
|
||||
- 每個功能或修復使用一個單一目的的 PR。
|
||||
- 遵循 ESLint 和 TypeScript 的最佳實務。
|
||||
- 撰寫清晰、描述性的 Commit 訊息,並引用 Issue(例如,`Fixes #123`)。
|
||||
- 提供全面的測試(`npm test`)。
|
||||
- 在提交前變基到最新的 `main` 分支。
|
||||
- 在提交前 Rebase 到最新的 `main` 分支。
|
||||
|
||||
### 提交拉取請求
|
||||
### 提交 Pull Request
|
||||
|
||||
- 如果希望獲得早期回饋,請以 **草稿 PR** 開始。
|
||||
- 遵循拉取請求範本,清晰地描述您的變更。
|
||||
- 在 PR 描述/標題中連結問題(例如,“修復 #123”)。
|
||||
- 如果希望獲得早期回饋,請以 **Draft PR** 開始。
|
||||
- 遵循 Pull Request 範本,清晰地描述您的變更。
|
||||
- 在 PR 描述/標題中連結 Issue(例如,「Fixes #123」)。
|
||||
- 為使用者介面變更提供螢幕截圖/影片。
|
||||
- 指明是否需要更新文件。
|
||||
|
||||
### 拉取請求政策
|
||||
### Pull Request 政策
|
||||
|
||||
- 必須引用一個已分配的 GitHub 問題。要獲得分配:在問題上評論“領取”,並在[Discord](https://discord.gg/roocode)上私訊 **Hannes Rudolph (`hrudolph`)**。分配將在帖子中確認。
|
||||
- 未連結的 PR 可能會被關閉。
|
||||
- 必須引用一個已指派的 GitHub Issue。如要被指派:請在 Issue 上留言「Claiming」,並在 [Discord](https://discord.gg/roocode) 上私訊 **Hannes Rudolph (`hrudolph`)**。指派結果將可在討論串中確認。
|
||||
- 未連結 Issue 的 PR 可能會被關閉。
|
||||
- PR 必須通過 CI 測試,與路線圖保持一致,並有清晰的文件。
|
||||
|
||||
### 審查流程
|
||||
|
||||
- **每日分類:** 維護人員進行快速檢查。
|
||||
- **每日 Triage:** 維護者進行快速檢查。
|
||||
- **每週深入審查:** 全面評估。
|
||||
- **根據回饋及時迭代**。
|
||||
|
||||
## 法律
|
||||
## 法律資訊
|
||||
|
||||
透過貢獻,您同意您的貢獻將根據 Apache 2.0 授權進行授權,這與 Roo Code 的授權一致。
|
||||
透過貢獻,您同意您的貢獻將根據 Apache 2.0 授權條款進行授權,這與 Roo Code 的授權一致。
|
||||
|
|
|
|||
32
locales/zh-TW/README.md
generated
32
locales/zh-TW/README.md
generated
|
|
@ -6,15 +6,15 @@
|
|||
<a href="https://www.reddit.com/r/RooCode/"><img src="https://img.shields.io/badge/Join%20r%2FRooCode-FF4500?style=flat&logo=reddit&logoColor=white" alt="Join r/RooCode"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>快速取得協助 → <a href="https://discord.gg/roocode">加入 Discord</a> • 偏好非同步?→ <a href="https://www.reddit.com/r/RooCode/">加入 r/RooCode</a></em>
|
||||
<em>快速取得協助 → <a href="https://discord.gg/roocode">加入 Discord</a> • 偏好非同步溝通?→ <a href="https://www.reddit.com/r/RooCode/">加入 r/RooCode</a></em>
|
||||
</p>
|
||||
|
||||
# Roo Code
|
||||
|
||||
> 你的 AI 驅動開發團隊,就在你的編輯器裡
|
||||
> 您的 AI 驅動開發團隊,就在您的編輯器中
|
||||
|
||||
<details>
|
||||
<summary>🌐 可用語言</summary>
|
||||
<summary>🌐 支援語言</summary>
|
||||
|
||||
- [English](../../README.md)
|
||||
- [Català](../ca/README.md)
|
||||
|
|
@ -51,14 +51,14 @@
|
|||
|
||||
## 模式
|
||||
|
||||
Roo Code 適應您的工作方式,而不是相反:
|
||||
Roo Code 會配合您的工作方式,而非要您配合它:
|
||||
|
||||
- 程式碼模式:日常編碼、編輯和檔案操作
|
||||
- 程式碼模式:日常開發、編輯和檔案操作
|
||||
- 架構師模式:規劃系統、規格和遷移
|
||||
- 詢問模式:快速回答、解釋和文件
|
||||
- 偵錯模式:追蹤問題、新增日誌、隔離根本原因
|
||||
- 偵錯模式:追蹤問題、新增日誌、鎖定根本原因
|
||||
- 自訂模式:為您的團隊或工作流程建置專門的模式
|
||||
- Roomote Control:Roomote Control 讓你能遠端控制在本機 VS Code 執行個體中運行的工作。
|
||||
- Roomote Control:Roomote Control 讓您能遠端控制在本機 VS Code 執行個體中運行的工作。
|
||||
|
||||
更多資訊:[使用模式](https://docs.roocode.com/basic-usage/using-modes) • [自訂模式](https://docs.roocode.com/advanced-usage/custom-modes) • [Roomote Control](https://docs.roocode.com/roo-code-cloud/roomote-control)
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ Roo Code 適應您的工作方式,而不是相反:
|
|||
| | | |
|
||||
| :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|
||||
| <a href="https://www.youtube.com/watch?v=Mcq3r1EPZ-4"><img src="https://img.youtube.com/vi/Mcq3r1EPZ-4/maxresdefault.jpg" width="100%"></a><br><b>安裝 Roo Code</b> | <a href="https://www.youtube.com/watch?v=ZBML8h5cCgo"><img src="https://img.youtube.com/vi/ZBML8h5cCgo/maxresdefault.jpg" width="100%"></a><br><b>設定設定檔</b> | <a href="https://www.youtube.com/watch?v=r1bpod1VWhg"><img src="https://img.youtube.com/vi/r1bpod1VWhg/maxresdefault.jpg" width="100%"></a><br><b>程式碼庫索引</b> |
|
||||
| <a href="https://www.youtube.com/watch?v=iiAv1eKOaxk"><img src="https://img.youtube.com/vi/iiAv1eKOaxk/maxresdefault.jpg" width="100%"></a><br><b>自訂模式</b> | <a href="https://www.youtube.com/watch?v=Ho30nyY332E"><img src="https://img.youtube.com/vi/Ho30nyY332E/maxresdefault.jpg" width="100%"></a><br><b>檢查點</b> | <a href="https://www.youtube.com/watch?v=HmnNSasv7T8"><img src="https://img.youtube.com/vi/HmnNSasv7T8/maxresdefault.jpg" width="100%"></a><br><b>上下文管理</b> |
|
||||
| <a href="https://www.youtube.com/watch?v=iiAv1eKOaxk"><img src="https://img.youtube.com/vi/iiAv1eKOaxk/maxresdefault.jpg" width="100%"></a><br><b>自訂模式</b> | <a href="https://www.youtube.com/watch?v=Ho30nyY332E"><img src="https://img.youtube.com/vi/Ho30nyY332E/maxresdefault.jpg" width="100%"></a><br><b>檢查點</b> | <a href="https://www.youtube.com/watch?v=HmnNSasv7T8"><img src="https://img.youtube.com/vi/HmnNSasv7T8/maxresdefault.jpg" width="100%"></a><br><b>上下文管理</b> |
|
||||
|
||||
</div>
|
||||
<p align="center">
|
||||
|
|
@ -82,12 +82,12 @@ Roo Code 適應您的工作方式,而不是相反:
|
|||
- **[YouTube 頻道](https://youtube.com/@roocodeyt?feature=shared):** 觀看教學和功能實際操作。
|
||||
- **[Discord 伺服器](https://discord.gg/roocode):** 加入社群以獲得即時協助和討論。
|
||||
- **[Reddit 社群](https://www.reddit.com/r/RooCode):** 分享您的經驗,看看其他人正在建立什麼。
|
||||
- **[GitHub 問題](https://github.com/RooCodeInc/Roo-Code/issues):** 回報錯誤並追蹤開發進度。
|
||||
- **[GitHub Issues](https://github.com/RooCodeInc/Roo-Code/issues):** 回報問題並追蹤開發進度。
|
||||
- **[功能請求](https://github.com/RooCodeInc/Roo-Code/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+Requests%22+sort%3Atop):** 有想法嗎?與開發人員分享。
|
||||
|
||||
---
|
||||
|
||||
## 本地設定與開發
|
||||
## 本機設定與開發
|
||||
|
||||
1. **複製**儲存庫:
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ Roo Code 適應您的工作方式,而不是相反:
|
|||
git clone https://github.com/RooCodeInc/Roo-Code.git
|
||||
```
|
||||
|
||||
2. **安裝依賴套件**:
|
||||
2. **安裝相依套件**:
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
|
|
@ -107,7 +107,7 @@ pnpm install
|
|||
|
||||
### 開發模式(F5)
|
||||
|
||||
對於積極的開發,請使用 VSCode 的內建偵錯功能:
|
||||
若要進行開發,請使用 VSCode 的內建偵錯功能:
|
||||
|
||||
在 VSCode 中按 `F5`(或前往 **執行** → **開始偵錯**)。這將在執行 Roo Code 擴充功能的新 VSCode 視窗中開啟。
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ pnpm install:vsix [-y] [--editor=<command>]
|
|||
- 詢問要使用的編輯器命令(code/cursor/code-insiders) - 預設為“code”
|
||||
- 解除安裝任何現有版本的擴充功能。
|
||||
- 建置最新的 VSIX 套件。
|
||||
- 安裝新建立的 VSIX。
|
||||
- 安裝新建置的 VSIX。
|
||||
- 提示您重新啟動 VS Code 以使變更生效。
|
||||
|
||||
選項:
|
||||
|
|
@ -144,7 +144,7 @@ pnpm install:vsix [-y] [--editor=<command>]
|
|||
pnpm vsix
|
||||
```
|
||||
2. 將在 `bin/` 目錄中產生一個 `.vsix` 檔案(例如 `bin/roo-cline-<version>.vsix`)。
|
||||
3. 使用 VSCode CLI 手動安裝
|
||||
3. 使用 VSCode CLI 手動安裝:
|
||||
```sh
|
||||
code --install-extension bin/roo-cline-<version>.vsix
|
||||
```
|
||||
|
|
@ -163,7 +163,7 @@ pnpm install:vsix [-y] [--editor=<command>]
|
|||
|
||||
## 貢獻
|
||||
|
||||
我們歡迎社群貢獻!請閱讀我們的 [CONTRIBUTING.md](CONTRIBUTING.md) 開始。
|
||||
我們歡迎社群貢獻!請從閱讀我們的 [CONTRIBUTING.md](CONTRIBUTING.md) 開始。
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -173,4 +173,4 @@ pnpm install:vsix [-y] [--editor=<command>]
|
|||
|
||||
---
|
||||
|
||||
**享受 Roo Code!** 無論您是將它拴在短繩上還是讓它自主漫遊,我們迫不及待地想看看您會建構什麼。如果您有問題或功能想法,請造訪我們的 [Reddit 社群](https://www.reddit.com/r/RooCode/)或 [Discord](https://discord.gg/roocode)。祝您開發愉快!
|
||||
**享受 Roo Code!** 無論您是想嚴格控管它,還是讓它自主運作,我們都迫不及待地想看看您會打造些什麼。如果您有問題或功能想法,請造訪我們的 [Reddit 社群](https://www.reddit.com/r/RooCode/)或 [Discord](https://discord.gg/roocode)。祝您開發愉快!
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
"vsix: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",
|
||||
"install:vsix": "pnpm install --frozen-lockfile && pnpm clean && pnpm vsix && node scripts/install-vsix.js",
|
||||
"install:vsix:nightly": "pnpm install --frozen-lockfile && pnpm clean && pnpm vsix:nightly && node scripts/install-vsix.js --nightly",
|
||||
"changeset:version": "cp CHANGELOG.md src/CHANGELOG.md && changeset version && cp -vf src/CHANGELOG.md .",
|
||||
"knip": "knip --include files",
|
||||
"evals": "dotenvx run -f packages/evals/.env.development packages/evals/.env.local -- docker compose -f packages/evals/docker-compose.yml --profile server --profile runner up --build --scale runner=0",
|
||||
|
|
@ -65,7 +66,8 @@
|
|||
"bluebird": ">=3.7.2",
|
||||
"glob": ">=11.1.0",
|
||||
"@types/react": "^18.3.23",
|
||||
"@types/react-dom": "^18.3.5"
|
||||
"@types/react-dom": "^18.3.5",
|
||||
"zod": "3.25.76"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"@roo-code/types": "workspace:^",
|
||||
"esbuild": "^0.25.0",
|
||||
"execa": "^9.5.2",
|
||||
"ignore": "^7.0.3",
|
||||
"openai": "^5.12.2",
|
||||
"zod": "^3.25.61"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,129 +0,0 @@
|
|||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`XML Protocol snapshots > should generate correct XML description for all fixtures combined 1`] = `
|
||||
"# Custom Tools
|
||||
|
||||
The following custom tools are available for this mode. Use them in the same way as built-in tools.
|
||||
|
||||
## simple
|
||||
Description: Simple tool
|
||||
Parameters:
|
||||
- value: (required) The input value (type: string)
|
||||
Usage:
|
||||
<simple>
|
||||
<value>value value here</value>
|
||||
</simple>
|
||||
|
||||
## cached
|
||||
Description: Cached tool
|
||||
Parameters:
|
||||
Usage:
|
||||
<cached>
|
||||
</cached>
|
||||
|
||||
## legacy
|
||||
Description: Legacy tool using args
|
||||
Parameters:
|
||||
- input: (required) The input string (type: string)
|
||||
Usage:
|
||||
<legacy>
|
||||
<input>input value here</input>
|
||||
</legacy>
|
||||
|
||||
## multi_toolA
|
||||
Description: Tool A
|
||||
Parameters:
|
||||
Usage:
|
||||
<multi_toolA>
|
||||
</multi_toolA>
|
||||
|
||||
## multi_toolB
|
||||
Description: Tool B
|
||||
Parameters:
|
||||
Usage:
|
||||
<multi_toolB>
|
||||
</multi_toolB>
|
||||
|
||||
## mixed_validTool
|
||||
Description: Valid
|
||||
Parameters:
|
||||
Usage:
|
||||
<mixed_validTool>
|
||||
</mixed_validTool>"
|
||||
`;
|
||||
|
||||
exports[`XML Protocol snapshots > should generate correct XML description for cached tool 1`] = `
|
||||
"# Custom Tools
|
||||
|
||||
The following custom tools are available for this mode. Use them in the same way as built-in tools.
|
||||
|
||||
## cached
|
||||
Description: Cached tool
|
||||
Parameters:
|
||||
Usage:
|
||||
<cached>
|
||||
</cached>"
|
||||
`;
|
||||
|
||||
exports[`XML Protocol snapshots > should generate correct XML description for legacy tool (using args) 1`] = `
|
||||
"# Custom Tools
|
||||
|
||||
The following custom tools are available for this mode. Use them in the same way as built-in tools.
|
||||
|
||||
## legacy
|
||||
Description: Legacy tool using args
|
||||
Parameters:
|
||||
- input: (required) The input string (type: string)
|
||||
Usage:
|
||||
<legacy>
|
||||
<input>input value here</input>
|
||||
</legacy>"
|
||||
`;
|
||||
|
||||
exports[`XML Protocol snapshots > should generate correct XML description for mixed export tool 1`] = `
|
||||
"# Custom Tools
|
||||
|
||||
The following custom tools are available for this mode. Use them in the same way as built-in tools.
|
||||
|
||||
## mixed_validTool
|
||||
Description: Valid
|
||||
Parameters:
|
||||
Usage:
|
||||
<mixed_validTool>
|
||||
</mixed_validTool>"
|
||||
`;
|
||||
|
||||
exports[`XML Protocol snapshots > should generate correct XML description for multi export tools 1`] = `
|
||||
"# Custom Tools
|
||||
|
||||
The following custom tools are available for this mode. Use them in the same way as built-in tools.
|
||||
|
||||
## multi_toolA
|
||||
Description: Tool A
|
||||
Parameters:
|
||||
Usage:
|
||||
<multi_toolA>
|
||||
</multi_toolA>
|
||||
|
||||
## multi_toolB
|
||||
Description: Tool B
|
||||
Parameters:
|
||||
Usage:
|
||||
<multi_toolB>
|
||||
</multi_toolB>"
|
||||
`;
|
||||
|
||||
exports[`XML Protocol snapshots > should generate correct XML description for simple tool 1`] = `
|
||||
"# Custom Tools
|
||||
|
||||
The following custom tools are available for this mode. Use them in the same way as built-in tools.
|
||||
|
||||
## simple
|
||||
Description: Simple tool
|
||||
Parameters:
|
||||
- value: (required) The input value (type: string)
|
||||
Usage:
|
||||
<simple>
|
||||
<value>value value here</value>
|
||||
</simple>"
|
||||
`;
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
// pnpm --filter @roo-code/core test src/custom-tools/__tests__/format-xml.spec.ts
|
||||
|
||||
import { type SerializedCustomToolDefinition, parametersSchema as z, defineCustomTool } from "@roo-code/types"
|
||||
|
||||
import { serializeCustomTool, serializeCustomTools } from "../serialize.js"
|
||||
import { formatXml } from "../format-xml.js"
|
||||
|
||||
import simpleTool from "./fixtures/simple.js"
|
||||
import cachedTool from "./fixtures/cached.js"
|
||||
import legacyTool from "./fixtures/legacy.js"
|
||||
import { toolA, toolB } from "./fixtures/multi.js"
|
||||
import { validTool as mixedValidTool } from "./fixtures/mixed.js"
|
||||
|
||||
const fixtureTools = {
|
||||
simple: simpleTool,
|
||||
cached: cachedTool,
|
||||
legacy: legacyTool,
|
||||
multi_toolA: toolA,
|
||||
multi_toolB: toolB,
|
||||
mixed_validTool: mixedValidTool,
|
||||
}
|
||||
|
||||
describe("formatXml", () => {
|
||||
it("should return empty string for empty tools array", () => {
|
||||
expect(formatXml([])).toBe("")
|
||||
})
|
||||
|
||||
it("should throw for undefined tools", () => {
|
||||
expect(() => formatXml(undefined as unknown as SerializedCustomToolDefinition[])).toThrow()
|
||||
})
|
||||
|
||||
it("should generate description for a single tool without args", () => {
|
||||
const tool = defineCustomTool({
|
||||
name: "my_tool",
|
||||
description: "A simple tool that does something",
|
||||
async execute() {
|
||||
return "done"
|
||||
},
|
||||
})
|
||||
|
||||
const serialized = serializeCustomTool(tool)
|
||||
const result = formatXml([serialized])
|
||||
|
||||
expect(result).toContain("# Custom Tools")
|
||||
expect(result).toContain("## my_tool")
|
||||
expect(result).toContain("Description: A simple tool that does something")
|
||||
expect(result).toContain("Parameters: None")
|
||||
expect(result).toContain("<my_tool>")
|
||||
expect(result).toContain("</my_tool>")
|
||||
})
|
||||
|
||||
it("should generate description for a tool with required args", () => {
|
||||
const tool = defineCustomTool({
|
||||
name: "greeter",
|
||||
description: "Greets a person by name",
|
||||
parameters: z.object({
|
||||
name: z.string().describe("The name of the person to greet"),
|
||||
}),
|
||||
async execute({ name }) {
|
||||
return `Hello, ${name}!`
|
||||
},
|
||||
})
|
||||
|
||||
const serialized = serializeCustomTool(tool)
|
||||
const result = formatXml([serialized])
|
||||
|
||||
expect(result).toContain("## greeter")
|
||||
expect(result).toContain("Description: Greets a person by name")
|
||||
expect(result).toContain("Parameters:")
|
||||
expect(result).toContain("- name: (required) The name of the person to greet (type: string)")
|
||||
expect(result).toContain("<greeter>")
|
||||
expect(result).toContain("<name>name value here</name>")
|
||||
expect(result).toContain("</greeter>")
|
||||
})
|
||||
|
||||
it("should generate description for a tool with optional args", () => {
|
||||
const tool = defineCustomTool({
|
||||
name: "configurable_tool",
|
||||
description: "A tool with optional configuration",
|
||||
parameters: z.object({
|
||||
input: z.string().describe("The input to process"),
|
||||
format: z.string().optional().describe("Output format"),
|
||||
}),
|
||||
async execute({ input, format }) {
|
||||
return format ? `${input} (${format})` : input
|
||||
},
|
||||
})
|
||||
|
||||
const serialized = serializeCustomTool(tool)
|
||||
const result = formatXml([serialized])
|
||||
|
||||
expect(result).toContain("- input: (required) The input to process (type: string)")
|
||||
expect(result).toContain("- format: (optional) Output format (type: string)")
|
||||
expect(result).toContain("<input>input value here</input>")
|
||||
expect(result).toContain("<format>optional format value</format>")
|
||||
})
|
||||
|
||||
it("should generate descriptions for multiple tools", () => {
|
||||
const tools = [
|
||||
defineCustomTool({
|
||||
name: "tool_a",
|
||||
description: "First tool",
|
||||
async execute() {
|
||||
return "a"
|
||||
},
|
||||
}),
|
||||
defineCustomTool({
|
||||
name: "tool_b",
|
||||
description: "Second tool",
|
||||
parameters: z.object({
|
||||
value: z.number().describe("A numeric value"),
|
||||
}),
|
||||
async execute() {
|
||||
return "b"
|
||||
},
|
||||
}),
|
||||
]
|
||||
|
||||
const serialized = serializeCustomTools(tools)
|
||||
const result = formatXml(serialized)
|
||||
|
||||
expect(result).toContain("## tool_a")
|
||||
expect(result).toContain("Description: First tool")
|
||||
expect(result).toContain("## tool_b")
|
||||
expect(result).toContain("Description: Second tool")
|
||||
expect(result).toContain("- value: (required) A numeric value (type: number)")
|
||||
})
|
||||
|
||||
it("should treat args in required array as required", () => {
|
||||
// Using a raw SerializedToolDefinition to test the required behavior.
|
||||
const tools: SerializedCustomToolDefinition[] = [
|
||||
{
|
||||
name: "test_tool",
|
||||
description: "Test tool",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
data: {
|
||||
type: "object",
|
||||
description: "Some data",
|
||||
},
|
||||
},
|
||||
required: ["data"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const result = formatXml(tools)
|
||||
|
||||
expect(result).toContain("- data: (required) Some data (type: object)")
|
||||
expect(result).toContain("<data>data value here</data>")
|
||||
})
|
||||
})
|
||||
|
||||
describe("XML Protocol snapshots", () => {
|
||||
it("should generate correct XML description for simple tool", () => {
|
||||
const serialized = serializeCustomTool(fixtureTools.simple)
|
||||
const result = formatXml([serialized])
|
||||
expect(result).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it("should generate correct XML description for cached tool", () => {
|
||||
const serialized = serializeCustomTool(fixtureTools.cached)
|
||||
const result = formatXml([serialized])
|
||||
expect(result).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it("should generate correct XML description for legacy tool (using args)", () => {
|
||||
const serialized = serializeCustomTool(fixtureTools.legacy)
|
||||
const result = formatXml([serialized])
|
||||
expect(result).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it("should generate correct XML description for multi export tools", () => {
|
||||
const serializedA = serializeCustomTool(fixtureTools.multi_toolA)
|
||||
const serializedB = serializeCustomTool(fixtureTools.multi_toolB)
|
||||
const result = formatXml([serializedA, serializedB])
|
||||
expect(result).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it("should generate correct XML description for mixed export tool", () => {
|
||||
const serialized = serializeCustomTool(fixtureTools.mixed_validTool)
|
||||
const result = formatXml([serialized])
|
||||
expect(result).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it("should generate correct XML description for all fixtures combined", () => {
|
||||
const allSerialized = Object.values(fixtureTools).map(serializeCustomTool)
|
||||
const result = formatXml(allSerialized)
|
||||
expect(result).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
import type { SerializedCustomToolDefinition, SerializedCustomToolParameters } from "@roo-code/types"
|
||||
|
||||
/**
|
||||
* Extract the type string from a parameter schema.
|
||||
* Handles both direct `type` property and `anyOf` schemas (used for nullable types).
|
||||
*/
|
||||
function getParameterType(parameter: SerializedCustomToolParameters): string {
|
||||
// Direct type property
|
||||
if (parameter.type) {
|
||||
return String(parameter.type)
|
||||
}
|
||||
|
||||
// Handle anyOf schema (used for nullable types like `string | null`)
|
||||
if (parameter.anyOf && Array.isArray(parameter.anyOf)) {
|
||||
const types = parameter.anyOf
|
||||
.map((schema) => (typeof schema === "object" && schema.type ? String(schema.type) : null))
|
||||
.filter((t): t is string => t !== null && t !== "null")
|
||||
|
||||
if (types.length > 0) {
|
||||
return types.join(" | ")
|
||||
}
|
||||
}
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
function getParameterDescription(name: string, parameter: SerializedCustomToolParameters, required: string[]): string {
|
||||
const requiredText = required.includes(name) ? "(required)" : "(optional)"
|
||||
const typeText = getParameterType(parameter)
|
||||
return `- ${name}: ${requiredText} ${parameter.description ?? ""} (type: ${typeText})`
|
||||
}
|
||||
|
||||
function getUsage(tool: SerializedCustomToolDefinition): string {
|
||||
const lines: string[] = [`<${tool.name}>`]
|
||||
|
||||
if (tool.parameters) {
|
||||
const required = tool.parameters.required ?? []
|
||||
|
||||
for (const [argName, _argType] of Object.entries(tool.parameters.properties ?? {})) {
|
||||
const placeholder = required.includes(argName) ? `${argName} value here` : `optional ${argName} value`
|
||||
lines.push(`<${argName}>${placeholder}</${argName}>`)
|
||||
}
|
||||
}
|
||||
|
||||
lines.push(`</${tool.name}>`)
|
||||
return lines.join("\n")
|
||||
}
|
||||
|
||||
function getDescription(tool: SerializedCustomToolDefinition): string {
|
||||
const parts: string[] = []
|
||||
|
||||
parts.push(`## ${tool.name}`)
|
||||
parts.push(`Description: ${tool.description}`)
|
||||
|
||||
if (tool.parameters?.properties) {
|
||||
const required = tool.parameters?.required ?? []
|
||||
parts.push("Parameters:")
|
||||
|
||||
for (const [name, parameter] of Object.entries(tool.parameters.properties)) {
|
||||
// What should we do with `boolean` values for `parameter`?
|
||||
if (typeof parameter !== "object") {
|
||||
continue
|
||||
}
|
||||
|
||||
parts.push(getParameterDescription(name, parameter, required))
|
||||
}
|
||||
} else {
|
||||
parts.push("Parameters: None")
|
||||
}
|
||||
|
||||
parts.push("Usage:")
|
||||
parts.push(getUsage(tool))
|
||||
|
||||
return parts.join("\n")
|
||||
}
|
||||
|
||||
export function formatXml(tools: SerializedCustomToolDefinition[]): string {
|
||||
if (tools.length === 0) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const descriptions = tools.map((tool) => getDescription(tool))
|
||||
|
||||
return `# Custom Tools
|
||||
|
||||
The following custom tools are available for this mode. Use them in the same way as built-in tools.
|
||||
|
||||
${descriptions.join("\n\n")}`
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
export * from "./custom-tool-registry.js"
|
||||
export * from "./serialize.js"
|
||||
export * from "./format-xml.js"
|
||||
export * from "./format-native.js"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./custom-tools/index.js"
|
||||
export * from "./debug-log/index.js"
|
||||
export * from "./message-utils/index.js"
|
||||
export * from "./worktree/index.js"
|
||||
|
|
|
|||
306
packages/core/src/worktree/__tests__/worktree-include.spec.ts
Normal file
306
packages/core/src/worktree/__tests__/worktree-include.spec.ts
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
import * as fs from "fs/promises"
|
||||
import * as path from "path"
|
||||
import * as os from "os"
|
||||
import { execFile } from "child_process"
|
||||
import { promisify } from "util"
|
||||
|
||||
import { WorktreeIncludeService } from "../worktree-include.js"
|
||||
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
async function execGit(cwd: string, args: string[]): Promise<string> {
|
||||
const { stdout } = await execFileAsync("git", args, { cwd, encoding: "utf8" })
|
||||
return stdout
|
||||
}
|
||||
|
||||
describe("WorktreeIncludeService", () => {
|
||||
let service: WorktreeIncludeService
|
||||
let tempDir: string
|
||||
|
||||
beforeEach(async () => {
|
||||
service = new WorktreeIncludeService()
|
||||
// Create a temp directory for each test
|
||||
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "worktree-test-"))
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
// Clean up temp directory
|
||||
try {
|
||||
await fs.rm(tempDir, { recursive: true })
|
||||
} catch {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
})
|
||||
|
||||
describe("hasWorktreeInclude", () => {
|
||||
it("should return true when .worktreeinclude exists", async () => {
|
||||
await fs.writeFile(path.join(tempDir, ".worktreeinclude"), "node_modules")
|
||||
|
||||
const result = await service.hasWorktreeInclude(tempDir)
|
||||
|
||||
expect(result).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false when .worktreeinclude does not exist", async () => {
|
||||
const result = await service.hasWorktreeInclude(tempDir)
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false for non-existent directory", async () => {
|
||||
const result = await service.hasWorktreeInclude("/non/existent/path")
|
||||
|
||||
expect(result).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe("branchHasWorktreeInclude", () => {
|
||||
it("should detect .worktreeinclude on the specified branch", async () => {
|
||||
const repoDir = path.join(tempDir, "repo")
|
||||
await fs.mkdir(repoDir, { recursive: true })
|
||||
|
||||
await execGit(repoDir, ["init"])
|
||||
await execGit(repoDir, ["config", "user.name", "Test User"])
|
||||
await execGit(repoDir, ["config", "user.email", "test@example.com"])
|
||||
|
||||
await fs.writeFile(path.join(repoDir, "README.md"), "test")
|
||||
await execGit(repoDir, ["add", "README.md"])
|
||||
await execGit(repoDir, ["commit", "-m", "init"])
|
||||
|
||||
const baseBranch = (await execGit(repoDir, ["rev-parse", "--abbrev-ref", "HEAD"])).trim()
|
||||
|
||||
expect(await service.branchHasWorktreeInclude(repoDir, baseBranch)).toBe(false)
|
||||
|
||||
await execGit(repoDir, ["checkout", "-b", "with-include"])
|
||||
await fs.writeFile(path.join(repoDir, ".worktreeinclude"), "node_modules")
|
||||
await execGit(repoDir, ["add", ".worktreeinclude"])
|
||||
await execGit(repoDir, ["commit", "-m", "add include"])
|
||||
|
||||
expect(await service.branchHasWorktreeInclude(repoDir, "with-include")).toBe(true)
|
||||
}, 30_000)
|
||||
})
|
||||
|
||||
describe("getStatus", () => {
|
||||
it("should return correct status when both files exist", async () => {
|
||||
const gitignoreContent = "node_modules\n.env\ndist"
|
||||
await fs.writeFile(path.join(tempDir, ".worktreeinclude"), "node_modules")
|
||||
await fs.writeFile(path.join(tempDir, ".gitignore"), gitignoreContent)
|
||||
|
||||
const result = await service.getStatus(tempDir)
|
||||
|
||||
expect(result.exists).toBe(true)
|
||||
expect(result.hasGitignore).toBe(true)
|
||||
expect(result.gitignoreContent).toBe(gitignoreContent)
|
||||
})
|
||||
|
||||
it("should return correct status when only .gitignore exists", async () => {
|
||||
const gitignoreContent = "node_modules\n.env"
|
||||
await fs.writeFile(path.join(tempDir, ".gitignore"), gitignoreContent)
|
||||
|
||||
const result = await service.getStatus(tempDir)
|
||||
|
||||
expect(result.exists).toBe(false)
|
||||
expect(result.hasGitignore).toBe(true)
|
||||
expect(result.gitignoreContent).toBe(gitignoreContent)
|
||||
})
|
||||
|
||||
it("should return correct status when only .worktreeinclude exists", async () => {
|
||||
await fs.writeFile(path.join(tempDir, ".worktreeinclude"), "node_modules")
|
||||
|
||||
const result = await service.getStatus(tempDir)
|
||||
|
||||
expect(result.exists).toBe(true)
|
||||
expect(result.hasGitignore).toBe(false)
|
||||
expect(result.gitignoreContent).toBeUndefined()
|
||||
})
|
||||
|
||||
it("should return correct status when neither file exists", async () => {
|
||||
const result = await service.getStatus(tempDir)
|
||||
|
||||
expect(result.exists).toBe(false)
|
||||
expect(result.hasGitignore).toBe(false)
|
||||
expect(result.gitignoreContent).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("createWorktreeInclude", () => {
|
||||
it("should create .worktreeinclude file with specified content", async () => {
|
||||
const content = "node_modules\n.env\ndist"
|
||||
|
||||
await service.createWorktreeInclude(tempDir, content)
|
||||
|
||||
const fileContent = await fs.readFile(path.join(tempDir, ".worktreeinclude"), "utf-8")
|
||||
expect(fileContent).toBe(content)
|
||||
})
|
||||
|
||||
it("should overwrite existing .worktreeinclude file", async () => {
|
||||
await fs.writeFile(path.join(tempDir, ".worktreeinclude"), "old content")
|
||||
const newContent = "new content"
|
||||
|
||||
await service.createWorktreeInclude(tempDir, newContent)
|
||||
|
||||
const fileContent = await fs.readFile(path.join(tempDir, ".worktreeinclude"), "utf-8")
|
||||
expect(fileContent).toBe(newContent)
|
||||
})
|
||||
})
|
||||
|
||||
describe("copyWorktreeIncludeFiles", () => {
|
||||
let sourceDir: string
|
||||
let targetDir: string
|
||||
|
||||
beforeEach(async () => {
|
||||
sourceDir = path.join(tempDir, "source")
|
||||
targetDir = path.join(tempDir, "target")
|
||||
await fs.mkdir(sourceDir, { recursive: true })
|
||||
await fs.mkdir(targetDir, { recursive: true })
|
||||
})
|
||||
|
||||
it("should return empty array when no .worktreeinclude exists", async () => {
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules")
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
it("should return empty array when no .gitignore exists", async () => {
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules")
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
it("should return empty array when patterns do not match", async () => {
|
||||
// .worktreeinclude wants node_modules, .gitignore only ignores .env
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), ".env")
|
||||
await fs.mkdir(path.join(sourceDir, "node_modules"), { recursive: true })
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
it("should copy files that match both patterns", async () => {
|
||||
// Both files include node_modules
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules")
|
||||
// Create a file in node_modules
|
||||
await fs.mkdir(path.join(sourceDir, "node_modules"), { recursive: true })
|
||||
await fs.writeFile(path.join(sourceDir, "node_modules", "package.json"), '{"name": "test"}')
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).toContain("node_modules")
|
||||
// Verify the file was copied
|
||||
const copiedContent = await fs.readFile(path.join(targetDir, "node_modules", "package.json"), "utf-8")
|
||||
expect(copiedContent).toBe('{"name": "test"}')
|
||||
})
|
||||
|
||||
it("should only copy intersection of patterns", async () => {
|
||||
// .worktreeinclude: node_modules, dist
|
||||
// .gitignore: node_modules, .env
|
||||
// Only node_modules should be copied (intersection)
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules\ndist")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules\n.env")
|
||||
await fs.mkdir(path.join(sourceDir, "node_modules"), { recursive: true })
|
||||
await fs.mkdir(path.join(sourceDir, "dist"), { recursive: true })
|
||||
await fs.writeFile(path.join(sourceDir, ".env"), "SECRET=123")
|
||||
await fs.writeFile(path.join(sourceDir, "node_modules", "test.txt"), "test")
|
||||
await fs.writeFile(path.join(sourceDir, "dist", "main.js"), "console.log('dist')")
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
// Only node_modules should be in the result (matches both)
|
||||
expect(result).toContain("node_modules")
|
||||
expect(result).not.toContain("dist") // only in .worktreeinclude
|
||||
expect(result).not.toContain(".env") // only in .gitignore
|
||||
|
||||
// Verify node_modules was copied
|
||||
const nodeModulesExists = await fs
|
||||
.access(path.join(targetDir, "node_modules"))
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
expect(nodeModulesExists).toBe(true)
|
||||
|
||||
// Verify dist was NOT copied
|
||||
const distExists = await fs
|
||||
.access(path.join(targetDir, "dist"))
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
expect(distExists).toBe(false)
|
||||
})
|
||||
|
||||
it("should skip .git directory", async () => {
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), ".git")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), ".git")
|
||||
await fs.mkdir(path.join(sourceDir, ".git"), { recursive: true })
|
||||
await fs.writeFile(path.join(sourceDir, ".git", "config"), "[core]")
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).not.toContain(".git")
|
||||
})
|
||||
|
||||
it("should copy single files", async () => {
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), ".env.local")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), ".env.local")
|
||||
await fs.writeFile(path.join(sourceDir, ".env.local"), "LOCAL_VAR=value")
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).toContain(".env.local")
|
||||
const copiedContent = await fs.readFile(path.join(targetDir, ".env.local"), "utf-8")
|
||||
expect(copiedContent).toBe("LOCAL_VAR=value")
|
||||
})
|
||||
|
||||
it("should ignore comment lines in pattern files", async () => {
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "# comment\nnode_modules\n# another comment")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules")
|
||||
await fs.mkdir(path.join(sourceDir, "node_modules"), { recursive: true })
|
||||
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).toContain("node_modules")
|
||||
})
|
||||
|
||||
it("should call progress callback with bytesCopied progress", async () => {
|
||||
// Set up files to copy
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules\n.env.local")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules\n.env.local")
|
||||
await fs.mkdir(path.join(sourceDir, "node_modules"), { recursive: true })
|
||||
await fs.writeFile(path.join(sourceDir, "node_modules", "test.txt"), "test")
|
||||
await fs.writeFile(path.join(sourceDir, ".env.local"), "LOCAL_VAR=value")
|
||||
|
||||
const progressCalls: Array<{ bytesCopied: number; itemName: string }> = []
|
||||
const onProgress = vi.fn((progress: { bytesCopied: number; itemName: string }) => {
|
||||
progressCalls.push({ ...progress })
|
||||
})
|
||||
|
||||
await service.copyWorktreeIncludeFiles(sourceDir, targetDir, onProgress)
|
||||
|
||||
// Should be called multiple times (initial + after each copy)
|
||||
expect(onProgress).toHaveBeenCalled()
|
||||
|
||||
// bytesCopied should increase over time
|
||||
expect(progressCalls.length).toBeGreaterThan(0)
|
||||
const finalCall = progressCalls[progressCalls.length - 1]
|
||||
expect(finalCall?.bytesCopied).toBeGreaterThan(0)
|
||||
|
||||
// Each call should have an item name
|
||||
expect(progressCalls.every((p) => typeof p.itemName === "string")).toBe(true)
|
||||
})
|
||||
|
||||
it("should not fail when progress callback is not provided", async () => {
|
||||
await fs.writeFile(path.join(sourceDir, ".worktreeinclude"), "node_modules")
|
||||
await fs.writeFile(path.join(sourceDir, ".gitignore"), "node_modules")
|
||||
await fs.mkdir(path.join(sourceDir, "node_modules"), { recursive: true })
|
||||
|
||||
// Should not throw when no callback is provided
|
||||
const result = await service.copyWorktreeIncludeFiles(sourceDir, targetDir)
|
||||
|
||||
expect(result).toContain("node_modules")
|
||||
})
|
||||
})
|
||||
})
|
||||
146
packages/core/src/worktree/__tests__/worktree-service.spec.ts
Normal file
146
packages/core/src/worktree/__tests__/worktree-service.spec.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
import * as path from "path"
|
||||
|
||||
import { WorktreeService } from "../worktree-service.js"
|
||||
|
||||
describe("WorktreeService", () => {
|
||||
describe("normalizePath", () => {
|
||||
let service: WorktreeService
|
||||
|
||||
beforeEach(() => {
|
||||
service = new WorktreeService()
|
||||
})
|
||||
|
||||
// Access private method for testing
|
||||
const callNormalizePath = (service: WorktreeService, p: string): string => {
|
||||
// @ts-expect-error - accessing private method for testing
|
||||
return service.normalizePath(p)
|
||||
}
|
||||
|
||||
it("should normalize paths with trailing slashes", () => {
|
||||
const result = callNormalizePath(service, "/home/user/project/")
|
||||
expect(result).toBe(path.normalize("/home/user/project"))
|
||||
})
|
||||
|
||||
it("should normalize paths with multiple trailing slashes", () => {
|
||||
const result = callNormalizePath(service, "/home/user/project///")
|
||||
// path.normalize already handles multiple slashes
|
||||
expect(result).toBe(path.normalize("/home/user/project"))
|
||||
})
|
||||
|
||||
it("should preserve root path /", () => {
|
||||
// This is a critical test - the old regex would turn "/" into ""
|
||||
// On Windows, path.normalize("/") returns "\", on Unix it returns "/"
|
||||
const result = callNormalizePath(service, "/")
|
||||
expect(result).toBe(path.sep)
|
||||
})
|
||||
|
||||
it("should handle paths without trailing slashes", () => {
|
||||
const result = callNormalizePath(service, "/home/user/project")
|
||||
expect(result).toBe(path.normalize("/home/user/project"))
|
||||
})
|
||||
|
||||
it("should handle relative paths", () => {
|
||||
const result = callNormalizePath(service, "./some/path/")
|
||||
expect(result).toBe(path.normalize("./some/path"))
|
||||
})
|
||||
|
||||
it("should handle empty string", () => {
|
||||
const result = callNormalizePath(service, "")
|
||||
expect(result).toBe(".")
|
||||
})
|
||||
|
||||
it("should handle Windows-style paths on non-Windows", () => {
|
||||
// path.normalize will convert separators appropriately
|
||||
const result = callNormalizePath(service, "C:\\Users\\test\\project")
|
||||
// On Unix, this stays as-is; on Windows it would normalize
|
||||
expect(result).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
||||
describe("parseWorktreeOutput", () => {
|
||||
let service: WorktreeService
|
||||
|
||||
beforeEach(() => {
|
||||
service = new WorktreeService()
|
||||
})
|
||||
|
||||
// Access private method for testing
|
||||
const callParseWorktreeOutput = (
|
||||
service: WorktreeService,
|
||||
output: string,
|
||||
currentCwd: string,
|
||||
): ReturnType<WorktreeService["parseWorktreeOutput"]> => {
|
||||
// @ts-expect-error - accessing private method for testing
|
||||
return service.parseWorktreeOutput(output, currentCwd)
|
||||
}
|
||||
|
||||
it("should parse porcelain output correctly", () => {
|
||||
const output = `worktree /home/user/repo
|
||||
HEAD abc123def456
|
||||
branch refs/heads/main
|
||||
|
||||
worktree /home/user/repo-feature
|
||||
HEAD def456abc123
|
||||
branch refs/heads/feature/test
|
||||
`
|
||||
const result = callParseWorktreeOutput(service, output, "/home/user/repo")
|
||||
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result[0]).toMatchObject({
|
||||
path: "/home/user/repo",
|
||||
branch: "main",
|
||||
commitHash: "abc123def456",
|
||||
isCurrent: true,
|
||||
})
|
||||
expect(result[1]).toMatchObject({
|
||||
path: "/home/user/repo-feature",
|
||||
branch: "feature/test",
|
||||
commitHash: "def456abc123",
|
||||
isCurrent: false,
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle detached HEAD worktrees", () => {
|
||||
const output = `worktree /home/user/repo-detached
|
||||
HEAD abc123def456
|
||||
detached
|
||||
`
|
||||
const result = callParseWorktreeOutput(service, output, "/home/user/other")
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0]).toMatchObject({
|
||||
path: "/home/user/repo-detached",
|
||||
isDetached: true,
|
||||
branch: "",
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle locked worktrees", () => {
|
||||
const output = `worktree /home/user/repo-locked
|
||||
HEAD abc123def456
|
||||
branch refs/heads/locked-branch
|
||||
locked some reason here
|
||||
`
|
||||
const result = callParseWorktreeOutput(service, output, "/home/user/other")
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0]).toMatchObject({
|
||||
isLocked: true,
|
||||
lockReason: "some reason here",
|
||||
})
|
||||
})
|
||||
|
||||
it("should handle bare worktrees", () => {
|
||||
const output = `worktree /home/user/repo.git
|
||||
bare
|
||||
`
|
||||
const result = callParseWorktreeOutput(service, output, "/home/user/other")
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0]).toMatchObject({
|
||||
path: "/home/user/repo.git",
|
||||
isBare: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
13
packages/core/src/worktree/index.ts
Normal file
13
packages/core/src/worktree/index.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* Worktree Module
|
||||
*
|
||||
* Platform-agnostic git worktree management functionality.
|
||||
* These exports are decoupled from VSCode and can be used by any consumer.
|
||||
*/
|
||||
|
||||
// Types
|
||||
export * from "./types.js"
|
||||
|
||||
// Services
|
||||
export { WorktreeService, worktreeService } from "./worktree-service.js"
|
||||
export { WorktreeIncludeService, worktreeIncludeService, type CopyProgressCallback } from "./worktree-include.js"
|
||||
15
packages/core/src/worktree/types.ts
Normal file
15
packages/core/src/worktree/types.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* Worktree Types
|
||||
*
|
||||
* Re-exports platform-agnostic type definitions from @roo-code/types.
|
||||
*/
|
||||
|
||||
export type {
|
||||
Worktree,
|
||||
WorktreeResult,
|
||||
BranchInfo,
|
||||
CreateWorktreeOptions,
|
||||
WorktreeIncludeStatus,
|
||||
WorktreeListResponse,
|
||||
WorktreeDefaultsResponse,
|
||||
} from "@roo-code/types"
|
||||
428
packages/core/src/worktree/worktree-include.ts
Normal file
428
packages/core/src/worktree/worktree-include.ts
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
/**
|
||||
* WorktreeIncludeService
|
||||
*
|
||||
* Platform-agnostic service for handling .worktreeinclude files.
|
||||
* Used to copy untracked files (like node_modules) when creating worktrees.
|
||||
*/
|
||||
|
||||
import { execFile, spawn } from "child_process"
|
||||
import * as fs from "fs/promises"
|
||||
import * as path from "path"
|
||||
import { promisify } from "util"
|
||||
|
||||
import ignore, { type Ignore } from "ignore"
|
||||
|
||||
import type { WorktreeIncludeStatus } from "./types.js"
|
||||
|
||||
/**
|
||||
* Progress info for copy tracking.
|
||||
* Shows activity without trying to predict total size (which is inaccurate).
|
||||
*/
|
||||
export interface CopyProgress {
|
||||
/** Current bytes copied */
|
||||
bytesCopied: number
|
||||
/** Name of current item being copied */
|
||||
itemName: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for reporting copy progress during worktree file copying.
|
||||
*/
|
||||
export type CopyProgressCallback = (progress: CopyProgress) => void
|
||||
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
/**
|
||||
* Service for managing .worktreeinclude files and copying files to new worktrees.
|
||||
* All methods are platform-agnostic and don't depend on VSCode APIs.
|
||||
*/
|
||||
export class WorktreeIncludeService {
|
||||
/**
|
||||
* Check if .worktreeinclude exists in a directory
|
||||
*/
|
||||
async hasWorktreeInclude(dir: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.access(path.join(dir, ".worktreeinclude"))
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific branch has .worktreeinclude file (in git, not local filesystem)
|
||||
* @param cwd - Current working directory (git repo)
|
||||
* @param branch - Branch name to check
|
||||
*/
|
||||
async branchHasWorktreeInclude(cwd: string, branch: string): Promise<boolean> {
|
||||
try {
|
||||
const ref = `${branch}:.worktreeinclude`
|
||||
// Use git cat-file -e to check if the file exists on the branch (without printing contents)
|
||||
await execFileAsync("git", ["cat-file", "-e", "--", ref], { cwd })
|
||||
return true
|
||||
} catch {
|
||||
// File doesn't exist on this branch
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status of .worktreeinclude and .gitignore
|
||||
*/
|
||||
async getStatus(dir: string): Promise<WorktreeIncludeStatus> {
|
||||
const worktreeIncludePath = path.join(dir, ".worktreeinclude")
|
||||
const gitignorePath = path.join(dir, ".gitignore")
|
||||
|
||||
let exists = false
|
||||
let hasGitignore = false
|
||||
let gitignoreContent: string | undefined
|
||||
|
||||
try {
|
||||
await fs.access(worktreeIncludePath)
|
||||
exists = true
|
||||
} catch {
|
||||
exists = false
|
||||
}
|
||||
|
||||
try {
|
||||
gitignoreContent = await fs.readFile(gitignorePath, "utf-8")
|
||||
hasGitignore = true
|
||||
} catch {
|
||||
hasGitignore = false
|
||||
}
|
||||
|
||||
return {
|
||||
exists,
|
||||
hasGitignore,
|
||||
gitignoreContent,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a .worktreeinclude file with the specified content
|
||||
*/
|
||||
async createWorktreeInclude(dir: string, content: string): Promise<void> {
|
||||
await fs.writeFile(path.join(dir, ".worktreeinclude"), content, "utf-8")
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy files matching .worktreeinclude patterns from source to target.
|
||||
* Only copies files that are ALSO in .gitignore (to avoid copying tracked files).
|
||||
*
|
||||
* @param sourceDir - The source directory containing the files to copy
|
||||
* @param targetDir - The target directory where files will be copied
|
||||
* @param onProgress - Optional callback to report copy progress (size-based)
|
||||
* @returns Array of copied file/directory paths
|
||||
*/
|
||||
async copyWorktreeIncludeFiles(
|
||||
sourceDir: string,
|
||||
targetDir: string,
|
||||
onProgress?: CopyProgressCallback,
|
||||
): Promise<string[]> {
|
||||
const worktreeIncludePath = path.join(sourceDir, ".worktreeinclude")
|
||||
const gitignorePath = path.join(sourceDir, ".gitignore")
|
||||
|
||||
// Check if both files exist
|
||||
let hasWorktreeInclude = false
|
||||
let hasGitignore = false
|
||||
|
||||
try {
|
||||
await fs.access(worktreeIncludePath)
|
||||
hasWorktreeInclude = true
|
||||
} catch {
|
||||
hasWorktreeInclude = false
|
||||
}
|
||||
|
||||
try {
|
||||
await fs.access(gitignorePath)
|
||||
hasGitignore = true
|
||||
} catch {
|
||||
hasGitignore = false
|
||||
}
|
||||
|
||||
if (!hasWorktreeInclude || !hasGitignore) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Parse both files
|
||||
const worktreeIncludePatterns = await this.parseIgnoreFile(worktreeIncludePath)
|
||||
const gitignorePatterns = await this.parseIgnoreFile(gitignorePath)
|
||||
|
||||
if (worktreeIncludePatterns.length === 0 || gitignorePatterns.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
// Create ignore matchers
|
||||
const worktreeIncludeMatcher = ignore().add(worktreeIncludePatterns)
|
||||
const gitignoreMatcher = ignore().add(gitignorePatterns)
|
||||
|
||||
// Find items that match BOTH patterns (intersection)
|
||||
const itemsToCopy = await this.findMatchingItems(sourceDir, worktreeIncludeMatcher, gitignoreMatcher)
|
||||
|
||||
if (itemsToCopy.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
let bytesCopied = 0
|
||||
|
||||
// Report initial progress
|
||||
if (onProgress && itemsToCopy.length > 0) {
|
||||
onProgress({ bytesCopied: 0, itemName: itemsToCopy[0]! })
|
||||
}
|
||||
|
||||
// Copy the items with progress tracking (no total size calculation)
|
||||
const copiedItems: string[] = []
|
||||
for (const item of itemsToCopy) {
|
||||
const sourcePath = path.join(sourceDir, item)
|
||||
const targetPath = path.join(targetDir, item)
|
||||
|
||||
try {
|
||||
const stats = await fs.stat(sourcePath)
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
// Copy directory with progress tracking
|
||||
bytesCopied = await this.copyDirectoryWithProgress(
|
||||
sourcePath,
|
||||
targetPath,
|
||||
item,
|
||||
bytesCopied,
|
||||
onProgress,
|
||||
)
|
||||
} else {
|
||||
// Report progress before copying
|
||||
onProgress?.({ bytesCopied, itemName: item })
|
||||
|
||||
// Ensure parent directory exists
|
||||
await fs.mkdir(path.dirname(targetPath), { recursive: true })
|
||||
await fs.copyFile(sourcePath, targetPath)
|
||||
|
||||
// Update bytes copied
|
||||
bytesCopied += this.getSizeOnDisk(stats)
|
||||
}
|
||||
|
||||
copiedItems.push(item)
|
||||
|
||||
// Report progress after copying
|
||||
onProgress?.({ bytesCopied, itemName: item })
|
||||
} catch (error) {
|
||||
// Log but don't fail on individual copy errors
|
||||
console.error(`Failed to copy ${item}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
return copiedItems
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size on disk of a file (accounts for filesystem block allocation).
|
||||
* Uses blksize to calculate actual disk usage including block overhead.
|
||||
*/
|
||||
private getSizeOnDisk(stats: { size: number; blksize?: number }): number {
|
||||
// Calculate size on disk using filesystem block size
|
||||
if (stats.blksize !== undefined && stats.blksize > 0) {
|
||||
return stats.blksize * Math.ceil(stats.size / stats.blksize)
|
||||
}
|
||||
// Fallback to logical size when blksize not available
|
||||
return stats.size
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total size on disk of a file or directory (recursively).
|
||||
* Uses native Node.js fs operations for cross-platform compatibility.
|
||||
*/
|
||||
private async getPathSize(targetPath: string): Promise<number> {
|
||||
try {
|
||||
const stats = await fs.stat(targetPath)
|
||||
|
||||
if (stats.isFile()) {
|
||||
return this.getSizeOnDisk(stats)
|
||||
}
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
return await this.getDirectorySizeRecursive(targetPath)
|
||||
}
|
||||
|
||||
return 0
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively calculate directory size on disk using Node.js fs.
|
||||
* Uses parallel processing for better performance on large directories.
|
||||
*/
|
||||
private async getDirectorySizeRecursive(dirPath: string): Promise<number> {
|
||||
try {
|
||||
const entries = await fs.readdir(dirPath, { withFileTypes: true })
|
||||
const sizes = await Promise.all(
|
||||
entries.map(async (entry) => {
|
||||
const entryPath = path.join(dirPath, entry.name)
|
||||
try {
|
||||
if (entry.isFile()) {
|
||||
const stats = await fs.stat(entryPath)
|
||||
return this.getSizeOnDisk(stats)
|
||||
} else if (entry.isDirectory()) {
|
||||
return await this.getDirectorySizeRecursive(entryPath)
|
||||
}
|
||||
return 0
|
||||
} catch {
|
||||
return 0 // Skip inaccessible files
|
||||
}
|
||||
}),
|
||||
)
|
||||
return sizes.reduce((sum, size) => sum + size, 0)
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current size of a directory (for progress tracking).
|
||||
*/
|
||||
private async getCurrentDirectorySize(dirPath: string): Promise<number> {
|
||||
try {
|
||||
await fs.access(dirPath)
|
||||
return await this.getDirectorySizeRecursive(dirPath)
|
||||
} catch {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy directory with progress polling using native cp command.
|
||||
* Starts native copy and polls target directory size to report progress.
|
||||
* Returns the updated bytesCopied count.
|
||||
*/
|
||||
private async copyDirectoryWithProgress(
|
||||
source: string,
|
||||
target: string,
|
||||
itemName: string,
|
||||
bytesCopiedBefore: number,
|
||||
onProgress?: CopyProgressCallback,
|
||||
): Promise<number> {
|
||||
// Ensure parent directory exists
|
||||
await fs.mkdir(path.dirname(target), { recursive: true })
|
||||
|
||||
const isWindows = process.platform === "win32"
|
||||
|
||||
// Start the copy process
|
||||
const copyPromise = new Promise<void>((resolve, reject) => {
|
||||
let proc: ReturnType<typeof spawn>
|
||||
|
||||
if (isWindows) {
|
||||
proc = spawn("robocopy", [source, target, "/E", "/NFL", "/NDL", "/NJH", "/NJS", "/NC", "/NS", "/NP"], {
|
||||
windowsHide: true,
|
||||
})
|
||||
} else {
|
||||
proc = spawn("cp", ["-r", "--", source, target])
|
||||
}
|
||||
|
||||
proc.on("close", (code) => {
|
||||
if (isWindows) {
|
||||
// robocopy returns non-zero for success (values < 8)
|
||||
if (code !== null && code < 8) {
|
||||
resolve()
|
||||
} else {
|
||||
reject(new Error(`robocopy failed with code ${code}`))
|
||||
}
|
||||
} else {
|
||||
if (code === 0) {
|
||||
resolve()
|
||||
} else {
|
||||
reject(new Error(`cp failed with code ${code}`))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
proc.on("error", reject)
|
||||
})
|
||||
|
||||
// Poll progress while copying
|
||||
const pollInterval = 500 // Poll every 500ms
|
||||
let polling = true
|
||||
|
||||
const pollProgress = async () => {
|
||||
while (polling) {
|
||||
const currentSize = await this.getCurrentDirectorySize(target)
|
||||
const totalCopied = bytesCopiedBefore + currentSize
|
||||
|
||||
onProgress?.({
|
||||
bytesCopied: totalCopied,
|
||||
itemName,
|
||||
})
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, pollInterval))
|
||||
}
|
||||
}
|
||||
|
||||
// Start polling and wait for copy to complete
|
||||
const pollPromise = pollProgress()
|
||||
|
||||
try {
|
||||
await copyPromise
|
||||
} finally {
|
||||
polling = false
|
||||
// Wait for final poll iteration to complete
|
||||
await pollPromise.catch(() => {})
|
||||
}
|
||||
|
||||
// Get the final size of the copied directory
|
||||
const finalSize = await this.getPathSize(target)
|
||||
return bytesCopiedBefore + finalSize
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a .gitignore-style file and return the patterns
|
||||
*/
|
||||
private async parseIgnoreFile(filePath: string): Promise<string[]> {
|
||||
try {
|
||||
const content = await fs.readFile(filePath, "utf-8")
|
||||
return content
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line && !line.startsWith("#"))
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find items in sourceDir that match both matchers
|
||||
*/
|
||||
private async findMatchingItems(
|
||||
sourceDir: string,
|
||||
includeMatcher: Ignore,
|
||||
gitignoreMatcher: Ignore,
|
||||
): Promise<string[]> {
|
||||
const matchingItems: string[] = []
|
||||
|
||||
try {
|
||||
const entries = await fs.readdir(sourceDir, { withFileTypes: true })
|
||||
|
||||
for (const entry of entries) {
|
||||
const relativePath = entry.name
|
||||
|
||||
// Skip .git directory
|
||||
if (relativePath === ".git") continue
|
||||
|
||||
// Check if this path matches both patterns
|
||||
// For .worktreeinclude, we want items that are "ignored" (matched)
|
||||
// For .gitignore, we want items that are "ignored" (matched)
|
||||
const matchesWorktreeInclude = includeMatcher.ignores(relativePath)
|
||||
const matchesGitignore = gitignoreMatcher.ignores(relativePath)
|
||||
|
||||
if (matchesWorktreeInclude && matchesGitignore) {
|
||||
matchingItems.push(relativePath)
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
|
||||
return matchingItems
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance for convenience
|
||||
export const worktreeIncludeService = new WorktreeIncludeService()
|
||||
315
packages/core/src/worktree/worktree-service.ts
Normal file
315
packages/core/src/worktree/worktree-service.ts
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
/**
|
||||
* WorktreeService
|
||||
*
|
||||
* Platform-agnostic service for git worktree operations.
|
||||
* Uses simple-git and native CLI commands - no VSCode dependencies.
|
||||
*/
|
||||
|
||||
import { exec, execFile } from "child_process"
|
||||
import * as path from "path"
|
||||
import { promisify } from "util"
|
||||
|
||||
import type { BranchInfo, CreateWorktreeOptions, Worktree, WorktreeResult } from "./types.js"
|
||||
|
||||
const execAsync = promisify(exec)
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
/**
|
||||
* Service for managing git worktrees.
|
||||
* All methods are platform-agnostic and don't depend on VSCode APIs.
|
||||
*/
|
||||
export class WorktreeService {
|
||||
/**
|
||||
* Check if git is installed on the system
|
||||
*/
|
||||
async checkGitInstalled(): Promise<boolean> {
|
||||
try {
|
||||
await execAsync("git --version")
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a directory is a git repository.
|
||||
*/
|
||||
async checkGitRepo(cwd: string): Promise<boolean> {
|
||||
try {
|
||||
await execAsync("git rev-parse --git-dir", { cwd })
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the git repository root path.
|
||||
*/
|
||||
async getGitRootPath(cwd: string): Promise<string | null> {
|
||||
try {
|
||||
const { stdout } = await execAsync("git rev-parse --show-toplevel", { cwd })
|
||||
return stdout.trim()
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current worktree path.
|
||||
*/
|
||||
async getCurrentWorktreePath(cwd: string): Promise<string | null> {
|
||||
try {
|
||||
const { stdout } = await execAsync("git rev-parse --show-toplevel", { cwd })
|
||||
return stdout.trim()
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current branch name.
|
||||
*/
|
||||
async getCurrentBranch(cwd: string): Promise<string | null> {
|
||||
try {
|
||||
const { stdout } = await execAsync("git rev-parse --abbrev-ref HEAD", { cwd })
|
||||
const branch = stdout.trim()
|
||||
return branch === "HEAD" ? null : branch
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List all worktrees in the repository
|
||||
*/
|
||||
async listWorktrees(cwd: string): Promise<Worktree[]> {
|
||||
try {
|
||||
const { stdout } = await execAsync("git worktree list --porcelain", { cwd })
|
||||
return this.parseWorktreeOutput(stdout, cwd)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new worktree
|
||||
*/
|
||||
async createWorktree(cwd: string, options: CreateWorktreeOptions): Promise<WorktreeResult> {
|
||||
try {
|
||||
const { path: worktreePath, branch, baseBranch, createNewBranch } = options
|
||||
|
||||
// Build the git worktree add command arguments
|
||||
const args: string[] = ["worktree", "add"]
|
||||
|
||||
if (createNewBranch && branch) {
|
||||
// Create new branch: git worktree add -b <branch> <path> [<base>]
|
||||
args.push("-b", branch, worktreePath)
|
||||
if (baseBranch) {
|
||||
args.push(baseBranch)
|
||||
}
|
||||
} else if (branch) {
|
||||
// Checkout existing branch: git worktree add <path> <branch>
|
||||
args.push(worktreePath, branch)
|
||||
} else {
|
||||
// Detached HEAD at current commit
|
||||
args.push("--detach", worktreePath)
|
||||
}
|
||||
|
||||
await execFileAsync("git", args, { cwd })
|
||||
|
||||
// Get the created worktree info
|
||||
const worktrees = await this.listWorktrees(cwd)
|
||||
const createdWorktree = worktrees.find(
|
||||
(wt) => this.normalizePath(wt.path) === this.normalizePath(worktreePath),
|
||||
)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Worktree created at ${worktreePath}`,
|
||||
worktree: createdWorktree,
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
return {
|
||||
success: false,
|
||||
message: `Failed to create worktree: ${errorMessage}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a worktree
|
||||
*/
|
||||
async deleteWorktree(cwd: string, worktreePath: string, force = false): Promise<WorktreeResult> {
|
||||
try {
|
||||
// Get worktree info BEFORE deletion to capture the branch name
|
||||
const worktrees = await this.listWorktrees(cwd)
|
||||
const worktreeToDelete = worktrees.find(
|
||||
(wt) => this.normalizePath(wt.path) === this.normalizePath(worktreePath),
|
||||
)
|
||||
|
||||
const args = ["worktree", "remove"]
|
||||
if (force) {
|
||||
args.push("--force")
|
||||
}
|
||||
args.push(worktreePath)
|
||||
await execFileAsync("git", args, { cwd })
|
||||
|
||||
// Also try to delete the branch if it exists
|
||||
if (worktreeToDelete?.branch) {
|
||||
try {
|
||||
await execFileAsync("git", ["branch", "-d", worktreeToDelete.branch], { cwd })
|
||||
} catch {
|
||||
// Branch deletion is best-effort
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Worktree removed from ${worktreePath}`,
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
return {
|
||||
success: false,
|
||||
message: `Failed to delete worktree: ${errorMessage}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available branches
|
||||
* @param cwd - Current working directory
|
||||
* @param includeWorktreeBranches - If true, include branches already checked out in worktrees (useful for base branch selection)
|
||||
*/
|
||||
async getAvailableBranches(cwd: string, includeWorktreeBranches = false): Promise<BranchInfo> {
|
||||
try {
|
||||
// Run all git commands in parallel for better performance
|
||||
const [worktrees, localResult, remoteResult, currentBranch] = await Promise.all([
|
||||
this.listWorktrees(cwd),
|
||||
execAsync('git branch --format="%(refname:short)"', { cwd }),
|
||||
execAsync('git branch -r --format="%(refname:short)"', { cwd }),
|
||||
this.getCurrentBranch(cwd),
|
||||
])
|
||||
|
||||
const branchesInWorktrees = new Set(worktrees.map((wt) => wt.branch).filter(Boolean))
|
||||
|
||||
// Filter local branches
|
||||
const localBranches = localResult.stdout
|
||||
.trim()
|
||||
.split("\n")
|
||||
.filter((b) => b && (includeWorktreeBranches || !branchesInWorktrees.has(b)))
|
||||
|
||||
// Filter remote branches
|
||||
const remoteBranches = remoteResult.stdout
|
||||
.trim()
|
||||
.split("\n")
|
||||
.filter(
|
||||
(b) =>
|
||||
b &&
|
||||
!b.includes("HEAD") &&
|
||||
(includeWorktreeBranches || !branchesInWorktrees.has(b.replace(/^origin\//, ""))),
|
||||
)
|
||||
|
||||
return {
|
||||
localBranches,
|
||||
remoteBranches,
|
||||
currentBranch: currentBranch || "",
|
||||
}
|
||||
} catch {
|
||||
return {
|
||||
localBranches: [],
|
||||
remoteBranches: [],
|
||||
currentBranch: "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkout a branch in the current worktree
|
||||
*/
|
||||
async checkoutBranch(cwd: string, branch: string): Promise<WorktreeResult> {
|
||||
try {
|
||||
await execFileAsync("git", ["checkout", branch], { cwd })
|
||||
return {
|
||||
success: true,
|
||||
message: `Checked out branch ${branch}`,
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
return {
|
||||
success: false,
|
||||
message: `Failed to checkout branch: ${errorMessage}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse git worktree list --porcelain output
|
||||
*/
|
||||
private parseWorktreeOutput(output: string, currentCwd: string): Worktree[] {
|
||||
const worktrees: Worktree[] = []
|
||||
const entries = output.trim().split("\n\n")
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.trim()) continue
|
||||
|
||||
const lines = entry.trim().split("\n")
|
||||
const worktree: Partial<Worktree> = {
|
||||
path: "",
|
||||
branch: "",
|
||||
commitHash: "",
|
||||
isCurrent: false,
|
||||
isBare: false,
|
||||
isDetached: false,
|
||||
isLocked: false,
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.startsWith("worktree ")) {
|
||||
worktree.path = line.substring(9).trim()
|
||||
} else if (line.startsWith("HEAD ")) {
|
||||
worktree.commitHash = line.substring(5).trim()
|
||||
} else if (line.startsWith("branch ")) {
|
||||
// branch refs/heads/main -> main
|
||||
const branchRef = line.substring(7).trim()
|
||||
worktree.branch = branchRef.replace(/^refs\/heads\//, "")
|
||||
} else if (line === "bare") {
|
||||
worktree.isBare = true
|
||||
} else if (line === "detached") {
|
||||
worktree.isDetached = true
|
||||
} else if (line === "locked") {
|
||||
worktree.isLocked = true
|
||||
} else if (line.startsWith("locked ")) {
|
||||
worktree.isLocked = true
|
||||
worktree.lockReason = line.substring(7).trim()
|
||||
}
|
||||
}
|
||||
|
||||
if (worktree.path) {
|
||||
worktree.isCurrent = this.normalizePath(worktree.path) === this.normalizePath(currentCwd)
|
||||
worktrees.push(worktree as Worktree)
|
||||
}
|
||||
}
|
||||
|
||||
return worktrees
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a path for comparison (handle trailing slashes, etc.)
|
||||
*/
|
||||
private normalizePath(p: string): string {
|
||||
// normalize resolves ./.. segments, removes duplicate slashes, and standardizes path separators
|
||||
let normalized = path.normalize(p)
|
||||
// however it doesn't remove trailing slashes
|
||||
// remove trailing slash, except for root paths (handles both / and \)
|
||||
if (normalized.length > 1 && (normalized.endsWith("/") || normalized.endsWith("\\"))) {
|
||||
normalized = normalized.slice(0, -1)
|
||||
}
|
||||
return normalized
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance for convenience
|
||||
export const worktreeService = new WorktreeService()
|
||||
|
|
@ -111,8 +111,8 @@ export class TelemetryService {
|
|||
this.captureEvent(TelemetryEventName.MODE_SWITCH, { taskId, newMode })
|
||||
}
|
||||
|
||||
public captureToolUsage(taskId: string, tool: string, toolProtocol: string): void {
|
||||
this.captureEvent(TelemetryEventName.TOOL_USED, { taskId, tool, toolProtocol })
|
||||
public captureToolUsage(taskId: string, tool: string): void {
|
||||
this.captureEvent(TelemetryEventName.TOOL_USED, { taskId, tool })
|
||||
}
|
||||
|
||||
public captureCheckpointCreated(taskId: string): void {
|
||||
|
|
@ -127,17 +127,11 @@ export class TelemetryService {
|
|||
this.captureEvent(TelemetryEventName.CHECKPOINT_RESTORED, { taskId })
|
||||
}
|
||||
|
||||
public captureContextCondensed(
|
||||
taskId: string,
|
||||
isAutomaticTrigger: boolean,
|
||||
usedCustomPrompt?: boolean,
|
||||
usedCustomApiHandler?: boolean,
|
||||
): void {
|
||||
public captureContextCondensed(taskId: string, isAutomaticTrigger: boolean, usedCustomPrompt?: boolean): void {
|
||||
this.captureEvent(TelemetryEventName.CONTEXT_CONDENSED, {
|
||||
taskId,
|
||||
isAutomaticTrigger,
|
||||
...(usedCustomPrompt !== undefined && { usedCustomPrompt }),
|
||||
...(usedCustomApiHandler !== undefined && { usedCustomApiHandler }),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
"clean": "rimraf dist .turbo"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^3.25.61"
|
||||
"zod": "3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@roo-code/config-eslint": "workspace:^",
|
||||
|
|
|
|||
|
|
@ -90,11 +90,6 @@ describe("getApiProtocol", () => {
|
|||
expect(getApiProtocol("anthropic", "gpt-4")).toBe("anthropic")
|
||||
})
|
||||
|
||||
it("should return 'anthropic' for claude-code provider", () => {
|
||||
expect(getApiProtocol("claude-code")).toBe("anthropic")
|
||||
expect(getApiProtocol("claude-code", "some-model")).toBe("anthropic")
|
||||
})
|
||||
|
||||
it("should return 'anthropic' for bedrock provider", () => {
|
||||
expect(getApiProtocol("bedrock")).toBe("anthropic")
|
||||
expect(getApiProtocol("bedrock", "gpt-4")).toBe("anthropic")
|
||||
|
|
|
|||
|
|
@ -94,14 +94,11 @@ export type OrganizationAllowList = z.infer<typeof organizationAllowListSchema>
|
|||
export const organizationDefaultSettingsSchema = globalSettingsSchema
|
||||
.pick({
|
||||
enableCheckpoints: true,
|
||||
fuzzyMatchThreshold: true,
|
||||
maxOpenTabsContext: true,
|
||||
maxReadFileLine: true,
|
||||
maxWorkspaceFiles: true,
|
||||
showRooIgnoredFiles: true,
|
||||
terminalCommandDelay: true,
|
||||
terminalCompressProgressBar: true,
|
||||
terminalOutputLineLimit: true,
|
||||
terminalShellIntegrationDisabled: true,
|
||||
terminalShellIntegrationTimeout: true,
|
||||
terminalZshClearEolMark: true,
|
||||
|
|
@ -113,7 +110,6 @@ export const organizationDefaultSettingsSchema = globalSettingsSchema
|
|||
maxReadFileLine: z.number().int().gte(-1).optional(),
|
||||
maxWorkspaceFiles: z.number().int().nonnegative().optional(),
|
||||
terminalCommandDelay: z.number().int().nonnegative().optional(),
|
||||
terminalOutputLineLimit: z.number().int().nonnegative().optional(),
|
||||
terminalShellIntegrationTimeout: z.number().int().nonnegative().optional(),
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,15 +6,7 @@ import type { Keys, Equals, AssertEqual } from "./type-fu.js"
|
|||
* ExperimentId
|
||||
*/
|
||||
|
||||
export const experimentIds = [
|
||||
"powerSteering",
|
||||
"multiFileApplyDiff",
|
||||
"preventFocusDisruption",
|
||||
"imageGeneration",
|
||||
"runSlashCommand",
|
||||
"multipleNativeToolCalls",
|
||||
"customTools",
|
||||
] as const
|
||||
export const experimentIds = ["preventFocusDisruption", "imageGeneration", "runSlashCommand", "customTools"] as const
|
||||
|
||||
export const experimentIdsSchema = z.enum(experimentIds)
|
||||
|
||||
|
|
@ -25,12 +17,9 @@ export type ExperimentId = z.infer<typeof experimentIdsSchema>
|
|||
*/
|
||||
|
||||
export const experimentsSchema = z.object({
|
||||
powerSteering: z.boolean().optional(),
|
||||
multiFileApplyDiff: z.boolean().optional(),
|
||||
preventFocusDisruption: z.boolean().optional(),
|
||||
imageGeneration: z.boolean().optional(),
|
||||
runSlashCommand: z.boolean().optional(),
|
||||
multipleNativeToolCalls: z.boolean().optional(),
|
||||
customTools: z.boolean().optional(),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -23,11 +23,40 @@ import { languagesSchema } from "./vscode.js"
|
|||
export const DEFAULT_WRITE_DELAY_MS = 1000
|
||||
|
||||
/**
|
||||
* Default terminal output character limit constant.
|
||||
* This provides a reasonable default that aligns with typical terminal usage
|
||||
* while preventing context window explosions from extremely long lines.
|
||||
* Terminal output preview size options for persisted command output.
|
||||
*
|
||||
* Controls how much command output is kept in memory as a "preview" before
|
||||
* the LLM decides to retrieve more via `read_command_output`. Larger previews
|
||||
* mean more immediate context but consume more of the context window.
|
||||
*
|
||||
* - `small`: 5KB preview - Best for long-running commands with verbose output
|
||||
* - `medium`: 10KB preview - Balanced default for most use cases
|
||||
* - `large`: 20KB preview - Best when commands produce critical info early
|
||||
*
|
||||
* @see OutputInterceptor - Uses this setting to determine when to spill to disk
|
||||
* @see PersistedCommandOutput - Contains the resulting preview and artifact reference
|
||||
*/
|
||||
export const DEFAULT_TERMINAL_OUTPUT_CHARACTER_LIMIT = 50_000
|
||||
export type TerminalOutputPreviewSize = "small" | "medium" | "large"
|
||||
|
||||
/**
|
||||
* Byte limits for each terminal output preview size.
|
||||
*
|
||||
* Maps preview size names to their corresponding byte thresholds.
|
||||
* When command output exceeds these thresholds, the excess is persisted
|
||||
* to disk and made available via the `read_command_output` tool.
|
||||
*/
|
||||
export const TERMINAL_PREVIEW_BYTES: Record<TerminalOutputPreviewSize, number> = {
|
||||
small: 5 * 1024, // 5KB
|
||||
medium: 10 * 1024, // 10KB
|
||||
large: 20 * 1024, // 20KB
|
||||
}
|
||||
|
||||
/**
|
||||
* Default terminal output preview size.
|
||||
* The "medium" (10KB) setting provides a good balance between immediate
|
||||
* visibility and context window conservation for most use cases.
|
||||
*/
|
||||
export const DEFAULT_TERMINAL_OUTPUT_PREVIEW_SIZE: TerminalOutputPreviewSize = "medium"
|
||||
|
||||
/**
|
||||
* Minimum checkpoint timeout in seconds.
|
||||
|
|
@ -63,7 +92,6 @@ export const globalSettingsSchema = z.object({
|
|||
openRouterImageApiKey: z.string().optional(),
|
||||
openRouterImageGenerationSelectedModel: z.string().optional(),
|
||||
|
||||
condensingApiConfigId: z.string().optional(),
|
||||
customCondensingPrompt: z.string().optional(),
|
||||
|
||||
autoApprovalEnabled: z.boolean().optional(),
|
||||
|
|
@ -148,8 +176,7 @@ export const globalSettingsSchema = z.object({
|
|||
maxImageFileSize: z.number().optional(),
|
||||
maxTotalImageSize: z.number().optional(),
|
||||
|
||||
terminalOutputLineLimit: z.number().optional(),
|
||||
terminalOutputCharacterLimit: z.number().optional(),
|
||||
terminalOutputPreviewSize: z.enum(["small", "medium", "large"]).optional(),
|
||||
terminalShellIntegrationTimeout: z.number().optional(),
|
||||
terminalShellIntegrationDisabled: z.boolean().optional(),
|
||||
terminalCommandDelay: z.number().optional(),
|
||||
|
|
@ -158,13 +185,10 @@ export const globalSettingsSchema = z.object({
|
|||
terminalZshOhMy: z.boolean().optional(),
|
||||
terminalZshP10k: z.boolean().optional(),
|
||||
terminalZdotdir: z.boolean().optional(),
|
||||
terminalCompressProgressBar: z.boolean().optional(),
|
||||
|
||||
diagnosticsEnabled: z.boolean().optional(),
|
||||
|
||||
rateLimitSeconds: z.number().optional(),
|
||||
diffEnabled: z.boolean().optional(),
|
||||
fuzzyMatchThreshold: z.number().optional(),
|
||||
experiments: experimentsSchema.optional(),
|
||||
|
||||
codebaseIndexModels: codebaseIndexModelsSchema.optional(),
|
||||
|
|
@ -175,7 +199,6 @@ export const globalSettingsSchema = z.object({
|
|||
telemetrySetting: telemetrySettingsSchema.optional(),
|
||||
|
||||
mcpEnabled: z.boolean().optional(),
|
||||
enableMcpServerCreation: z.boolean().optional(),
|
||||
|
||||
mode: z.string().optional(),
|
||||
modeApiConfigs: z.record(z.string(), z.string()).optional(),
|
||||
|
|
@ -197,6 +220,20 @@ export const globalSettingsSchema = z.object({
|
|||
hasOpenedModeSelector: z.boolean().optional(),
|
||||
lastModeExportPath: z.string().optional(),
|
||||
lastModeImportPath: z.string().optional(),
|
||||
lastSettingsExportPath: z.string().optional(),
|
||||
lastTaskExportPath: z.string().optional(),
|
||||
lastImageSavePath: z.string().optional(),
|
||||
|
||||
/**
|
||||
* Path to worktree to auto-open after switching workspaces.
|
||||
* Used by the worktree feature to open the Roo Code sidebar in a new window.
|
||||
*/
|
||||
worktreeAutoOpenPath: z.string().optional(),
|
||||
/**
|
||||
* Whether to show the worktree selector in the home screen.
|
||||
* @default true
|
||||
*/
|
||||
showWorktreesInHomeScreen: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export type GlobalSettings = z.infer<typeof globalSettingsSchema>
|
||||
|
|
@ -327,8 +364,6 @@ export const EVALS_SETTINGS: RooCodeSettings = {
|
|||
soundEnabled: false,
|
||||
soundVolume: 0.5,
|
||||
|
||||
terminalOutputLineLimit: 500,
|
||||
terminalOutputCharacterLimit: DEFAULT_TERMINAL_OUTPUT_CHARACTER_LIMIT,
|
||||
terminalShellIntegrationTimeout: 30000,
|
||||
terminalCommandDelay: 0,
|
||||
terminalPowershellCounter: false,
|
||||
|
|
@ -336,14 +371,10 @@ export const EVALS_SETTINGS: RooCodeSettings = {
|
|||
terminalZshClearEolMark: true,
|
||||
terminalZshP10k: false,
|
||||
terminalZdotdir: true,
|
||||
terminalCompressProgressBar: true,
|
||||
terminalShellIntegrationDisabled: true,
|
||||
|
||||
diagnosticsEnabled: true,
|
||||
|
||||
diffEnabled: true,
|
||||
fuzzyMatchThreshold: 1,
|
||||
|
||||
enableCheckpoints: false,
|
||||
|
||||
rateLimitSeconds: 0,
|
||||
|
|
|
|||
|
|
@ -19,16 +19,6 @@ export const historyItemSchema = z.object({
|
|||
size: z.number().optional(),
|
||||
workspace: z.string().optional(),
|
||||
mode: z.string().optional(),
|
||||
/**
|
||||
* The tool protocol used by this task. Once a task uses tools with a specific
|
||||
* protocol (XML or Native), it is permanently locked to that protocol.
|
||||
*
|
||||
* - "xml": Tool calls are parsed from XML text (no tool IDs)
|
||||
* - "native": Tool calls come as tool_call chunks with IDs
|
||||
*
|
||||
* This ensures task resumption works correctly even when NTC settings change.
|
||||
*/
|
||||
toolProtocol: z.enum(["xml", "native"]).optional(),
|
||||
apiConfigName: z.string().optional(), // Provider profile name for sticky profile feature
|
||||
status: z.enum(["active", "completed", "delegated"]).optional(),
|
||||
delegatedToId: z.string().optional(), // Last child this parent delegated to
|
||||
|
|
|
|||
|
|
@ -28,5 +28,6 @@ export * from "./tool-params.js"
|
|||
export * from "./type-fu.js"
|
||||
export * from "./vscode-extension-host.js"
|
||||
export * from "./vscode.js"
|
||||
export * from "./worktree.js"
|
||||
|
||||
export * from "./providers/index.js"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { z } from "zod"
|
||||
|
||||
/**
|
||||
* Maximum number of MCP tools that can be enabled before showing a warning.
|
||||
* LLMs tend to perform poorly when given too many tools to choose from.
|
||||
*/
|
||||
export const MAX_MCP_TOOLS_THRESHOLD = 60
|
||||
|
||||
/**
|
||||
* McpServerUse
|
||||
*/
|
||||
|
|
@ -128,3 +134,53 @@ export type McpErrorEntry = {
|
|||
timestamp: number
|
||||
level: "error" | "warn" | "info"
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of counting enabled MCP tools across servers.
|
||||
*/
|
||||
export interface EnabledMcpToolsCount {
|
||||
/** Number of enabled and connected MCP servers */
|
||||
enabledServerCount: number
|
||||
/** Total number of enabled tools across all enabled servers */
|
||||
enabledToolCount: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of enabled MCP tools across all enabled and connected servers.
|
||||
* This is a pure function that can be used in both backend and frontend contexts.
|
||||
*
|
||||
* @param servers - Array of MCP server objects
|
||||
* @returns Object with enabledToolCount and enabledServerCount
|
||||
*
|
||||
* @example
|
||||
* const { enabledToolCount, enabledServerCount } = countEnabledMcpTools(mcpServers)
|
||||
* if (enabledToolCount > MAX_MCP_TOOLS_THRESHOLD) {
|
||||
* // Show warning
|
||||
* }
|
||||
*/
|
||||
export function countEnabledMcpTools(servers: McpServer[]): EnabledMcpToolsCount {
|
||||
let serverCount = 0
|
||||
let toolCount = 0
|
||||
|
||||
for (const server of servers) {
|
||||
// Skip disabled servers
|
||||
if (server.disabled) continue
|
||||
|
||||
// Skip servers that are not connected
|
||||
if (server.status !== "connected") continue
|
||||
|
||||
serverCount++
|
||||
|
||||
// Count enabled tools on this server
|
||||
if (server.tools) {
|
||||
for (const tool of server.tools) {
|
||||
// Tool is enabled if enabledForPrompt is undefined (default) or true
|
||||
if (tool.enabledForPrompt !== false) {
|
||||
toolCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { enabledToolCount: toolCount, enabledServerCount: serverCount }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ export function isNonBlockingAsk(ask: ClineAsk): ask is NonBlockingAsk {
|
|||
* - `condense_context`: Context condensation/summarization has started
|
||||
* - `condense_context_error`: Error occurred during context condensation
|
||||
* - `codebase_search_result`: Results from searching the codebase
|
||||
* - `too_many_tools_warning`: Warning that too many MCP tools are enabled, which may confuse the LLM
|
||||
*/
|
||||
export const clineSays = [
|
||||
"error",
|
||||
|
|
@ -180,6 +181,8 @@ export const clineSays = [
|
|||
"sliding_window_truncation",
|
||||
"codebase_search_result",
|
||||
"user_edit_todos",
|
||||
"too_many_tools_warning",
|
||||
"tool",
|
||||
] as const
|
||||
|
||||
export const clineSaySchema = z.enum(clineSays)
|
||||
|
|
|
|||
|
|
@ -110,10 +110,6 @@ export const modelInfoSchema = z.object({
|
|||
isStealthModel: z.boolean().optional(),
|
||||
// Flag to indicate if the model is free (no cost)
|
||||
isFree: z.boolean().optional(),
|
||||
// Flag to indicate if the model supports native tool calling (OpenAI-style function calling)
|
||||
supportsNativeTools: z.boolean().optional(),
|
||||
// Default tool protocol preferred by this model (if not specified, falls back to capability/provider defaults)
|
||||
defaultToolProtocol: z.enum(["xml", "native"]).optional(),
|
||||
// Exclude specific native tools from being available (only applies to native protocol)
|
||||
// These tools will be removed from the set of tools available to the model
|
||||
excludedTools: z.array(z.string()).optional(),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import {
|
|||
basetenModels,
|
||||
bedrockModels,
|
||||
cerebrasModels,
|
||||
claudeCodeModels,
|
||||
deepSeekModels,
|
||||
doubaoModels,
|
||||
featherlessModels,
|
||||
|
|
@ -123,7 +122,6 @@ export const providerNames = [
|
|||
"bedrock",
|
||||
"baseten",
|
||||
"cerebras",
|
||||
"claude-code",
|
||||
"doubao",
|
||||
"deepseek",
|
||||
"featherless",
|
||||
|
|
@ -170,9 +168,7 @@ export type ProviderSettingsEntry = z.infer<typeof providerSettingsEntrySchema>
|
|||
|
||||
const baseProviderSettingsSchema = z.object({
|
||||
includeMaxTokens: z.boolean().optional(),
|
||||
diffEnabled: z.boolean().optional(),
|
||||
todoListEnabled: z.boolean().optional(),
|
||||
fuzzyMatchThreshold: z.number().optional(),
|
||||
modelTemperature: z.number().nullish(),
|
||||
rateLimitSeconds: z.number().optional(),
|
||||
consecutiveMistakeLimit: z.number().min(0).optional(),
|
||||
|
|
@ -185,9 +181,6 @@ const baseProviderSettingsSchema = z.object({
|
|||
|
||||
// Model verbosity.
|
||||
verbosity: verbosityLevelsSchema.optional(),
|
||||
|
||||
// Tool protocol override for this profile.
|
||||
toolProtocol: z.enum(["xml", "native"]).optional(),
|
||||
})
|
||||
|
||||
// Several of the providers share common model config properties.
|
||||
|
|
@ -202,8 +195,6 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({
|
|||
anthropicBeta1MContext: z.boolean().optional(), // Enable 'context-1m-2025-08-07' beta for 1M context window.
|
||||
})
|
||||
|
||||
const claudeCodeSchema = apiModelIdProviderModelSchema.extend({})
|
||||
|
||||
const openRouterSchema = baseProviderSettingsSchema.extend({
|
||||
openRouterApiKey: z.string().optional(),
|
||||
openRouterModelId: z.string().optional(),
|
||||
|
|
@ -437,7 +428,6 @@ const defaultSchema = z.object({
|
|||
|
||||
export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProvider", [
|
||||
anthropicSchema.merge(z.object({ apiProvider: z.literal("anthropic") })),
|
||||
claudeCodeSchema.merge(z.object({ apiProvider: z.literal("claude-code") })),
|
||||
openRouterSchema.merge(z.object({ apiProvider: z.literal("openrouter") })),
|
||||
bedrockSchema.merge(z.object({ apiProvider: z.literal("bedrock") })),
|
||||
vertexSchema.merge(z.object({ apiProvider: z.literal("vertex") })),
|
||||
|
|
@ -479,7 +469,6 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
|
|||
export const providerSettingsSchema = z.object({
|
||||
apiProvider: providerNamesSchema.optional(),
|
||||
...anthropicSchema.shape,
|
||||
...claudeCodeSchema.shape,
|
||||
...openRouterSchema.shape,
|
||||
...bedrockSchema.shape,
|
||||
...vertexSchema.shape,
|
||||
|
|
@ -568,7 +557,6 @@ export const isTypicalProvider = (key: unknown): key is TypicalProvider =>
|
|||
|
||||
export const modelIdKeysByProvider: Record<TypicalProvider, ModelIdKey> = {
|
||||
anthropic: "apiModelId",
|
||||
"claude-code": "apiModelId",
|
||||
openrouter: "openRouterModelId",
|
||||
bedrock: "apiModelId",
|
||||
vertex: "apiModelId",
|
||||
|
|
@ -608,7 +596,7 @@ export const modelIdKeysByProvider: Record<TypicalProvider, ModelIdKey> = {
|
|||
*/
|
||||
|
||||
// Providers that use Anthropic-style API protocol.
|
||||
export const ANTHROPIC_STYLE_PROVIDERS: ProviderName[] = ["anthropic", "claude-code", "bedrock", "minimax"]
|
||||
export const ANTHROPIC_STYLE_PROVIDERS: ProviderName[] = ["anthropic", "bedrock", "minimax"]
|
||||
|
||||
export const getApiProtocol = (provider: ProviderName | undefined, modelId?: string): "anthropic" | "openai" => {
|
||||
if (provider && ANTHROPIC_STYLE_PROVIDERS.includes(provider)) {
|
||||
|
|
@ -655,7 +643,6 @@ export const MODELS_BY_PROVIDER: Record<
|
|||
label: "Cerebras",
|
||||
models: Object.keys(cerebrasModels),
|
||||
},
|
||||
"claude-code": { id: "claude-code", label: "Claude Code", models: Object.keys(claudeCodeModels) },
|
||||
deepseek: {
|
||||
id: "deepseek",
|
||||
label: "DeepSeek",
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
import { normalizeClaudeCodeModelId } from "../claude-code.js"
|
||||
|
||||
describe("normalizeClaudeCodeModelId", () => {
|
||||
test("should return valid model IDs unchanged", () => {
|
||||
expect(normalizeClaudeCodeModelId("claude-sonnet-4-5")).toBe("claude-sonnet-4-5")
|
||||
expect(normalizeClaudeCodeModelId("claude-opus-4-5")).toBe("claude-opus-4-5")
|
||||
expect(normalizeClaudeCodeModelId("claude-haiku-4-5")).toBe("claude-haiku-4-5")
|
||||
})
|
||||
|
||||
test("should normalize sonnet models with date suffix to claude-sonnet-4-5", () => {
|
||||
// Sonnet 4.5 with date
|
||||
expect(normalizeClaudeCodeModelId("claude-sonnet-4-5-20250929")).toBe("claude-sonnet-4-5")
|
||||
// Sonnet 4 (legacy)
|
||||
expect(normalizeClaudeCodeModelId("claude-sonnet-4-20250514")).toBe("claude-sonnet-4-5")
|
||||
// Claude 3.7 Sonnet
|
||||
expect(normalizeClaudeCodeModelId("claude-3-7-sonnet-20250219")).toBe("claude-sonnet-4-5")
|
||||
// Claude 3.5 Sonnet
|
||||
expect(normalizeClaudeCodeModelId("claude-3-5-sonnet-20241022")).toBe("claude-sonnet-4-5")
|
||||
})
|
||||
|
||||
test("should normalize opus models with date suffix to claude-opus-4-5", () => {
|
||||
// Opus 4.5 with date
|
||||
expect(normalizeClaudeCodeModelId("claude-opus-4-5-20251101")).toBe("claude-opus-4-5")
|
||||
// Opus 4.1 (legacy)
|
||||
expect(normalizeClaudeCodeModelId("claude-opus-4-1-20250805")).toBe("claude-opus-4-5")
|
||||
// Opus 4 (legacy)
|
||||
expect(normalizeClaudeCodeModelId("claude-opus-4-20250514")).toBe("claude-opus-4-5")
|
||||
})
|
||||
|
||||
test("should normalize haiku models with date suffix to claude-haiku-4-5", () => {
|
||||
// Haiku 4.5 with date
|
||||
expect(normalizeClaudeCodeModelId("claude-haiku-4-5-20251001")).toBe("claude-haiku-4-5")
|
||||
// Claude 3.5 Haiku
|
||||
expect(normalizeClaudeCodeModelId("claude-3-5-haiku-20241022")).toBe("claude-haiku-4-5")
|
||||
})
|
||||
|
||||
test("should handle case-insensitive model family matching", () => {
|
||||
expect(normalizeClaudeCodeModelId("Claude-Sonnet-4-5-20250929")).toBe("claude-sonnet-4-5")
|
||||
expect(normalizeClaudeCodeModelId("CLAUDE-OPUS-4-5-20251101")).toBe("claude-opus-4-5")
|
||||
})
|
||||
|
||||
test("should fallback to default for unrecognized models", () => {
|
||||
expect(normalizeClaudeCodeModelId("unknown-model")).toBe("claude-sonnet-4-5")
|
||||
expect(normalizeClaudeCodeModelId("gpt-4")).toBe("claude-sonnet-4-5")
|
||||
})
|
||||
})
|
||||
|
|
@ -11,8 +11,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0, // $3 per million input tokens (≤200K context)
|
||||
outputPrice: 15.0, // $15 per million output tokens (≤200K context)
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
|
|
@ -34,8 +32,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0, // $3 per million input tokens (≤200K context)
|
||||
outputPrice: 15.0, // $15 per million output tokens (≤200K context)
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
|
|
@ -57,8 +53,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 5.0, // $5 per million input tokens
|
||||
outputPrice: 25.0, // $25 per million output tokens
|
||||
cacheWritesPrice: 6.25, // $6.25 per million tokens
|
||||
|
|
@ -70,8 +64,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0, // $15 per million input tokens
|
||||
outputPrice: 75.0, // $75 per million output tokens
|
||||
cacheWritesPrice: 18.75, // $18.75 per million tokens
|
||||
|
|
@ -83,8 +75,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0, // $15 per million input tokens
|
||||
outputPrice: 75.0, // $75 per million output tokens
|
||||
cacheWritesPrice: 18.75, // $18.75 per million tokens
|
||||
|
|
@ -96,8 +86,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0, // $3 per million input tokens
|
||||
outputPrice: 15.0, // $15 per million output tokens
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
|
|
@ -110,8 +98,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0, // $3 per million input tokens
|
||||
outputPrice: 15.0, // $15 per million output tokens
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
|
|
@ -122,8 +108,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0, // $3 per million input tokens
|
||||
outputPrice: 15.0, // $15 per million output tokens
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
|
|
@ -134,8 +118,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 5.0,
|
||||
cacheWritesPrice: 1.25,
|
||||
|
|
@ -146,8 +128,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
|
|
@ -158,8 +138,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.25,
|
||||
outputPrice: 1.25,
|
||||
cacheWritesPrice: 0.3,
|
||||
|
|
@ -170,8 +148,6 @@ export const anthropicModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 5.0,
|
||||
cacheWritesPrice: 1.25,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ export const basetenModels = {
|
|||
contextWindow: 262_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -21,7 +20,6 @@ export const basetenModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.2,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -33,7 +31,6 @@ export const basetenModels = {
|
|||
contextWindow: 163_840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 2.55,
|
||||
outputPrice: 5.95,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -45,7 +42,6 @@ export const basetenModels = {
|
|||
contextWindow: 163_840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 2.55,
|
||||
outputPrice: 5.95,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -57,7 +53,6 @@ export const basetenModels = {
|
|||
contextWindow: 163_840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.77,
|
||||
outputPrice: 0.77,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -69,7 +64,6 @@ export const basetenModels = {
|
|||
contextWindow: 163_840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.5,
|
||||
outputPrice: 1.5,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -82,7 +76,6 @@ export const basetenModels = {
|
|||
contextWindow: 163_840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 0.45,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -95,7 +88,6 @@ export const basetenModels = {
|
|||
contextWindow: 128_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.5,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -107,7 +99,6 @@ export const basetenModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.22,
|
||||
outputPrice: 0.8,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -119,7 +110,6 @@ export const basetenModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.38,
|
||||
outputPrice: 1.53,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -131,7 +121,6 @@ export const basetenModels = {
|
|||
contextWindow: 262_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ export const bedrockModels = {
|
|||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -34,7 +32,6 @@ export const bedrockModels = {
|
|||
contextWindow: 300_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.8,
|
||||
outputPrice: 3.2,
|
||||
cacheWritesPrice: 0.8, // per million tokens
|
||||
|
|
@ -48,7 +45,6 @@ export const bedrockModels = {
|
|||
contextWindow: 300_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 4.0,
|
||||
cacheWritesPrice: 1.0, // per million tokens
|
||||
|
|
@ -60,7 +56,6 @@ export const bedrockModels = {
|
|||
contextWindow: 300_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.06,
|
||||
outputPrice: 0.24,
|
||||
cacheWritesPrice: 0.06, // per million tokens
|
||||
|
|
@ -74,7 +69,6 @@ export const bedrockModels = {
|
|||
contextWindow: 1_000_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.33,
|
||||
outputPrice: 2.75,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -89,7 +83,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.035,
|
||||
outputPrice: 0.14,
|
||||
cacheWritesPrice: 0.035, // per million tokens
|
||||
|
|
@ -104,8 +97,6 @@ export const bedrockModels = {
|
|||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -120,8 +111,6 @@ export const bedrockModels = {
|
|||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
|
|
@ -136,8 +125,6 @@ export const bedrockModels = {
|
|||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 5.0,
|
||||
outputPrice: 25.0,
|
||||
cacheWritesPrice: 6.25,
|
||||
|
|
@ -152,8 +139,6 @@ export const bedrockModels = {
|
|||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
|
|
@ -168,8 +153,6 @@ export const bedrockModels = {
|
|||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -183,8 +166,6 @@ export const bedrockModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -198,8 +179,6 @@ export const bedrockModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.8,
|
||||
outputPrice: 4.0,
|
||||
cacheWritesPrice: 1.0,
|
||||
|
|
@ -214,8 +193,6 @@ export const bedrockModels = {
|
|||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 5.0,
|
||||
cacheWritesPrice: 1.25, // 5m cache writes
|
||||
|
|
@ -229,8 +206,6 @@ export const bedrockModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
},
|
||||
|
|
@ -239,8 +214,6 @@ export const bedrockModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
},
|
||||
|
|
@ -249,8 +222,6 @@ export const bedrockModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
},
|
||||
|
|
@ -259,8 +230,6 @@ export const bedrockModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.25,
|
||||
outputPrice: 1.25,
|
||||
},
|
||||
|
|
@ -269,7 +238,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 1.35,
|
||||
outputPrice: 5.4,
|
||||
},
|
||||
|
|
@ -278,7 +246,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.5,
|
||||
outputPrice: 1.5,
|
||||
description: "GPT-OSS 20B - Optimized for low latency and local/specialized use cases",
|
||||
|
|
@ -288,7 +255,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 2.0,
|
||||
outputPrice: 6.0,
|
||||
description: "GPT-OSS 120B - Production-ready, general-purpose, high-reasoning model",
|
||||
|
|
@ -298,7 +264,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.72,
|
||||
outputPrice: 0.72,
|
||||
description: "Llama 3.3 Instruct (70B)",
|
||||
|
|
@ -308,7 +273,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.72,
|
||||
outputPrice: 0.72,
|
||||
description: "Llama 3.2 Instruct (90B)",
|
||||
|
|
@ -318,7 +282,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.16,
|
||||
outputPrice: 0.16,
|
||||
description: "Llama 3.2 Instruct (11B)",
|
||||
|
|
@ -328,7 +291,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.15,
|
||||
description: "Llama 3.2 Instruct (3B)",
|
||||
|
|
@ -338,7 +300,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.1,
|
||||
description: "Llama 3.2 Instruct (1B)",
|
||||
|
|
@ -348,7 +309,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 2.4,
|
||||
outputPrice: 2.4,
|
||||
description: "Llama 3.1 Instruct (405B)",
|
||||
|
|
@ -358,7 +318,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.72,
|
||||
outputPrice: 0.72,
|
||||
description: "Llama 3.1 Instruct (70B)",
|
||||
|
|
@ -368,7 +327,6 @@ export const bedrockModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.9,
|
||||
outputPrice: 0.9,
|
||||
description: "Llama 3.1 Instruct (70B) (w/ latency optimized inference)",
|
||||
|
|
@ -378,7 +336,6 @@ export const bedrockModels = {
|
|||
contextWindow: 8_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.22,
|
||||
outputPrice: 0.22,
|
||||
description: "Llama 3.1 Instruct (8B)",
|
||||
|
|
@ -388,7 +345,6 @@ export const bedrockModels = {
|
|||
contextWindow: 8_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 2.65,
|
||||
outputPrice: 3.5,
|
||||
},
|
||||
|
|
@ -397,7 +353,6 @@ export const bedrockModels = {
|
|||
contextWindow: 4_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 0.6,
|
||||
},
|
||||
|
|
@ -406,7 +361,6 @@ export const bedrockModels = {
|
|||
contextWindow: 8_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.2,
|
||||
description: "Amazon Titan Text Lite",
|
||||
|
|
@ -416,7 +370,6 @@ export const bedrockModels = {
|
|||
contextWindow: 8_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 0.6,
|
||||
description: "Amazon Titan Text Express",
|
||||
|
|
@ -426,8 +379,6 @@ export const bedrockModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
preserveReasoning: true,
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
|
|
@ -438,8 +389,6 @@ export const bedrockModels = {
|
|||
contextWindow: 196_608,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
preserveReasoning: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 1.2,
|
||||
|
|
@ -450,8 +399,6 @@ export const bedrockModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 1.2,
|
||||
description: "Qwen3 Next 80B (MoE model with 3B active parameters)",
|
||||
|
|
@ -461,8 +408,6 @@ export const bedrockModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.45,
|
||||
outputPrice: 1.8,
|
||||
description: "Qwen3 Coder 480B (MoE model with 35B active parameters)",
|
||||
|
|
|
|||
|
|
@ -6,24 +6,13 @@ export type CerebrasModelId = keyof typeof cerebrasModels
|
|||
export const cerebrasDefaultModelId: CerebrasModelId = "gpt-oss-120b"
|
||||
|
||||
export const cerebrasModels = {
|
||||
"zai-glm-4.6": {
|
||||
maxTokens: 16384, // Conservative default to avoid premature rate limiting (Cerebras reserves quota upfront)
|
||||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Fast general-purpose model on Cerebras (up to 1,000 tokens/s). To be deprecated soon.",
|
||||
},
|
||||
"zai-glm-4.7": {
|
||||
maxTokens: 16384, // Conservative default to avoid premature rate limiting (Cerebras reserves quota upfront)
|
||||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1.0,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
@ -34,8 +23,6 @@ export const cerebrasModels = {
|
|||
contextWindow: 64000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Intelligent model with ~1400 tokens/s",
|
||||
|
|
@ -45,8 +32,6 @@ export const cerebrasModels = {
|
|||
contextWindow: 64000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Powerful model with ~2600 tokens/s",
|
||||
|
|
@ -56,8 +41,6 @@ export const cerebrasModels = {
|
|||
contextWindow: 64000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "SOTA coding performance with ~2500 tokens/s",
|
||||
|
|
@ -67,8 +50,6 @@ export const cerebrasModels = {
|
|||
contextWindow: 64000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -51,8 +51,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek R1 0528 model.",
|
||||
|
|
@ -62,8 +60,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek R1 model.",
|
||||
|
|
@ -73,8 +69,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek V3 model.",
|
||||
|
|
@ -84,8 +78,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek V3.1 model.",
|
||||
|
|
@ -95,8 +87,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.23,
|
||||
outputPrice: 0.9,
|
||||
description:
|
||||
|
|
@ -107,8 +97,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 3.0,
|
||||
description:
|
||||
|
|
@ -119,8 +107,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.25,
|
||||
outputPrice: 0.35,
|
||||
description:
|
||||
|
|
@ -131,8 +117,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072, // From Groq
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Unsloth Llama 3.3 70B Instruct model.",
|
||||
|
|
@ -142,8 +126,6 @@ export const chutesModels = {
|
|||
contextWindow: 512000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "ChutesAI Llama 4 Scout 17B Instruct model, 512K context.",
|
||||
|
|
@ -153,8 +135,6 @@ export const chutesModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Unsloth Mistral Nemo Instruct model.",
|
||||
|
|
@ -164,8 +144,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Unsloth Gemma 3 12B IT model.",
|
||||
|
|
@ -175,8 +153,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Nous DeepHermes 3 Llama 3 8B Preview model.",
|
||||
|
|
@ -186,8 +162,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Unsloth Gemma 3 4B IT model.",
|
||||
|
|
@ -197,8 +171,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Nvidia Llama 3.3 Nemotron Super 49B model.",
|
||||
|
|
@ -208,8 +180,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Nvidia Llama 3.1 Nemotron Ultra 253B model.",
|
||||
|
|
@ -219,8 +189,6 @@ export const chutesModels = {
|
|||
contextWindow: 256000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "ChutesAI Llama 4 Maverick 17B Instruct FP8 model.",
|
||||
|
|
@ -230,8 +198,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek V3 Base model.",
|
||||
|
|
@ -241,8 +207,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek R1 Zero model.",
|
||||
|
|
@ -252,8 +216,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek V3 (0324) model.",
|
||||
|
|
@ -263,8 +225,6 @@ export const chutesModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 235B A22B Instruct 2507 model with 262K context window.",
|
||||
|
|
@ -274,8 +234,6 @@ export const chutesModels = {
|
|||
contextWindow: 40960,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 235B A22B model.",
|
||||
|
|
@ -285,8 +243,6 @@ export const chutesModels = {
|
|||
contextWindow: 40960,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 32B model.",
|
||||
|
|
@ -296,8 +252,6 @@ export const chutesModels = {
|
|||
contextWindow: 40960,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 30B A3B model.",
|
||||
|
|
@ -307,8 +261,6 @@ export const chutesModels = {
|
|||
contextWindow: 40960,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 14B model.",
|
||||
|
|
@ -318,8 +270,6 @@ export const chutesModels = {
|
|||
contextWindow: 40960,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 8B model.",
|
||||
|
|
@ -329,8 +279,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Microsoft MAI-DS-R1 FP8 model.",
|
||||
|
|
@ -340,8 +288,6 @@ export const chutesModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "TNGTech DeepSeek R1T Chimera model.",
|
||||
|
|
@ -351,8 +297,6 @@ export const chutesModels = {
|
|||
contextWindow: 151329,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
@ -363,8 +307,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
@ -375,8 +317,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1,
|
||||
outputPrice: 3,
|
||||
description: "GLM-4.5-turbo model with 128K token context window, optimized for fast inference.",
|
||||
|
|
@ -386,8 +326,6 @@ export const chutesModels = {
|
|||
contextWindow: 202752,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
@ -398,8 +336,6 @@ export const chutesModels = {
|
|||
contextWindow: 202752,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.15,
|
||||
outputPrice: 3.25,
|
||||
description: "GLM-4.6-turbo model with 200K-token context window, optimized for fast inference.",
|
||||
|
|
@ -409,8 +345,6 @@ export const chutesModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
@ -421,8 +355,6 @@ export const chutesModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 Coder 480B A35B Instruct FP8 model, optimized for coding tasks.",
|
||||
|
|
@ -432,8 +364,6 @@ export const chutesModels = {
|
|||
contextWindow: 75000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1481,
|
||||
outputPrice: 0.5926,
|
||||
description: "Moonshot AI Kimi K2 Instruct model with 75k context window.",
|
||||
|
|
@ -443,8 +373,6 @@ export const chutesModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1999,
|
||||
outputPrice: 0.8001,
|
||||
description: "Moonshot AI Kimi K2 Instruct 0905 model with 256k context window.",
|
||||
|
|
@ -454,8 +382,6 @@ export const chutesModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.077968332,
|
||||
outputPrice: 0.31202496,
|
||||
description: "Qwen3 235B A22B Thinking 2507 model with 262K context window.",
|
||||
|
|
@ -465,8 +391,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
@ -477,8 +401,6 @@ export const chutesModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description:
|
||||
|
|
@ -489,8 +411,6 @@ export const chutesModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.16,
|
||||
outputPrice: 0.65,
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -1,160 +0,0 @@
|
|||
import type { ModelInfo } from "../model.js"
|
||||
|
||||
/**
|
||||
* Rate limit information from Claude Code API
|
||||
*/
|
||||
export interface ClaudeCodeRateLimitInfo {
|
||||
// 5-hour limit info
|
||||
fiveHour: {
|
||||
status: string
|
||||
utilization: number
|
||||
resetTime: number // Unix timestamp
|
||||
}
|
||||
// 7-day (weekly) limit info (Sonnet-specific)
|
||||
weekly?: {
|
||||
status: string
|
||||
utilization: number
|
||||
resetTime: number // Unix timestamp
|
||||
}
|
||||
// 7-day unified limit info
|
||||
weeklyUnified?: {
|
||||
status: string
|
||||
utilization: number
|
||||
resetTime: number // Unix timestamp
|
||||
}
|
||||
// Representative claim type
|
||||
representativeClaim?: string
|
||||
// Overage status
|
||||
overage?: {
|
||||
status: string
|
||||
disabledReason?: string
|
||||
}
|
||||
// Fallback percentage
|
||||
fallbackPercentage?: number
|
||||
// Organization ID
|
||||
organizationId?: string
|
||||
// Timestamp when this was fetched
|
||||
fetchedAt: number
|
||||
}
|
||||
|
||||
// Regex pattern to strip date suffix from model names
|
||||
const DATE_SUFFIX_PATTERN = /-\d{8}$/
|
||||
|
||||
// Models that work with Claude Code OAuth tokens
|
||||
// See: https://docs.anthropic.com/en/docs/claude-code
|
||||
// NOTE: Claude Code is subscription-based with no per-token cost - pricing fields are 0
|
||||
export const claudeCodeModels = {
|
||||
"claude-haiku-4-5": {
|
||||
maxTokens: 32768,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsReasoningEffort: ["disable", "low", "medium", "high"],
|
||||
reasoningEffort: "medium",
|
||||
description: "Claude Haiku 4.5 - Fast and efficient with thinking",
|
||||
},
|
||||
"claude-sonnet-4-5": {
|
||||
maxTokens: 32768,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsReasoningEffort: ["disable", "low", "medium", "high"],
|
||||
reasoningEffort: "medium",
|
||||
description: "Claude Sonnet 4.5 - Balanced performance with thinking",
|
||||
},
|
||||
"claude-opus-4-5": {
|
||||
maxTokens: 32768,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsReasoningEffort: ["disable", "low", "medium", "high"],
|
||||
reasoningEffort: "medium",
|
||||
description: "Claude Opus 4.5 - Most capable with thinking",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
||||
// Claude Code - Only models that work with Claude Code OAuth tokens
|
||||
export type ClaudeCodeModelId = keyof typeof claudeCodeModels
|
||||
export const claudeCodeDefaultModelId: ClaudeCodeModelId = "claude-sonnet-4-5"
|
||||
|
||||
/**
|
||||
* Model family patterns for normalization.
|
||||
* Maps regex patterns to their canonical Claude Code model IDs.
|
||||
*
|
||||
* Order matters - more specific patterns should come first.
|
||||
*/
|
||||
const MODEL_FAMILY_PATTERNS: Array<{ pattern: RegExp; target: ClaudeCodeModelId }> = [
|
||||
// Opus models (any version) → claude-opus-4-5
|
||||
{ pattern: /opus/i, target: "claude-opus-4-5" },
|
||||
// Haiku models (any version) → claude-haiku-4-5
|
||||
{ pattern: /haiku/i, target: "claude-haiku-4-5" },
|
||||
// Sonnet models (any version) → claude-sonnet-4-5
|
||||
{ pattern: /sonnet/i, target: "claude-sonnet-4-5" },
|
||||
]
|
||||
|
||||
/**
|
||||
* Normalizes a Claude model ID to a valid Claude Code model ID.
|
||||
*
|
||||
* This function handles backward compatibility for legacy model names
|
||||
* that may include version numbers or date suffixes. It maps:
|
||||
* - claude-sonnet-4-5-20250929, claude-sonnet-4-20250514, claude-3-7-sonnet-20250219, claude-3-5-sonnet-20241022 → claude-sonnet-4-5
|
||||
* - claude-opus-4-5-20251101, claude-opus-4-1-20250805, claude-opus-4-20250514 → claude-opus-4-5
|
||||
* - claude-haiku-4-5-20251001, claude-3-5-haiku-20241022 → claude-haiku-4-5
|
||||
*
|
||||
* @param modelId - The model ID to normalize (may be a legacy format)
|
||||
* @returns A valid ClaudeCodeModelId, or the original ID if already valid
|
||||
*
|
||||
* @example
|
||||
* normalizeClaudeCodeModelId("claude-sonnet-4-5") // returns "claude-sonnet-4-5"
|
||||
* normalizeClaudeCodeModelId("claude-3-5-sonnet-20241022") // returns "claude-sonnet-4-5"
|
||||
* normalizeClaudeCodeModelId("claude-opus-4-1-20250805") // returns "claude-opus-4-5"
|
||||
*/
|
||||
export function normalizeClaudeCodeModelId(modelId: string): ClaudeCodeModelId {
|
||||
// If already a valid model ID, return as-is
|
||||
// Use Object.hasOwn() instead of 'in' operator to avoid matching inherited properties like 'toString'
|
||||
if (Object.hasOwn(claudeCodeModels, modelId)) {
|
||||
return modelId as ClaudeCodeModelId
|
||||
}
|
||||
|
||||
// Strip date suffix if present (e.g., -20250514)
|
||||
const withoutDate = modelId.replace(DATE_SUFFIX_PATTERN, "")
|
||||
|
||||
// Check if stripping the date makes it valid
|
||||
if (Object.hasOwn(claudeCodeModels, withoutDate)) {
|
||||
return withoutDate as ClaudeCodeModelId
|
||||
}
|
||||
|
||||
// Match by model family
|
||||
for (const { pattern, target } of MODEL_FAMILY_PATTERNS) {
|
||||
if (pattern.test(modelId)) {
|
||||
return target
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to default if no match (shouldn't happen with valid Claude models)
|
||||
return claudeCodeDefaultModelId
|
||||
}
|
||||
|
||||
/**
|
||||
* Reasoning effort configuration for Claude Code thinking mode.
|
||||
* Maps reasoning effort level to budget_tokens for the thinking process.
|
||||
*
|
||||
* Note: With interleaved thinking (enabled via beta header), budget_tokens
|
||||
* can exceed max_tokens as the token limit becomes the entire context window.
|
||||
* The max_tokens is drawn from the model's maxTokens definition.
|
||||
*
|
||||
* @see https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#interleaved-thinking
|
||||
*/
|
||||
export const claudeCodeReasoningConfig = {
|
||||
low: { budgetTokens: 16_000 },
|
||||
medium: { budgetTokens: 32_000 },
|
||||
high: { budgetTokens: 64_000 },
|
||||
} as const
|
||||
|
||||
export type ClaudeCodeReasoningLevel = keyof typeof claudeCodeReasoningConfig
|
||||
|
|
@ -8,7 +8,6 @@ export const deepInfraDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 1.2,
|
||||
description: "Qwen 3 Coder 480B A35B Instruct Turbo model, 256K context.",
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ export const deepSeekModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.28, // $0.28 per million tokens (cache miss) - Updated Dec 9, 2025
|
||||
outputPrice: 0.42, // $0.42 per million tokens - Updated Dec 9, 2025
|
||||
cacheWritesPrice: 0.28, // $0.28 per million tokens (cache miss) - Updated Dec 9, 2025
|
||||
|
|
@ -27,8 +25,6 @@ export const deepSeekModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
preserveReasoning: true,
|
||||
inputPrice: 0.28, // $0.28 per million tokens (cache miss) - Updated Dec 9, 2025
|
||||
outputPrice: 0.42, // $0.42 per million tokens - Updated Dec 9, 2025
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ export const doubaoModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.0001, // $0.0001 per million tokens (cache miss)
|
||||
outputPrice: 0.0004, // $0.0004 per million tokens
|
||||
cacheWritesPrice: 0.0001, // $0.0001 per million tokens (cache miss)
|
||||
|
|
@ -21,8 +19,6 @@ export const doubaoModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.0002, // $0.0002 per million tokens
|
||||
outputPrice: 0.0008, // $0.0008 per million tokens
|
||||
cacheWritesPrice: 0.0002, // $0.0002 per million
|
||||
|
|
@ -34,8 +30,6 @@ export const doubaoModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.00015, // $0.00015 per million tokens
|
||||
outputPrice: 0.0006, // $0.0006 per million tokens
|
||||
cacheWritesPrice: 0.00015, // $0.00015 per million
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ export const featherlessModels = {
|
|||
contextWindow: 32678,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek V3 0324 model.",
|
||||
|
|
@ -23,7 +22,6 @@ export const featherlessModels = {
|
|||
contextWindow: 32678,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "DeepSeek R1 0528 model.",
|
||||
|
|
@ -33,7 +31,6 @@ export const featherlessModels = {
|
|||
contextWindow: 32678,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Kimi K2 Instruct model.",
|
||||
|
|
@ -43,7 +40,6 @@ export const featherlessModels = {
|
|||
contextWindow: 32678,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "GPT-OSS 120B model.",
|
||||
|
|
@ -53,7 +49,6 @@ export const featherlessModels = {
|
|||
contextWindow: 32678,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
description: "Qwen3 Coder 480B A35B Instruct model.",
|
||||
|
|
|
|||
|
|
@ -5,16 +5,22 @@ export type FireworksModelId =
|
|||
| "accounts/fireworks/models/kimi-k2-instruct-0905"
|
||||
| "accounts/fireworks/models/kimi-k2-thinking"
|
||||
| "accounts/fireworks/models/minimax-m2"
|
||||
| "accounts/fireworks/models/minimax-m2p1"
|
||||
| "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507"
|
||||
| "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct"
|
||||
| "accounts/fireworks/models/deepseek-r1-0528"
|
||||
| "accounts/fireworks/models/deepseek-v3"
|
||||
| "accounts/fireworks/models/deepseek-v3p1"
|
||||
| "accounts/fireworks/models/deepseek-v3p2"
|
||||
| "accounts/fireworks/models/glm-4p5"
|
||||
| "accounts/fireworks/models/glm-4p5-air"
|
||||
| "accounts/fireworks/models/glm-4p6"
|
||||
| "accounts/fireworks/models/glm-4p7"
|
||||
| "accounts/fireworks/models/gpt-oss-20b"
|
||||
| "accounts/fireworks/models/gpt-oss-120b"
|
||||
| "accounts/fireworks/models/llama-v3p3-70b-instruct"
|
||||
| "accounts/fireworks/models/llama4-maverick-instruct-basic"
|
||||
| "accounts/fireworks/models/llama4-scout-instruct-basic"
|
||||
|
||||
export const fireworksDefaultModelId: FireworksModelId = "accounts/fireworks/models/kimi-k2-instruct-0905"
|
||||
|
||||
|
|
@ -24,8 +30,6 @@ export const fireworksModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.15,
|
||||
|
|
@ -37,8 +41,6 @@ export const fireworksModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
description:
|
||||
|
|
@ -49,7 +51,6 @@ export const fireworksModels = {
|
|||
contextWindow: 256000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
supportsTemperature: true,
|
||||
preserveReasoning: true,
|
||||
defaultTemperature: 1.0,
|
||||
|
|
@ -64,8 +65,6 @@ export const fireworksModels = {
|
|||
contextWindow: 204800,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 1.2,
|
||||
description:
|
||||
|
|
@ -76,8 +75,6 @@ export const fireworksModels = {
|
|||
contextWindow: 256000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.22,
|
||||
outputPrice: 0.88,
|
||||
description: "Latest Qwen3 thinking model, competitive against the best closed source models in Jul 2025.",
|
||||
|
|
@ -87,8 +84,6 @@ export const fireworksModels = {
|
|||
contextWindow: 256000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.45,
|
||||
outputPrice: 1.8,
|
||||
description: "Qwen3's most agentic code model to date.",
|
||||
|
|
@ -98,8 +93,6 @@ export const fireworksModels = {
|
|||
contextWindow: 160000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3,
|
||||
outputPrice: 8,
|
||||
description:
|
||||
|
|
@ -110,8 +103,6 @@ export const fireworksModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.9,
|
||||
outputPrice: 0.9,
|
||||
description:
|
||||
|
|
@ -122,8 +113,6 @@ export const fireworksModels = {
|
|||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.56,
|
||||
outputPrice: 1.68,
|
||||
description:
|
||||
|
|
@ -134,8 +123,6 @@ export const fireworksModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.55,
|
||||
outputPrice: 2.19,
|
||||
description:
|
||||
|
|
@ -146,8 +133,6 @@ export const fireworksModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.55,
|
||||
outputPrice: 2.19,
|
||||
description:
|
||||
|
|
@ -158,8 +143,6 @@ export const fireworksModels = {
|
|||
contextWindow: 198000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.55,
|
||||
outputPrice: 2.19,
|
||||
description:
|
||||
|
|
@ -170,8 +153,6 @@ export const fireworksModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.07,
|
||||
outputPrice: 0.3,
|
||||
description:
|
||||
|
|
@ -182,11 +163,69 @@ export const fireworksModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
description:
|
||||
"OpenAI gpt-oss-120b: Production-grade, general-purpose model that fits on a single H100 GPU. Features complex reasoning, configurable effort, full chain-of-thought transparency, and supports function calling, tool use, and structured outputs.",
|
||||
},
|
||||
"accounts/fireworks/models/minimax-m2p1": {
|
||||
maxTokens: 4096,
|
||||
contextWindow: 204800,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 1.2,
|
||||
description:
|
||||
"MiniMax M2.1 is an upgraded version of M2 with improved performance on complex reasoning, coding, and long-context understanding tasks.",
|
||||
},
|
||||
"accounts/fireworks/models/deepseek-v3p2": {
|
||||
maxTokens: 16384,
|
||||
contextWindow: 163840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.56,
|
||||
outputPrice: 1.68,
|
||||
description:
|
||||
"DeepSeek V3.2 is the latest iteration of the V3 model family with enhanced reasoning capabilities, improved code generation, and better instruction following.",
|
||||
},
|
||||
"accounts/fireworks/models/glm-4p7": {
|
||||
maxTokens: 25344,
|
||||
contextWindow: 198000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.55,
|
||||
outputPrice: 2.19,
|
||||
description:
|
||||
"Z.ai GLM-4.7 is the latest coding model with exceptional performance on complex programming tasks. Features improved reasoning capabilities and enhanced code generation quality.",
|
||||
},
|
||||
"accounts/fireworks/models/llama-v3p3-70b-instruct": {
|
||||
maxTokens: 16384,
|
||||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.9,
|
||||
outputPrice: 0.9,
|
||||
description:
|
||||
"Meta Llama 3.3 70B Instruct is a highly capable instruction-tuned model with strong reasoning, coding, and general task performance.",
|
||||
},
|
||||
"accounts/fireworks/models/llama4-maverick-instruct-basic": {
|
||||
maxTokens: 16384,
|
||||
contextWindow: 131072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.22,
|
||||
outputPrice: 0.88,
|
||||
description:
|
||||
"Llama 4 Maverick is Meta's latest multimodal model with vision capabilities, optimized for instruction following and coding tasks.",
|
||||
},
|
||||
"accounts/fireworks/models/llama4-scout-instruct-basic": {
|
||||
maxTokens: 16384,
|
||||
contextWindow: 131072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
description:
|
||||
"Llama 4 Scout is a smaller, faster variant of Llama 4 with multimodal capabilities, ideal for quick iterations and cost-effective deployments.",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["low", "high"],
|
||||
reasoningEffort: "low",
|
||||
|
|
@ -20,16 +18,19 @@ export const geminiModels = {
|
|||
defaultTemperature: 1,
|
||||
inputPrice: 4.0,
|
||||
outputPrice: 18.0,
|
||||
cacheReadsPrice: 0.4,
|
||||
tiers: [
|
||||
{
|
||||
contextWindow: 200_000,
|
||||
inputPrice: 2.0,
|
||||
outputPrice: 12.0,
|
||||
cacheReadsPrice: 0.2,
|
||||
},
|
||||
{
|
||||
contextWindow: Infinity,
|
||||
inputPrice: 4.0,
|
||||
outputPrice: 18.0,
|
||||
cacheReadsPrice: 0.4,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -37,26 +38,21 @@ export const geminiModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
reasoningEffort: "medium",
|
||||
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.075,
|
||||
cacheWritesPrice: 1.0,
|
||||
inputPrice: 0.5,
|
||||
outputPrice: 3.0,
|
||||
cacheReadsPrice: 0.05,
|
||||
},
|
||||
// 2.5 Pro models
|
||||
"gemini-2.5-pro": {
|
||||
maxTokens: 64_000,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
|
|
@ -85,8 +81,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
|
|
@ -114,8 +108,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
|
|
@ -141,8 +133,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
|
|
@ -172,8 +162,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.3,
|
||||
|
|
@ -187,8 +175,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.3,
|
||||
|
|
@ -202,8 +188,6 @@ export const geminiModels = {
|
|||
maxTokens: 64_000,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.3,
|
||||
|
|
@ -219,8 +203,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.1,
|
||||
|
|
@ -234,8 +216,6 @@ export const geminiModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.1,
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ export const groqModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.05,
|
||||
outputPrice: 0.08,
|
||||
description: "Meta Llama 3.1 8B Instant model, 128K context.",
|
||||
|
|
@ -30,8 +28,6 @@ export const groqModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.59,
|
||||
outputPrice: 0.79,
|
||||
description: "Meta Llama 3.3 70B Versatile model, 128K context.",
|
||||
|
|
@ -41,8 +37,6 @@ export const groqModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.11,
|
||||
outputPrice: 0.34,
|
||||
description: "Meta Llama 4 Scout 17B Instruct model, 128K context.",
|
||||
|
|
@ -52,8 +46,6 @@ export const groqModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.29,
|
||||
outputPrice: 0.59,
|
||||
description: "Alibaba Qwen 3 32B model, 128K context.",
|
||||
|
|
@ -63,8 +55,6 @@ export const groqModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.15,
|
||||
|
|
@ -76,8 +66,6 @@ export const groqModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.75,
|
||||
description:
|
||||
|
|
@ -88,8 +76,6 @@ export const groqModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.5,
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ export * from "./baseten.js"
|
|||
export * from "./bedrock.js"
|
||||
export * from "./cerebras.js"
|
||||
export * from "./chutes.js"
|
||||
export * from "./claude-code.js"
|
||||
export * from "./deepseek.js"
|
||||
export * from "./doubao.js"
|
||||
export * from "./featherless.js"
|
||||
|
|
@ -19,6 +18,7 @@ export * from "./moonshot.js"
|
|||
export * from "./ollama.js"
|
||||
export * from "./openai.js"
|
||||
export * from "./openai-codex.js"
|
||||
export * from "./openai-codex-rate-limits.js"
|
||||
export * from "./openrouter.js"
|
||||
export * from "./qwen-code.js"
|
||||
export * from "./requesty.js"
|
||||
|
|
@ -38,7 +38,6 @@ import { basetenDefaultModelId } from "./baseten.js"
|
|||
import { bedrockDefaultModelId } from "./bedrock.js"
|
||||
import { cerebrasDefaultModelId } from "./cerebras.js"
|
||||
import { chutesDefaultModelId } from "./chutes.js"
|
||||
import { claudeCodeDefaultModelId } from "./claude-code.js"
|
||||
import { deepSeekDefaultModelId } from "./deepseek.js"
|
||||
import { doubaoDefaultModelId } from "./doubao.js"
|
||||
import { featherlessDefaultModelId } from "./featherless.js"
|
||||
|
|
@ -127,8 +126,6 @@ export function getProviderDefaultModelId(
|
|||
return deepInfraDefaultModelId
|
||||
case "vscode-lm":
|
||||
return vscodeLlmDefaultModelId
|
||||
case "claude-code":
|
||||
return claudeCodeDefaultModelId
|
||||
case "cerebras":
|
||||
return cerebrasDefaultModelId
|
||||
case "sambanova":
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ export const ioIntelligenceModels = {
|
|||
contextWindow: 128000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
description: "DeepSeek R1 reasoning model",
|
||||
},
|
||||
"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8": {
|
||||
|
|
@ -26,7 +25,6 @@ export const ioIntelligenceModels = {
|
|||
contextWindow: 430000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
description: "Llama 4 Maverick 17B model",
|
||||
},
|
||||
"Intel/Qwen3-Coder-480B-A35B-Instruct-int4-mixed-ar": {
|
||||
|
|
@ -34,7 +32,6 @@ export const ioIntelligenceModels = {
|
|||
contextWindow: 106000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
description: "Qwen3 Coder 480B specialized for coding",
|
||||
},
|
||||
"openai/gpt-oss-120b": {
|
||||
|
|
@ -42,7 +39,6 @@ export const ioIntelligenceModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
description: "OpenAI GPT-OSS 120B model",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@ export const litellmDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ export const lMStudioDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ export const minimaxModels = {
|
|||
contextWindow: 192_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["search_and_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
preserveReasoning: true,
|
||||
|
|
@ -30,8 +28,6 @@ export const minimaxModels = {
|
|||
contextWindow: 192_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["search_and_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
preserveReasoning: true,
|
||||
|
|
@ -47,8 +43,6 @@ export const minimaxModels = {
|
|||
contextWindow: 192_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["search_and_replace"],
|
||||
excludedTools: ["apply_diff"],
|
||||
preserveReasoning: true,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ export const mistralModels = {
|
|||
contextWindow: 128_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 2.0,
|
||||
outputPrice: 5.0,
|
||||
},
|
||||
|
|
@ -21,8 +19,6 @@ export const mistralModels = {
|
|||
contextWindow: 131_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.4,
|
||||
outputPrice: 2.0,
|
||||
},
|
||||
|
|
@ -31,8 +27,6 @@ export const mistralModels = {
|
|||
contextWindow: 131_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.4,
|
||||
outputPrice: 2.0,
|
||||
},
|
||||
|
|
@ -41,8 +35,6 @@ export const mistralModels = {
|
|||
contextWindow: 256_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 0.9,
|
||||
},
|
||||
|
|
@ -51,8 +43,6 @@ export const mistralModels = {
|
|||
contextWindow: 131_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 2.0,
|
||||
outputPrice: 6.0,
|
||||
},
|
||||
|
|
@ -61,8 +51,6 @@ export const mistralModels = {
|
|||
contextWindow: 131_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.1,
|
||||
},
|
||||
|
|
@ -71,8 +59,6 @@ export const mistralModels = {
|
|||
contextWindow: 131_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.04,
|
||||
outputPrice: 0.04,
|
||||
},
|
||||
|
|
@ -81,8 +67,6 @@ export const mistralModels = {
|
|||
contextWindow: 32_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 0.6,
|
||||
},
|
||||
|
|
@ -91,8 +75,6 @@ export const mistralModels = {
|
|||
contextWindow: 131_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 2.0,
|
||||
outputPrice: 6.0,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ export const moonshotModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6, // $0.60 per million tokens (cache miss)
|
||||
outputPrice: 2.5, // $2.50 per million tokens
|
||||
cacheWritesPrice: 0, // $0 per million tokens (cache miss)
|
||||
|
|
@ -24,8 +22,6 @@ export const moonshotModels = {
|
|||
contextWindow: 262144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.15,
|
||||
|
|
@ -37,8 +33,6 @@ export const moonshotModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 2.4, // $2.40 per million tokens (cache miss)
|
||||
outputPrice: 10, // $10.00 per million tokens
|
||||
cacheWritesPrice: 0, // $0 per million tokens (cache miss)
|
||||
|
|
@ -50,8 +44,6 @@ export const moonshotModels = {
|
|||
contextWindow: 262_144, // 262,144 tokens
|
||||
supportsImages: false, // Text-only (no image/vision support)
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6, // $0.60 per million tokens (cache miss)
|
||||
outputPrice: 2.5, // $2.50 per million tokens
|
||||
cacheWritesPrice: 0, // $0 per million tokens (cache miss)
|
||||
|
|
@ -61,6 +53,19 @@ export const moonshotModels = {
|
|||
defaultTemperature: 1.0,
|
||||
description: `The kimi-k2-thinking model is a general-purpose agentic reasoning model developed by Moonshot AI. Thanks to its strength in deep reasoning and multi-turn tool use, it can solve even the hardest problems.`,
|
||||
},
|
||||
"kimi-k2.5": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.6, // $0.60 per million tokens (cache miss)
|
||||
outputPrice: 3.0, // $3.00 per million tokens
|
||||
cacheReadsPrice: 0.1, // $0.10 per million tokens (cache hit)
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1.0,
|
||||
description:
|
||||
"Kimi K2.5 is the latest generation of Moonshot AI's Kimi series, featuring improved reasoning capabilities and enhanced performance across diverse tasks.",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
||||
export const MOONSHOT_DEFAULT_TEMPERATURE = 0.6
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ export const ollamaDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
|
|||
29
packages/types/src/providers/openai-codex-rate-limits.ts
Normal file
29
packages/types/src/providers/openai-codex-rate-limits.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
* OpenAI Codex usage/rate limit information (ChatGPT subscription)
|
||||
*/
|
||||
export interface OpenAiCodexRateLimitInfo {
|
||||
primary?: {
|
||||
/** Used percent in 0–100 */
|
||||
usedPercent: number
|
||||
/** Window length in minutes, when provided */
|
||||
windowMinutes?: number
|
||||
/** Reset time (unix ms since epoch), when provided */
|
||||
resetsAt?: number
|
||||
}
|
||||
secondary?: {
|
||||
/** Used percent in 0–100 */
|
||||
usedPercent: number
|
||||
/** Window length in minutes, when provided */
|
||||
windowMinutes?: number
|
||||
/** Reset time (unix ms since epoch), when provided */
|
||||
resetsAt?: number
|
||||
}
|
||||
credits?: {
|
||||
hasCredits: boolean
|
||||
unlimited: boolean
|
||||
balance?: string
|
||||
}
|
||||
planType?: string
|
||||
/** Timestamp when this was fetched (unix ms since epoch) */
|
||||
fetchedAt: number
|
||||
}
|
||||
|
|
@ -27,8 +27,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5.1-codex-max": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -44,8 +42,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5.1-codex": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -61,8 +57,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5.2-codex": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -77,8 +71,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5.1": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -95,8 +87,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -113,8 +103,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5-codex": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -130,8 +118,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5-codex-mini": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -147,8 +133,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5.1-codex-mini": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -163,8 +147,6 @@ export const openAiCodexModels = {
|
|||
"gpt-5.2": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5.1-codex-max": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -29,8 +27,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5.2": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -52,8 +48,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5.2-codex": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -72,8 +66,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5.2-chat-latest": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 128_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -86,8 +78,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5.1": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -109,8 +99,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5.1-codex": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -128,8 +116,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5.1-codex-mini": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -146,8 +132,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -168,8 +152,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5-mini": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -190,8 +172,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5-codex": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -208,8 +188,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5-nano": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -227,8 +205,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5-chat-latest": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -241,8 +217,6 @@ export const openAiNativeModels = {
|
|||
"gpt-4.1": {
|
||||
maxTokens: 32_768,
|
||||
contextWindow: 1_047_576,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -258,8 +232,6 @@ export const openAiNativeModels = {
|
|||
"gpt-4.1-mini": {
|
||||
maxTokens: 32_768,
|
||||
contextWindow: 1_047_576,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -275,8 +247,6 @@ export const openAiNativeModels = {
|
|||
"gpt-4.1-nano": {
|
||||
maxTokens: 32_768,
|
||||
contextWindow: 1_047_576,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -292,8 +262,6 @@ export const openAiNativeModels = {
|
|||
o3: {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 2.0,
|
||||
|
|
@ -310,8 +278,6 @@ export const openAiNativeModels = {
|
|||
"o3-high": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 2.0,
|
||||
|
|
@ -323,8 +289,6 @@ export const openAiNativeModels = {
|
|||
"o3-low": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 2.0,
|
||||
|
|
@ -336,8 +300,6 @@ export const openAiNativeModels = {
|
|||
"o4-mini": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.1,
|
||||
|
|
@ -354,8 +316,6 @@ export const openAiNativeModels = {
|
|||
"o4-mini-high": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.1,
|
||||
|
|
@ -367,8 +327,6 @@ export const openAiNativeModels = {
|
|||
"o4-mini-low": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.1,
|
||||
|
|
@ -380,8 +338,6 @@ export const openAiNativeModels = {
|
|||
"o3-mini": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.1,
|
||||
|
|
@ -394,8 +350,6 @@ export const openAiNativeModels = {
|
|||
"o3-mini-high": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.1,
|
||||
|
|
@ -407,8 +361,6 @@ export const openAiNativeModels = {
|
|||
"o3-mini-low": {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.1,
|
||||
|
|
@ -420,8 +372,6 @@ export const openAiNativeModels = {
|
|||
o1: {
|
||||
maxTokens: 100_000,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 15,
|
||||
|
|
@ -432,8 +382,6 @@ export const openAiNativeModels = {
|
|||
"o1-preview": {
|
||||
maxTokens: 32_768,
|
||||
contextWindow: 128_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 15,
|
||||
|
|
@ -444,8 +392,6 @@ export const openAiNativeModels = {
|
|||
"o1-mini": {
|
||||
maxTokens: 65_536,
|
||||
contextWindow: 128_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 1.1,
|
||||
|
|
@ -456,8 +402,6 @@ export const openAiNativeModels = {
|
|||
"gpt-4o": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 128_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 2.5,
|
||||
|
|
@ -471,8 +415,6 @@ export const openAiNativeModels = {
|
|||
"gpt-4o-mini": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 128_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.15,
|
||||
|
|
@ -486,8 +428,6 @@ export const openAiNativeModels = {
|
|||
"codex-mini-latest": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 200_000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 1.5,
|
||||
|
|
@ -501,8 +441,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5-2025-08-07": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -523,8 +461,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5-mini-2025-08-07": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -545,8 +481,6 @@ export const openAiNativeModels = {
|
|||
"gpt-5-nano-2025-08-07": {
|
||||
maxTokens: 128000,
|
||||
contextWindow: 400000,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
includedTools: ["apply_patch"],
|
||||
excludedTools: ["apply_diff", "write_to_file"],
|
||||
supportsImages: true,
|
||||
|
|
@ -570,8 +504,6 @@ export const openAiModelInfoSaneDefaults: ModelInfo = {
|
|||
supportsPromptCache: false,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ export const openRouterDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ export const qwenCodeModels = {
|
|||
contextWindow: 1_000_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -23,8 +21,6 @@ export const qwenCodeModels = {
|
|||
contextWindow: 1_000_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@ export const requestyDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ export const sambaNovaModels = {
|
|||
contextWindow: 16384,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.2,
|
||||
description: "Meta Llama 3.1 8B Instruct model with 16K context window.",
|
||||
|
|
@ -30,8 +28,6 @@ export const sambaNovaModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 1.2,
|
||||
description: "Meta Llama 3.3 70B Instruct model with 128K context window.",
|
||||
|
|
@ -42,8 +38,6 @@ export const sambaNovaModels = {
|
|||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsReasoningBudget: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 5.0,
|
||||
outputPrice: 7.0,
|
||||
description: "DeepSeek R1 reasoning model with 32K context window.",
|
||||
|
|
@ -53,8 +47,6 @@ export const sambaNovaModels = {
|
|||
contextWindow: 32768,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 4.5,
|
||||
description: "DeepSeek V3 model with 32K context window.",
|
||||
|
|
@ -64,8 +56,6 @@ export const sambaNovaModels = {
|
|||
contextWindow: 32768,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 4.5,
|
||||
description: "DeepSeek V3.1 model with 32K context window.",
|
||||
|
|
@ -75,8 +65,6 @@ export const sambaNovaModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.63,
|
||||
outputPrice: 1.8,
|
||||
description: "Meta Llama 4 Maverick 17B 128E Instruct model with 128K context window.",
|
||||
|
|
@ -86,8 +74,6 @@ export const sambaNovaModels = {
|
|||
contextWindow: 8192,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.4,
|
||||
outputPrice: 0.8,
|
||||
description: "Alibaba Qwen 3 32B model with 8K context window.",
|
||||
|
|
@ -97,8 +83,6 @@ export const sambaNovaModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.22,
|
||||
outputPrice: 0.59,
|
||||
description: "OpenAI gpt oss 120b model with 128k context window.",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ export const unboundDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ export const vercelAiGatewayDefaultModelInfo: ModelInfo = {
|
|||
contextWindow: 200000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 3,
|
||||
outputPrice: 15,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["low", "high"],
|
||||
reasoningEffort: "low",
|
||||
|
|
@ -20,16 +18,19 @@ export const vertexModels = {
|
|||
defaultTemperature: 1,
|
||||
inputPrice: 4.0,
|
||||
outputPrice: 18.0,
|
||||
cacheReadsPrice: 0.4,
|
||||
tiers: [
|
||||
{
|
||||
contextWindow: 200_000,
|
||||
inputPrice: 2.0,
|
||||
outputPrice: 12.0,
|
||||
cacheReadsPrice: 0.2,
|
||||
},
|
||||
{
|
||||
contextWindow: Infinity,
|
||||
inputPrice: 4.0,
|
||||
outputPrice: 18.0,
|
||||
cacheReadsPrice: 0.4,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -37,25 +38,20 @@ export const vertexModels = {
|
|||
maxTokens: 65_536,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
|
||||
reasoningEffort: "medium",
|
||||
|
||||
supportsTemperature: true,
|
||||
defaultTemperature: 1,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 2.5,
|
||||
cacheReadsPrice: 0.075,
|
||||
cacheWritesPrice: 1.0,
|
||||
inputPrice: 0.5,
|
||||
outputPrice: 3.0,
|
||||
cacheReadsPrice: 0.05,
|
||||
},
|
||||
"gemini-2.5-flash-preview-05-20:thinking": {
|
||||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.15,
|
||||
|
|
@ -68,8 +64,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.15,
|
||||
|
|
@ -79,8 +73,6 @@ export const vertexModels = {
|
|||
maxTokens: 64_000,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.3,
|
||||
|
|
@ -94,8 +86,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
|
||||
inputPrice: 0.15,
|
||||
|
|
@ -108,8 +98,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
|
||||
inputPrice: 0.15,
|
||||
|
|
@ -119,8 +107,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5,
|
||||
|
|
@ -130,8 +116,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5,
|
||||
|
|
@ -141,8 +125,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5,
|
||||
|
|
@ -154,8 +136,6 @@ export const vertexModels = {
|
|||
maxTokens: 64_000,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 2.5,
|
||||
|
|
@ -182,8 +162,6 @@ export const vertexModels = {
|
|||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
|
||||
inputPrice: 0,
|
||||
|
|
@ -193,8 +171,6 @@ export const vertexModels = {
|
|||
maxTokens: 8192,
|
||||
contextWindow: 2_097_152,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
|
||||
inputPrice: 0,
|
||||
|
|
@ -204,8 +180,6 @@ export const vertexModels = {
|
|||
maxTokens: 8192,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.15,
|
||||
|
|
@ -215,8 +189,6 @@ export const vertexModels = {
|
|||
maxTokens: 8192,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
|
||||
inputPrice: 0.075,
|
||||
|
|
@ -226,8 +198,6 @@ export const vertexModels = {
|
|||
maxTokens: 8192,
|
||||
contextWindow: 32_768,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
|
||||
inputPrice: 0,
|
||||
|
|
@ -237,8 +207,6 @@ export const vertexModels = {
|
|||
maxTokens: 8192,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.075,
|
||||
|
|
@ -248,8 +216,6 @@ export const vertexModels = {
|
|||
maxTokens: 8192,
|
||||
contextWindow: 2_097_152,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: false,
|
||||
|
||||
inputPrice: 1.25,
|
||||
|
|
@ -260,8 +226,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0, // $3 per million input tokens (≤200K context)
|
||||
outputPrice: 15.0, // $15 per million output tokens (≤200K context)
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
|
|
@ -283,8 +247,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07'
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0, // $3 per million input tokens (≤200K context)
|
||||
outputPrice: 15.0, // $15 per million output tokens (≤200K context)
|
||||
cacheWritesPrice: 3.75, // $3.75 per million tokens
|
||||
|
|
@ -306,8 +268,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 5.0,
|
||||
cacheWritesPrice: 1.25,
|
||||
|
|
@ -319,8 +279,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 5.0,
|
||||
outputPrice: 25.0,
|
||||
cacheWritesPrice: 6.25,
|
||||
|
|
@ -332,8 +290,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
|
|
@ -345,8 +301,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
|
|
@ -357,8 +311,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -371,8 +323,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -383,8 +333,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -395,8 +343,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
|
|
@ -407,8 +353,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 5.0,
|
||||
cacheWritesPrice: 1.25,
|
||||
|
|
@ -419,8 +363,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 15.0,
|
||||
outputPrice: 75.0,
|
||||
cacheWritesPrice: 18.75,
|
||||
|
|
@ -431,8 +373,6 @@ export const vertexModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.25,
|
||||
outputPrice: 1.25,
|
||||
cacheWritesPrice: 0.3,
|
||||
|
|
@ -442,8 +382,6 @@ export const vertexModels = {
|
|||
maxTokens: 64_000,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsPromptCache: true,
|
||||
|
||||
inputPrice: 0.1,
|
||||
|
|
@ -458,7 +396,6 @@ export const vertexModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.35,
|
||||
outputPrice: 1.15,
|
||||
description: "Meta Llama 4 Maverick 17B Instruct model, 128K context.",
|
||||
|
|
@ -468,7 +405,6 @@ export const vertexModels = {
|
|||
contextWindow: 163_840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 1.35,
|
||||
outputPrice: 5.4,
|
||||
description: "DeepSeek R1 (0528). Available in us-central1",
|
||||
|
|
@ -478,7 +414,6 @@ export const vertexModels = {
|
|||
contextWindow: 163_840,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 1.7,
|
||||
description: "DeepSeek V3.1. Available in us-west2",
|
||||
|
|
@ -488,7 +423,6 @@ export const vertexModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
description: "OpenAI gpt-oss 120B. Available in us-central1",
|
||||
|
|
@ -498,7 +432,6 @@ export const vertexModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.075,
|
||||
outputPrice: 0.3,
|
||||
description: "OpenAI gpt-oss 20B. Available in us-central1",
|
||||
|
|
@ -508,7 +441,6 @@ export const vertexModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 1.0,
|
||||
outputPrice: 4.0,
|
||||
description: "Qwen3 Coder 480B A35B Instruct. Available in us-south1",
|
||||
|
|
@ -518,11 +450,19 @@ export const vertexModels = {
|
|||
contextWindow: 262_144,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
inputPrice: 0.25,
|
||||
outputPrice: 1.0,
|
||||
description: "Qwen3 235B A22B Instruct. Available in us-south1",
|
||||
},
|
||||
"moonshotai/kimi-k2-thinking-maas": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 262_144,
|
||||
supportsPromptCache: false,
|
||||
supportsImages: false,
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.5,
|
||||
description: "Kimi K2 Thinking Model with 256K context window.",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
||||
// Vertex AI models that support 1M context window beta
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ export const xaiModels = {
|
|||
contextWindow: 256_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 1.5,
|
||||
cacheWritesPrice: 0.02,
|
||||
|
|
@ -26,8 +24,6 @@ export const xaiModels = {
|
|||
contextWindow: 2_000_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 0.5,
|
||||
cacheWritesPrice: 0.05,
|
||||
|
|
@ -42,8 +38,6 @@ export const xaiModels = {
|
|||
contextWindow: 2_000_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 0.5,
|
||||
cacheWritesPrice: 0.05,
|
||||
|
|
@ -58,8 +52,6 @@ export const xaiModels = {
|
|||
contextWindow: 2_000_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 0.5,
|
||||
cacheWritesPrice: 0.05,
|
||||
|
|
@ -74,8 +66,6 @@ export const xaiModels = {
|
|||
contextWindow: 2_000_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 0.5,
|
||||
cacheWritesPrice: 0.05,
|
||||
|
|
@ -90,8 +80,6 @@ export const xaiModels = {
|
|||
contextWindow: 256_000,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 0.75,
|
||||
|
|
@ -105,8 +93,6 @@ export const xaiModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 0.5,
|
||||
cacheWritesPrice: 0.07,
|
||||
|
|
@ -122,8 +108,6 @@ export const xaiModels = {
|
|||
contextWindow: 131072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 0.75,
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ export const internationalZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.2,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -30,8 +28,6 @@ export const internationalZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.2,
|
||||
outputPrice: 1.1,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -44,8 +40,6 @@ export const internationalZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 2.2,
|
||||
outputPrice: 8.9,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -58,8 +52,6 @@ export const internationalZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 1.1,
|
||||
outputPrice: 4.5,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -71,8 +63,6 @@ export const internationalZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -84,8 +74,6 @@ export const internationalZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 1.8,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -93,13 +81,23 @@ export const internationalZAiModels = {
|
|||
description:
|
||||
"GLM-4.5V is Z.AI's multimodal visual reasoning model (image/video/text/file input), optimized for GUI tasks, grounding, and document/video understanding.",
|
||||
},
|
||||
"glm-4.6v": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.3,
|
||||
outputPrice: 0.9,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0.05,
|
||||
description:
|
||||
"GLM-4.6V is an advanced multimodal vision model with improved performance and cost-efficiency for visual understanding tasks.",
|
||||
},
|
||||
"glm-4.6": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.6,
|
||||
outputPrice: 2.2,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -112,8 +110,6 @@ export const internationalZAiModels = {
|
|||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsReasoningEffort: ["disable", "medium"],
|
||||
reasoningEffort: "medium",
|
||||
preserveReasoning: true,
|
||||
|
|
@ -124,13 +120,59 @@ export const internationalZAiModels = {
|
|||
description:
|
||||
"GLM-4.7 is Zhipu's latest model with built-in thinking capabilities enabled by default. It provides enhanced reasoning for complex tasks while maintaining fast response times.",
|
||||
},
|
||||
"glm-4.7-flash": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0,
|
||||
description:
|
||||
"GLM-4.7-Flash is a free, high-speed variant of GLM-4.7 offering fast responses for reasoning and coding tasks.",
|
||||
},
|
||||
"glm-4.7-flashx": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.07,
|
||||
outputPrice: 0.4,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0.01,
|
||||
description:
|
||||
"GLM-4.7-FlashX is an ultra-fast variant of GLM-4.7 with exceptional speed and cost-effectiveness for high-throughput applications.",
|
||||
},
|
||||
"glm-4.6v-flash": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0,
|
||||
description:
|
||||
"GLM-4.6V-Flash is a free, high-speed multimodal vision model for rapid image understanding and visual reasoning tasks.",
|
||||
},
|
||||
"glm-4.6v-flashx": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.04,
|
||||
outputPrice: 0.4,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0.004,
|
||||
description:
|
||||
"GLM-4.6V-FlashX is an ultra-fast multimodal vision model optimized for high-speed visual processing at low cost.",
|
||||
},
|
||||
"glm-4-32b-0414-128k": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: false,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.1,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -147,8 +189,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.29,
|
||||
outputPrice: 1.14,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -161,8 +201,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.6,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -175,8 +213,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.29,
|
||||
outputPrice: 1.14,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -189,8 +225,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.6,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -202,8 +236,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -215,8 +247,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.29,
|
||||
outputPrice: 0.93,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -229,8 +259,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 204_800,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
inputPrice: 0.29,
|
||||
outputPrice: 1.14,
|
||||
cacheWritesPrice: 0,
|
||||
|
|
@ -243,8 +271,6 @@ export const mainlandZAiModels = {
|
|||
contextWindow: 204_800,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: "native",
|
||||
supportsReasoningEffort: ["disable", "medium"],
|
||||
reasoningEffort: "medium",
|
||||
preserveReasoning: true,
|
||||
|
|
@ -255,6 +281,66 @@ export const mainlandZAiModels = {
|
|||
description:
|
||||
"GLM-4.7 is Zhipu's latest model with built-in thinking capabilities enabled by default. It provides enhanced reasoning for complex tasks while maintaining fast response times.",
|
||||
},
|
||||
"glm-4.7-flash": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 204_800,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0,
|
||||
description:
|
||||
"GLM-4.7-Flash is a free, high-speed variant of GLM-4.7 offering fast responses for reasoning and coding tasks.",
|
||||
},
|
||||
"glm-4.7-flashx": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 204_800,
|
||||
supportsImages: false,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.035,
|
||||
outputPrice: 0.2,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0.005,
|
||||
description:
|
||||
"GLM-4.7-FlashX is an ultra-fast variant of GLM-4.7 with exceptional speed and cost-effectiveness for high-throughput applications.",
|
||||
},
|
||||
"glm-4.6v": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.45,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0.025,
|
||||
description:
|
||||
"GLM-4.6V is an advanced multimodal vision model with improved performance and cost-efficiency for visual understanding tasks.",
|
||||
},
|
||||
"glm-4.6v-flash": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0,
|
||||
description:
|
||||
"GLM-4.6V-Flash is a free, high-speed multimodal vision model for rapid image understanding and visual reasoning tasks.",
|
||||
},
|
||||
"glm-4.6v-flashx": {
|
||||
maxTokens: 16_384,
|
||||
contextWindow: 131_072,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.02,
|
||||
outputPrice: 0.2,
|
||||
cacheWritesPrice: 0,
|
||||
cacheReadsPrice: 0.002,
|
||||
description:
|
||||
"GLM-4.6V-FlashX is an ultra-fast multimodal vision model optimized for high-speed visual processing at low cost.",
|
||||
},
|
||||
} as const satisfies Record<string, ModelInfo>
|
||||
|
||||
export const ZAI_DEFAULT_TEMPERATURE = 0.6
|
||||
|
|
|
|||
|
|
@ -89,9 +89,7 @@ export type TaskProviderEvents = {
|
|||
*/
|
||||
|
||||
export interface CreateTaskOptions {
|
||||
enableDiff?: boolean
|
||||
enableCheckpoints?: boolean
|
||||
fuzzyMatchThreshold?: number
|
||||
consecutiveMistakeLimit?: number
|
||||
experiments?: Record<string, boolean>
|
||||
initialTodos?: TodoItem[]
|
||||
|
|
|
|||
|
|
@ -32,3 +32,69 @@ export const commandExecutionStatusSchema = z.discriminatedUnion("status", [
|
|||
])
|
||||
|
||||
export type CommandExecutionStatus = z.infer<typeof commandExecutionStatusSchema>
|
||||
|
||||
/**
|
||||
* PersistedCommandOutput
|
||||
*
|
||||
* Represents the result of a terminal command execution that may have been
|
||||
* truncated and persisted to disk.
|
||||
*
|
||||
* When command output exceeds the configured preview threshold, the full
|
||||
* output is saved to a disk artifact file. The LLM receives this structure
|
||||
* which contains:
|
||||
* - A preview of the output (for immediate display in context)
|
||||
* - Metadata about the full output (size, truncation status)
|
||||
* - A path to the artifact file for later retrieval via `read_command_output`
|
||||
*
|
||||
* ## Usage in execute_command Response
|
||||
*
|
||||
* The response format depends on whether truncation occurred:
|
||||
*
|
||||
* **Not truncated** (output fits in preview):
|
||||
* ```json
|
||||
* {
|
||||
* "preview": "full output here...",
|
||||
* "totalBytes": 1234,
|
||||
* "artifactPath": null,
|
||||
* "truncated": false
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **Truncated** (output exceeded threshold):
|
||||
* ```json
|
||||
* {
|
||||
* "preview": "first 4KB of output...",
|
||||
* "totalBytes": 1048576,
|
||||
* "artifactPath": "/path/to/tasks/123/command-output/cmd-1706119234567.txt",
|
||||
* "truncated": true
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @see OutputInterceptor - Creates these results during command execution
|
||||
* @see ReadCommandOutputTool - Retrieves full content from artifact files
|
||||
*/
|
||||
export interface PersistedCommandOutput {
|
||||
/**
|
||||
* Preview of the command output, truncated to the preview threshold.
|
||||
* Always contains the beginning of the output, even if truncated.
|
||||
*/
|
||||
preview: string
|
||||
|
||||
/**
|
||||
* Total size of the command output in bytes.
|
||||
* Useful for determining if additional reads are needed.
|
||||
*/
|
||||
totalBytes: number
|
||||
|
||||
/**
|
||||
* Absolute path to the artifact file containing full output.
|
||||
* `null` if output wasn't truncated (no artifact was created).
|
||||
*/
|
||||
artifactPath: string | null
|
||||
|
||||
/**
|
||||
* Whether the output was truncated (exceeded preview threshold).
|
||||
* When `true`, use `read_command_output` to retrieve full content.
|
||||
*/
|
||||
truncated: boolean
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export type ToolGroup = z.infer<typeof toolGroupsSchema>
|
|||
export const toolNames = [
|
||||
"execute_command",
|
||||
"read_file",
|
||||
"read_command_output",
|
||||
"write_to_file",
|
||||
"apply_diff",
|
||||
"search_and_replace",
|
||||
|
|
@ -32,10 +33,10 @@ export const toolNames = [
|
|||
"attempt_completion",
|
||||
"switch_mode",
|
||||
"new_task",
|
||||
"fetch_instructions",
|
||||
"codebase_search",
|
||||
"update_todo_list",
|
||||
"run_slash_command",
|
||||
"skill",
|
||||
"generate_image",
|
||||
"custom_tool",
|
||||
] as const
|
||||
|
|
@ -57,48 +58,3 @@ export const toolUsageSchema = z.record(
|
|||
)
|
||||
|
||||
export type ToolUsage = z.infer<typeof toolUsageSchema>
|
||||
|
||||
/**
|
||||
* Tool protocol constants
|
||||
*/
|
||||
export const TOOL_PROTOCOL = {
|
||||
XML: "xml",
|
||||
NATIVE: "native",
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Tool protocol type for system prompt generation
|
||||
* Derived from TOOL_PROTOCOL constants to ensure type safety
|
||||
*/
|
||||
export type ToolProtocol = (typeof TOOL_PROTOCOL)[keyof typeof TOOL_PROTOCOL]
|
||||
|
||||
/**
|
||||
* Default model info properties for native tool support.
|
||||
* Used to merge with cached model info that may lack these fields.
|
||||
* Router providers (Requesty, Unbound, LiteLLM) assume all models support native tools.
|
||||
*/
|
||||
export const NATIVE_TOOL_DEFAULTS = {
|
||||
supportsNativeTools: true,
|
||||
defaultToolProtocol: TOOL_PROTOCOL.NATIVE,
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Checks if the protocol is native (non-XML).
|
||||
*
|
||||
* @param protocol - The tool protocol to check
|
||||
* @returns True if protocol is native
|
||||
*/
|
||||
export function isNativeProtocol(protocol: ToolProtocol): boolean {
|
||||
return protocol === TOOL_PROTOCOL.NATIVE
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the effective protocol from settings or falls back to the default XML.
|
||||
* This function is safe to use in webview-accessible code as it doesn't depend on vscode module.
|
||||
*
|
||||
* @param toolProtocol - Optional tool protocol from settings
|
||||
* @returns The effective tool protocol (defaults to "xml")
|
||||
*/
|
||||
export function getEffectiveProtocol(toolProtocol?: ToolProtocol): ToolProtocol {
|
||||
return toolProtocol || TOOL_PROTOCOL.XML
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import type { SerializedCustomToolDefinition } from "./custom-tool.js"
|
|||
import type { GitCommit } from "./git.js"
|
||||
import type { McpServer } from "./mcp.js"
|
||||
import type { ModelRecord, RouterModels } from "./model.js"
|
||||
import type { OpenAiCodexRateLimitInfo } from "./providers/openai-codex-rate-limits.js"
|
||||
import type { WorktreeIncludeStatus } from "./worktree.js"
|
||||
|
||||
/**
|
||||
* ExtensionMessage
|
||||
|
|
@ -28,6 +30,8 @@ export interface ExtensionMessage {
|
|||
type:
|
||||
| "action"
|
||||
| "state"
|
||||
| "taskHistoryUpdated"
|
||||
| "taskHistoryItemUpdated"
|
||||
| "selectedImages"
|
||||
| "theme"
|
||||
| "workspaceUpdated"
|
||||
|
|
@ -93,10 +97,19 @@ export interface ExtensionMessage {
|
|||
| "interactionRequired"
|
||||
| "browserSessionUpdate"
|
||||
| "browserSessionNavigate"
|
||||
| "claudeCodeRateLimits"
|
||||
| "customToolsResult"
|
||||
| "modes"
|
||||
| "taskWithAggregatedCosts"
|
||||
| "openAiCodexRateLimits"
|
||||
// Worktree response types
|
||||
| "worktreeList"
|
||||
| "worktreeResult"
|
||||
| "worktreeCopyProgress"
|
||||
| "branchList"
|
||||
| "worktreeDefaults"
|
||||
| "worktreeIncludeStatus"
|
||||
| "branchWorktreeIncludeResult"
|
||||
| "folderSelected"
|
||||
text?: string
|
||||
payload?: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
checkpointWarning?: {
|
||||
|
|
@ -114,7 +127,11 @@ export interface ExtensionMessage {
|
|||
| "switchTab"
|
||||
| "toggleAutoApprove"
|
||||
invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage"
|
||||
state?: ExtensionState
|
||||
/**
|
||||
* Partial state updates are allowed to reduce message size (e.g. omit large fields like taskHistory).
|
||||
* The webview is responsible for merging.
|
||||
*/
|
||||
state?: Partial<ExtensionState>
|
||||
images?: string[]
|
||||
filePaths?: string[]
|
||||
openedTabs?: Array<{
|
||||
|
|
@ -164,7 +181,9 @@ export interface ExtensionMessage {
|
|||
customMode?: ModeConfig
|
||||
slug?: string
|
||||
success?: boolean
|
||||
values?: Record<string, any> // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
/** Generic payload for extension messages that use `values` */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
values?: Record<string, any>
|
||||
requestId?: string
|
||||
promptText?: string
|
||||
results?:
|
||||
|
|
@ -204,6 +223,62 @@ export interface ExtensionMessage {
|
|||
childrenCost: number
|
||||
}
|
||||
historyItem?: HistoryItem
|
||||
taskHistory?: HistoryItem[] // For taskHistoryUpdated: full sorted task history
|
||||
/** For taskHistoryItemUpdated: single updated/added history item */
|
||||
taskHistoryItem?: HistoryItem
|
||||
// Worktree response properties
|
||||
worktrees?: Array<{
|
||||
path: string
|
||||
branch: string
|
||||
commitHash: string
|
||||
isCurrent: boolean
|
||||
isBare: boolean
|
||||
isDetached: boolean
|
||||
isLocked: boolean
|
||||
lockReason?: string
|
||||
}>
|
||||
isGitRepo?: boolean
|
||||
isMultiRoot?: boolean
|
||||
isSubfolder?: boolean
|
||||
gitRootPath?: string
|
||||
worktreeResult?: {
|
||||
success: boolean
|
||||
message: string
|
||||
worktree?: {
|
||||
path: string
|
||||
branch: string
|
||||
commitHash: string
|
||||
isCurrent: boolean
|
||||
isBare: boolean
|
||||
isDetached: boolean
|
||||
isLocked: boolean
|
||||
lockReason?: string
|
||||
}
|
||||
}
|
||||
localBranches?: string[]
|
||||
remoteBranches?: string[]
|
||||
currentBranch?: string
|
||||
suggestedBranch?: string
|
||||
suggestedPath?: string
|
||||
worktreeIncludeExists?: boolean
|
||||
worktreeIncludeStatus?: WorktreeIncludeStatus
|
||||
hasGitignore?: boolean
|
||||
gitignoreContent?: string
|
||||
// branchWorktreeIncludeResult
|
||||
branch?: string
|
||||
hasWorktreeInclude?: boolean
|
||||
// worktreeCopyProgress (size-based)
|
||||
copyProgressBytesCopied?: number
|
||||
copyProgressTotalBytes?: number
|
||||
copyProgressItemName?: string
|
||||
// folderSelected
|
||||
path?: string
|
||||
}
|
||||
|
||||
export interface OpenAiCodexRateLimitsMessage {
|
||||
type: "openAiCodexRateLimits"
|
||||
values?: OpenAiCodexRateLimitInfo
|
||||
error?: string
|
||||
}
|
||||
|
||||
export type ExtensionState = Pick<
|
||||
|
|
@ -241,8 +316,7 @@ export type ExtensionState = Pick<
|
|||
| "soundEnabled"
|
||||
| "soundVolume"
|
||||
| "maxConcurrentFileReads"
|
||||
| "terminalOutputLineLimit"
|
||||
| "terminalOutputCharacterLimit"
|
||||
| "terminalOutputPreviewSize"
|
||||
| "terminalShellIntegrationTimeout"
|
||||
| "terminalShellIntegrationDisabled"
|
||||
| "terminalCommandDelay"
|
||||
|
|
@ -251,16 +325,12 @@ export type ExtensionState = Pick<
|
|||
| "terminalZshOhMy"
|
||||
| "terminalZshP10k"
|
||||
| "terminalZdotdir"
|
||||
| "terminalCompressProgressBar"
|
||||
| "diagnosticsEnabled"
|
||||
| "diffEnabled"
|
||||
| "fuzzyMatchThreshold"
|
||||
| "language"
|
||||
| "modeApiConfigs"
|
||||
| "customModePrompts"
|
||||
| "customSupportPrompts"
|
||||
| "enhancementApiConfigId"
|
||||
| "condensingApiConfigId"
|
||||
| "customCondensingPrompt"
|
||||
| "codebaseIndexConfig"
|
||||
| "codebaseIndexModels"
|
||||
|
|
@ -276,6 +346,7 @@ export type ExtensionState = Pick<
|
|||
| "includeCurrentCost"
|
||||
| "maxGitStatusFiles"
|
||||
| "requestDelaySeconds"
|
||||
| "showWorktreesInHomeScreen"
|
||||
> & {
|
||||
version: string
|
||||
clineMessages: ClineMessage[]
|
||||
|
|
@ -302,11 +373,10 @@ export type ExtensionState = Pick<
|
|||
experiments: Experiments // Map of experiment IDs to their enabled state
|
||||
|
||||
mcpEnabled: boolean
|
||||
enableMcpServerCreation: boolean
|
||||
|
||||
mode: string
|
||||
customModes: ModeConfig[]
|
||||
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true} if diffEnabled)
|
||||
toolRequirements?: Record<string, boolean> // Map of tool names to their requirements (e.g. {"apply_diff": true})
|
||||
|
||||
cwd?: string // Current working directory
|
||||
telemetrySetting: TelemetrySetting
|
||||
|
|
@ -346,7 +416,6 @@ export type ExtensionState = Pick<
|
|||
remoteControlEnabled: boolean
|
||||
taskSyncEnabled: boolean
|
||||
featureRoomoteControlEnabled: boolean
|
||||
claudeCodeIsAuthenticated?: boolean
|
||||
openAiCodexIsAuthenticated?: boolean
|
||||
debug?: boolean
|
||||
}
|
||||
|
|
@ -445,7 +514,6 @@ export interface WebviewMessage {
|
|||
| "deleteMessageConfirm"
|
||||
| "submitEditedMessage"
|
||||
| "editMessageConfirm"
|
||||
| "enableMcpServerCreation"
|
||||
| "remoteControlEnabled"
|
||||
| "taskSyncEnabled"
|
||||
| "searchCommits"
|
||||
|
|
@ -477,8 +545,6 @@ export interface WebviewMessage {
|
|||
| "cloudLandingPageSignIn"
|
||||
| "rooCloudSignOut"
|
||||
| "rooCloudManualUrl"
|
||||
| "claudeCodeSignIn"
|
||||
| "claudeCodeSignOut"
|
||||
| "openAiCodexSignIn"
|
||||
| "openAiCodexSignOut"
|
||||
| "switchOrganization"
|
||||
|
|
@ -533,11 +599,23 @@ export interface WebviewMessage {
|
|||
| "openDebugApiHistory"
|
||||
| "openDebugUiHistory"
|
||||
| "downloadErrorDiagnostics"
|
||||
| "requestClaudeCodeRateLimits"
|
||||
| "requestOpenAiCodexRateLimits"
|
||||
| "refreshCustomTools"
|
||||
| "requestModes"
|
||||
| "switchMode"
|
||||
| "debugSetting"
|
||||
// Worktree messages
|
||||
| "listWorktrees"
|
||||
| "createWorktree"
|
||||
| "deleteWorktree"
|
||||
| "switchWorktree"
|
||||
| "getAvailableBranches"
|
||||
| "getWorktreeDefaults"
|
||||
| "getWorktreeIncludeStatus"
|
||||
| "checkBranchWorktreeInclude"
|
||||
| "createWorktreeInclude"
|
||||
| "checkoutBranch"
|
||||
| "browseForWorktreePath"
|
||||
text?: string
|
||||
editedMessageContent?: string
|
||||
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud"
|
||||
|
|
@ -562,6 +640,7 @@ export interface WebviewMessage {
|
|||
promptMode?: string | "enhance"
|
||||
customPrompt?: PromptComponent
|
||||
dataUrls?: string[]
|
||||
/** Generic payload for webview messages that use `values` */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
values?: Record<string, any>
|
||||
query?: string
|
||||
|
|
@ -628,6 +707,18 @@ export interface WebviewMessage {
|
|||
codebaseIndexOpenRouterApiKey?: string
|
||||
}
|
||||
updatedSettings?: RooCodeSettings
|
||||
// Worktree properties
|
||||
worktreePath?: string
|
||||
worktreeBranch?: string
|
||||
worktreeBaseBranch?: string
|
||||
worktreeCreateNewBranch?: boolean
|
||||
worktreeForce?: boolean
|
||||
worktreeNewWindow?: boolean
|
||||
worktreeIncludeContent?: string
|
||||
}
|
||||
|
||||
export interface RequestOpenAiCodexRateLimitsMessage {
|
||||
type: "requestOpenAiCodexRateLimits"
|
||||
}
|
||||
|
||||
export const checkoutDiffPayloadSchema = z.object({
|
||||
|
|
@ -703,7 +794,7 @@ export interface ClineSayTool {
|
|||
| "newFileCreated"
|
||||
| "codebaseSearch"
|
||||
| "readFile"
|
||||
| "fetchInstructions"
|
||||
| "readCommandOutput"
|
||||
| "listFilesTopLevel"
|
||||
| "listFilesRecursive"
|
||||
| "searchFiles"
|
||||
|
|
@ -714,7 +805,14 @@ export interface ClineSayTool {
|
|||
| "imageGenerated"
|
||||
| "runSlashCommand"
|
||||
| "updateTodoList"
|
||||
| "skill"
|
||||
path?: string
|
||||
// For readCommandOutput
|
||||
readStart?: number
|
||||
readEnd?: number
|
||||
totalBytes?: number
|
||||
searchPattern?: string
|
||||
matchCount?: number
|
||||
diff?: string
|
||||
content?: string
|
||||
// Unified diff statistics computed by the extension
|
||||
|
|
@ -754,6 +852,8 @@ export interface ClineSayTool {
|
|||
args?: string
|
||||
source?: string
|
||||
description?: string
|
||||
// Properties for skill tool
|
||||
skill?: string
|
||||
}
|
||||
|
||||
// Must keep in sync with system prompt.
|
||||
|
|
|
|||
99
packages/types/src/worktree.ts
Normal file
99
packages/types/src/worktree.ts
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/**
|
||||
* Worktree Types
|
||||
*
|
||||
* Platform-agnostic type definitions for git worktree operations.
|
||||
* These types are decoupled from VSCode and can be used by any consumer.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a git worktree
|
||||
*/
|
||||
export interface Worktree {
|
||||
/** Absolute path to the worktree directory */
|
||||
path: string
|
||||
/** Branch name - empty string if detached HEAD */
|
||||
branch: string
|
||||
/** Current commit hash */
|
||||
commitHash: string
|
||||
/** Whether this is the current worktree (matches cwd) */
|
||||
isCurrent: boolean
|
||||
/** Whether this is the bare/main repository */
|
||||
isBare: boolean
|
||||
/** Whether HEAD is detached (not on a branch) */
|
||||
isDetached: boolean
|
||||
/** Whether the worktree is locked */
|
||||
isLocked: boolean
|
||||
/** Reason for lock if locked */
|
||||
lockReason?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of a worktree operation (create, delete, etc.)
|
||||
*/
|
||||
export interface WorktreeResult {
|
||||
/** Whether the operation succeeded */
|
||||
success: boolean
|
||||
/** Human-readable message describing the result */
|
||||
message: string
|
||||
/** The worktree that was affected (if applicable) */
|
||||
worktree?: Worktree
|
||||
}
|
||||
|
||||
/**
|
||||
* Branch information for worktree creation
|
||||
*/
|
||||
export interface BranchInfo {
|
||||
/** Local branches available */
|
||||
localBranches: string[]
|
||||
/** Remote branches available */
|
||||
remoteBranches: string[]
|
||||
/** Currently checked out branch */
|
||||
currentBranch: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for creating a worktree
|
||||
*/
|
||||
export interface CreateWorktreeOptions {
|
||||
/** Path where the worktree will be created */
|
||||
path: string
|
||||
/** Branch name to checkout or create */
|
||||
branch?: string
|
||||
/** Base branch to create new branch from */
|
||||
baseBranch?: string
|
||||
/** If true, create a new branch; if false, checkout existing branch */
|
||||
createNewBranch?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Status of .worktreeinclude file
|
||||
*/
|
||||
export interface WorktreeIncludeStatus {
|
||||
/** Whether .worktreeinclude exists in the directory */
|
||||
exists: boolean
|
||||
/** Whether .gitignore exists in the directory */
|
||||
hasGitignore: boolean
|
||||
/** Content of .gitignore (for creating .worktreeinclude) */
|
||||
gitignoreContent?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Response for listWorktrees handler
|
||||
*/
|
||||
export interface WorktreeListResponse {
|
||||
worktrees: Worktree[]
|
||||
isGitRepo: boolean
|
||||
error?: string
|
||||
isMultiRoot: boolean
|
||||
isSubfolder: boolean
|
||||
gitRootPath: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Response for worktree defaults
|
||||
*/
|
||||
export interface WorktreeDefaultsResponse {
|
||||
suggestedBranch: string
|
||||
suggestedPath: string
|
||||
error?: string
|
||||
}
|
||||
337
pnpm-lock.yaml
generated
337
pnpm-lock.yaml
generated
|
|
@ -14,6 +14,7 @@ overrides:
|
|||
glob: '>=11.1.0'
|
||||
'@types/react': ^18.3.23
|
||||
'@types/react-dom': ^18.3.5
|
||||
zod: 3.25.76
|
||||
|
||||
importers:
|
||||
|
||||
|
|
@ -103,6 +104,12 @@ importers:
|
|||
commander:
|
||||
specifier: ^12.1.0
|
||||
version: 12.1.0
|
||||
cross-spawn:
|
||||
specifier: ^7.0.6
|
||||
version: 7.0.6
|
||||
execa:
|
||||
specifier: ^9.5.2
|
||||
version: 9.6.0
|
||||
fuzzysort:
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
|
|
@ -262,7 +269,7 @@ importers:
|
|||
version: 0.518.0(react@18.3.1)
|
||||
next:
|
||||
specifier: ~15.2.8
|
||||
version: 15.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
version: 15.2.8(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
|
@ -297,8 +304,8 @@ importers:
|
|||
specifier: ^1.1.2
|
||||
version: 1.1.2(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
specifier: workspace:^
|
||||
|
|
@ -371,7 +378,7 @@ importers:
|
|||
version: 0.518.0(react@18.3.1)
|
||||
next:
|
||||
specifier: ~15.2.8
|
||||
version: 15.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
version: 15.2.8(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
|
@ -412,8 +419,8 @@ importers:
|
|||
specifier: ^6.1.86
|
||||
version: 6.1.86
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
specifier: workspace:^
|
||||
|
|
@ -438,7 +445,7 @@ importers:
|
|||
version: 10.4.21(postcss@8.5.4)
|
||||
next-sitemap:
|
||||
specifier: ^4.2.3
|
||||
version: 4.2.3(next@15.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
version: 4.2.3(next@15.2.8(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
postcss:
|
||||
specifier: ^8.5.4
|
||||
version: 8.5.4
|
||||
|
|
@ -449,8 +456,8 @@ importers:
|
|||
packages/build:
|
||||
dependencies:
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
specifier: workspace:^
|
||||
|
|
@ -483,7 +490,7 @@ importers:
|
|||
specifier: ^4.8.1
|
||||
version: 4.8.1
|
||||
zod:
|
||||
specifier: ^3.25.76
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
|
|
@ -551,11 +558,14 @@ importers:
|
|||
execa:
|
||||
specifier: ^9.5.2
|
||||
version: 9.6.0
|
||||
ignore:
|
||||
specifier: ^7.0.3
|
||||
version: 7.0.5
|
||||
openai:
|
||||
specifier: ^5.12.2
|
||||
version: 5.12.2(ws@8.18.3)(zod@3.25.76)
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
|
|
@ -584,7 +594,7 @@ importers:
|
|||
version: 0.13.0
|
||||
drizzle-orm:
|
||||
specifier: ^0.44.1
|
||||
version: 0.44.1(@libsql/client@0.15.8)(better-sqlite3@11.10.0)(gel@2.1.0)(postgres@3.4.7)
|
||||
version: 0.44.1(@libsql/client@0.15.8)(@opentelemetry/api@1.9.0)(better-sqlite3@11.10.0)(gel@2.1.0)(postgres@3.4.7)
|
||||
execa:
|
||||
specifier: ^9.6.0
|
||||
version: 9.6.0
|
||||
|
|
@ -610,8 +620,8 @@ importers:
|
|||
specifier: ^5.5.5
|
||||
version: 5.5.5
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
specifier: workspace:^
|
||||
|
|
@ -672,8 +682,8 @@ importers:
|
|||
specifier: ^5.0.0
|
||||
version: 5.1.1
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
specifier: workspace:^
|
||||
|
|
@ -694,8 +704,8 @@ importers:
|
|||
packages/types:
|
||||
dependencies:
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
specifier: workspace:^
|
||||
|
|
@ -756,7 +766,7 @@ importers:
|
|||
version: 1.2.0
|
||||
'@mistralai/mistralai':
|
||||
specifier: ^1.9.18
|
||||
version: 1.9.18(zod@3.25.61)
|
||||
version: 1.9.18(zod@3.25.76)
|
||||
'@modelcontextprotocol/sdk':
|
||||
specifier: 1.12.0
|
||||
version: 1.12.0
|
||||
|
|
@ -844,6 +854,9 @@ importers:
|
|||
isbinaryfile:
|
||||
specifier: ^5.0.2
|
||||
version: 5.0.4
|
||||
json-stream-stringify:
|
||||
specifier: ^3.1.6
|
||||
version: 3.1.6
|
||||
jwt-decode:
|
||||
specifier: ^4.0.0
|
||||
version: 4.0.0
|
||||
|
|
@ -867,7 +880,7 @@ importers:
|
|||
version: 0.5.17
|
||||
openai:
|
||||
specifier: ^5.12.2
|
||||
version: 5.12.2(ws@8.18.3)(zod@3.25.61)
|
||||
version: 5.12.2(ws@8.18.3)(zod@3.25.76)
|
||||
os-name:
|
||||
specifier: ^6.0.0
|
||||
version: 6.1.0
|
||||
|
|
@ -974,9 +987,15 @@ importers:
|
|||
specifier: ^2.8.0
|
||||
version: 2.8.0
|
||||
zod:
|
||||
specifier: 3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@ai-sdk/openai-compatible':
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.31(zod@3.25.76)
|
||||
'@openrouter/ai-sdk-provider':
|
||||
specifier: ^2.0.4
|
||||
version: 2.1.1(ai@6.0.57(zod@3.25.76))(zod@3.25.76)
|
||||
'@roo-code/build':
|
||||
specifier: workspace:^
|
||||
version: link:../packages/build
|
||||
|
|
@ -1049,6 +1068,9 @@ importers:
|
|||
'@vscode/vsce':
|
||||
specifier: 3.3.2
|
||||
version: 3.3.2
|
||||
ai:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.57(zod@3.25.76)
|
||||
esbuild-wasm:
|
||||
specifier: ^0.25.0
|
||||
version: 0.25.12
|
||||
|
|
@ -1084,7 +1106,7 @@ importers:
|
|||
version: 3.2.4(@types/debug@4.1.12)(@types/node@20.17.50)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0)
|
||||
zod-to-ts:
|
||||
specifier: ^1.2.0
|
||||
version: 1.2.0(typescript@5.8.3)(zod@3.25.61)
|
||||
version: 1.2.0(typescript@5.8.3)(zod@3.25.76)
|
||||
|
||||
webview-ui:
|
||||
dependencies:
|
||||
|
|
@ -1115,6 +1137,9 @@ importers:
|
|||
'@radix-ui/react-progress':
|
||||
specifier: ^1.1.2
|
||||
version: 1.1.6(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-radio-group':
|
||||
specifier: ^1.3.8
|
||||
version: 1.3.8(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-select':
|
||||
specifier: ^2.1.6
|
||||
version: 2.2.4(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
|
@ -1211,6 +1236,9 @@ importers:
|
|||
react:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1
|
||||
react-compiler-runtime:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0(react@18.3.1)
|
||||
react-dom:
|
||||
specifier: ^18.3.1
|
||||
version: 18.3.1(react@18.3.1)
|
||||
|
|
@ -1287,8 +1315,8 @@ importers:
|
|||
specifier: ^0.2.2
|
||||
version: 0.2.2(@types/react@18.3.23)(react@18.3.1)
|
||||
zod:
|
||||
specifier: ^3.25.61
|
||||
version: 3.25.61
|
||||
specifier: 3.25.76
|
||||
version: 3.25.76
|
||||
devDependencies:
|
||||
'@roo-code/config-eslint':
|
||||
specifier: workspace:^
|
||||
|
|
@ -1338,6 +1366,9 @@ importers:
|
|||
'@vitest/ui':
|
||||
specifier: ^3.2.3
|
||||
version: 3.2.4(vitest@3.2.4)
|
||||
babel-plugin-react-compiler:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
identity-obj-proxy:
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
|
|
@ -1356,6 +1387,38 @@ packages:
|
|||
'@adobe/css-tools@4.4.2':
|
||||
resolution: {integrity: sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==}
|
||||
|
||||
'@ai-sdk/gateway@3.0.25':
|
||||
resolution: {integrity: sha512-j0AQeA7hOVqwImykQlganf/Euj3uEXf0h3G0O4qKTDpEwE+EZGIPnVimCWht5W91lAetPZSfavDyvfpuPDd2PQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/openai-compatible@1.0.31':
|
||||
resolution: {integrity: sha512-znBvaVHM0M6yWNerIEy3hR+O8ZK2sPcE7e2cxfb6kYLEX3k//JH5VDnRnajseVofg7LXtTCFFdjsB7WLf1BdeQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/provider-utils@3.0.20':
|
||||
resolution: {integrity: sha512-iXHVe0apM2zUEzauqJwqmpC37A5rihrStAih5Ks+JE32iTe4LZ58y17UGBjpQQTCRw9YxMeo2UFLxLpBluyvLQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/provider-utils@4.0.10':
|
||||
resolution: {integrity: sha512-VeDAiCH+ZK8Xs4hb9Cw7pHlujWNL52RKe8TExOkrw6Ir1AmfajBZTb9XUdKOZO08RwQElIKA8+Ltm+Gqfo8djQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/provider@2.0.1':
|
||||
resolution: {integrity: sha512-KCUwswvsC5VsW2PWFqF8eJgSCu5Ysj7m1TxiHTVA6g7k360bk0RNQENT8KTMAYEs+8fWPD3Uu4dEmzGHc+jGng==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@ai-sdk/provider@3.0.5':
|
||||
resolution: {integrity: sha512-2Xmoq6DBJqmSl80U6V9z5jJSJP7ehaJJQMy2iFUqTay06wdCqTnPVBBQbtEL8RCChenL+q5DC5H5WzU3vV3v8w==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@alcalzone/ansi-tokenize@0.2.3':
|
||||
resolution: {integrity: sha512-jsElTJ0sQ4wHRz+C45tfect76BwbTbgkgKByOzpCN9xG61N5V6u/glvg1CsNJhq2xJIFpKHSwG3D2wPPuEYOrQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
|
@ -2374,7 +2437,7 @@ packages:
|
|||
'@mistralai/mistralai@1.9.18':
|
||||
resolution: {integrity: sha512-D/vNAGEvWMsg95tzgLTg7pPnW9leOPyH+nh1Os05NwxVPbUykoYgMAwOEX7J46msahWdvZ4NQQuxUXIUV2P6dg==}
|
||||
peerDependencies:
|
||||
zod: '>= 3'
|
||||
zod: 3.25.76
|
||||
|
||||
'@mixmark-io/domino@2.2.0':
|
||||
resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==}
|
||||
|
|
@ -2573,6 +2636,17 @@ packages:
|
|||
'@open-draft/until@2.1.0':
|
||||
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
|
||||
|
||||
'@openrouter/ai-sdk-provider@2.1.1':
|
||||
resolution: {integrity: sha512-UypPbVnSExxmG/4Zg0usRiit3auvQVrjUXSyEhm0sZ9GQnW/d8p/bKgCk2neh1W5YyRSo7PNQvCrAEBHZnqQkQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
ai: ^6.0.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@opentelemetry/api@1.9.0':
|
||||
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
'@oxc-resolver/binding-darwin-arm64@11.2.0':
|
||||
resolution: {integrity: sha512-ruKLkS+Dm/YIJaUhzEB7zPI+jh3EXxu0QnNV8I7t9jf0lpD2VnltuyRbhrbJEkksklZj//xCMyFFsILGjiU2Mg==}
|
||||
cpu: [arm64]
|
||||
|
|
@ -3074,6 +3148,19 @@ packages:
|
|||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-radio-group@1.3.8':
|
||||
resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==}
|
||||
peerDependencies:
|
||||
'@types/react': ^18.3.23
|
||||
'@types/react-dom': ^18.3.5
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.10':
|
||||
resolution: {integrity: sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==}
|
||||
peerDependencies:
|
||||
|
|
@ -3087,6 +3174,19 @@ packages:
|
|||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.11':
|
||||
resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==}
|
||||
peerDependencies:
|
||||
'@types/react': ^18.3.23
|
||||
'@types/react-dom': ^18.3.5
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.9':
|
||||
resolution: {integrity: sha512-ZzrIFnMYHHCNqSNCsuN6l7wlewBEq0O0BCSBkabJMFXVO51LRUTq71gLP1UxFvmrXElqmPjA5VX7IqC9VpazAQ==}
|
||||
peerDependencies:
|
||||
|
|
@ -3801,6 +3901,9 @@ packages:
|
|||
'@socket.io/component-emitter@3.1.2':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
'@standard-schema/spec@1.1.0':
|
||||
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
|
||||
|
||||
'@standard-schema/utils@0.3.0':
|
||||
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
|
||||
|
||||
|
|
@ -4421,6 +4524,10 @@ packages:
|
|||
resolution: {integrity: sha512-e4kQK9mP8ntpo3dACWirGod/hHv4qO5JMj9a/0a2AZto7b4persj5YP7t1Er372gTtYFTYxNhMx34jRvHooglw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
'@vercel/oidc@3.1.0':
|
||||
resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
'@vitejs/plugin-react@4.4.1':
|
||||
resolution: {integrity: sha512-IpEm5ZmeXAP/osiBXVVP5KjFMzbWOonMs0NaQQl+xYnUAcq4oHUBsF2+p4MgKWG4YMmFYJU8A6sxRPuowllm6w==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
|
@ -4573,6 +4680,12 @@ packages:
|
|||
resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
|
||||
ai@6.0.57:
|
||||
resolution: {integrity: sha512-5wYcMQmOaNU71wGv4XX1db3zvn4uLjLbTKIo6cQZPWOJElA0882XI7Eawx6TCd5jbjOvKMIP+KLWbpVomAFT2g==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
ajv@6.12.6:
|
||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||
|
||||
|
|
@ -4747,6 +4860,9 @@ packages:
|
|||
b4a@1.6.7:
|
||||
resolution: {integrity: sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==}
|
||||
|
||||
babel-plugin-react-compiler@1.0.0:
|
||||
resolution: {integrity: sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==}
|
||||
|
||||
bail@1.0.5:
|
||||
resolution: {integrity: sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==}
|
||||
|
||||
|
|
@ -6152,6 +6268,10 @@ packages:
|
|||
resolution: {integrity: sha512-6RxOBZ/cYgd8usLwsEl+EC09Au/9BcmCKYF2/xbml6DNczf7nv0MQb+7BA2F+li6//I+28VNlQR37XfQtcAJuA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
eventsource-parser@3.0.6:
|
||||
resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
eventsource@3.0.7:
|
||||
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
|
@ -7271,9 +7391,16 @@ packages:
|
|||
json-schema-traverse@0.4.1:
|
||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||
|
||||
json-schema@0.4.0:
|
||||
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1:
|
||||
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
||||
|
||||
json-stream-stringify@3.1.6:
|
||||
resolution: {integrity: sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==}
|
||||
engines: {node: '>=7.10.1'}
|
||||
|
||||
json-stringify-safe@5.0.1:
|
||||
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
|
||||
|
||||
|
|
@ -8265,7 +8392,7 @@ packages:
|
|||
hasBin: true
|
||||
peerDependencies:
|
||||
ws: ^8.18.0
|
||||
zod: ^3.23.8
|
||||
zod: 3.25.76
|
||||
peerDependenciesMeta:
|
||||
ws:
|
||||
optional: true
|
||||
|
|
@ -8759,6 +8886,11 @@ packages:
|
|||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
|
||||
react-compiler-runtime@1.0.0:
|
||||
resolution: {integrity: sha512-rRfjYv66HlG8896yPUDONgKzG5BxZD1nV9U6rkm+7VCuvQc903C4MjcoZR4zPw53IKSOX9wMQVpA1IAbRtzQ7w==}
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental
|
||||
|
||||
react-cookie-consent@9.0.0:
|
||||
resolution: {integrity: sha512-Blyj+m+Zz7SFHYqT18p16EANgnSg2sIyU6Yp3vk83AnOnSW7qnehPkUe4+8+qxztJrNmCH5GP+VHsWzAKVOoZA==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -10636,25 +10768,19 @@ packages:
|
|||
zod-to-json-schema@3.24.5:
|
||||
resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==}
|
||||
peerDependencies:
|
||||
zod: ^3.24.1
|
||||
zod: 3.25.76
|
||||
|
||||
zod-to-ts@1.2.0:
|
||||
resolution: {integrity: sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==}
|
||||
peerDependencies:
|
||||
typescript: ^4.9.4 || ^5.0.2
|
||||
zod: ^3
|
||||
zod: 3.25.76
|
||||
|
||||
zod-validation-error@3.4.1:
|
||||
resolution: {integrity: sha512-1KP64yqDPQ3rupxNv7oXhf7KdhHHgaqbKuspVoiN93TT0xrBjql+Svjkdjq/Qh/7GSMmgQs3AfvBT0heE35thw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
zod: ^3.24.4
|
||||
|
||||
zod@3.23.8:
|
||||
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
|
||||
|
||||
zod@3.25.61:
|
||||
resolution: {integrity: sha512-fzfJgUw78LTNnHujj9re1Ov/JJQkRZZGDMcYqSx7Hp4rPOkKywaFHq0S6GoHeXs0wGNE/sIOutkXgnwzrVOGCQ==}
|
||||
zod: 3.25.76
|
||||
|
||||
zod@3.25.76:
|
||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||
|
|
@ -10684,6 +10810,41 @@ snapshots:
|
|||
|
||||
'@adobe/css-tools@4.4.2': {}
|
||||
|
||||
'@ai-sdk/gateway@3.0.25(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.5
|
||||
'@ai-sdk/provider-utils': 4.0.10(zod@3.25.76)
|
||||
'@vercel/oidc': 3.1.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/openai-compatible@1.0.31(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 2.0.1
|
||||
'@ai-sdk/provider-utils': 3.0.20(zod@3.25.76)
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/provider-utils@3.0.20(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 2.0.1
|
||||
'@standard-schema/spec': 1.1.0
|
||||
eventsource-parser: 3.0.6
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/provider-utils@4.0.10(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.5
|
||||
'@standard-schema/spec': 1.1.0
|
||||
eventsource-parser: 3.0.6
|
||||
zod: 3.25.76
|
||||
|
||||
'@ai-sdk/provider@2.0.1':
|
||||
dependencies:
|
||||
json-schema: 0.4.0
|
||||
|
||||
'@ai-sdk/provider@3.0.5':
|
||||
dependencies:
|
||||
json-schema: 0.4.0
|
||||
|
||||
'@alcalzone/ansi-tokenize@0.2.3':
|
||||
dependencies:
|
||||
ansi-styles: 6.2.3
|
||||
|
|
@ -12198,10 +12359,10 @@ snapshots:
|
|||
dependencies:
|
||||
exenv-es6: 1.1.1
|
||||
|
||||
'@mistralai/mistralai@1.9.18(zod@3.25.61)':
|
||||
'@mistralai/mistralai@1.9.18(zod@3.25.76)':
|
||||
dependencies:
|
||||
zod: 3.25.61
|
||||
zod-to-json-schema: 3.24.5(zod@3.25.61)
|
||||
zod: 3.25.76
|
||||
zod-to-json-schema: 3.24.5(zod@3.25.76)
|
||||
|
||||
'@mixmark-io/domino@2.2.0': {}
|
||||
|
||||
|
|
@ -12369,6 +12530,13 @@ snapshots:
|
|||
|
||||
'@open-draft/until@2.1.0': {}
|
||||
|
||||
'@openrouter/ai-sdk-provider@2.1.1(ai@6.0.57(zod@3.25.76))(zod@3.25.76)':
|
||||
dependencies:
|
||||
ai: 6.0.57(zod@3.25.76)
|
||||
zod: 3.25.76
|
||||
|
||||
'@opentelemetry/api@1.9.0': {}
|
||||
|
||||
'@oxc-resolver/binding-darwin-arm64@11.2.0':
|
||||
optional: true
|
||||
|
||||
|
|
@ -12862,6 +13030,24 @@ snapshots:
|
|||
'@types/react': 18.3.23
|
||||
'@types/react-dom': 18.3.7(@types/react@18.3.23)
|
||||
|
||||
'@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-use-previous': 1.1.1(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-use-size': 1.1.1(@types/react@18.3.23)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.23
|
||||
'@types/react-dom': 18.3.7(@types/react@18.3.23)
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.10(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.2
|
||||
|
|
@ -12879,6 +13065,23 @@ snapshots:
|
|||
'@types/react': 18.3.23
|
||||
'@types/react-dom': 18.3.7(@types/react@18.3.23)
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-id': 1.1.1(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.23)(react@18.3.1)
|
||||
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.23)(react@18.3.1)
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.3.23
|
||||
'@types/react-dom': 18.3.7(@types/react@18.3.23)
|
||||
|
||||
'@radix-ui/react-roving-focus@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.23))(@types/react@18.3.23)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.2
|
||||
|
|
@ -13735,6 +13938,8 @@ snapshots:
|
|||
|
||||
'@socket.io/component-emitter@3.1.2': {}
|
||||
|
||||
'@standard-schema/spec@1.1.0': {}
|
||||
|
||||
'@standard-schema/utils@0.3.0': {}
|
||||
|
||||
'@swc/counter@0.1.3': {}
|
||||
|
|
@ -14392,6 +14597,8 @@ snapshots:
|
|||
satori: 0.12.2
|
||||
yoga-wasm-web: 0.3.3
|
||||
|
||||
'@vercel/oidc@3.1.0': {}
|
||||
|
||||
'@vitejs/plugin-react@4.4.1(vite@6.3.6(@types/node@20.17.57)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.19.4)(yaml@2.8.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.27.1
|
||||
|
|
@ -14614,6 +14821,14 @@ snapshots:
|
|||
dependencies:
|
||||
humanize-ms: 1.2.1
|
||||
|
||||
ai@6.0.57(zod@3.25.76):
|
||||
dependencies:
|
||||
'@ai-sdk/gateway': 3.0.25(zod@3.25.76)
|
||||
'@ai-sdk/provider': 3.0.5
|
||||
'@ai-sdk/provider-utils': 4.0.10(zod@3.25.76)
|
||||
'@opentelemetry/api': 1.9.0
|
||||
zod: 3.25.76
|
||||
|
||||
ajv@6.12.6:
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
|
|
@ -14838,6 +15053,10 @@ snapshots:
|
|||
|
||||
b4a@1.6.7: {}
|
||||
|
||||
babel-plugin-react-compiler@1.0.0:
|
||||
dependencies:
|
||||
'@babel/types': 7.27.1
|
||||
|
||||
bail@1.0.5: {}
|
||||
|
||||
bail@2.0.2: {}
|
||||
|
|
@ -15141,7 +15360,7 @@ snapshots:
|
|||
dependencies:
|
||||
devtools-protocol: 0.0.1367902
|
||||
mitt: 3.0.1
|
||||
zod: 3.23.8
|
||||
zod: 3.25.76
|
||||
|
||||
chromium-bidi@5.1.0(devtools-protocol@0.0.1452169):
|
||||
dependencies:
|
||||
|
|
@ -15819,9 +16038,10 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
drizzle-orm@0.44.1(@libsql/client@0.15.8)(better-sqlite3@11.10.0)(gel@2.1.0)(postgres@3.4.7):
|
||||
drizzle-orm@0.44.1(@libsql/client@0.15.8)(@opentelemetry/api@1.9.0)(better-sqlite3@11.10.0)(gel@2.1.0)(postgres@3.4.7):
|
||||
optionalDependencies:
|
||||
'@libsql/client': 0.15.8
|
||||
'@opentelemetry/api': 1.9.0
|
||||
better-sqlite3: 11.10.0
|
||||
gel: 2.1.0
|
||||
postgres: 3.4.7
|
||||
|
|
@ -16296,6 +16516,8 @@ snapshots:
|
|||
|
||||
eventsource-parser@3.0.2: {}
|
||||
|
||||
eventsource-parser@3.0.6: {}
|
||||
|
||||
eventsource@3.0.7:
|
||||
dependencies:
|
||||
eventsource-parser: 3.0.2
|
||||
|
|
@ -17598,8 +17820,12 @@ snapshots:
|
|||
|
||||
json-schema-traverse@0.4.1: {}
|
||||
|
||||
json-schema@0.4.0: {}
|
||||
|
||||
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||
|
||||
json-stream-stringify@3.1.6: {}
|
||||
|
||||
json-stringify-safe@5.0.1: {}
|
||||
|
||||
json5@2.2.3: {}
|
||||
|
|
@ -18647,20 +18873,20 @@ snapshots:
|
|||
|
||||
netmask@2.0.2: {}
|
||||
|
||||
next-sitemap@4.2.3(next@15.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
|
||||
next-sitemap@4.2.3(next@15.2.8(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)):
|
||||
dependencies:
|
||||
'@corex/deepmerge': 4.0.43
|
||||
'@next/env': 13.5.11
|
||||
fast-glob: 3.3.3
|
||||
minimist: 1.2.8
|
||||
next: 15.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
next: 15.2.8(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
|
||||
next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
next@15.2.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
next@15.2.8(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@1.0.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@next/env': 15.2.8
|
||||
'@swc/counter': 0.1.3
|
||||
|
|
@ -18680,6 +18906,8 @@ snapshots:
|
|||
'@next/swc-linux-x64-musl': 15.2.5
|
||||
'@next/swc-win32-arm64-msvc': 15.2.5
|
||||
'@next/swc-win32-x64-msvc': 15.2.5
|
||||
'@opentelemetry/api': 1.9.0
|
||||
babel-plugin-react-compiler: 1.0.0
|
||||
sharp: 0.33.5
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
|
|
@ -18852,11 +19080,6 @@ snapshots:
|
|||
is-inside-container: 1.0.0
|
||||
is-wsl: 3.1.0
|
||||
|
||||
openai@5.12.2(ws@8.18.3)(zod@3.25.61):
|
||||
optionalDependencies:
|
||||
ws: 8.18.3
|
||||
zod: 3.25.61
|
||||
|
||||
openai@5.12.2(ws@8.18.3)(zod@3.25.76):
|
||||
optionalDependencies:
|
||||
ws: 8.18.3
|
||||
|
|
@ -19396,6 +19619,10 @@ snapshots:
|
|||
strip-json-comments: 2.0.1
|
||||
optional: true
|
||||
|
||||
react-compiler-runtime@1.0.0(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
react-cookie-consent@9.0.0(react@18.3.1):
|
||||
dependencies:
|
||||
js-cookie: 2.2.1
|
||||
|
|
@ -21692,27 +21919,19 @@ snapshots:
|
|||
compress-commons: 6.0.2
|
||||
readable-stream: 4.7.0
|
||||
|
||||
zod-to-json-schema@3.24.5(zod@3.25.61):
|
||||
dependencies:
|
||||
zod: 3.25.61
|
||||
|
||||
zod-to-json-schema@3.24.5(zod@3.25.76):
|
||||
dependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
zod-to-ts@1.2.0(typescript@5.8.3)(zod@3.25.61):
|
||||
zod-to-ts@1.2.0(typescript@5.8.3)(zod@3.25.76):
|
||||
dependencies:
|
||||
typescript: 5.8.3
|
||||
zod: 3.25.61
|
||||
zod: 3.25.76
|
||||
|
||||
zod-validation-error@3.4.1(zod@3.25.76):
|
||||
dependencies:
|
||||
zod: 3.25.76
|
||||
|
||||
zod@3.23.8: {}
|
||||
|
||||
zod@3.25.61: {}
|
||||
|
||||
zod@3.25.76: {}
|
||||
|
||||
zustand@5.0.9(@types/react@18.3.23)(react@19.2.3):
|
||||
|
|
|
|||
BIN
releases/3.42.0-release.png
Normal file
BIN
releases/3.42.0-release.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
releases/3.43.0-release.png
Normal file
BIN
releases/3.43.0-release.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
releases/3.44.0-release.png
Normal file
BIN
releases/3.44.0-release.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
BIN
releases/3.45.0-release.png
Normal file
BIN
releases/3.45.0-release.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
|
|
@ -5,6 +5,9 @@ const readline = require("readline")
|
|||
// detect "yes" flags
|
||||
const autoYes = process.argv.includes("-y")
|
||||
|
||||
// detect nightly flag
|
||||
const isNightly = process.argv.includes("--nightly")
|
||||
|
||||
// detect editor command from args or default to "code"
|
||||
const editorArg = process.argv.find((arg) => arg.startsWith("--editor="))
|
||||
const defaultEditor = editorArg ? editorArg.split("=")[1] : "code"
|
||||
|
|
@ -24,14 +27,29 @@ const askQuestion = (question) => {
|
|||
|
||||
async function main() {
|
||||
try {
|
||||
const packageJson = JSON.parse(fs.readFileSync("./src/package.json", "utf-8"))
|
||||
const name = packageJson.name
|
||||
const version = packageJson.version
|
||||
const vsixFileName = `./bin/${name}-${version}.vsix`
|
||||
const publisher = packageJson.publisher
|
||||
const extensionId = `${publisher}.${name}`
|
||||
let name, version, publisher
|
||||
|
||||
console.log("\n🚀 Roo Code VSIX Installer")
|
||||
if (isNightly) {
|
||||
// For nightly, read the nightly-specific package.json and get publisher from src
|
||||
const nightlyPackageJson = JSON.parse(
|
||||
fs.readFileSync("./apps/vscode-nightly/package.nightly.json", "utf-8"),
|
||||
)
|
||||
const srcPackageJson = JSON.parse(fs.readFileSync("./src/package.json", "utf-8"))
|
||||
name = nightlyPackageJson.name
|
||||
version = nightlyPackageJson.version
|
||||
publisher = srcPackageJson.publisher
|
||||
} else {
|
||||
const packageJson = JSON.parse(fs.readFileSync("./src/package.json", "utf-8"))
|
||||
name = packageJson.name
|
||||
version = packageJson.version
|
||||
publisher = packageJson.publisher
|
||||
}
|
||||
|
||||
const vsixFileName = `./bin/${name}-${version}.vsix`
|
||||
const extensionId = `${publisher}.${name}`
|
||||
const buildType = isNightly ? "Nightly" : "Regular"
|
||||
|
||||
console.log(`\n🚀 Roo Code VSIX Installer (${buildType})`)
|
||||
console.log("========================")
|
||||
console.log("\nThis script will:")
|
||||
console.log("1. Uninstall any existing version of the Roo Code extension")
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue