Skip to content

Latest commit

 

History

History
341 lines (241 loc) · 13 KB

File metadata and controls

341 lines (241 loc) · 13 KB

deeplossless — Agent Integration Guide

deeplossless is a transparent proxy that sits between you (the AI coding agent) and the DeepSeek API. It automatically caches tool results, compresses long conversations, detects failure patterns, and injects relevant context — without changing any of your code.

If you are an AI agent reading this: install SKILL.md to your skills directory. It contains the exact commands to discover and query LCM endpoints.

Agent-specific install:

# Claude Code
cp SKILL.md ~/.claude/skills/deeplossless.md

# Codex
cp SKILL.md ~/.codex/skills/deeplossless.md

# OpenCode
cp SKILL.md ~/.config/opencode/skills/deeplossless.md

# OpenClaw
cp SKILL.md ~/.openclaw/skills/deeplossless.md
# OpenClaw config (~/.openclaw/config.yaml or env):
#   model_provider: openai_compatible
#   base_url: https://localhost:8080/v1
#   api_key: $DEEPSEEK_API_KEY

# Any agent — copy to its skills directory

1) Start deeplossless

Single command. Replace sk-... with whatever API key you have:

deeplossless

All defaults are sane: HTTPS on 127.0.0.1:8080 (self-signed cert auto-generated), DB at ~/.deeplossless/lcm.db. Run deeplossless trust once to trust the certificate.

If deeplossless is not on PATH, build it:

cd <repo-root>
cargo build --release
./target/release/deeplossless

Optional flags (agent can pass these without user input):

Flag Default Meaning
--port 8080 Listen port
--db-path ~/.deeplossless/lcm.db SQLite database path
--audit-mode full full / onerror / off
--snapshot-mode manual auto / manual / off
--onerror-ring-size 50 Buffer size for OnError audit mode
--runtime-profile autonomous minimal / efficient / exploratory / autonomous
--rate-limit 100 Max requests/second
--log-dir (none) JSONL request logging
--dry-run (off) Mock mode, no upstream calls
--lcm-context-tokens 0 (off) LCM context injection budget (e.g. 1024). Merges DAG context into last user message without adding new messages

TLS (HTTPS) is always enabled. A self-signed certificate is auto-generated. Run deeplossless trust once to configure it, or pass custom certs with the flags above.


2) Point your API client at deeplossless

You must include /v1 in the base URL. This is the only configuration change needed.

For Claude Code / Codex / Cursor / etc.

Set the base URL to https://localhost:8080/v1 and use any model name — deeplossless forwards to upstream:

Base URL:  https://localhost:8080/v1
Model:     deepseek-v4-flash  (or any valid DeepSeek model)
API Key:   sk-...              (same key passed to deeplossless)

Self-configuring (if you are an agent editing config files)

Claude Code — edit ~/.claude/settings.json:

{
  "apiKeyHelper": null,
  "env": {
    "ANTHROPIC_BASE_URL": "https://localhost:8080/v1",
    "ANTHROPIC_API_KEY": "sk-..."
  }
}

Cursor — no config file edit needed. If the user has Cursor configured to use DeepSeek, install the Cursor DeepSeek extension and set the Base URL there.

Generic OpenAI-compatible client (most agents use this):

{ "baseURL": "https://localhost:8080/v1" }

cURL test — verify it works:

curl https://localhost:8080/health
# → "healthy"

curl -s https://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json" \
  -d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"1+1"}]}'
# → JSON response with choices

3) Resilience: never let deeplossless become a single point of failure

deeplossless sits in your request path. If it crashes, hangs, or can't reach upstream, you must keep working by falling back to direct API calls. Implement this pattern once and it covers every failure mode.

Prerequisite: know your direct upstream URL

deeplossless forwards to https://api.deepseek.com by default. Store the direct URL so you can bypass the proxy when needed:

DIRECT = "https://api.deepseek.com/v1/chat/completions"
PROXY  = "https://localhost:8080/v1/chat/completions"

Startup health check

Before routing any request through deeplossless, probe it:

GET https://localhost:8080/health

If the response is not healthy within 2 seconds: use DIRECT for everything. Do not attempt to start deeplossless yourself. The user may have intentionally stopped it.

Per-request timeout + fallback

Set a short timeout on every proxy request (2–5 seconds for connection + response start). If the proxy times out or returns 5xx on any request, immediately switch to DIRECT for that request and all subsequent requests in this session.

async function call_llm(body):
    if PROXY_HEALTHY:
        try:
            response = await fetch(PROXY, body, timeout=5s)
            if response.status < 500:
                return response
        except TimeoutError, ConnectionError:
            pass
    // Fallback — proxy is down or unresponsive
    PROXY_HEALTHY = false
    return await fetch(DIRECT, body)

Do NOT retry deeplossless mid-session

Once you fall back to direct, stay on DIRECT for the rest of the session. Do not ping /health repeatedly or try to reconnect. The user's task must not be interrupted by proxy recovery attempts. Re-check health only at the start of a new session.

Signal the failure to the user

When you fall back, tell the user once — concisely:

deeplossless is unavailable, falling back to direct API. Caching and context compression are disabled for this session. Restart deeplossless before your next conversation to re-enable.

What you lose on fallback

When running direct, these features are unavailable:

  • Tool cache interception
  • DAG context injection (<lcm_context>)
  • Failure memory
  • Multi-agent file locking
  • Execution audit trail

Your core function (reading code, editing files, answering questions) continues uninterrupted. The user may observe higher token usage without compression — that is expected.


4) What deeplossless does automatically

These require zero code changes in your agent logic:

Feature Trigger Effect
Protocol translation Responses API → Chat Completions You can call either /v1/chat/completions or /v1/responses
DAG context injection Every request Relevant compressed history appended as <lcm_context> in system prompt
Tool cache interception Tool calls in streaming responses If a cached result exists, the tool call is replaced with cached text — no execution
Failure auto-detection Tool results with error patterns Recorded in failure memory, surfaced via /v1/lcm/runtime/stats
Message + execution persistence Every request/response Stored in SQLite WAL, searchable via FTS5
Session fingerprinting First 3 messages SHA-256 dedup for session identity
Parallel group detection Assistant messages with ≥2 tool calls Span metadata + HappensBefore edges + join DAG node created

Important: Your system prompt will contain a <lcm_context> block with compressed conversation context. This is normal and desired — it means deeplossless is compressing old messages to save tokens. Do not remove or override it.

Tool calls may not execute: If deeplossless has a cached result for a tool call, it intercepts the streaming response and returns text instead of a tool_use block. Your agent should check for text content, not assume every tool call will produce a function_call event.


5) What you can actively use (optional)

These endpoints let you get more value. Call them if it makes sense for your workflow.

Before each turn: inject context

First, discover the current conversation ID:

GET /v1/lcm/current
→ { "conversation_id": 8 }

Then query past context with the conversation ID:

GET /v1/lcm/grep/{conv_id}?query=<user question>
→ { "matches": [{ "excerpt": "...", "node_id": 42 }] }

Returns relevant DAG nodes (summaries, messages, snippets) matching the query. Append the excerpts to your system message before composing the response.

Before/after each tool call: cache

GET /v1/lcm/cache?tool=grep&args={"pattern":"foo"}
→ { "hit": true, "result": "src/main.rs:42 found" }

POST /v1/lcm/cache/put
{ "tool": "grep", "args": "{...}", "result": "...", "files": ["src/main.rs"] }

Check cache before executing a tool — if hit, skip execution entirely. Store results after execution.

When a fix fails: failure memory

POST /v1/lcm/failure
{ "conv_id": 1, "signature": "import_error", "attempted_fix": "pip install",
  "why_failed": "virtualenv not activated", "assumptions": "[\"pip available\"]" }

Prevents retrying the same failed approach. The runtime will flag the signature in /v1/lcm/runtime/stats.

Monitoring

GET /v1/lcm/runtime/stats     → token counts, cache hit rate, failure streaks
GET /v1/lcm/status/{conv_id}  → DAG node count, token budget, compression stats
GET /v1/lcm/health/{conv_id}  → DAG invariants check (cycles, orphans, symmetry)

Multi-agent safety

POST /v1/lcm/file/claim    { "path": "src/main.rs", "conv_id": 1 }
→ 200 OK or 409 CONFLICT

POST /v1/lcm/file/release  { "path": "src/main.rs", "conv_id": 1 }

Prevents two concurrent agents from editing the same file.

Planning persistence

POST /v1/lcm/plan     { "conv_id": 1, "goal": "...", "pending_steps": [...], "assumptions": [...] }
GET  /v1/lcm/plan/{conv_id}

Persists execution plans across sessions. Resumable after restart.

Compress on demand

POST /v1/lcm/compress  { "conv_id": 1, "from_idx": 0, "to_idx": 20, "level": 1 }

Manually compress a message range into a summary node. Level 1 = preserve details, Level 2 = bullet points, Level 3 = aggressive.

Audit & replay

GET  /v1/lcm/audit/{conv_id}          → full execution audit trail
GET  /v1/lcm/audit/report/{conv_id}   → aggregated audit report
GET  /v1/lcm/replay/{execution_id}    → replay an execution from event log
POST /v1/lcm/snapshot                 → take an execution snapshot for rollback
POST /v1/lcm/rollback                 → rollback to a previous DAG checkpoint

Search

GET /v1/lcm/global/search?q=...     → search ALL conversations (cross-session)
GET /v1/lcm/execution/search?q=...  → search execution units (tool calls, results)
GET /v1/lcm/similar/{hash}          → find semantically similar DAG nodes
GET /v1/lcm/sessions                → list all conversations with event counts
GET /v1/lcm/sessions/{id}/events    → execution events for a session
GET /v1/lcm/sessions/{id}/system-prompt  → deduplicated system prompt history

Latency & Cache

GET /v1/lcm/latency          → recent upstream request latency records
GET /v1/lcm/latency/summary  → aggregated P50/P95/P99 latency stats
GET /v1/lcm/cache/stability  → system prompt cache stability metrics

6) Authentication model

deeplossless learns your API key from the first request — it reads the Authorization: Bearer sk-... header and caches it. You do not need to pre-configure the key. Just send your first request with the key and it works.

For LCM endpoints (cache, grep, plan, failure, etc.), deeplossless checks an optional --admin-key first, then falls back to the cached API key.


7) Configuration checklist

For the human user (not the agent):

  1. Start deeplossless: deeplossless (API key from $DEEPSEEK_API_KEY env or first request)
  2. Health check: curl -sk https://localhost:8080/healthhealthy
  3. For sandboxed agents (OpenClaw, etc.): use http://127.0.0.1:8081/v1 (no TLS)
  4. Set base URL: https://localhost:8080/v1 (must include /v1)
  5. Done. Everything else is automatic.

8) Troubleshooting

Symptom Likely cause Fix
Connection refused deeplossless not running Fall back to DIRECT (see §3). Do not attempt to start it.
404 on /chat/completions Base URL missing /v1 Use https://localhost:8080/v1
401 Unauthorized API key not passed Include Authorization: Bearer sk-... in first request
502 Bad Gateway Upstream API unreachable Fall back to DIRECT (see §3). Upstream may be down or rate-limited.
Proxy hangs / timeout deeplossless blocked on DB or upstream Fall back to DIRECT (see §3). Do not retry.
Empty responses Compaction removed old messages Check /v1/lcm/status/{conv_id} for DAG state
Tool calls not firing Cache interception Check /v1/lcm/cache for existing entries
Slow first request DB migration running Wait ~1s, subsequent requests are fast