Python SDK, CLI, and local FastAPI wrapper for DeepSeek Chat.
Project description
DeepWrap
Table of Contents
- Installation
- Quick Start
- Authentication
- CLI Authentication
- Python SDK Usage
- Supported Models
- God Mode
- CLI Usage
- Interactive CLI Commands
- Local FastAPI Server
- HTTP API
- Streaming Over HTTP
- Environment Variables
- API Design
- Examples
- Error Handling
- Notes
- Security Notice
- Disclaimer
- License
DeepWrap is a lightweight Python SDK, CLI, and local HTTP API wrapper for DeepSeek Chat with session support, browser authentication, streaming, and local developer tooling.
It provides:
- A simple Python client
- Session-based chat support
- Streaming and non-streaming chat responses
- Structured streaming with separated thinking and response chunks
- Browser-based authentication
- Local token storage and reuse
- Interactive terminal UI
- FastAPI server mode
- Internal proof-of-work handling
- Default autonomous agent mode with native command, code, search, and file tools
Repository: https://github.com/Kuduxaaa/deepwrap
Installation
pip install deepwrap
Install directly from GitHub:
pip install git+https://github.com/Kuduxaaa/deepwrap.git
For local development:
git clone https://github.com/Kuduxaaa/deepwrap.git
cd deepwrap
pip install -e ".[dev]"
Quick Start
Authenticate once:
deepwrap auth
Then use DeepWrap from Python:
from deepwrap import Client
client = Client()
chat = client.chats.create_session(model="expert")
response = chat.respond(
"Hello, introduce yourself in one sentence.",
stream=False,
)
print(response)
Or start the interactive terminal UI:
deepwrap
Authentication
DeepWrap uses a Bearer token.
Token resolution order:
- Explicit
api_key DEEPWRAP_API_KEYDEEPSEEK_API_KEY- Saved local config from
deepwrap auth - Browser authentication only when explicitly requested with
Client.from_browser_auth()orallow_browser_auth=True
Client is the main entrypoint for DeepWrap. It resolves bearer tokens from an explicit API key, environment variables, saved local config, or browser auth, then exposes session-based chat and PoW-backed request handling.
Direct Token
from deepwrap import Client
client = Client(api_key="YOUR_BEARER_TOKEN")
Environment Variable
export DEEPWRAP_API_KEY="YOUR_BEARER_TOKEN"
DeepWrap also supports:
export DEEPSEEK_API_KEY="YOUR_BEARER_TOKEN"
Then:
from deepwrap import Client
client = Client()
Browser Auth from Python
DeepWrap supports browser-based authentication from Python. You can bootstrap a client with Client.from_browser_auth() or use allow_browser_auth=True, and the library will capture a bearer token from an authenticated browser session before creating the HTTP session.
from deepwrap import Client
client = Client.from_browser_auth()
Equivalent:
from deepwrap import Client
client = Client(allow_browser_auth=True)
CLI Authentication
Authenticate using browser login:
deepwrap auth
Manually enter and save a token:
deepwrap auth --manual
Save a token directly:
deepwrap auth --token "YOUR_BEARER_TOKEN"
Show current config status:
deepwrap config
Remove the saved token:
deepwrap logout
Python SDK Usage
Basic Non-Streaming Chat
from deepwrap import Client
client = Client()
chat = client.chats.create_session(model="expert")
response = chat.respond(
"Explain quantum computing in one short sentence.",
thinking=True,
search=True,
stream=False,
)
print(response)
Streaming Chat
from deepwrap import Client
client = Client()
chat = client.chats.create_session(model="expert")
for chunk in chat.respond(
"Write a short explanation of black holes.",
thinking=True,
search=True,
stream=True,
):
print(chunk, end="", flush=True)
print()
Multi-Turn Chat
from deepwrap import Client
client = Client()
chat = client.chats.create_session(model="expert")
print(chat.respond("My name is Nika.", stream=False))
print(chat.respond("What is my name?", stream=False))
The ChatSession keeps track of the latest message ID internally, so follow-up messages stay inside the same conversation.
Agent mode
Agent mode is enabled by default. It upgrades regular chat sessions with native tools that the model can call repeatedly before returning its final answer:
exec— execute a command with the host operating system's shell.grep— regex-search file contents with optional glob filters.read_file— read any text file.write_file— write complete content to a file.edit_file— perform guarded exact-string substitutions.exec_code— run Python code with access to installed modules.start_job— launch a long command in its own background process.job_status— check a background job without blocking.job_output— read paginated stdout or stderr while a job runs.list_jobs— list jobs owned by the current client.stop_job— terminate a job and its process group.
from pathlib import Path
from deepwrap import Client
client = Client(
working_directory=Path.cwd(),
command_timeout=30,
max_agent_rounds=8,
)
chat = client.chats.create_session(model="expert")
result = chat.respond(
"Find every Python file containing ChatSession and summarize its usage.",
stream=False,
)
print(result)
for execution in result.tools_used:
print(execution.name, execution.arguments, execution.output)
Streaming returns an AgentStream. Final-answer chunks arrive incrementally, and
the same execution history is available after or during consumption:
response = chat.respond("Inspect this project.", stream=True)
for chunk in response:
print(chunk, end="", flush=True)
for execution in response.tools_used:
print(execution.name, execution.arguments, execution.output)
For immediate progress while the agent is planning or running tools, pass an event callback:
def show_progress(event):
print(f"[{event.type}] {event.message}", flush=True)
response = chat.respond(
"Build a complete landing page in one HTML file.",
stream=True,
on_event=show_progress,
)
Events include started, planning, thinking, tool_started, tool_completed,
responding, and completed. The history remains available as
response.events; tool events also include arguments, output, and duration.
Background jobs
Long-running commands can execute concurrently without blocking the agent response:
response = chat.respond(
"Start the crawler as a background job and return immediately.",
stream=False,
)
job = next(
execution.output
for execution in response.tools_used
if execution.name == "start_job"
)
print(job["id"], job["state"])
# A later turn in the same Client can inspect status and logs.
print(chat.respond("Check that job and show its latest output.", stream=False))
Each job has an independent process group and file-backed stdout/stderr logs.
job_output returns next_offset, allowing the agent to resume reading only new
output. Jobs remain available across chat turns while the same Client process is
alive. See examples/15_background_jobs.py for a complete example.
Run network scanners and similar tools only against systems and networks you own or are explicitly authorized to assess.
Non-streaming AgentResponse remains a subclass of str, so existing string
handling continues to work. Each tools_used entry contains name, arguments,
and output.
Disable agent operations globally or for one request:
client = Client(agent_mode=False)
plain_response = chat.respond("Hello", agent=False, stream=False)
The interactive CLI always starts directly in agent mode; no activation command
is required. The Python SDK and local HTTP API still accept an agent boolean
for applications that explicitly need plain-chat behavior.
Natural-language CLI actions
Every slash-command capability is also registered as an agent tool. Users can control the CLI naturally without remembering command syntax:
Please clear this chat and screen.
Start a new conversation.
Switch to the default model and enable search.
Hide thinking output.
Save my current settings.
Show the current status.
Exit DeepWrap.
Token changes schedule the secure hidden-input prompt; credentials are never accepted as model-generated tool arguments. Direct slash commands remain available.
Local images are handled automatically through a dedicated vision session, even
when the current model is expert:
What can you see in /home/user/Pictures/photo.jpg?
The CLI agent selects inspect_image, uploads the file to a temporary vision chat,
and feeds the visual analysis back into the current conversation. Manual
/model vision and /attach remain useful when several follow-up prompts should
reuse the same uploaded image.
Thinking output works in agent mode as well as plain mode. Enabling or disabling God Mode updates the current session in place, so conversation and image context are preserved.
For large repositories, grep and read_file return bounded pages with
has_more and next_offset. The agent protocol instructs the model to search
broadly, narrow relevant files, and follow pagination instead of flooding its
context with entire projects.
Agent mode executes model-generated commands and code and can read or modify any path available to the current operating-system user. Run it only in an environment where that level of access is intended. Use
working_directory, a dedicated user, container, or virtual machine when isolation is required.
Runnable examples:
examples/11_agent.py— agent-driven project search and summary.examples/12_native_tools.py— direct use of all six native tools.examples/13_agent_file_edit.py— autonomous read/edit/verification workflow.examples/14_agent_exec.py— command and Python execution workflow.examples/15_background_jobs.py— concurrent process jobs and later inspection.
Vision file uploads
Files can be attached only to a vision session. DeepWrap uploads the file,
waits for DeepSeek to process it, and forwards its file ID with the prompt.
chat = client.chats.create_session(model="vision")
response = chat.respond(
"Describe this image.",
files=["./photo.png"],
stream=False,
)
You can also upload once and reuse the returned ID:
uploaded = chat.upload_file("./photo.png")
response = chat.respond("What is visible?", file_ids=[uploaded.id], stream=False)
Pseudo function calling
DeepWrap supplies tool definitions through a synthetic system protocol. The model
either answers normally or returns a strict <deepwrap_tool_call> JSON envelope.
Passing functions enables the automatic tool/result loop; omitting it returns the
parsed call for execution by the application.
from deepwrap import Tool
add = Tool(
name="add",
description="Add two integers.",
parameters={
"type": "object",
"properties": {
"a": {"type": "integer"},
"b": {"type": "integer"},
},
"required": ["a", "b"],
},
)
result = chat.respond_with_tools(
"What is 20 + 22?",
[add],
functions={"add": lambda a, b: a + b},
)
print(result.content)
print(result.tool_calls)
Tool calling is non-streaming because the complete envelope must be validated before a function can be selected or executed.
Supported Models
DeepWrap currently supports:
expert
default
vision
Web search is supported only by default (Instant). DeepWrap always sends
search_enabled=false for expert and vision, even if search=True is passed.
Example:
chat = client.chats.create_session(model="default")
God Mode
DeepWrap includes an optional God Mode for chat sessions.
When god_mode is enabled, DeepWrap injects a one-time override prompt into the first user turn of the session. This prompt attempts to alter the model’s default behavior by making it less restricted and reducing the effect of built-in safety guardrails.
This can materially change the model’s behavior and may cause it to generate content that is harmful, unethical, inappropriate, or unsuitable for general use.
Because this mode is implemented through prompt injection at the start of a session, its behavior is intentionally intrusive and may diverge from normal model behavior. It should only be used in controlled development and research environments.
God Mode is disabled by default and must be enabled explicitly per session.
Python SDK
from deepwrap import Client
client = Client()
chat = client.chats.create_session(
model="expert",
god_mode=True,
)
response = chat.respond(
"Give me a blunt explanation of Python metaclasses.",
stream=False,
)
print(response)
CLI Usage
Run the interactive terminal interface:
deepwrap
To attach an image in interactive mode:
/model vision
/attach ./photo.png
Describe this image.
Use /attachments to inspect pending files and /detach to clear them. Pending
attachments are consumed after the next successful response.
Send a single message from the terminal:
deepwrap chat "Explain recursion in one sentence."
Use a specific model:
deepwrap chat "Hello" --model expert
Disable thinking output:
deepwrap chat "Give me three facts about Tbilisi." --no-thinking
Disable search:
deepwrap chat "Explain Python decorators." --no-search
Stream output:
deepwrap chat "Write a short story about AI." --stream
Use a direct token:
deepwrap chat "Hello" --token "YOUR_BEARER_TOKEN"
Interactive CLI Commands
Inside the interactive terminal UI:
/help Show help
/exit Exit the CLI
/quit Exit the CLI
/clear Clear the terminal
/new Start a fresh chat session
/model <name> Switch model: expert, default, vision
/token Set token interactively
/token "<token>" Set token inline
/thinking on|off Show or hide thinking blocks
/search on|off Enable or disable search
/god on|off Enable or disable God Mode
/save Save current settings
/status Show current session status
Example:
/model expert
/thinking off
/search on
/new
Local FastAPI Server
DeepWrap can run as a local HTTP API.
Start the server:
deepwrap api
Specify host and port:
deepwrap api --host 127.0.0.1 --port 8000
Enable reload for development:
deepwrap api --reload
Use more workers:
deepwrap api --workers 2
Set log level:
deepwrap api --log-level debug
HTTP API
Health Check
curl http://127.0.0.1:8000/health
Example response:
{
"ok": true,
"app": "deepwrap",
"version": "0.2.2",
"token_configured": true,
"cached_clients": 1,
"active_sessions": 0
}
One-Shot Chat Request
curl -X POST http://127.0.0.1:8000/chat \
-H "Content-Type: application/json" \
-d '{
"message": "Explain recursion in one sentence.",
"model": "expert",
"thinking": true,
"search": true,
"stream": false
}'
Example response:
{
"model": "expert",
"response": "Recursion is a technique where a function solves a problem by calling itself on smaller versions of the same problem.",
"session_id": null
}
Create Persistent Session
curl -X POST http://127.0.0.1:8000/sessions \
-H "Content-Type: application/json" \
-d '{
"model": "expert"
}'
Example response:
{
"session_id": "chat_abc123",
"model": "expert",
"god_mode": false
}
Use Persistent Session
curl -X POST http://127.0.0.1:8000/chat \
-H "Content-Type: application/json" \
-d '{
"session_id": "chat_abc123",
"message": "My name is Nika.",
"model": "expert"
}'
Then:
curl -X POST http://127.0.0.1:8000/chat \
-H "Content-Type: application/json" \
-d '{
"session_id": "chat_abc123",
"message": "What is my name?",
"model": "expert"
}'
Delete Session
curl -X DELETE http://127.0.0.1:8000/sessions/chat_abc123
Streaming Over HTTP
Plain Text Streaming
curl -N -X POST http://127.0.0.1:8000/chat \
-H "Content-Type: application/json" \
-d '{
"message": "Explain black holes simply.",
"model": "expert",
"stream": true,
"stream_format": "text"
}'
Server-Sent Events Streaming
curl -N -X POST http://127.0.0.1:8000/chat \
-H "Content-Type: application/json" \
-d '{
"message": "Explain black holes simply.",
"model": "expert",
"stream": true,
"stream_format": "sse"
}'
SSE output format:
data: chunk text
data: more chunk text
event: done
data: [DONE]
Environment Variables
DeepWrap checks the following environment variables:
DEEPWRAP_API_KEY
DEEPSEEK_API_KEY
DEEPSEEK_BASE_URL
DEEPSEEK_BASE_DOMAIN
Example:
export DEEPWRAP_API_KEY="YOUR_BEARER_TOKEN"
Optional custom base URL:
export DEEPSEEK_BASE_URL="https://chat.deepseek.com"
export DEEPSEEK_BASE_DOMAIN="chat.deepseek.com"
API Design
DeepWrap exposes a small SDK surface:
from deepwrap import Client
Create a client:
client = Client()
Create a chat session:
chat = client.chats.create_session(model="expert")
Send a message:
response = chat.respond("Hello", stream=False)
Stream a message:
for chunk in chat.respond("Hello", stream=True):
print(chunk, end="")
Use structured chunks:
for kind, chunk in chat.respond_structured("Hello"):
print(kind, chunk)
Examples
Switch Models
from deepwrap import Client
client = Client()
expert_chat = client.chats.create_session(model="expert")
default_chat = client.chats.create_session(model="default")
print(expert_chat.respond("Explain recursion in one sentence.", stream=False))
print(default_chat.respond("Explain recursion in one sentence.", stream=False))
Hide Thinking Output
from deepwrap import Client
client = Client()
chat = client.chats.create_session(model="expert")
response = chat.respond(
"Give me three facts about Tbilisi.",
thinking=False,
search=True,
stream=False,
)
print(response)
Disable Search
from deepwrap import Client
client = Client()
chat = client.chats.create_session(model="expert")
response = chat.respond(
"Explain Python generators.",
thinking=True,
search=False,
stream=False,
)
print(response)
Error Handling
Example:
from deepwrap import Client
try:
client = Client()
chat = client.chats.create_session(model="expert")
response = chat.respond("Hello", stream=False)
print(response)
except ValueError as exc:
print(f"Configuration error: {exc}")
except RuntimeError as exc:
print(f"API error: {exc}")
except Exception as exc:
print(f"Unexpected error: {exc}")
Notes
DeepWrap is designed as a developer-focused wrapper.
It handles:
- HTTP session headers
- Authorization
- Chat session creation
- Streaming response parsing
- Proof-of-work challenge solving
- CLI interaction
- Local API serving
The goal is to provide a clean interface while keeping the internal implementation modular and extensible.
Security Notice
Do not commit your Bearer token.
Avoid hardcoding tokens in public repositories.
Recommended:
export DEEPWRAP_API_KEY="YOUR_BEARER_TOKEN"
Or use:
deepwrap auth
Tokens saved by DeepWrap are stored locally in the user config directory.
Disclaimer
This project is an unofficial wrapper.
It is not affiliated with, endorsed by, or officially supported by DeepSeek.
Use responsibly and respect the terms of service of any service you interact with.
License
MIT License
Copyright (c) 2026 Nika Kudukhashvili
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, subject to the conditions of the MIT License.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
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 deepwrap-0.2.2.tar.gz.
File metadata
- Download URL: deepwrap-0.2.2.tar.gz
- Upload date:
- Size: 72.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
78ad3ed8aa041f3fe0eaa962cfae74cc86bcaef451aa7fe4a266c40eb48ba60d
|
|
| MD5 |
6461b7a74cdc538e40ed468baa7749fd
|
|
| BLAKE2b-256 |
01c3ef5449679e3901611b419c4169df178049352f868cdfeeb783a1e8ec47a9
|
Provenance
The following attestation bundles were made for deepwrap-0.2.2.tar.gz:
Publisher:
publish.yml on Kuduxaaa/deepwrap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
deepwrap-0.2.2.tar.gz -
Subject digest:
78ad3ed8aa041f3fe0eaa962cfae74cc86bcaef451aa7fe4a266c40eb48ba60d - Sigstore transparency entry: 2145775234
- Sigstore integration time:
-
Permalink:
Kuduxaaa/deepwrap@1db3c3c8d5df7034360d5ffb7d85ee24cd0946cf -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/Kuduxaaa
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1db3c3c8d5df7034360d5ffb7d85ee24cd0946cf -
Trigger Event:
release
-
Statement type:
File details
Details for the file deepwrap-0.2.2-py3-none-any.whl.
File metadata
- Download URL: deepwrap-0.2.2-py3-none-any.whl
- Upload date:
- Size: 66.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
660476bf55e018a90456aff6f3b0da42bead5d083c93b21ed22f4b561875a226
|
|
| MD5 |
009c8000e63512ef06c0691fcf9cfda3
|
|
| BLAKE2b-256 |
d7770c26b0a80a6a0fd66941ccbf34c706965ea4d33c5bd4fcefd886c953940b
|
Provenance
The following attestation bundles were made for deepwrap-0.2.2-py3-none-any.whl:
Publisher:
publish.yml on Kuduxaaa/deepwrap
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
deepwrap-0.2.2-py3-none-any.whl -
Subject digest:
660476bf55e018a90456aff6f3b0da42bead5d083c93b21ed22f4b561875a226 - Sigstore transparency entry: 2145775239
- Sigstore integration time:
-
Permalink:
Kuduxaaa/deepwrap@1db3c3c8d5df7034360d5ffb7d85ee24cd0946cf -
Branch / Tag:
refs/tags/v0.2.2 - Owner: https://github.com/Kuduxaaa
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1db3c3c8d5df7034360d5ffb7d85ee24cd0946cf -
Trigger Event:
release
-
Statement type: