clientcoded 0.1.0__tar.gz

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,182 @@
1
+ Metadata-Version: 2.4
2
+ Name: clientcoded
3
+ Version: 0.1.0
4
+ Summary: ClientCoded SDK - Trace your AI agent's tool calls for root cause analysis
5
+ Home-page: https://github.com/ClientCoded/clientcoded-python
6
+ Author: ClientCoded
7
+ Author-email: travis@clientcoded.com
8
+ Keywords: ai agent testing qa tracing evaluation
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Testing
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: requests>=2.20.0
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: home-page
28
+ Dynamic: keywords
29
+ Dynamic: requires-dist
30
+ Dynamic: requires-python
31
+ Dynamic: summary
32
+
33
+ # ClientCoded Python SDK
34
+
35
+ Trace your AI agent's tool calls for root cause analysis when failures occur.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install clientcoded
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```python
46
+ import clientcoded
47
+
48
+ # Configure once at startup
49
+ clientcoded.configure(
50
+ agent_id="your-agent-id",
51
+ api_key="your-api-key"
52
+ )
53
+
54
+ # Decorate any function your agent calls
55
+ @clientcoded.trace
56
+ def get_invoice(invoice_id):
57
+ return stripe.Invoice.retrieve(invoice_id)
58
+
59
+ @clientcoded.trace
60
+ def search_knowledge_base(query):
61
+ return pinecone.query(query)
62
+
63
+ @clientcoded.trace
64
+ def update_crm(contact_id, data):
65
+ return hubspot.update_contact(contact_id, data)
66
+ ```
67
+
68
+ ## Conversation Tracking
69
+
70
+ ```python
71
+ # At the start of each conversation
72
+ clientcoded.set_conversation_id("conv-123")
73
+
74
+ # At each turn
75
+ clientcoded.set_turn(1)
76
+ response = agent.handle_message("What is my invoice total?")
77
+
78
+ clientcoded.set_turn(2)
79
+ response = agent.handle_message("Can you break that down by line item?")
80
+ ```
81
+
82
+ ## Async Support
83
+
84
+ ```python
85
+ @clientcoded.trace_async
86
+ async def get_invoice(invoice_id):
87
+ return await stripe.Invoice.aretrieve(invoice_id)
88
+ ```
89
+
90
+ ## Custom Names
91
+
92
+ ```python
93
+ @clientcoded.trace(name="stripe_invoice_lookup")
94
+ def get_invoice(invoice_id):
95
+ return stripe.Invoice.retrieve(invoice_id)
96
+ ```
97
+
98
+ ## Manual Logging
99
+
100
+ For complex operations where decorators don't fit:
101
+
102
+ ```python
103
+ import time
104
+
105
+ start = time.time()
106
+ try:
107
+ result = complex_multi_step_operation()
108
+ clientcoded.log_trace(
109
+ "complex_operation",
110
+ input_data={"step": "final"},
111
+ output_data=result,
112
+ latency_ms=int((time.time() - start) * 1000)
113
+ )
114
+ except Exception as e:
115
+ clientcoded.log_trace(
116
+ "complex_operation",
117
+ input_data={"step": "final"},
118
+ error=str(e),
119
+ latency_ms=int((time.time() - start) * 1000)
120
+ )
121
+ raise
122
+ ```
123
+
124
+ ## LangChain Integration
125
+
126
+ ```python
127
+ from langchain.tools import tool
128
+ import clientcoded
129
+
130
+ clientcoded.configure(agent_id="your-agent-id", api_key="your-api-key")
131
+
132
+ @tool
133
+ @clientcoded.trace
134
+ def search_database(query: str) -> str:
135
+ """Search the company database."""
136
+ return db.execute(query)
137
+ ```
138
+
139
+ ## LlamaIndex Integration
140
+
141
+ ```python
142
+ from llama_index.core.tools import FunctionTool
143
+ import clientcoded
144
+
145
+ clientcoded.configure(agent_id="your-agent-id", api_key="your-api-key")
146
+
147
+ @clientcoded.trace
148
+ def query_index(question: str) -> str:
149
+ return index.query(question)
150
+
151
+ tool = FunctionTool.from_defaults(fn=query_index)
152
+ ```
153
+
154
+ ## What Gets Traced
155
+
156
+ For each decorated function call, the SDK logs:
157
+ - Function name (or custom name)
158
+ - Input arguments (truncated to 2000 chars)
159
+ - Output (truncated to 2000 chars)
160
+ - Error message if the function threw
161
+ - Latency in milliseconds
162
+ - Conversation ID and turn number (if set)
163
+
164
+ ## What Doesn't Get Traced
165
+
166
+ - The SDK never captures environment variables
167
+ - The SDK never captures file contents
168
+ - Large inputs/outputs are truncated, not stored in full
169
+ - All trace sends are fire-and-forget with a 2-second timeout
170
+
171
+ ## Safety
172
+
173
+ - The SDK will **never** break your agent. Every trace send is wrapped in try/catch.
174
+ - Trace sends happen in background threads. Zero impact on response latency.
175
+ - If the ClientCoded API is down, traces are silently dropped. Your agent continues normally.
176
+ - No sensitive data filtering in v0.1. Do not decorate functions that handle passwords, tokens, or PII directly. Wrap them in a function that sanitizes first.
177
+
178
+ ## Configuration
179
+
180
+ | Environment Variable | Default | Description |
181
+ |---|---|---|
182
+ | CLIENTCODED_TRACE_URL | https://clientcoded.app.n8n.cloud/webhook/ap-35-trace-ingest | Custom trace endpoint |
@@ -0,0 +1,150 @@
1
+ # ClientCoded Python SDK
2
+
3
+ Trace your AI agent's tool calls for root cause analysis when failures occur.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install clientcoded
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```python
14
+ import clientcoded
15
+
16
+ # Configure once at startup
17
+ clientcoded.configure(
18
+ agent_id="your-agent-id",
19
+ api_key="your-api-key"
20
+ )
21
+
22
+ # Decorate any function your agent calls
23
+ @clientcoded.trace
24
+ def get_invoice(invoice_id):
25
+ return stripe.Invoice.retrieve(invoice_id)
26
+
27
+ @clientcoded.trace
28
+ def search_knowledge_base(query):
29
+ return pinecone.query(query)
30
+
31
+ @clientcoded.trace
32
+ def update_crm(contact_id, data):
33
+ return hubspot.update_contact(contact_id, data)
34
+ ```
35
+
36
+ ## Conversation Tracking
37
+
38
+ ```python
39
+ # At the start of each conversation
40
+ clientcoded.set_conversation_id("conv-123")
41
+
42
+ # At each turn
43
+ clientcoded.set_turn(1)
44
+ response = agent.handle_message("What is my invoice total?")
45
+
46
+ clientcoded.set_turn(2)
47
+ response = agent.handle_message("Can you break that down by line item?")
48
+ ```
49
+
50
+ ## Async Support
51
+
52
+ ```python
53
+ @clientcoded.trace_async
54
+ async def get_invoice(invoice_id):
55
+ return await stripe.Invoice.aretrieve(invoice_id)
56
+ ```
57
+
58
+ ## Custom Names
59
+
60
+ ```python
61
+ @clientcoded.trace(name="stripe_invoice_lookup")
62
+ def get_invoice(invoice_id):
63
+ return stripe.Invoice.retrieve(invoice_id)
64
+ ```
65
+
66
+ ## Manual Logging
67
+
68
+ For complex operations where decorators don't fit:
69
+
70
+ ```python
71
+ import time
72
+
73
+ start = time.time()
74
+ try:
75
+ result = complex_multi_step_operation()
76
+ clientcoded.log_trace(
77
+ "complex_operation",
78
+ input_data={"step": "final"},
79
+ output_data=result,
80
+ latency_ms=int((time.time() - start) * 1000)
81
+ )
82
+ except Exception as e:
83
+ clientcoded.log_trace(
84
+ "complex_operation",
85
+ input_data={"step": "final"},
86
+ error=str(e),
87
+ latency_ms=int((time.time() - start) * 1000)
88
+ )
89
+ raise
90
+ ```
91
+
92
+ ## LangChain Integration
93
+
94
+ ```python
95
+ from langchain.tools import tool
96
+ import clientcoded
97
+
98
+ clientcoded.configure(agent_id="your-agent-id", api_key="your-api-key")
99
+
100
+ @tool
101
+ @clientcoded.trace
102
+ def search_database(query: str) -> str:
103
+ """Search the company database."""
104
+ return db.execute(query)
105
+ ```
106
+
107
+ ## LlamaIndex Integration
108
+
109
+ ```python
110
+ from llama_index.core.tools import FunctionTool
111
+ import clientcoded
112
+
113
+ clientcoded.configure(agent_id="your-agent-id", api_key="your-api-key")
114
+
115
+ @clientcoded.trace
116
+ def query_index(question: str) -> str:
117
+ return index.query(question)
118
+
119
+ tool = FunctionTool.from_defaults(fn=query_index)
120
+ ```
121
+
122
+ ## What Gets Traced
123
+
124
+ For each decorated function call, the SDK logs:
125
+ - Function name (or custom name)
126
+ - Input arguments (truncated to 2000 chars)
127
+ - Output (truncated to 2000 chars)
128
+ - Error message if the function threw
129
+ - Latency in milliseconds
130
+ - Conversation ID and turn number (if set)
131
+
132
+ ## What Doesn't Get Traced
133
+
134
+ - The SDK never captures environment variables
135
+ - The SDK never captures file contents
136
+ - Large inputs/outputs are truncated, not stored in full
137
+ - All trace sends are fire-and-forget with a 2-second timeout
138
+
139
+ ## Safety
140
+
141
+ - The SDK will **never** break your agent. Every trace send is wrapped in try/catch.
142
+ - Trace sends happen in background threads. Zero impact on response latency.
143
+ - If the ClientCoded API is down, traces are silently dropped. Your agent continues normally.
144
+ - No sensitive data filtering in v0.1. Do not decorate functions that handle passwords, tokens, or PII directly. Wrap them in a function that sanitizes first.
145
+
146
+ ## Configuration
147
+
148
+ | Environment Variable | Default | Description |
149
+ |---|---|---|
150
+ | CLIENTCODED_TRACE_URL | https://clientcoded.app.n8n.cloud/webhook/ap-35-trace-ingest | Custom trace endpoint |
@@ -0,0 +1,20 @@
1
+ from .trace import (
2
+ configure,
3
+ set_conversation_id,
4
+ set_turn,
5
+ increment_turn,
6
+ trace,
7
+ trace_async,
8
+ log_trace,
9
+ )
10
+
11
+ __version__ = "0.1.0"
12
+ __all__ = [
13
+ "configure",
14
+ "set_conversation_id",
15
+ "set_turn",
16
+ "increment_turn",
17
+ "trace",
18
+ "trace_async",
19
+ "log_trace",
20
+ ]
@@ -0,0 +1,225 @@
1
+ # ClientCoded Python SDK
2
+ # pip install clientcoded
3
+
4
+ import requests
5
+ import functools
6
+ import time
7
+ import uuid
8
+ import threading
9
+ import os
10
+
11
+ CLIENTCODED_API = os.environ.get(
12
+ "CLIENTCODED_TRACE_URL",
13
+ "https://clientcoded.app.n8n.cloud/webhook/ap-35-trace-ingest"
14
+ )
15
+
16
+ _context = threading.local()
17
+
18
+
19
+ def configure(agent_id, api_key, trace_url=None):
20
+ """
21
+ Configure the SDK globally.
22
+
23
+ Args:
24
+ agent_id: Your agent's ID from ClientCoded dashboard
25
+ api_key: Your API key from ClientCoded dashboard
26
+ trace_url: Optional custom trace endpoint URL
27
+ """
28
+ _context.agent_id = agent_id
29
+ _context.api_key = api_key
30
+ if trace_url:
31
+ global CLIENTCODED_API
32
+ CLIENTCODED_API = trace_url
33
+
34
+
35
+ def set_conversation_id(conversation_id):
36
+ """Call this at the start of each conversation."""
37
+ _context.conversation_id = conversation_id
38
+ _context.turn = 0
39
+
40
+
41
+ def set_turn(turn_number):
42
+ """Call this at the start of each turn."""
43
+ _context.turn = turn_number
44
+
45
+
46
+ def increment_turn():
47
+ """Increment the turn counter by 1."""
48
+ current = getattr(_context, 'turn', 0)
49
+ _context.turn = current + 1
50
+
51
+
52
+ def trace(func=None, *, name=None):
53
+ """
54
+ Decorator that traces a function call.
55
+
56
+ Usage:
57
+ @trace
58
+ def get_invoice(invoice_id):
59
+ return stripe.Invoice.retrieve(invoice_id)
60
+
61
+ @trace(name="stripe_lookup")
62
+ def get_invoice(invoice_id):
63
+ return stripe.Invoice.retrieve(invoice_id)
64
+ """
65
+ def decorator(fn):
66
+ @functools.wraps(fn)
67
+ def wrapper(*args, **kwargs):
68
+ trace_id = str(uuid.uuid4())
69
+ tool_name = name or fn.__name__
70
+ start = time.time()
71
+ error = None
72
+ result = None
73
+ try:
74
+ result = fn(*args, **kwargs)
75
+ return result
76
+ except Exception as e:
77
+ error = str(e)
78
+ raise
79
+ finally:
80
+ _send_trace(
81
+ trace_id=trace_id,
82
+ tool_name=tool_name,
83
+ args=args,
84
+ kwargs=kwargs,
85
+ result=result,
86
+ error=error,
87
+ latency_ms=int((time.time() - start) * 1000)
88
+ )
89
+ return wrapper
90
+
91
+ if func is not None:
92
+ return decorator(func)
93
+ return decorator
94
+
95
+
96
+ def trace_async(func=None, *, name=None):
97
+ """
98
+ Decorator that traces an async function call.
99
+
100
+ Usage:
101
+ @trace_async
102
+ async def get_invoice(invoice_id):
103
+ return await stripe.Invoice.aretrieve(invoice_id)
104
+ """
105
+ def decorator(fn):
106
+ @functools.wraps(fn)
107
+ async def wrapper(*args, **kwargs):
108
+ trace_id = str(uuid.uuid4())
109
+ tool_name = name or fn.__name__
110
+ start = time.time()
111
+ error = None
112
+ result = None
113
+ try:
114
+ result = await fn(*args, **kwargs)
115
+ return result
116
+ except Exception as e:
117
+ error = str(e)
118
+ raise
119
+ finally:
120
+ _send_trace(
121
+ trace_id=trace_id,
122
+ tool_name=tool_name,
123
+ args=args,
124
+ kwargs=kwargs,
125
+ result=result,
126
+ error=error,
127
+ latency_ms=int((time.time() - start) * 1000)
128
+ )
129
+ return wrapper
130
+
131
+ if func is not None:
132
+ return decorator(func)
133
+ return decorator
134
+
135
+
136
+ def log_trace(tool_name, input_data=None, output_data=None, error=None, latency_ms=None):
137
+ """
138
+ Manual trace logging for cases where decorators don't fit.
139
+
140
+ Usage:
141
+ start = time.time()
142
+ try:
143
+ result = some_complex_operation()
144
+ log_trace("complex_op", input_data={"key": "val"}, output_data=result)
145
+ except Exception as e:
146
+ log_trace("complex_op", input_data={"key": "val"}, error=str(e))
147
+ """
148
+ _send_trace(
149
+ trace_id=str(uuid.uuid4()),
150
+ tool_name=tool_name,
151
+ args=(),
152
+ kwargs=input_data or {},
153
+ result=output_data,
154
+ error=error,
155
+ latency_ms=latency_ms
156
+ )
157
+
158
+
159
+ def _send_trace(trace_id, tool_name, args, kwargs, result, error, latency_ms):
160
+ """Fire-and-forget trace send. Never breaks the customer's agent."""
161
+ agent_id = getattr(_context, 'agent_id', None)
162
+ api_key = getattr(_context, 'api_key', None)
163
+
164
+ if not agent_id or not api_key:
165
+ return
166
+
167
+ payload = {
168
+ "agent_id": agent_id,
169
+ "api_key": api_key,
170
+ "trace_id": trace_id,
171
+ "conversation_id": getattr(_context, 'conversation_id', None),
172
+ "turn": getattr(_context, 'turn', None),
173
+ "tool_name": tool_name,
174
+ "input": _safe_serialize_input(args, kwargs),
175
+ "output": _safe_serialize_output(result),
176
+ "error": error,
177
+ "latency_ms": latency_ms,
178
+ "timestamp": time.time()
179
+ }
180
+
181
+ # Fire and forget in a background thread
182
+ thread = threading.Thread(target=_post_trace, args=(payload,), daemon=True)
183
+ thread.start()
184
+
185
+
186
+ def _post_trace(payload):
187
+ """Send trace to ClientCoded. Silent failure."""
188
+ try:
189
+ requests.post(
190
+ CLIENTCODED_API,
191
+ json=payload,
192
+ timeout=2
193
+ )
194
+ except Exception:
195
+ pass
196
+
197
+
198
+ def _safe_serialize_input(args, kwargs):
199
+ """Serialize inputs, truncate large values."""
200
+ try:
201
+ serialized = {}
202
+ if args:
203
+ serialized["args"] = [_truncate(str(a)) for a in args]
204
+ if kwargs:
205
+ serialized["kwargs"] = {k: _truncate(str(v)) for k, v in kwargs.items()}
206
+ return serialized
207
+ except Exception:
208
+ return {"error": "unserializable"}
209
+
210
+
211
+ def _safe_serialize_output(result):
212
+ """Serialize output, truncate large responses."""
213
+ if result is None:
214
+ return None
215
+ try:
216
+ return _truncate(str(result))
217
+ except Exception:
218
+ return "unserializable"
219
+
220
+
221
+ def _truncate(s, max_len=2000):
222
+ """Truncate string to max length."""
223
+ if len(s) > max_len:
224
+ return s[:max_len] + "... (truncated)"
225
+ return s
@@ -0,0 +1,182 @@
1
+ Metadata-Version: 2.4
2
+ Name: clientcoded
3
+ Version: 0.1.0
4
+ Summary: ClientCoded SDK - Trace your AI agent's tool calls for root cause analysis
5
+ Home-page: https://github.com/ClientCoded/clientcoded-python
6
+ Author: ClientCoded
7
+ Author-email: travis@clientcoded.com
8
+ Keywords: ai agent testing qa tracing evaluation
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Testing
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: requests>=2.20.0
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: home-page
28
+ Dynamic: keywords
29
+ Dynamic: requires-dist
30
+ Dynamic: requires-python
31
+ Dynamic: summary
32
+
33
+ # ClientCoded Python SDK
34
+
35
+ Trace your AI agent's tool calls for root cause analysis when failures occur.
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install clientcoded
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```python
46
+ import clientcoded
47
+
48
+ # Configure once at startup
49
+ clientcoded.configure(
50
+ agent_id="your-agent-id",
51
+ api_key="your-api-key"
52
+ )
53
+
54
+ # Decorate any function your agent calls
55
+ @clientcoded.trace
56
+ def get_invoice(invoice_id):
57
+ return stripe.Invoice.retrieve(invoice_id)
58
+
59
+ @clientcoded.trace
60
+ def search_knowledge_base(query):
61
+ return pinecone.query(query)
62
+
63
+ @clientcoded.trace
64
+ def update_crm(contact_id, data):
65
+ return hubspot.update_contact(contact_id, data)
66
+ ```
67
+
68
+ ## Conversation Tracking
69
+
70
+ ```python
71
+ # At the start of each conversation
72
+ clientcoded.set_conversation_id("conv-123")
73
+
74
+ # At each turn
75
+ clientcoded.set_turn(1)
76
+ response = agent.handle_message("What is my invoice total?")
77
+
78
+ clientcoded.set_turn(2)
79
+ response = agent.handle_message("Can you break that down by line item?")
80
+ ```
81
+
82
+ ## Async Support
83
+
84
+ ```python
85
+ @clientcoded.trace_async
86
+ async def get_invoice(invoice_id):
87
+ return await stripe.Invoice.aretrieve(invoice_id)
88
+ ```
89
+
90
+ ## Custom Names
91
+
92
+ ```python
93
+ @clientcoded.trace(name="stripe_invoice_lookup")
94
+ def get_invoice(invoice_id):
95
+ return stripe.Invoice.retrieve(invoice_id)
96
+ ```
97
+
98
+ ## Manual Logging
99
+
100
+ For complex operations where decorators don't fit:
101
+
102
+ ```python
103
+ import time
104
+
105
+ start = time.time()
106
+ try:
107
+ result = complex_multi_step_operation()
108
+ clientcoded.log_trace(
109
+ "complex_operation",
110
+ input_data={"step": "final"},
111
+ output_data=result,
112
+ latency_ms=int((time.time() - start) * 1000)
113
+ )
114
+ except Exception as e:
115
+ clientcoded.log_trace(
116
+ "complex_operation",
117
+ input_data={"step": "final"},
118
+ error=str(e),
119
+ latency_ms=int((time.time() - start) * 1000)
120
+ )
121
+ raise
122
+ ```
123
+
124
+ ## LangChain Integration
125
+
126
+ ```python
127
+ from langchain.tools import tool
128
+ import clientcoded
129
+
130
+ clientcoded.configure(agent_id="your-agent-id", api_key="your-api-key")
131
+
132
+ @tool
133
+ @clientcoded.trace
134
+ def search_database(query: str) -> str:
135
+ """Search the company database."""
136
+ return db.execute(query)
137
+ ```
138
+
139
+ ## LlamaIndex Integration
140
+
141
+ ```python
142
+ from llama_index.core.tools import FunctionTool
143
+ import clientcoded
144
+
145
+ clientcoded.configure(agent_id="your-agent-id", api_key="your-api-key")
146
+
147
+ @clientcoded.trace
148
+ def query_index(question: str) -> str:
149
+ return index.query(question)
150
+
151
+ tool = FunctionTool.from_defaults(fn=query_index)
152
+ ```
153
+
154
+ ## What Gets Traced
155
+
156
+ For each decorated function call, the SDK logs:
157
+ - Function name (or custom name)
158
+ - Input arguments (truncated to 2000 chars)
159
+ - Output (truncated to 2000 chars)
160
+ - Error message if the function threw
161
+ - Latency in milliseconds
162
+ - Conversation ID and turn number (if set)
163
+
164
+ ## What Doesn't Get Traced
165
+
166
+ - The SDK never captures environment variables
167
+ - The SDK never captures file contents
168
+ - Large inputs/outputs are truncated, not stored in full
169
+ - All trace sends are fire-and-forget with a 2-second timeout
170
+
171
+ ## Safety
172
+
173
+ - The SDK will **never** break your agent. Every trace send is wrapped in try/catch.
174
+ - Trace sends happen in background threads. Zero impact on response latency.
175
+ - If the ClientCoded API is down, traces are silently dropped. Your agent continues normally.
176
+ - No sensitive data filtering in v0.1. Do not decorate functions that handle passwords, tokens, or PII directly. Wrap them in a function that sanitizes first.
177
+
178
+ ## Configuration
179
+
180
+ | Environment Variable | Default | Description |
181
+ |---|---|---|
182
+ | CLIENTCODED_TRACE_URL | https://clientcoded.app.n8n.cloud/webhook/ap-35-trace-ingest | Custom trace endpoint |
@@ -0,0 +1,9 @@
1
+ README.md
2
+ setup.py
3
+ clientcoded/__init__.py
4
+ clientcoded/trace.py
5
+ clientcoded.egg-info/PKG-INFO
6
+ clientcoded.egg-info/SOURCES.txt
7
+ clientcoded.egg-info/dependency_links.txt
8
+ clientcoded.egg-info/requires.txt
9
+ clientcoded.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ requests>=2.20.0
@@ -0,0 +1 @@
1
+ clientcoded
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,28 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="clientcoded",
5
+ version="0.1.0",
6
+ description="ClientCoded SDK - Trace your AI agent's tool calls for root cause analysis",
7
+ long_description=open("README.md").read(),
8
+ long_description_content_type="text/markdown",
9
+ author="ClientCoded",
10
+ author_email="travis@clientcoded.com",
11
+ url="https://github.com/ClientCoded/clientcoded-python",
12
+ packages=find_packages(),
13
+ install_requires=["requests>=2.20.0"],
14
+ python_requires=">=3.8",
15
+ classifiers=[
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.8",
21
+ "Programming Language :: Python :: 3.9",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Topic :: Software Development :: Testing",
26
+ ],
27
+ keywords="ai agent testing qa tracing evaluation",
28
+ )