Aniket Wagh 8a830f6354
fix(deps): depend on renamed tenki package instead of tenki-sandbox (#5087)
* fix(deps): depend on renamed tenki package instead of tenki-sandbox

tenki-sandbox has been removed from PyPI and republished as tenki. Its old wheel URL still resolves, so existing lockfiles keep installing and the breakage is invisible to anyone with a warm lock; any fresh resolution fails with 'tenki-sandbox was not found in the package registry'.

tenki 1.0.2 still ships the tenki_sandbox module, so the imports in community/tenki/provider.py and sandbox.py are unchanged.

Fixes #5081

* fix(tenki): point install guidance at the renamed distribution

The rename to `tenki` left the user-facing remediation still naming the
removed package. `_import_client` raised "pip install tenki-sandbox" on the
missing-extra path — the exact instruction this change proves now 404s on
PyPI, handed to the user at the exact moment they need it to work.

Update that message and the remaining `tenki-sandbox` references in the
provider, sandbox adapter, README, sandbox AGENTS.md and the test docstring.
The imported module stays `tenki_sandbox`, so the distribution and module
names now differ; each mention says so rather than just swapping the string.

No behavior change beyond the error text.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(tenki): migrate the provider to the 1.x workspace-only API

Renaming the dependency was not enough. tenki 1.0.2 keeps the tenki_sandbox
module name but not its contract: Client.create dropped project_id and has no
**kwargs to absorb it, and IdentityWorkspace no longer carries `projects`
(the attribute is gone from the package entirely). Both configuration paths
therefore failed before a sandbox could be created — explicit project scope
raised TypeError, and automatic scope raised AttributeError walking
workspace.projects.

Scope is now the workspace alone. _resolve_scope returns a single workspace id,
auto-selecting when the account has exactly one, and project_id is gone from
create_kwargs and from the documented config surface.

A stale project_id in config.yaml warns rather than fails. SandboxConfig is
extra="allow", so simply not reading the key would leave it scoping nothing
with no signal; it also used to short-circuit the identity lookup, so operators
with more than one workspace need to know they must now set workspace_id.

The suite passed against the broken provider because the fake client took
**kwargs and swallowed the project_id the real SDK rejects. The double now
mirrors 1.0.2 — keyword-only, no **kwargs — so an unexpected argument is a
TypeError in tests exactly as it is against the SDK. Reintroducing the old
create call fails 20 tests; before this change it failed none.

Verified against the exact locked wheels: every other kwarg the provider
passes (name, workspace_id, sticky, wait, max_duration, image, cpu_cores,
memory_mb, env) and every SDK surface it touches (who_am_i, Identity.workspaces,
wait_ready, exec, close, the fs API, the four terminal exception classes) is
unchanged in 1.0.2.

Reported by willem-bd in review.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(config): drop sandbox.project_id from the Tenki example

The canonical example still documented project_id as a supported optional key
after the provider stopped honouring it, so an operator following it could set
the key, get no scope from it, and hit a workspace-resolution failure with
nothing in the example to explain why.

Replaced with a migration note rather than a silent deletion: someone upgrading
already has the key in their config.yaml and needs to know it is inert now and
that workspace_id is what scopes a sandbox on Tenki 1.x.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Aniket Wagh <aniketwaghh@users.noreply.github.com>
2026-08-30 10:37:58 +08:00

103 lines
3.9 KiB
TOML

[project]
name = "deerflow-harness"
version = "2.1.0"
description = "DeerFlow agent harness framework"
requires-python = ">=3.12"
dependencies = [
"agent-client-protocol>=0.4.0",
"agent-sandbox>=0.0.30",
"croniter>=6.0.0",
# Exact pin by design (extension-system version contract): the host pins
# the contract version it implements, extensions declare ranges. A range
# here would let pip resolve a newer contract package than this harness
# implements, making newer extensions look supported at runtime.
"deerflow-extension-api==0.2.0",
"dotenv>=0.9.9",
"exa-py>=1.0.0",
"httpx>=0.28.0",
"kubernetes>=30.0.0",
# Lower bound reflects what the lockfile resolves and tests run against
# (langgraph 1.2.9 pulls langchain >=1.3 transitively).
"langchain>=1.3",
"langchain-anthropic>=1.4.1",
"langchain-deepseek>=1.0.1",
"langchain-mcp-adapters>=0.2.2",
"langchain-openviking==0.1.0",
"langchain-openai>=1.2.1",
"langfuse>=3.4.1",
"langgraph>=1.2.9,<1.3",
"langgraph-api>=0.8.1",
"langgraph-cli>=0.4.24",
# Standalone Studio's pre-runtime persistence repair is validated against
# the 0.30.0 store lifecycle and must not resolve an older implementation.
"langgraph-runtime-inmem>=0.30.0",
"markdownify>=1.2.2",
"markitdown[all,xlsx]>=0.0.1a2",
"packaging>=24.2",
"pydantic>=2.12.5",
"pyyaml>=6.0.3",
"readabilipy>=0.3.0",
"tavily-python>=0.7.17",
"firecrawl-py>=1.15.0",
"tiktoken>=0.8.0",
"ddgs>=9.10.0",
"duckdb>=1.4.4",
"langchain-google-genai>=4.2.1",
"langgraph-checkpoint-sqlite>=3.1.1,<3.2",
"langgraph-sdk>=0.1.51",
"sqlalchemy[asyncio]>=2.0,<3.0",
"aiosqlite>=0.19",
"alembic>=1.13",
"cryptography>=50.0.0",
"e2b-code-interpreter>=2.8.0",
]
[project.scripts]
deerflow = "deerflow.tui.cli:main"
[project.optional-dependencies]
# Terminal workbench (TUI). Kept optional so the core harness install stays lean;
# the `deerflow` console script degrades to headless help when textual is absent.
tui = ["textual>=0.80"]
# GroundRoute needs no extra packages (httpx is already a core dependency). This
# empty extra exists so the documented `uv add 'deerflow-harness[groundroute]'`
# install command resolves cleanly without an "unknown extra" warning.
groundroute = []
ollama = ["langchain-ollama>=0.3.0"]
postgres = [
"asyncpg>=0.29",
"langgraph-checkpoint-postgres>=3.1.1,<3.2",
"psycopg[binary]>=3.3.3",
"psycopg-pool>=3.3.0",
]
# Cross-process SSE stream bridge (stream_bridge.type: redis). Optional so
# single-process / memory-bridge installs do not pull redis. The Docker image
# always installs this extra because Docker defaults to the redis bridge.
redis = ["redis>=5.0.0"]
pymupdf = ["pymupdf4llm>=0.0.17"]
boxlite = ["boxlite>=0.9.7"]
# Tenki cloud sandbox provider (deerflow.community.tenki). Optional so a default
# install stays free of the Tenki SDK; only pulled in when the provider is used.
# The distribution is ``tenki``; it still ships the ``tenki_sandbox`` module that
# provider.py and sandbox.py import.
tenki = ["tenki>=1.0.0"]
# OpenSandbox remote sandbox provider (deerflow.community.opensandbox). The
# sync SDK is loaded only when this provider is selected.
opensandbox = ["opensandbox>=0.1.15,<0.2.0"]
# Agent observability (Monocle). Optional so a default install stays free of the
# OpenTelemetry stack; only pulled in when MONOCLE_TRACING is used.
monocle = ["monocle_apptrace>=0.8.8"]
# Agentic browser control (browser_navigate/click/type/... tool group). Optional
# so the core harness install stays lean; import is lazy inside the private
# Playwright loop. After install, run `playwright install chromium` once.
browser = ["playwright>=1.40"]
# Optional Chinese tokenization for the FTS5 memory retrieval adapter.
memory-zh = ["jieba>=0.42.1"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["deerflow"]