File size: 3,138 Bytes
70f2179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

"""Configuration model for the OpenCode harness primitive."""

from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, Field


Provider = Literal["openai_compatible", "openai", "anthropic"]


class OpenCodeConfig(BaseModel):
    """All configuration required to launch one OpenCode rollout in a sandbox.

    Field names are provider-agnostic. The primitive maps ``provider`` onto the
    correct ``opencode.json`` provider block (``@ai-sdk/openai-compatible``,
    ``@ai-sdk/openai``, or ``@ai-sdk/anthropic``) and injects ``base_url`` /
    ``api_key`` into it.
    """

    # --- LLM endpoint ---------------------------------------------------------
    provider: Provider = "openai_compatible"
    base_url: str
    api_key: str = "intercepted"
    model: str = "intercepted/model"
    request_timeout_ms: int = 600_000

    # --- OpenCode CLI ---------------------------------------------------------
    opencode_version: str = "latest"
    disabled_tools: list[str] = Field(
        default_factory=lambda: ["webfetch", "question"]
    )
    enabled_tools: list[str] | None = None
    system_prompt: str | None = None
    extra_opencode_json: dict[str, Any] = Field(default_factory=dict)

    # --- CLI invocation -------------------------------------------------------
    run_format: Literal["default", "json"] = "json"
    agent_timeout_s: float = 900.0
    extra_env: dict[str, str] = Field(default_factory=dict)
    extra_setup_shell: str | None = None

    # --- Sandbox paths --------------------------------------------------------
    # Root directory inside the sandbox where the primitive writes config,
    # task files, and logs. E2B's default user is ``user`` with home
    # ``/home/user``. Override when using a root-privileged backend (Docker).
    sandbox_home: str = "/home/user"

    # --- Transparent-proxy tuning --------------------------------------------
    # Cap ``max_tokens`` / ``max_completion_tokens`` on forwarded requests.
    # OpenCode defaults to a very large number (~32000) which exceeds some
    # provider limits (e.g. gpt-4o-mini = 16384). Only used in
    # ``mode="transparent_proxy"``. ``None`` disables the cap.
    proxy_max_tokens_cap: int | None = 16384
    # Per-turn top-k logprobs the proxy requests from the upstream.
    proxy_top_logprobs: int = 5
    # Disable reasoning/thinking mode for Qwen3 / Qwen3.5 models. Proxy sets
    # ``extra_body.chat_template_kwargs.enable_thinking=false`` on forwarded
    # requests. Ignored by providers that don't support the field.
    proxy_disable_thinking: bool = False


_PROVIDER_NPM = {
    "openai_compatible": "@ai-sdk/openai-compatible",
    "openai": "@ai-sdk/openai",
    "anthropic": "@ai-sdk/anthropic",
}


def provider_npm_package(provider: Provider) -> str:
    """Return the AI SDK npm package opencode should use for a provider."""
    return _PROVIDER_NPM[provider]