Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 83 additions & 123 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,123 +1,83 @@
# Ultracite Code Standards

This project uses **Ultracite**, a zero-config preset that enforces strict code quality standards through automated formatting and linting.

## Quick Reference

- **Format code**: `npm exec -- ultracite fix`
- **Check for issues**: `npm exec -- ultracite check`
- **Diagnose setup**: `npm exec -- ultracite doctor`

Biome (the underlying engine) provides robust linting and formatting. Most issues are automatically fixable.

---

## Core Principles

Write code that is **accessible, performant, type-safe, and maintainable**. Focus on clarity and explicit intent over brevity.

### Type Safety & Explicitness

- Use explicit types for function parameters and return values when they enhance clarity
- Prefer `unknown` over `any` when the type is genuinely unknown
- Use const assertions (`as const`) for immutable values and literal types
- Leverage TypeScript's type narrowing instead of type assertions
- Use meaningful variable names instead of magic numbers - extract constants with descriptive names

### Modern JavaScript/TypeScript

- Use arrow functions for callbacks and short functions
- Prefer `for...of` loops over `.forEach()` and indexed `for` loops
- Use optional chaining (`?.`) and nullish coalescing (`??`) for safer property access
- Prefer template literals over string concatenation
- Use destructuring for object and array assignments
- Use `const` by default, `let` only when reassignment is needed, never `var`

### Async & Promises

- Always `await` promises in async functions - don't forget to use the return value
- Use `async/await` syntax instead of promise chains for better readability
- Handle errors appropriately in async code with try-catch blocks
- Don't use async functions as Promise executors

### React & JSX

- Use function components over class components
- Call hooks at the top level only, never conditionally
- Specify all dependencies in hook dependency arrays correctly
- Use the `key` prop for elements in iterables (prefer unique IDs over array indices)
- Nest children between opening and closing tags instead of passing as props
- Don't define components inside other components
- Use semantic HTML and ARIA attributes for accessibility:
- Provide meaningful alt text for images
- Use proper heading hierarchy
- Add labels for form inputs
- Include keyboard event handlers alongside mouse events
- Use semantic elements (`<button>`, `<nav>`, etc.) instead of divs with roles

### Error Handling & Debugging

- Remove `console.log`, `debugger`, and `alert` statements from production code
- Throw `Error` objects with descriptive messages, not strings or other values
- Use `try-catch` blocks meaningfully - don't catch errors just to rethrow them
- Prefer early returns over nested conditionals for error cases

### Code Organization

- Keep functions focused and under reasonable cognitive complexity limits
- Extract complex conditions into well-named boolean variables
- Use early returns to reduce nesting
- Prefer simple conditionals over nested ternary operators
- Group related code together and separate concerns

### Security

- Add `rel="noopener"` when using `target="_blank"` on links
- Avoid `dangerouslySetInnerHTML` unless absolutely necessary
- Don't use `eval()` or assign directly to `document.cookie`
- Validate and sanitize user input

### Performance

- Avoid spread syntax in accumulators within loops
- Use top-level regex literals instead of creating them in loops
- Prefer specific imports over namespace imports
- Avoid barrel files (index files that re-export everything)
- Use proper image components (e.g., Next.js `<Image>`) over `<img>` tags

### Framework-Specific Guidance

**Next.js:**
- Use Next.js `<Image>` component for images
- Use `next/head` or App Router metadata API for head elements
- Use Server Components for async data fetching instead of async Client Components

**React 19+:**
- Use ref as a prop instead of `React.forwardRef`

**Solid/Svelte/Vue/Qwik:**
- Use `class` and `for` attributes (not `className` or `htmlFor`)

---

## Testing

- Write assertions inside `it()` or `test()` blocks
- Avoid done callbacks in async tests - use async/await instead
- Don't use `.only` or `.skip` in committed code
- Keep test suites reasonably flat - avoid excessive `describe` nesting

## When Biome Can't Help

Biome's linter will catch most issues automatically. Focus your attention on:

1. **Business logic correctness** - Biome can't validate your algorithms
2. **Meaningful naming** - Use descriptive names for functions, variables, and types
3. **Architecture decisions** - Component structure, data flow, and API design
4. **Edge cases** - Handle boundary conditions and error states
5. **User experience** - Accessibility, performance, and usability considerations
6. **Documentation** - Add comments for complex logic, but prefer self-documenting code

---

Most formatting and common issues are automatically fixed by Biome. Run `npm exec -- ultracite fix` before committing to ensure compliance.
# PROJECT KNOWLEDGE BASE

**Generated:** 2026-02-23 14:40 KST
**Commit:** 4671d67
**Branch:** main
**Mode:** update
Comment on lines +3 to +6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

커밋 해시 및 브랜치 메타데이터가 즉시 낡아집니다

**Commit:** 4671d67는 이 PR이 머지된 이후 첫 번째 커밋부터 정확하지 않은 정보가 됩니다. **Branch:** main도 현재 PR 브랜치(feat/reasoning-mode-friendli)와 일치하지 않습니다. 이 파일이 도구에 의해 생성된다면 CI 파이프라인에서 자동으로 갱신해야 하고, 그렇지 않다면 빠르게 낡아지는 메타데이터 블록 전체를 제거하는 것을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 3 - 6, The autogenerated metadata block (timestamp,
the lines beginning with "**Commit:** 4671d67" and "**Branch:** main") will
quickly become stale; remove this entire metadata block from AGENTS.md or change
the generator to stop embedding mutable fields and instead inject dynamic values
at build time (or have CI update them). Specifically, remove the hard-coded
"**Commit:**" and "**Branch:**" entries (and the generated timestamp) from the
file OR modify the doc-generation step to populate those fields during CI so
they stay accurate.


## OVERVIEW
`code-editing-agent` is a Bun + TypeScript CLI agent with two runtime paths: interactive TUI (`cli.ts`) and JSONL event streaming (`headless.ts`).
Core source code lives in `src/`, benchmark integration lives in `benchmark/`, and run artifacts are persisted under `jobs/`.

## STRUCTURE
```text
code-editing-agent/
|- src/ # Runtime code, tools, interaction, command handling
| |- AGENTS.md # Source-level conventions and navigation
| |- entrypoints/
| | `- AGENTS.md # Runtime front-door invariants (CLI/headless)
| `- tools/
| |- AGENTS.md # Tool subsystem boundaries and rules
| `- modify/
| `- AGENTS.md # High-risk file mutation constraints
|- benchmark/ # Harbor terminal-bench adapter (Python + templates)
|- jobs/ # Generated benchmark run artifacts (do not edit manually)
|- dist/ # TypeScript build output
|- package/dist/ # Published package artifacts
|- package.json # Canonical scripts and toolchain entrypoints
`- bunfig.toml # Bun test root (`src`)
```

## WHERE TO LOOK
| Task | Location | Notes |
Comment on lines +31 to +32
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

WHERE TO LOOK 및 CODE MAP 테이블 앞 빈 줄 누락

## WHERE TO LOOK(line 31)과 ## CODE MAP(line 42) 헤딩 바로 다음에 테이블이 시작되어 MD058 규칙을 위반합니다. (line 17 경고는 펜스 코드 블록 내부의 | 문자에 의한 오탐입니다.)

🔧 제안 수정
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
 |------|----------|-------|
 ## CODE MAP
+
 | Symbol | Type | Location | Refs | Role |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## WHERE TO LOOK
| Task | Location | Notes |
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
Suggested change
## WHERE TO LOOK
| Task | Location | Notes |
## CODE MAP
| Symbol | Type | Location | Refs | Role |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 31 - 32, Add a blank line after the headings "##
WHERE TO LOOK" and "## CODE MAP" so their following tables are separated from
the headings (fixing the MD058 violation); locate the headings in AGENTS.md and
insert an empty line directly after each heading (immediately after the "##
WHERE TO LOOK" and "## CODE MAP" lines).

|------|----------|-------|
| Interactive runtime loop | `src/entrypoints/cli.ts` | Input loop, command execution, stream lifecycle |
| Headless event pipeline | `src/entrypoints/headless.ts` | JSONL events for benchmark/verifier integration |
| Model/provider/tool orchestration | `src/agent.ts` | Agent manager, provider selection, stream setup |
| Tool registration map | `src/tools/index.ts` | Stable tool key names to implementations |
| Deterministic file editing | `src/tools/modify/edit-file.ts` | Hashline mode + legacy compatibility mode |
| Stream rendering behavior | `src/interaction/pi-tui-stream-renderer.ts` | Text/reasoning/tool output rendering |
| Benchmark adapter rules | `benchmark/AGENTS.md` | Trajectory conversion and validation constraints |

## CODE MAP
| Symbol | Type | Location | Refs | Role |
|--------|------|----------|------|------|
| `run` | function | `src/entrypoints/cli.ts:1553` | n/a | Main interactive session loop |
| `processAgentResponse` | function | `src/entrypoints/cli.ts:1255` | n/a | Handles one stream turn and continuation |
| `shouldContinueManualToolLoop` | constant fn | `src/interaction/tool-loop-control.ts:5` | 9 | Shared continuation gate for CLI/headless |
| `executeEditFile` | function | `src/tools/modify/edit-file.ts:1042` | 32 | Primary file mutation entrypoint |
| `AgentManager` | class | `src/agent.ts:163` | 2 | Central manager for model, provider, and tool config |
Comment on lines +44 to +49
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

CODE MAP의 하드코딩된 라인 번호와 참조 횟수는 유지 비용이 큽니다

:1553, :1255, :5, :1042, :163 같은 정확한 라인 번호와 Refs 열의 숫자(9, 32, 2)는 코드베이스가 변경될 때마다 즉시 부정확해집니다. 라인 번호 없이 파일 경로만 유지하거나, 이 테이블 전체를 자동 생성 단계로 관리하는 방안을 고려해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 44 - 49, The CODE MAP in AGENTS.md hardcodes fragile
line numbers and reference counts for symbols like run, processAgentResponse,
shouldContinueManualToolLoop, executeEditFile, and AgentManager; remove the
inline line-number suffixes (e.g., :1553) and the Refs column from the table so
it contains only symbol names, types, and file paths, or replace the table with
a small autogenerated section (a script or build step) that extracts current
line numbers and reference counts from the repository; update the table rows to
use only the file path (e.g., src/entrypoints/cli.ts) and symbol name/type and
add a note that line numbers are intentionally omitted or will be generated
automatically.


## CONVENTIONS
- Runtime and scripts are Bun-first (`packageManager: bun@1.3.9`); prefer `bun run <script>` over ad-hoc `npm exec`.
- Canonical quality flow is `check` (non-mutating) and `lint` (mutating via `ultracite fix`).
- Tests are colocated in `src/**` as `*.test.ts` and executed with `bun test` (`bunfig.toml` test root is `src`).
- `tsconfig.json` enforces `strict` and builds from `src` to `dist`; do not treat `dist` as source-of-truth.
- Legacy code should always be fully deprecated, and aggressive updates without backward-compatibility guarantees are acceptable in this repository.

## ANTI-PATTERNS (THIS PROJECT)
- Editing generated outputs (`jobs/`, `dist/`, `package/dist/`) as if they were source code.
- Using shell commands (`cat`, `sed`, `rm`, `find`, `grep`) for file operations that dedicated tools already cover.
- Stopping at planning/todo updates without executing the concrete actions.
- For benchmark work: changing event types without updating trajectory conversion rules in `benchmark/harbor_agent.py`.

## UNIQUE STYLES
- File edits favor hashline-aware operations (`LINE#HASH` + `expected_file_hash`) for stale-safe modifications.
- Manual tool-loop continuation is intentionally constrained to finish reasons `tool-calls` and `unknown`.
- Headless mode emits structured event types (`user`, `tool_call`, `tool_result`, `assistant`, `error`) consumed by benchmark tooling.

## COMMANDS
```bash
bun install
bun run start
bun run headless -- --prompt "<task>"
bun run check
bun run lint
bun run typecheck
bun run test
bun run build
```

## NOTES
- Root rules are global; see `src/AGENTS.md`, `src/entrypoints/AGENTS.md`, `src/tools/AGENTS.md`, and `src/tools/modify/AGENTS.md` for local, non-duplicated guidance.
- `benchmark/AGENTS.md` is intentionally specialized and should remain benchmark-focused.
1 change: 0 additions & 1 deletion benchmark/harbor_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ def create_run_agent_commands(self, instruction: str) -> list[ExecInput]:

env = {
"FRIENDLI_TOKEN": os.environ.get("FRIENDLI_TOKEN", ""),
"TMUX_CLEANUP_SESSION": "false",
"BUN_INSTALL": "/root/.bun",
"PATH": "/root/.bun/bin:/usr/local/bin:/usr/bin:/bin",
}
Expand Down
3 changes: 1 addition & 2 deletions benchmark/install-agent.sh.j2
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ echo "Installing system dependencies..."
# Required tools:
# - curl, git, ca-certificates: for cloning and downloading
# - unzip, tar: for extracting archives (bun install, ripgrep auto-download)
# - tmux: required for shell execution
# - ripgrep: for code search (faster than grep)
apt-get update -qq && apt-get install -y -qq --no-install-recommends \
curl git ca-certificates unzip tar tmux ripgrep \
curl git ca-certificates unzip tar ripgrep \
&& rm -rf /var/lib/apt/lists/*
Comment on lines 10 to 12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

tmux 제거로 terminal-bench@2.0 실행이 중단될 수 있습니다.

terminal-bench는 각 태스크 실행 시 전용 컨테이너 내부에서 tmux 세션을 생성하여 터미널 녹화 및 명령 실행을 수행합니다. 따라서 에이전트의 Docker 이미지에 tmux가 설치되어 있지 않으면 벤치마크가 런타임에 실패합니다.

🐛 `tmux` 재추가 제안
-  curl git ca-certificates unzip tar ripgrep \
+  curl git ca-certificates unzip tar ripgrep tmux \
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
apt-get update -qq && apt-get install -y -qq --no-install-recommends \
curl git ca-certificates unzip tar tmux ripgrep \
curl git ca-certificates unzip tar ripgrep \
&& rm -rf /var/lib/apt/lists/*
apt-get update -qq && apt-get install -y -qq --no-install-recommends \
curl git ca-certificates unzip tar ripgrep tmux \
&& rm -rf /var/lib/apt/lists/*
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@benchmark/install-agent.sh.j2` around lines 10 - 12, The install script
removed tmux which causes terminal-bench@2.0 to fail at runtime because it
spawns tmux sessions; update the apt-get install command (the line containing
"apt-get install -y -qq --no-install-recommends \ curl git ca-certificates unzip
tar ripgrep \") to include "tmux" in the package list so the agent Docker image
has tmux available during benchmark runs.


echo "Installing bun..."
Expand Down
52 changes: 52 additions & 0 deletions src/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# SOURCE KNOWLEDGE BASE

**Generated:** 2026-02-23 14:40 KST
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

하드코딩된 타임스탬프는 즉시 낡아집니다

**Generated:** 2026-02-23 14:40 KST는 커밋 이후 문서가 변경되어도 갱신되지 않으므로 독자에게 오해를 줄 수 있습니다. 해당 줄을 제거하거나, 지속적으로 갱신할 수 없다면 생성 날짜 대신 섹션 내용을 직접 최신화하는 방식을 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/AGENTS.md` at line 3, Remove the hardcoded timestamp line "**Generated:**
2026-02-23 14:40 KST" from the document (the exact literal string) because it
will become outdated; either delete that line entirely or replace it with a
non-dated status marker such as "Last updated: <maintainer-update-required>" or
a note instructing maintainers to update the section content manually so the
file stays accurate without a stale generated date.

**Scope:** `src/**`

## OVERVIEW
`src/` contains the runtime implementation for CLI/headless execution, tool orchestration, interaction rendering, and session middleware.

## STRUCTURE
```text
src/
|- entrypoints/ # CLI and headless runtime loops
| `- AGENTS.md # Entry-point-specific invariants
|- interaction/ # Stream rendering and continuation controls
|- tools/ # Tool implementations and registration
| |- AGENTS.md # Tool subsystem overview
| `- modify/
| `- AGENTS.md # File mutation invariants and failure modes
|- commands/ # Slash command implementations
|- context/ # Session, history, skills, and prompt assembly
|- middleware/ # Cross-turn behavior (todo continuation, routing)
|- skills/ # Built-in skill content and metadata
|- agent.ts # Agent manager and stream setup boundary
`- index.ts # CLI bootstrap entrypoint
```

## WHERE TO LOOK
| Task | Location | Notes |
Comment on lines +27 to +28
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

테이블 앞 빈 줄 누락 (MD058)

## WHERE TO LOOK 헤딩과 테이블 사이에 빈 줄이 없습니다. markdownlint MD058 규칙에 따라 테이블 앞뒤에 빈 줄이 필요합니다.

🔧 제안 수정
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## WHERE TO LOOK
| Task | Location | Notes |
## WHERE TO LOOK
| Task | Location | Notes |
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 28-28: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/AGENTS.md` around lines 27 - 28, Add a blank line between the "## WHERE
TO LOOK" heading and the following table (the "| Task | Location | Notes |" row)
so the heading and markdown table are separated as required by markdownlint
MD058; ensure there is also a blank line after the table if not already present.

|------|----------|-------|
| Follow interactive input lifecycle | `src/entrypoints/cli.ts` | `run` -> `processInput` -> `processAgentResponse` |
| Follow headless JSON event emission | `src/entrypoints/headless.ts` | Emits `user/tool_call/tool_result/assistant/error` |
| Change loop continuation policy | `src/interaction/tool-loop-control.ts` | Shared by CLI and headless |
| Adjust provider/model behavior | `src/agent.ts` | `AgentManager` owns stream setup and options |
| Modify slash command wiring | `src/commands/index.ts` | Keep aliases and command metadata aligned |
| Update auto-todo behavior | `src/middleware/todo-continuation.ts` | Drives cross-turn completion reminders |

## CONVENTIONS
- Keep runtime parity between `cli.ts` and `headless.ts` for continuation decisions and tool-loop safety boundaries.
- Keep tests colocated with source (`*.test.ts` beside implementation); this repo does not use a separate test directory.
- Prefer shared helpers for cross-runtime policies (`tool-loop-control.ts`) instead of duplicating literals.
- Treat `src/index.ts` as bootstrap-only; avoid placing runtime logic there.
- If a change alters event semantics in headless mode, verify benchmark compatibility via `benchmark/AGENTS.md` rules.

## ANTI-PATTERNS
- Adding runtime behavior only in one entrypoint when it should apply to both CLI and headless.
- Duplicating finish-reason continuation logic instead of reusing `shouldContinueManualToolLoop`.
- Introducing new command flows without corresponding tests in `src/**.test.ts`.
- Treating `src/tui/` as active runtime code without first adding real modules (currently an empty boundary).

## NOTES
- For entrypoint-specific constraints, see `src/entrypoints/AGENTS.md`.
- For tool subsystem and file mutation constraints, see `src/tools/AGENTS.md` and `src/tools/modify/AGENTS.md`.
48 changes: 48 additions & 0 deletions src/agent-reasoning-default.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { agentManager } from "./agent";

describe("AgentManager reasoning mode defaults", () => {
let originalProvider: ReturnType<typeof agentManager.getProvider>;
let originalModelId: ReturnType<typeof agentManager.getModelId>;
let originalReasoningMode: ReturnType<typeof agentManager.getReasoningMode>;

beforeEach(() => {
originalProvider = agentManager.getProvider();
originalModelId = agentManager.getModelId();
originalReasoningMode = agentManager.getReasoningMode();
});

afterEach(() => {
agentManager.setProvider(originalProvider);
agentManager.setModelId(originalModelId);
agentManager.setReasoningMode(originalReasoningMode);
});

it("selects preserved as default for GLM-5", () => {
agentManager.setProvider("friendli");
agentManager.setModelId("zai-org/GLM-5");

expect(agentManager.getReasoningMode()).toBe("preserved");
});

it("selects interleaved as default for MiniMax M2.5", () => {
agentManager.setProvider("friendli");
agentManager.setModelId("MiniMaxAI/MiniMax-M2.5");

expect(agentManager.getReasoningMode()).toBe("interleaved");
});

it("selects on as default for anthropic models", () => {
agentManager.setProvider("anthropic");

expect(agentManager.getReasoningMode()).toBe("on");
});

it("still allows explicit override after default selection", () => {
agentManager.setProvider("friendli");
agentManager.setModelId("MiniMaxAI/MiniMax-M2.5");
agentManager.setReasoningMode("on");

expect(agentManager.getReasoningMode()).toBe("on");
});
});
68 changes: 68 additions & 0 deletions src/agent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { agentManager, selectTranslationReasoningMode } from "./agent";

describe("AgentManager translation state", () => {
it("enables translation by default", () => {
expect(agentManager.isTranslationEnabled()).toBe(true);
});

it("toggles translation state on and off", () => {
const originalState = agentManager.isTranslationEnabled();

try {
agentManager.setTranslationEnabled(false);
expect(agentManager.isTranslationEnabled()).toBe(false);

agentManager.setTranslationEnabled(true);
expect(agentManager.isTranslationEnabled()).toBe(true);
} finally {
agentManager.setTranslationEnabled(originalState);
}
});
});

describe("selectTranslationReasoningMode", () => {
it("prefers off when available", () => {
expect(selectTranslationReasoningMode(["preserved", "off", "on"])).toBe(
"off"
);
});

it("falls back to on when off is unavailable", () => {
expect(selectTranslationReasoningMode(["interleaved", "on"])).toBe("on");
});
});

describe("AgentManager translation reasoning selection", () => {
let originalProvider: ReturnType<typeof agentManager.getProvider>;
let originalModelId: ReturnType<typeof agentManager.getModelId>;
let originalReasoningMode: ReturnType<typeof agentManager.getReasoningMode>;

beforeEach(() => {
originalProvider = agentManager.getProvider();
originalModelId = agentManager.getModelId();
originalReasoningMode = agentManager.getReasoningMode();
});

afterEach(() => {
agentManager.setProvider(originalProvider);
agentManager.setModelId(originalModelId);
agentManager.setReasoningMode(originalReasoningMode);
});

it("uses off for translation when off is selectable", () => {
agentManager.setProvider("friendli");
agentManager.setModelId("zai-org/GLM-5");
agentManager.setReasoningMode("preserved");

expect(agentManager.getTranslationReasoningMode()).toBe("off");
});

it("uses on for translation when off is unavailable", () => {
agentManager.setProvider("friendli");
agentManager.setModelId("MiniMaxAI/MiniMax-M2.5");
agentManager.setReasoningMode("interleaved");

expect(agentManager.getTranslationReasoningMode()).toBe("on");
});
});
Loading