atensec-thoth 0.1.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,714 @@
1
+ Metadata-Version: 2.4
2
+ Name: atensec-thoth
3
+ Version: 0.1.16
4
+ Summary: AI agent governance SDK by Aten Security
5
+ License-File: LICENSE
6
+ Author: Aten Engineering
7
+ Author-email: engineering@atensecurity.com
8
+ Requires-Python: >=3.12,<3.15
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Provides-Extra: anthropic
14
+ Provides-Extra: autogen
15
+ Provides-Extra: claude
16
+ Provides-Extra: langchain
17
+ Provides-Extra: openai
18
+ Requires-Dist: anyio (>=4.0)
19
+ Requires-Dist: boto3 (>=1.34)
20
+ Requires-Dist: httpx (>=0.27)
21
+ Requires-Dist: pydantic (>=2.0)
22
+ Project-URL: Documentation, https://docs.atensecurity.com
23
+ Project-URL: Homepage, https://atensecurity.com/thoth
24
+ Project-URL: Repository, https://github.com/atensecurity/thoth-py
25
+ Description-Content-Type: text/markdown
26
+
27
+ # Thoth SDK
28
+
29
+ Thoth SDK instruments your AI agents for governance, policy enforcement, and behavioral monitoring.
30
+ Every tool call is evaluated against your organization's security policies in <100ms — blocking,
31
+ stepping up for human approval, or silently observing based on your configured enforcement mode.
32
+
33
+ **Package name:** `atensec-thoth` | **PyPI:** `pip install atensec-thoth`
34
+
35
+ ---
36
+
37
+ ## Table of Contents
38
+
39
+ 1. [Installation](#installation)
40
+ 2. [Quick Start](#quick-start)
41
+ 3. [What's New Since 0.1.15](#whats-new-since-0115)
42
+ 4. [Legacy Compatibility (`ThothClient`)](#legacy-compatibility-thothclient)
43
+ 5. [How It Works](#how-it-works)
44
+ 6. [Integration Examples](#integration-examples)
45
+ - [LangChain AgentExecutor](#langchain-agentexecutor)
46
+ - [LangGraph](#langgraph)
47
+ - [Claude Agent SDK (`query`)](#claude-agent-sdk-query)
48
+ - [OpenAI Function Calling](#openai-function-calling)
49
+ - [Anthropic Claude](#anthropic-claude)
50
+ - [CrewAI](#crewai)
51
+ - [AutoGen](#autogen)
52
+ - [Custom Tools (Generic)](#custom-tools-generic)
53
+ 7. [Enforcement Modes](#enforcement-modes)
54
+ 8. [Policy Decisions](#policy-decisions)
55
+ 9. [Handling Violations](#handling-violations)
56
+ 10. [Step-Up Authentication](#step-up-authentication)
57
+ 11. [Session Inspection](#session-inspection)
58
+ 12. [Configuration Reference](#configuration-reference)
59
+ 13. [Dashboard](#dashboard)
60
+
61
+ ---
62
+
63
+ ## Installation
64
+
65
+ ```bash
66
+ pip install atensec-thoth
67
+ ```
68
+
69
+ **With LangChain / LangGraph support:**
70
+
71
+ ```bash
72
+ pip install "atensec-thoth[langchain]"
73
+ ```
74
+
75
+ **With OpenAI support:**
76
+
77
+ ```bash
78
+ pip install "atensec-thoth[openai]"
79
+ ```
80
+
81
+ **With Claude Agent SDK support:**
82
+
83
+ ```bash
84
+ pip install "atensec-thoth[claude]"
85
+ ```
86
+
87
+ **With AutoGen support:**
88
+
89
+ ```bash
90
+ pip install "atensec-thoth[autogen]"
91
+ ```
92
+
93
+ **Requirements:** Python 3.12+
94
+
95
+ ---
96
+
97
+ ## Quick Start
98
+
99
+ **1. Get your API key** from your Thoth dashboard at `https://<tenant>.<apex-domain>` under
100
+ **Settings → API Keys**.
101
+
102
+ **2. Set environment variables:**
103
+
104
+ ```bash
105
+ export THOTH_API_KEY="thoth_live_..."
106
+ export THOTH_API_URL="https://enforce.<tenant>.<apex-domain>"
107
+ ```
108
+
109
+ **3. Instrument your agent — three lines of code:**
110
+
111
+ ```python
112
+ import os
113
+ import thoth
114
+
115
+ # Instrument your agent — returns the same object, mutated in-place
116
+ agent = thoth.instrument(
117
+ agent,
118
+ agent_id="document-summarizer",
119
+ approved_scope=["read_file", "summarize"], # tools outside this list are blocked
120
+ tenant_id=os.environ["THOTH_TENANT_ID"],
121
+ api_url=os.environ["THOTH_API_URL"],
122
+ user_id="alice@example.com",
123
+ enforcement="block", # default deny
124
+ # api_key set via THOTH_API_KEY env var
125
+ )
126
+
127
+ # Every tool call is now governed — no other changes required
128
+ result = agent.run("Summarize the attached document and send it to the team.")
129
+ ```
130
+
131
+ That's it. No AWS credentials, no infrastructure setup — the SDK sends events and enforcement
132
+ requests over HTTPS to your tenant API URL.
133
+
134
+ ---
135
+
136
+ ## What's New Since 0.1.15
137
+
138
+ If you're upgrading from `0.1.15`, these are the material integration changes:
139
+
140
+ - **Package publish target is now `atensec-thoth`** (docs/examples updated accordingly).
141
+ - **Decision model expanded** beyond `ALLOW/BLOCK/STEP_UP`:
142
+ - `MODIFY`: enforcer can sanitize/transform tool args before execution.
143
+ - `DEFER`: enforcer can defer execution with retry guidance.
144
+ - **Decision envelope context surfaced end-to-end**:
145
+ - `decision_reason_code`, `action_classification`, `authorization_decision`
146
+ - `risk_score`, `latency_ms`, `pack_id`, `pack_version`, `rule_version`
147
+ - `matched_rule_ids`, `matched_control_ids`, `regulatory_regimes`, `policy_references`, `model_signals`
148
+ - `fastml_features`, `score_components`, `top_contributors`, `decision_evidence`, `receipt`
149
+ - **Async tool wrappers use async enforcement path** (`acheck`) and preserve sync/async behavior.
150
+ - **Structured tool metadata emission** now includes normalized `tool_call` payload and result summaries.
151
+ - **Enforcer payload now includes richer context** when provided:
152
+ - `tool_args`, `environment`, `enforcement_trace_id`
153
+ - `session_intent`, `purpose`, `data_classification`, `task_context`
154
+ - **Release automation moved to tag-driven public workflow** in `atensecurity/thoth-py`, with release notes sourced from `CHANGELOG.md`.
155
+
156
+ ---
157
+
158
+ ## Legacy Compatibility (`ThothClient`)
159
+
160
+ `thoth.instrument()`, `thoth.instrument_anthropic()`, and `thoth.instrument_openai()` are the
161
+ preferred APIs for new integrations.
162
+
163
+ `ThothClient` is still exported for backward compatibility with older examples and wrappers:
164
+
165
+ ```python
166
+ from thoth import ThothClient
167
+
168
+ client = ThothClient(
169
+ agent_id="document-summarizer",
170
+ approved_scope=["read_file", "summarize"],
171
+ tenant_id="acme-corp",
172
+ api_url="https://enforce.acme.example",
173
+ )
174
+
175
+ agent = client.wrap(agent) # legacy alias for client.instrument(agent)
176
+ ```
177
+
178
+ For new code, prefer the module-level APIs shown in Quick Start.
179
+
180
+ ---
181
+
182
+ ## How It Works
183
+
184
+ ```
185
+ Agent calls tool
186
+ │
187
+ ▼
188
+ Thoth intercepts (wrap_tool)
189
+ │
190
+ ├── Emits TOOL_CALL_PRE event → Aten API (async, non-blocking)
191
+ │
192
+ ├── Calls enforcer /v1/enforce
193
+ │ │
194
+ │ ├── ALLOW → tool executes normally
195
+ │ ├── STEP_UP → waits for human approval (polls /v1/enforce/hold/{token})
196
+ │ └── BLOCK → raises ThothPolicyViolation
197
+ │
198
+ ├── Tool executes (if allowed)
199
+ │
200
+ └── Emits TOOL_CALL_POST event → Aten API (async, non-blocking)
201
+ ```
202
+
203
+ Events are batched and flushed to the Aten ingest API in a background daemon thread with
204
+ at-most-10 per batch. If the enforcer is unreachable, Thoth fails closed (BLOCK) and logs a
205
+ warning. Tool execution is prevented until policy checks are reachable again.
206
+
207
+ ---
208
+
209
+ ## Integration Examples
210
+
211
+ ### LangChain AgentExecutor
212
+
213
+ Thoth detects `AgentExecutor` automatically and wraps both `tool.run` and `tool._run`:
214
+
215
+ ```python
216
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
217
+ from langchain_openai import ChatOpenAI
218
+ from langchain.tools import tool
219
+ import thoth
220
+
221
+ @tool
222
+ def web_search(query: str) -> str:
223
+ """Search the web for current information."""
224
+ ...
225
+
226
+ @tool
227
+ def read_file(path: str) -> str:
228
+ """Read a file from the local filesystem."""
229
+ ...
230
+
231
+ llm = ChatOpenAI(model="gpt-4o")
232
+ agent = create_openai_tools_agent(llm, tools=[web_search, read_file], prompt=...)
233
+ executor = AgentExecutor(agent=agent, tools=[web_search, read_file])
234
+
235
+ # One call instruments all tools
236
+ executor = thoth.instrument(
237
+ executor,
238
+ agent_id="research-agent",
239
+ approved_scope=["web_search", "read_file"],
240
+ tenant_id="acme-corp",
241
+ user_id="bob@acme.com",
242
+ enforcement="block",
243
+ )
244
+
245
+ # Now every tool invocation is policy-checked
246
+ result = executor.invoke({"input": "Find recent SEC filings for AAPL"})
247
+ ```
248
+
249
+ ### LangGraph
250
+
251
+ For LangGraph agents, wrap tool callables directly using `Tracer.wrap_tool`. Because LangGraph
252
+ doesn't use `AgentExecutor`, the low-level API is needed here:
253
+
254
+ ```python
255
+ import os
256
+ import thoth
257
+ from thoth.models import ThothConfig, EnforcementMode
258
+ from thoth.session import SessionContext
259
+ from thoth.emitter import HttpEmitter
260
+ from thoth.enforcer_client import EnforcerClient
261
+ from thoth.step_up import StepUpClient
262
+ from thoth.tracer import Tracer
263
+ from langchain_anthropic import ChatAnthropic
264
+ from langchain_core.tools import tool
265
+ from langgraph.prebuilt import create_react_agent
266
+
267
+ @tool
268
+ def search_database(query: str) -> str:
269
+ """Search the internal knowledge base."""
270
+ ...
271
+
272
+ @tool
273
+ def send_slack_message(channel: str, message: str) -> str:
274
+ """Post a message to Slack."""
275
+ ...
276
+
277
+ api_key = os.environ["THOTH_API_KEY"]
278
+ config = ThothConfig(
279
+ agent_id="langgraph-analyst",
280
+ approved_scope=["search_database", "send_slack_message"],
281
+ tenant_id=os.environ["THOTH_TENANT_ID"],
282
+ user_id="alice@acme.com",
283
+ enforcement=EnforcementMode.BLOCK,
284
+ api_key=api_key,
285
+ )
286
+ session = SessionContext(config)
287
+ tracer = Tracer(
288
+ config=config,
289
+ session=session,
290
+ emitter=HttpEmitter(api_url=config.resolved_api_url, api_key=api_key),
291
+ enforcer=EnforcerClient(config),
292
+ step_up=StepUpClient(config),
293
+ )
294
+
295
+ governed_search = tracer.wrap_tool("search_database", search_database)
296
+ governed_slack = tracer.wrap_tool("send_slack_message", send_slack_message)
297
+
298
+ llm = ChatAnthropic(model="claude-sonnet-4-6")
299
+ agent = create_react_agent(llm, [governed_search, governed_slack])
300
+
301
+ result = agent.invoke({"messages": [("user", "Search for Q4 data and post it to #analytics")]})
302
+ ```
303
+
304
+ See `examples/langgraph_example.py` for the full working script.
305
+
306
+ ### Claude Agent SDK (`query`)
307
+
308
+ For `claude-agent-sdk`, instrument `ClaudeAgentOptions` instead of a `.tools` list.
309
+ Thoth hooks into `can_use_tool` and tool lifecycle hooks.
310
+
311
+ ```python
312
+ import anyio
313
+ import os
314
+ from claude_agent_sdk import ClaudeAgentOptions, query
315
+ import thoth
316
+
317
+
318
+ async def prompt_stream():
319
+ # can_use_tool callbacks require streaming mode in claude-agent-sdk
320
+ yield {
321
+ "type": "user",
322
+ "message": {"role": "user", "content": "Read README.md and summarize risks."},
323
+ "parent_tool_use_id": None,
324
+ "session_id": "thoth-demo-session",
325
+ }
326
+
327
+
328
+ async def main():
329
+ options = ClaudeAgentOptions(
330
+ max_turns=1,
331
+ allowed_tools=["Read"], # auto-allow list in Claude SDK
332
+ disallowed_tools=["Bash"], # explicit deny list in Claude SDK
333
+ )
334
+
335
+ options = thoth.instrument_claude_agent_sdk(
336
+ options,
337
+ agent_id="claude-agent-sdk-demo",
338
+ approved_scope=["Read"], # Thoth policy scope
339
+ tenant_id=os.environ["THOTH_TENANT_ID"],
340
+ user_id="alice@acme.com",
341
+ enforcement="block",
342
+ )
343
+
344
+ async for message in query(prompt=prompt_stream(), options=options):
345
+ print(message)
346
+
347
+
348
+ anyio.run(main)
349
+ ```
350
+
351
+ See `examples/claude_agent_sdk_example.py` for the full working script.
352
+
353
+ ### Anthropic Claude
354
+
355
+ Use `instrument_anthropic()` to wrap tool functions for the Anthropic agentic loop:
356
+
357
+ ```python
358
+ import os
359
+ import anthropic
360
+ import thoth
361
+ from thoth import ThothPolicyViolation
362
+
363
+ governed = thoth.instrument_anthropic(
364
+ {"search_docs": search_docs, "delete_record": delete_record},
365
+ agent_id="claude-research-agent",
366
+ approved_scope=["search_docs"],
367
+ tenant_id=os.environ["THOTH_TENANT_ID"],
368
+ user_id="alice@acme.com",
369
+ enforcement="step_up",
370
+ # THOTH_API_KEY read from env automatically
371
+ )
372
+
373
+ client = anthropic.Anthropic()
374
+ messages = [{"role": "user", "content": "Find our data retention policy."}]
375
+
376
+ while True:
377
+ response = client.messages.create(
378
+ model="claude-opus-4-6", max_tokens=1024, tools=TOOLS, messages=messages
379
+ )
380
+ if response.stop_reason == "end_turn":
381
+ break
382
+ tool_results = []
383
+ for block in response.content:
384
+ if block.type == "tool_use":
385
+ try:
386
+ result = governed[block.name](block.input) # Thoth runs here
387
+ except ThothPolicyViolation as e:
388
+ result = f"[blocked: {e.reason}]"
389
+ tool_results.append({"type": "tool_result", "tool_use_id": block.id, "content": str(result)})
390
+ messages += [{"role": "assistant", "content": response.content},
391
+ {"role": "user", "content": tool_results}]
392
+ ```
393
+
394
+ See `examples/anthropic_example.py` for the full working script.
395
+
396
+ ### OpenAI Function Calling
397
+
398
+ Use `instrument_openai()` to wrap tool functions for the OpenAI tool-calling loop:
399
+
400
+ ```python
401
+ import os
402
+ import openai
403
+ import thoth
404
+ from thoth import ThothPolicyViolation
405
+
406
+ def search_docs(query: str) -> str:
407
+ ...
408
+
409
+ def send_email(to: str, subject: str, body: str) -> str:
410
+ ...
411
+
412
+ governed = thoth.instrument_openai(
413
+ {"search_docs": search_docs, "send_email": send_email},
414
+ agent_id="openai-agent",
415
+ approved_scope=["search_docs"],
416
+ tenant_id=os.environ["THOTH_TENANT_ID"],
417
+ user_id="charlie@acme.com",
418
+ enforcement="block",
419
+ # THOTH_API_KEY read from env automatically
420
+ )
421
+
422
+ client = openai.OpenAI()
423
+ messages = [{"role": "user", "content": "Find docs about access control"}]
424
+
425
+ while True:
426
+ response = client.chat.completions.create(model="gpt-4o", tools=TOOLS, messages=messages)
427
+ msg = response.choices[0].message
428
+ if not msg.tool_calls:
429
+ break
430
+ messages.append(msg)
431
+ for call in msg.tool_calls:
432
+ try:
433
+ import json
434
+ result = governed[call.function.name](json.loads(call.function.arguments))
435
+ except ThothPolicyViolation as e:
436
+ result = f"[blocked: {e.reason}]"
437
+ messages.append({"role": "tool", "tool_call_id": call.id, "content": str(result)})
438
+ ```
439
+
440
+ See `examples/openai_example.py` for the full working script.
441
+
442
+ ### CrewAI
443
+
444
+ `thoth.instrument()` detects CrewAI `Agent` objects automatically:
445
+
446
+ ```python
447
+ import os
448
+ import thoth
449
+ from crewai import Agent
450
+ from crewai.tools import tool
451
+
452
+ @tool("web_search")
453
+ def web_search(query: str) -> str:
454
+ """Search the web."""
455
+ ...
456
+
457
+ researcher = Agent(role="Researcher", goal="Find information", tools=[web_search])
458
+
459
+ thoth.instrument(
460
+ researcher,
461
+ agent_id="crewai-researcher",
462
+ approved_scope=["web_search"],
463
+ tenant_id=os.environ["THOTH_TENANT_ID"],
464
+ user_id="alice@acme.com",
465
+ enforcement="block",
466
+ # THOTH_API_KEY read from env automatically
467
+ )
468
+ ```
469
+
470
+ See `examples/crewai_example.py` for the full working script.
471
+
472
+ ### AutoGen
473
+
474
+ Use `wrap_autogen_tools()` to govern AutoGen's `function_map`:
475
+
476
+ ```python
477
+ import os
478
+ import autogen
479
+ from thoth.integrations.autogen import wrap_autogen_tools
480
+ from thoth.tracer import Tracer
481
+ # ... build tracer as shown in the LangGraph section above ...
482
+
483
+ governed = wrap_autogen_tools(
484
+ {"search_docs": search_docs, "send_email": send_email},
485
+ tracer=tracer,
486
+ )
487
+
488
+ user_proxy = autogen.UserProxyAgent(
489
+ name="user_proxy",
490
+ function_map=governed, # Thoth enforcement runs on every function call
491
+ )
492
+ ```
493
+
494
+ See `examples/autogen_example.py` for the full working script.
495
+
496
+ ### Custom Tools (Generic)
497
+
498
+ Any object with a `.tools` list and tools that have a `.run` method or are directly callable
499
+ will be instrumented automatically:
500
+
501
+ ```python
502
+ import thoth
503
+ from thoth import ThothPolicyViolation
504
+
505
+ class FileTool:
506
+ name = "read_file"
507
+
508
+ def run(self, path: str) -> str:
509
+ with open(path) as f:
510
+ return f.read()
511
+
512
+ class MyAgent:
513
+ tools = [FileTool()]
514
+
515
+ def run(self, prompt: str) -> str:
516
+ # ... your agent logic calls self.tools[0].run(...)
517
+ ...
518
+
519
+ agent = MyAgent()
520
+
521
+ agent = thoth.instrument(
522
+ agent,
523
+ agent_id="file-agent",
524
+ approved_scope=["read_file"],
525
+ tenant_id="acme-corp",
526
+ enforcement="block",
527
+ )
528
+
529
+ try:
530
+ result = agent.tools[0].run("/etc/passwd")
531
+ except ThothPolicyViolation as e:
532
+ print(f"Blocked: {e.tool_name} — {e.reason}")
533
+ if e.violation_id:
534
+ print(f"Violation record: {e.violation_id}")
535
+ ```
536
+
537
+ ---
538
+
539
+ ## Enforcement Modes
540
+
541
+ Set via the `enforcement` parameter to `instrument()`.
542
+
543
+ | Mode | Value | Behavior |
544
+ |---|---|---|
545
+ | Observe | `observe` | All tool calls pass through. Events are still emitted for audit. No blocking, no step-up. Use for initial rollout and baselining. |
546
+ | Step-Up | `step_up` | Suspicious calls trigger a human approval request (e.g. Slack DM to a reviewer). Tool execution is held until approved or timed out. |
547
+ | Block | `block` | Calls that violate policy raise `ThothPolicyViolation` immediately. |
548
+ | Progressive | `progressive` | Escalating mode. Enforcer chooses the appropriate response per tool call based on policy rules. |
549
+
550
+ ---
551
+
552
+ ## Policy Decisions
553
+
554
+ The enforcer returns one of five decisions for each tool call:
555
+
556
+ | Decision | Meaning | Agent behavior |
557
+ |---|---|---|
558
+ | `ALLOW` | Call is within policy. | Tool executes immediately. |
559
+ | `STEP_UP` | Call requires human approval. | SDK polls `/v1/enforce/hold/{token}` until approved or timed out. On timeout → `BLOCK`. |
560
+ | `MODIFY` | Call is allowed with transformed/sanitized arguments. | SDK rewrites the tool call args and then executes the tool. |
561
+ | `DEFER` | Call is postponed pending more context/workflow state. | SDK raises `ThothPolicyViolation` with defer context and timeout guidance. |
562
+ | `BLOCK` | Call violates policy. | `ThothPolicyViolation` is raised before the tool executes. |
563
+
564
+ Enforcer errors (for example, network timeout or 5xx) fail closed: the SDK treats them as
565
+ `BLOCK` and raises `ThothPolicyViolation`. Authentication/ingress failures include diagnostic hints
566
+ in logs to speed up misconfiguration debugging.
567
+
568
+ ---
569
+
570
+ ## Handling Violations
571
+
572
+ ```python
573
+ from thoth import ThothPolicyViolation
574
+
575
+ try:
576
+ result = agent.tools[0].run(user_input)
577
+ except ThothPolicyViolation as e:
578
+ # e.tool_name — the tool that was blocked
579
+ # e.reason — human-readable policy reason
580
+ # e.violation_id — reference ID for the violation record in Maat dashboard
581
+ # e.decision_reason_code / e.action_classification / e.authorization_decision
582
+ # e.risk_score / e.pack_id / e.pack_version / e.rule_version
583
+ # e.matched_rule_ids / e.matched_control_ids / e.regulatory_regimes
584
+ # e.policy_references / e.model_signals
585
+ # e.fastml_features / e.score_components / e.top_contributors / e.decision_evidence
586
+ # e.enforcement_trace_id / e.receipt
587
+ logger.warning("Policy violation on %s: %s (id=%s)", e.tool_name, e.reason, e.violation_id)
588
+ return {"error": "This action is not permitted under your current access policy."}
589
+ ```
590
+
591
+ ---
592
+
593
+ ## Step-Up Authentication
594
+
595
+ When the enforcer returns `STEP_UP`, Thoth automatically:
596
+
597
+ 1. Sends an approval request to the configured notification channel (Slack by default).
598
+ 2. Polls `/v1/enforce/hold/{hold_token}` every `step_up_poll_interval_seconds` (default: 5s).
599
+ 3. If approved within `step_up_timeout_minutes` (default: 15 minutes) → tool executes.
600
+ 4. If timed out → raises `ThothPolicyViolation` with reason `"step-up auth timeout"`.
601
+
602
+ Configure timeouts via `ThothConfig`:
603
+
604
+ ```python
605
+ from thoth.models import ThothConfig, EnforcementMode
606
+
607
+ config = ThothConfig(
608
+ agent_id="sensitive-agent",
609
+ approved_scope=["delete_record"],
610
+ tenant_id="acme-corp",
611
+ enforcement=EnforcementMode.STEP_UP,
612
+ step_up_timeout_minutes=5, # fail fast in production
613
+ step_up_poll_interval_seconds=3,
614
+ )
615
+ ```
616
+
617
+ ---
618
+
619
+ ## Session Inspection
620
+
621
+ Each `instrument()` call creates a `SessionContext` stored in a `contextvars.ContextVar`. Inspect
622
+ it from anywhere in the same async context:
623
+
624
+ ```python
625
+ from thoth import get_current_session
626
+
627
+ session = get_current_session()
628
+ if session:
629
+ print(f"Session ID: {session.session_id}")
630
+ print(f"Tools called: {session.tool_calls}")
631
+ print(f"Token spend: {session.token_spend}")
632
+ print(f"In scope: {session.is_in_scope('web_search')}")
633
+ ```
634
+
635
+ ---
636
+
637
+ ## Configuration Reference
638
+
639
+ ### `instrument()` parameters
640
+
641
+ | Parameter | Type | Default | Description |
642
+ |---|---|---|---|
643
+ | `agent` | `Any` | — | Agent object to instrument. Must have a `.tools` list. |
644
+ | `agent_id` | `str` | — | Stable identifier for this agent definition. Used in policy rules. |
645
+ | `approved_scope` | `list[str]` | — | List of tool names this agent is authorized to call. |
646
+ | `tenant_id` | `str` | — | Your Maat tenant ID. |
647
+ | `user_id` | `str` | `"system"` | Identity of the user on whose behalf the agent acts. |
648
+ | `enforcement` | `str` | `"block"` | Enforcement mode: `observe`, `step_up`, `block`, or `progressive`. |
649
+ | `api_key` | `str \| None` | `$THOTH_API_KEY` | API key from the Aten dashboard. Events sent over HTTPS — no AWS credentials required. |
650
+ | `event_ingest_token` | `str \| None` | `$THOTH_EVENT_INGEST_TOKEN` | Optional dedicated token sent as `X-Thoth-Event-Ingest-Token` for `/v1/events/batch`. |
651
+ | `api_url` | `str \| None` | `$THOTH_API_URL` | Required tenant API base URL used for both event ingestion and policy checks. |
652
+ | `session_id` | `str \| None` | auto-generated UUID | Pass an existing session ID to continue a session across calls. |
653
+ | `session_intent` | `str \| None` | `None` | Intent label used for minimum-necessary/session-scope policies. |
654
+ | `purpose` | `str \| None` | `None` | Policy context for allowed business purpose. |
655
+ | `data_classification` | `str \| None` | `None` | Policy context for data sensitivity. |
656
+ | `task_context` | `dict[str, Any] \| None` | `{}` | Optional delegation metadata (`initiated_by`, `task_id`, `chain`, etc.). |
657
+ | `environment` | `str \| None` | `$THOTH_ENVIRONMENT` or `"prod"` | Environment selector sent to enforcer policy lookup. |
658
+ | `enforcement_trace_id` | `str \| None` | `session_id` | Correlation ID propagated across enforcement/evidence paths. |
659
+
660
+ ### `ThothConfig` fields
661
+
662
+ | Field | Type | Default | Description |
663
+ |---|---|---|---|
664
+ | `agent_id` | `str` | — | Stable identifier for this agent. |
665
+ | `approved_scope` | `list[str]` | — | Tool names the agent is authorized to call. |
666
+ | `tenant_id` | `str` | — | Your Maat tenant ID. |
667
+ | `user_id` | `str` | `"system"` | User identity for the session. |
668
+ | `enforcement` | `EnforcementMode` | `BLOCK` | Enforcement mode. |
669
+ | `api_key` | `str \| None` | `None` | Aten API key. Falls back to `THOTH_API_KEY` env var via `_build_components`. |
670
+ | `event_ingest_token` | `str \| None` | `None` | Optional dedicated token for telemetry ingest. Falls back to `THOTH_EVENT_INGEST_TOKEN`. |
671
+ | `api_url` | `str \| None` | `None` | Required tenant API base URL. Provide directly or via `THOTH_API_URL`. Used for both `/v1/enforce` and `/v1/events/batch`. |
672
+ | `step_up_timeout_minutes` | `int` | `15` | Timeout for step-up approval. |
673
+ | `step_up_poll_interval_seconds` | `int` | `5` | Polling interval for step-up hold status. |
674
+ | `session_intent` | `str \| None` | `None` | Session purpose used by intent-scoped compliance packs. |
675
+ | `purpose` | `str \| None` | `None` | Business-purpose label propagated to policy checks and telemetry. |
676
+ | `data_classification` | `str \| None` | `None` | Sensitivity label propagated to policy checks and telemetry. |
677
+ | `task_context` | `dict[str, Any]` | `{}` | Delegation/task metadata included in enforcement payload + events. |
678
+ | `environment` | `str` | `"prod"` | Environment selector included in `/v1/enforce` payload. |
679
+ | `enforcement_trace_id` | `str \| None` | `None` | Optional explicit trace ID; falls back to `session_id`. |
680
+
681
+ ### Environment Variables
682
+
683
+ | Variable | Description |
684
+ |---|---|
685
+ | `THOTH_TENANT_ID` | Tenant identifier used by your application to pass `tenant_id` into SDK APIs (the SDK does not auto-read this by itself). |
686
+ | `THOTH_API_KEY` | API key from the Aten dashboard. Enables HTTPS event transport. Example: `thoth_live_abc123...` |
687
+ | `THOTH_EVENT_INGEST_TOKEN` | Optional dedicated telemetry token for `/v1/events/batch` (`X-Thoth-Event-Ingest-Token` header). |
688
+ | `THOTH_API_URL` | Required tenant API base URL for both event ingestion and policy checks. Example: `https://enforce.<tenant>.<apex-domain>` |
689
+ | `THOTH_ENVIRONMENT` | Optional environment selector (`prod`, `staging`, `dev`, etc.) sent to the enforcer payload. |
690
+ | `THOTH_LOG_LEVEL` | Optional SDK logger level override (`DEBUG`, `INFO`, `WARNING`, `ERROR`). If unset, SDK falls back to `LOG_LEVEL` when present. |
691
+
692
+ Resolution precedence:
693
+ - `THOTH_API_URL` overrides `api_url`.
694
+
695
+ ---
696
+
697
+ ## Dashboard
698
+
699
+ View sessions, violations, step-up requests, and policy decisions in your Thoth dashboard at
700
+ `https://<tenant>.<apex-domain>`.
701
+
702
+ The dashboard shows:
703
+ - **Sessions** — per-agent session timelines with all tool calls
704
+ - **Violations** — blocked or escalated actions with full context
705
+ - **Approvals** — step-up queue for human reviewers
706
+ - **Policies** — view and edit the rules driving enforcement decisions
707
+ - **Behavioral Analytics** — drift detection and anomaly scores over time
708
+
709
+ ---
710
+
711
+ ## License
712
+
713
+ Copyright 2026 Aten Security, Inc. All rights reserved.
714
+