Chatsee SDK (Python)
Instrument an LLM agent so every turn arrives at ChatSee as a trace: what the user asked, what the agent answered, which tools ran, how long each one took, what failed, and who it was for.
pip install chatsee-ai
Quick start
from chatsee import ChatseeTracker
tracker = ChatseeTracker(
agent_id="agent_1",
tenant_id="tenant_1",
api_base_url="dev", # environment alias, or a full URL
user_id="u_123", # optional: who the end user is
)
tracker.start_turn("Where is my order?")
with tracker.track_tool_call("lookup_order", {"id": "A-91"}) as call:
call["result"] = lookup_order("A-91")
tracker.end_turn("It ships tomorrow.")
One start_turn … end_turn pair is one turn. Everything logged in between —
tool calls, exceptions, metadata — belongs to that turn and is sent in a single
request when it closes.
What gets captured
| Captured | How |
|---|---|
| User and bot message | start_turn / end_turn |
| End user identity | user_id (see below) |
| Session grouping | session_id, or the API generates one |
| Tool calls: name, arguments, result, error | track_tool_call / log_tool_call |
| Per-tool duration | measured automatically by track_tool_call |
| Turn duration | measured between start_turn and end_turn |
| Errors | log_exception, or any exception raised inside track_tool_call |
| System prompt | start_turn(system_prompt=...) |
| Anything else | start_turn(metadata={...}) |
Durations are milliseconds of wall clock. When a duration was not measured it is
sent as absent, never as 0 — downstream latency figures are built from real
measurements only, so an unmeasured call is excluded rather than counted as
instant.
Timing tool calls
track_tool_call is the recommended form: it times the call, records the
result, and still logs the call if the tool raises before re-raising to you.
with tracker.track_tool_call("search", {"q": q}) as call:
call["result"] = search(q) # exceptions here are logged, then re-raised
If you already have the timing, or the call happened elsewhere, log it directly:
tracker.log_tool_call("search", {"q": q}, result=hits, duration_ms=412)
tracker.log_tool_call("refund", {"id": "A-91"}, error="gateway timeout")
Both feed the per-tool metrics the ChatSee front end reads — call counts, error rate, and p50/p95 latency per tool.
Identifying the end user
user_id is a first-class field, so traces can be filtered and grouped by
person rather than by conversation. It is optional — when nothing is supplied,
ingestion assigns a deterministic anonymous id per session — but a real id is
what lets you follow one user across sessions.
tracker = ChatseeTracker(..., user_id="u_123") # one tracker, one user
tracker.start_turn("Hello", user_id="u_456") # one tracker, many users
Precedence: start_turn(user_id=...), then the tracker-level user_id, then
metadata["user_id"] — the older metadata form keeps working as a fallback.
Environments
Select an environment by passing an alias as api_base_url, or any full URL.
| Alias | URL |
|---|---|
dev |
https://dev-react.chatsee.ai/api |
dev-legacy |
https://dev.chatsee.ai/api |
qa (default) |
https://qa.chatsee.ai/api |
demo |
https://gcp-demo.chatsee.ai/api |
poc |
https://app.chatsee.ai/api |
Redaction classifiers are fetched from the same environment
(…/v1/redaction/fetch-classifiers); override with redaction_classifiers_url.
Closing a conversation early
Conversations are normally flushed by an inactivity timer. If you know a turn is the last one, say so and it flushes immediately:
tracker.end_turn("Glad I could help.", is_final_turn=True)
Batching
Send many turns as one API call — one Processor run instead of one per turn. Useful for backfills and imports.
tracker.send_batch([
{"user_message": "hi", "bot_message": "hello", "session_id": "s1"},
{"user_message": "thanks", "bot_message": "any time", "session_id": "s1"},
])
Redaction
Redaction runs client-side, before anything leaves the process. Classifiers come from your environment and are cached.
tracker = ChatseeTracker(..., redaction_enabled=True) # redacts each turn
Or redact a payload on its own, without a tracker:
from chatsee import redact
redact({"message": "Card 4111 1111 1111 1111"}, api_base_url="qa", fields_to_redact="*")
Defaults to user_message, bot_message and interactions; set
redaction_fields_to_redact (or fields_to_redact="*") to change that.
Closed-loop remediations
Pull remediation skills for this agent and acknowledge the ones you have
injected into its system prompt. Requires mcp_server_url and mcp_api_key;
tenant and agent are resolved server-side from the key.
tracker = ChatseeTracker(..., mcp_server_url="https://…", mcp_api_key="…")
pending = tracker.fetch_remediations() # or mode="all"
tracker.acknowledge_remediations([r["id"] for r in pending["remediations"]])
Track Claude Code (adapter)
Claude Code is a closed CLI, so rather than instrumenting it the adapter reads its session logs, reconstructs each turn and sends it through the SDK.
# preview (sends nothing)
python -m chatsee.adapters.claude_code --latest --dry-run
# one-time hook install -> every completed turn auto-streams, no terminal needed
python -m chatsee.adapters.claude_code --install-hook \
--agent-id <AGENT_ID> --tenant-id <TENANT_ID> --env dev
# remove it
python -m chatsee.adapters.claude_code --uninstall-hook
Alternatives to the hook: --watch (foreground tail) or a one-shot run. A
per-session checkpoint (~/.chatsee/claude_code_state.json) prevents duplicates.
Redaction is on by default here. Claude Code turns — tool arguments and
results especially — often contain secrets and PII, so the adapter redacts
client-side before sending (user_message, bot_message,
tool_calls_details, exception, system_prompt). Change the set with
--redact-fields a,b,c, or disable with --no-redact (not recommended). The
setting is preserved in installed hooks.
Notes
agent_idandtenant_idare required; there is no API key on the tracking path.verify_ssldefaults toFalsefor the internal environments; setTruefor public ones.- Encryption support has been removed from this SDK.
Release files for chatsee-ai 0.12.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| chatsee_ai-0.12.1.tar.gz | 32.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chatsee_ai-0.12.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 61.1 kB
Release files / chatsee_ai-0.12.1.tar.gz
| Download URL | chatsee_ai-0.12.1.tar.gz |
|---|---|
| Size | 32.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ba4de4b84438923f5eeeecdc4769309944a3993ea6379f578f53f261a4ee5d9d
|
|
BLAKE2b-256 checksum How to use checksums |
2cdf0cd084ca2b816bd2537ecfa7770816e42f13853a291f53690d4a2ed1115b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / chatsee_ai-0.12.1-py3-none-any.whl
| Download URL | chatsee_ai-0.12.1-py3-none-any.whl |
|---|---|
| Size | 28.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2a465c114ca26c3280a65bd50ee767daa0c0faafa04db789ea221ce5f30486d0
|
|
BLAKE2b-256 checksum How to use checksums |
b54db23a7a0b5499e0ea840a0c18688198e5933dc7a47801aec20c2210e85f42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|