mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 13:16:24 +00:00
fix(tenki): parse sticky environment values as booleans (#5849)
* fix(tenki): parse sticky environment values as booleans * docs(tenki): keep agent guidance within chain limit --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
parent
8712d495e2
commit
5850b0da9f
@ -102,6 +102,10 @@ policy or network-mode mismatch; only the provider may replace it after the
|
||||
orphan grace, local teardown reservation, and cross-instance teardown lease.
|
||||
Destroy the sandbox, sidecar, and both networks together.
|
||||
|
||||
### Tenki `sticky`
|
||||
|
||||
Env values stay strings; parse booleans before SDK calls (`bool("false")` is true).
|
||||
|
||||
### E2B Mount Uploads
|
||||
|
||||
E2B uploads host mounts during sandbox creation using binary file objects.
|
||||
|
||||
@ -25,6 +25,12 @@ sandbox:
|
||||
PYTHONUNBUFFERED: "1"
|
||||
```
|
||||
|
||||
`sticky` also accepts an environment reference such as `sticky: $TENKI_STICKY`.
|
||||
Boolean strings are case-insensitive: `false`, `0`, `off`, and `no` disable host
|
||||
pinning; `true`, `1`, `on`, and `yes` enable it. Invalid boolean values are
|
||||
rejected when the provider loads its configuration. Omitted or `null` values
|
||||
keep pinning disabled.
|
||||
|
||||
Install the optional SDK before selecting this provider:
|
||||
|
||||
```bash
|
||||
|
||||
@ -26,6 +26,8 @@ import uuid
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from pydantic import TypeAdapter
|
||||
|
||||
from deerflow.config import get_app_config
|
||||
from deerflow.sandbox.acquire_serialization import AcquireSerializer
|
||||
from deerflow.sandbox.identity import derive_sandbox_scope_token
|
||||
@ -141,6 +143,7 @@ class TenkiSandboxProvider(WarmPoolLifecycleMixin[TenkiSandbox], SandboxProvider
|
||||
replicas = _opt("replicas")
|
||||
idle_timeout = _opt("idle_timeout")
|
||||
max_duration = _opt("max_duration")
|
||||
sticky = _opt("sticky", False)
|
||||
environment = dict(_opt("environment") or {})
|
||||
# Fail fast on a misconfigured key (e.g. "bad-key"): the per-call env goes
|
||||
# through the same POSIX-name check in execute_command, but this static
|
||||
@ -159,7 +162,7 @@ class TenkiSandboxProvider(WarmPoolLifecycleMixin[TenkiSandbox], SandboxProvider
|
||||
# Off by default (the SDK default). Warm-pool sandboxes stay running
|
||||
# between turns, so host pinning only matters to deployments that
|
||||
# also pause/resume; expose it rather than decide for them.
|
||||
"sticky": bool(_opt("sticky", False)),
|
||||
"sticky": TypeAdapter(bool).validate_python(sticky) if sticky is not None else False,
|
||||
"api_key": api_key, # None → SDK falls back to TENKI_API_KEY / TENKI_AUTH_TOKEN
|
||||
"base_url": _opt("base_url"),
|
||||
"image": _opt("image"), # None → Tenki account default base image
|
||||
|
||||
@ -25,6 +25,7 @@ import pytest
|
||||
|
||||
from deerflow.community.tenki.provider import _BOOTSTRAP_TIMEOUT, TenkiSandboxProvider, _import_client
|
||||
from deerflow.community.tenki.sandbox import TenkiSandbox
|
||||
from deerflow.config.app_config import AppConfig
|
||||
|
||||
# ── Fake Tenki SDK ────────────────────────────────────────────────────
|
||||
|
||||
@ -755,6 +756,42 @@ def test_create_waits_client_side_and_configures_lifetime(monkeypatch):
|
||||
provider.shutdown()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("value", "expected"),
|
||||
[("false", False), ("0", False), ("off", False), ("no", False), ("FALSE", False), ("true", True), ("1", True), ("on", True), ("yes", True)],
|
||||
)
|
||||
def test_create_sticky_from_environment(monkeypatch, tmp_path, value, expected):
|
||||
monkeypatch.setenv("TEST_TENKI_STICKY", value)
|
||||
config_path = tmp_path / "config.yaml"
|
||||
config_path.write_text("models: []\nsandbox:\n use: deerflow.community.tenki:TenkiSandboxProvider\n sticky: $TEST_TENKI_STICKY\n idle_timeout: 0\n", encoding="utf-8")
|
||||
config = AppConfig.from_file(config_path)
|
||||
client = _FakeClient()
|
||||
monkeypatch.setattr("deerflow.community.tenki.provider.get_app_config", lambda: config)
|
||||
monkeypatch.setattr("deerflow.community.tenki.provider._import_client", lambda: lambda **kw: client)
|
||||
provider = TenkiSandboxProvider()
|
||||
try:
|
||||
provider.acquire("thread-1", user_id="u1")
|
||||
assert client.create_kwargs[0]["sticky"] is expected
|
||||
finally:
|
||||
provider.shutdown()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [False, True, None])
|
||||
def test_create_sticky_native_value(monkeypatch, value):
|
||||
client = _FakeClient()
|
||||
provider = _install(monkeypatch, client=client, config_attrs={"sticky": value, "idle_timeout": 0})
|
||||
try:
|
||||
provider.acquire("thread-1", user_id="u1")
|
||||
assert client.create_kwargs[0]["sticky"] is bool(value)
|
||||
finally:
|
||||
provider.shutdown()
|
||||
|
||||
|
||||
def test_sticky_rejects_invalid_boolean(monkeypatch):
|
||||
with pytest.raises(ValueError, match="valid boolean"):
|
||||
_install(monkeypatch, config_attrs={"sticky": "not-a-boolean"})
|
||||
|
||||
|
||||
def test_create_default_lifetime_is_explicit(monkeypatch):
|
||||
client = _FakeClient()
|
||||
provider = _install(monkeypatch, client=client)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user