///|
enum Agent {
Codex
OpenCode
}
///|
fn parse_agent(raw : String) -> Agent raise {
match raw {
"codex" => Codex
"opencode" => OpenCode
_ => fail("unsupported agent: \{raw}; expected codex or opencode")
}
}
///|
fn translation_opencode_config() -> @opencode.ConfigObject {
{ "permission": Json::string("deny") }
}
///|
fn translation_opencode_thread_options(
model : String?,
) -> @opencode.ThreadOptions {
@opencode.ThreadOptions::ThreadOptions(
model=model.unwrap_or("opencode-go/deepseek-v4-flash"),
title="mdt-translate",
)
}
///|
fn translation_codex_thread_options(model : String?) -> @codex.ThreadOptions {
@codex.ThreadOptions::ThreadOptions(
model=model.unwrap_or("gpt-5.6-luna"),
sandbox_mode=@codex.ReadOnly,
skip_git_repo_check=true,
approval_policy=@codex.Never,
)
}
///|
fn translation_system_prompt(lang : String) -> String {
[
"You are a markdown translator. Translate the user's input markdown to \{lang}.",
"Strict rules:",
"- Preserve all code blocks, inline code, links, HTML tags, and YAML/TOML frontmatter exactly as-is (do not translate code, URLs, fence languages, or attribute values).",
"- Translate prose in headings, paragraphs, lists, blockquotes, and table cells.",
"- Keep the original markdown structure (heading levels, list markers, blank lines).",
"- Output ONLY the translated markdown. No commentary, no explanation, no fence wrapping.",
].join("\n")
}
///|
fn translation_prompt(lang : String, text : String) -> String {
[translation_system_prompt(lang), "", "Input markdown:", text].join("\n")
}
///|
async fn translate_markdown_with_client(
client : @agent.Cli,
lang : String,
text : String,
) -> String {
client.start().prompt(@agent.Prompt::Prompt(translation_prompt(lang, text))).text
}
///|
async fn translate_markdown(
agent : Agent,
lang : String,
model : String?,
text : String,
) -> String {
match agent {
Codex => {
let client = @agent_codex.codex_cli(
thread_options=translation_codex_thread_options(model),
)
translate_markdown_with_client(client, lang, text)
}
OpenCode => {
let client = @agent_opencode.opencode_cli(
options=@opencode.ClientOptions::ClientOptions(
config=translation_opencode_config(),
),
thread_options=translation_opencode_thread_options(model),
)
translate_markdown_with_client(client, lang, text)
}
}
}