DeepSeek-native secure tool runtime — Level 2 semi-production candidate. Policy-enforced, runner-isolated, fail-closed.
Project description
SeekFlow v0.3.7 — Level 2 Semi-production
DeepSeek-native | Policy-enforced | Runner-isolated | Fail-closed
SeekFlow is a DeepSeek-native secure tool runtime with policy-enforced execution, process isolation, and hard timeout kill. Purpose-built around DeepSeek's thinking mode, prompt caching, JSON repair, and FIM. Not a generic OpenAI wrapper.
Status: main branch is Level 2 semi-production. PyPI stable is
0.1.0. See docs/security/levels.md for security level definitions.
v0.3.7 completes the Level 2 semi-production security baseline: runner minimum isolation, ContainerRunner codegen-trusted gate, ProcessRunner output bounding for all types, cache policy restrictions, trusted_output in ToolPolicy, no-policy deny-by-default, and ContainerSandbox zombie prevention via explicit docker kill/rm.
Why SeekFlow over LangChain or CrewAI for DeepSeek?
| SeekFlow | LangChain | CrewAI | |
|---|---|---|---|
| DeepSeek thinking management | Auto-detect + budget | Manual extra_body |
Not supported |
| JSON repair (confidence-gated) | 8-rule + 4-level | None | None |
| Prompt cache stabilization | CacheCompiler (90%+ hit) | None | None |
| Circuit breaker (3-state) | ✅ | None | None |
| Policy Engine + ToolPolicy | ✅ | None | None |
| Path sandbox + SSRF protection | ✅ | None | None |
| Secret redaction pipeline | ✅ | None | None |
| Preflight cost budgeting | ✅ | Manual | Manual |
| FIM (Fill-in-the-Middle) | Built-in | None | None |
| Balance/cost tracking | Real-time cache-aware | Manual | Manual |
Benchmark: 48 runs, 3 rounds × 4 scenarios, blind judge (deepseek-v4-pro)
| Framework | Quality | Tokens/task | Cost/task | Time | Cache |
|---|---|---|---|---|---|
| SeekFlow Fast | 8.7 | 8,688 | CNY0.00108 | 49s | 91% |
| SeekFlow Stable | 8.8 | 12,945 | CNY0.00167 | 72s | 64% |
| LangChain | 8.8 | 10,231 | CNY0.00120 | 59s | 90% |
| CrewAI | 8.7 | 17,414 | CNY0.00149 | 72s | 90% |
Quick Start
pip install seekflow
export DEEPSEEK_API_KEY="sk-..."
Safe by default — dangerous tools require explicit opt-in:
from seekflow import DeepSeekAgent
from seekflow.types import ToolPolicy
agent = DeepSeekAgent(
role="分析师",
goal="分析数据并给出建议",
backstory="经验丰富的数据分析师",
model="deepseek-v4-pro", # primary model for complex reasoning
)
agent.with_default_tools() # only 'calculate' is loaded by default
# For file/network/code tools, opt in explicitly:
agent2 = DeepSeekAgent(
role="研究员",
goal="搜索并分析信息",
backstory="资深研究员",
dangerous_tools=True, # explicit opt-in
)
agent2.with_default_tools() # all 11 tools available
Tool-level security with ToolPolicy:
from seekflow import tool
from seekflow.types import ToolPolicy
@tool(trusted=True)
def read_file(path: str) -> str:
"""Read a file within the workspace."""
...
td = read_file.with_policy(ToolPolicy(
capabilities={"filesystem.read"},
risk="read",
workspace_root="/workspace",
timeout_s=2.0,
parallel_safe=True,
))
Preflight cost control:
from seekflow.budget import CostBudget
budget = CostBudget(max_cny=0.20, max_prompt_tokens=200_000)
result = agent.run("Analyze Q3 financials", max_cost=budget.max_cny)
Security Architecture (v0.3.7)
┌─────────────────────────────────────────────────┐
│ Agent Layer Agent / Crew / Task / Graph │
│ Presets / Memory / Checkpoint │
├─────────────────────────────────────────────────┤
│ Policy Layer PolicyEngine.authorize() │
│ ToolPolicy (capability/risk) │
│ Normalized context (PR-4) │
├─────────────────────────────────────────────────┤
│ Runtime chat() / chat_stream() │
│ Thinking mode / Cache │
│ State machine (StepKind) │
├─────────────────────────────────────────────────┤
│ Security safe_join() / validate_url() │
│ redact_secrets() │
│ UntrustedContent wrapper │
│ close_object_schema (PR-5) │
├─────────────────────────────────────────────────┤
│ Runners InProcessRunner (trusted reads) │
│ ProcessRunner (hard timeout) │
│ ContainerRunner (Docker, PR-2) │
├─────────────────────────────────────────────────┤
│ Tool System @tool → Schema → Registry │
│ Executor (repair + coerce) │
│ limits.py (PR-6) │
│ Audit trail + runner_name │
├─────────────────────────────────────────────────┤
│ Sandbox NoSandbox / LocalThread │
│ ProcessSandbox / Container │
├─────────────────────────────────────────────────┤
│ DeepSeek API DeepSeekClient │
│ Thinking / FIM / Batch / Balance │
└─────────────────────────────────────────────────┘
Features
Security (new in v0.2.0)
| Feature | Description |
|---|---|
| Policy Engine | Centralized authorization for every tool call |
| ToolPolicy | Capability, risk level, timeout, parallel-safety per tool |
| Path Sandbox | safe_join() blocks directory traversal |
| SSRF Protection | validate_url() blocks private IPs, localhost, metadata endpoints |
| Secret Redaction | API keys, JWTs, connection strings redacted from logs/traces |
| Untrusted Content | Tool outputs wrapped as data, not instructions |
| Dangerous Tools Off | File/network/code tools require dangerous_tools=True |
| Per-Tool Timeout | Hard timeout via ProcessRunner (terminate → kill); ContainerRunner for code_exec |
| Audit Trail | ToolAuditRecord with args/result hashes per execution |
DeepSeek Thinking Mode — Fully Leveraged
agent = DeepSeekAgent(thinking=True, mode="stable")
# New in v0.2.0: ThinkingRouter dynamically selects budget
from seekflow.reasoning import ThinkingRouter
router = ThinkingRouter()
decision = router.route(task="complex analysis", tools_count=5, max_risk="read")
# → ThinkingDecision(enable_thinking=True, budget_tokens=2048)
JSON Repair Pipeline (confidence-gated)
4-level repair with dangerous-tool protection:
| Level | Method | Confidence | Dangerous tools |
|---|---|---|---|
| 0 | json.loads native |
1.0 | ✅ Allowed |
| 1 | Syntactic repair | 0.60–0.99 | ❌ Denied if < 0.85 |
| 2 | Model re-emission | N/A | ✅ Allowed (expensive) |
| 3 | Fail-closed | 0.0 | ❌ Denied |
Prompt Cache Compiler
from seekflow.cache import CacheCompiler
compiler = CacheCompiler()
compiled = compiler.compile(system_prompt, tools_schema)
# → prefix_bytes, cacheable_byte_range, tools_schema_hash
prediction = compiler.predict_cache_hit(compiled, messages)
# → {"hit": True, "confidence": 1.0, "matched_bytes": 1247}
Production Reliability
| Component | v0.3.7 Status |
|---|---|
| Tool Runners | InProcessRunner / ProcessRunner (hard kill) / ContainerRunner (Docker) |
| Schema Validation | Draft202012Validator + close_object_schema (hallucination defense) |
| Resource Limits | max_input_bytes / max_output_bytes enforced pre/post execution |
| Retry Control | Read tools + idempotent-only retry; side-effect tools execute once |
| Circuit Breaker | 3-state. Non-retryable errors excluded from upstream CB |
| Retry Executor | 429 bounded (attempt + deadline + Retry-After cap) |
| Cost Budget | Preflight estimation with hard stops |
| Context Window | Deep-copied messages, append-only compression |
| Trace Recorder | Full execution timeline with JSON export |
| State Machine | RunState + StepKind typed phases |
Sandbox (code execution isolation)
from seekflow.sandbox import NoSandbox, ProcessSandbox, ContainerSandbox
# Default: code execution denied
sandbox = NoSandbox()
# Development: subprocess with basic isolation
sandbox = ProcessSandbox() # no inherited env, temp dir
# Production: Docker container with full isolation
sandbox = ContainerSandbox(image="python:3.11-slim")
# --network none, --memory 256m, --read-only, non-root user
Breaking Changes (v0.2.0)
| Change | Migration |
|---|---|
Agent.with_default_tools() loads only calculate |
Use Agent(dangerous_tools=True) for old behavior |
ToolCall.arguments type: dict → dict | str |
Handle isinstance(args, str) for repair |
repair_message_order() no semantic injection |
No action — purely internal |
embed_files_into_message() returns new dict |
Assign return value instead of relying on mutation |
_sanitize_tool_output() removed |
Use UntrustedContent / wrap_untrusted() |
Documentation
- Changelog v0.2.0 — full release notes
- Security Policy — vulnerability reporting + security model
- PRD: Security Hardening — design decisions
- Issues — 30 tracer-bullet issues with acceptance criteria
- Tests — 620+ tests covering security, retry, policy, tools, agent
Security Status (v0.3.x)
SeekFlow v0.3.x supports Level 2 semi-production under these conditions:
- All tools must have ToolPolicy.
code_execanddestructiverequire ContainerRunner / ContainerSandbox.- Policy.runner cannot decrease the required isolation level (minimum isolation enforced).
- ContainerRunner only accepts tools with
ToolPolicy(trusted=True, container_codegen_trusted=True). - ProcessRunner provides timeout isolation, not a full security sandbox.
- All ProcessRunner outputs are size-bounded in the child process.
- Tool outputs are untrusted by default (
trusted_output=False). - Cache is restricted to read tools or idempotent network with explicit opt-in.
- No-policy tools are denied by default (
allow_unsafe_no_policy_executionopt-in). - Network tools require allowed_domains.
- Filesystem tools require workspace_root.
- Untrusted third-party tools and arbitrary MCP servers are not supported.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file seekflow-0.3.7-py3-none-any.whl.
File metadata
- Download URL: seekflow-0.3.7-py3-none-any.whl
- Upload date:
- Size: 183.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dbf8d630949eb18a10185154109ab79b2759f18edf7371c86e1cc2c5159ef1ed
|
|
| MD5 |
ee0501ab5be72778993d9e441b4b2ad4
|
|
| BLAKE2b-256 |
f9c38480dd0a363e0c711092beae35b4e17e5bc65d2c78edf3d300c8dc64e984
|