copilotkit-intelligence-runtime 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.
Files changed (42) hide show
  1. copilotkit_intelligence_runtime-0.1.0/.gitignore +6 -0
  2. copilotkit_intelligence_runtime-0.1.0/LICENSE +21 -0
  3. copilotkit_intelligence_runtime-0.1.0/PKG-INFO +403 -0
  4. copilotkit_intelligence_runtime-0.1.0/README.md +390 -0
  5. copilotkit_intelligence_runtime-0.1.0/examples/conformance.py +86 -0
  6. copilotkit_intelligence_runtime-0.1.0/package.json +1 -0
  7. copilotkit_intelligence_runtime-0.1.0/project.json +45 -0
  8. copilotkit_intelligence_runtime-0.1.0/pyproject.toml +45 -0
  9. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_intelligence/__init__.py +62 -0
  10. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_intelligence/client.py +805 -0
  11. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_intelligence/entitlements.py +142 -0
  12. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_intelligence/inspector.py +182 -0
  13. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_intelligence/learned_skills.py +98 -0
  14. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_intelligence/py.typed +0 -0
  15. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_intelligence/resources.py +134 -0
  16. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/__init__.py +27 -0
  17. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/a2ui.py +559 -0
  18. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/agents.py +64 -0
  19. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/finalizer.py +75 -0
  20. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/gateway.py +287 -0
  21. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/mcp_apps.py +299 -0
  22. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/models.py +77 -0
  23. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/platform.py +67 -0
  24. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/py.typed +0 -0
  25. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/runtime.py +878 -0
  26. copilotkit_intelligence_runtime-0.1.0/src/copilotkit_runtime/telemetry.py +263 -0
  27. copilotkit_intelligence_runtime-0.1.0/tests/test_a2ui.py +173 -0
  28. copilotkit_intelligence_runtime-0.1.0/tests/test_entitlements_runtime.py +78 -0
  29. copilotkit_intelligence_runtime-0.1.0/tests/test_finalizer.py +25 -0
  30. copilotkit_intelligence_runtime-0.1.0/tests/test_gateway.py +186 -0
  31. copilotkit_intelligence_runtime-0.1.0/tests/test_inspector_runtime.py +162 -0
  32. copilotkit_intelligence_runtime-0.1.0/tests/test_intelligence_sdk.py +276 -0
  33. copilotkit_intelligence_runtime-0.1.0/tests/test_mcp_apps.py +43 -0
  34. copilotkit_intelligence_runtime-0.1.0/tests/test_memory_result_types.py +102 -0
  35. copilotkit_intelligence_runtime-0.1.0/tests/test_runtime.py +460 -0
  36. copilotkit_intelligence_runtime-0.1.0/tests/test_sdk_entitlements.py +380 -0
  37. copilotkit_intelligence_runtime-0.1.0/tests/test_sdk_inspector.py +267 -0
  38. copilotkit_intelligence_runtime-0.1.0/tests/test_sdk_learned_skills.py +461 -0
  39. copilotkit_intelligence_runtime-0.1.0/tests/test_sdk_lifecycle.py +247 -0
  40. copilotkit_intelligence_runtime-0.1.0/tests/test_telemetry.py +264 -0
  41. copilotkit_intelligence_runtime-0.1.0/tests/test_thread_result_types.py +138 -0
  42. copilotkit_intelligence_runtime-0.1.0/uv.lock +1097 -0
@@ -0,0 +1,6 @@
1
+ .venv/
2
+ dist/
3
+ __pycache__/
4
+ .pytest_cache/
5
+ .mypy_cache/
6
+ .ruff_cache/
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Atai Barkai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,403 @@
1
+ Metadata-Version: 2.5
2
+ Name: copilotkit-intelligence-runtime
3
+ Version: 0.1.0
4
+ Summary: Native ASGI runtime for CopilotKit Intelligence
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.11
8
+ Requires-Dist: httpx<1,>=0.27
9
+ Requires-Dist: mcp<2,>=1.12
10
+ Requires-Dist: starlette<1,>=0.41
11
+ Requires-Dist: websockets<16,>=14
12
+ Description-Content-Type: text/markdown
13
+
14
+ # CopilotKit Intelligence Runtime for Python
15
+
16
+ Host Python agents and the CopilotKit Intelligence API in an ASGI application.
17
+ The package requires Python 3.11 or later and an Intelligence project API key.
18
+
19
+ ## Use Intelligence without a server
20
+
21
+ The `copilotkit_intelligence` SDK is separate from the `copilotkit_runtime` ASGI application.
22
+ Both imports ship in this package. The SDK does not import ASGI, start an agent, or mount routes.
23
+ Use it from a script or worker to manage threads, recall memories, and record annotations.
24
+
25
+ ```python
26
+ import asyncio
27
+ import os
28
+
29
+ from copilotkit_intelligence import Intelligence
30
+
31
+
32
+ async def main():
33
+ async with Intelligence(api_key=os.environ["CPK_INTELLIGENCE_API_KEY"]) as intelligence:
34
+ thread = await intelligence.get_or_create_thread(
35
+ thread_id="9dcc02ea-695d-4635-8efc-649c1b94ab90",
36
+ user_id="customer-42",
37
+ agent_id="support",
38
+ learning_container_id="support-quality",
39
+ )
40
+ memories = await intelligence.recall_memories(
41
+ user_id="customer-42",
42
+ query="support preferences",
43
+ limit=5,
44
+ )
45
+ print(thread["thread"]["id"], memories["memories"])
46
+
47
+
48
+ asyncio.run(main())
49
+ ```
50
+
51
+ `learning_container_id` assigns a new thread to an existing Learning Container.
52
+ Intelligence owns that binding and rejects attempts to move a bound thread.
53
+
54
+ The SDK also provides `list_threads`, `get_thread`, `create_thread`, `update_thread`, and `archive_thread`.
55
+ `get_thread_messages`, `get_thread_events`, and `get_thread_state` read persisted thread data.
56
+ `delete_thread` permanently deletes a thread and its history.
57
+
58
+ Thread and history methods return dictionaries with public `TypedDict` annotations.
59
+ `ThreadSummary` describes metadata. `ThreadMessagesResponse` and `ThreadEventsResponse` describe persisted history.
60
+ `ThreadStateResponse` distinguishes a snapshot, no snapshot, and a snapshot decode error through the `kind` field.
61
+ `AnnotateResponse` includes the annotation ID and duplicate marker. Structured message content and custom event fields retain their JSON values.
62
+
63
+ Memory methods include `list_memories`, `create_memory`, `update_memory`, `remove_memory`, and `recall_memories`.
64
+ Results use public `TypedDict` annotations: `MemorySummary`, `ListMemoriesResponse`, `RecallMemoriesResponse`, and `SaveMemoryResponse`.
65
+ Your editor can show Memory fields, recall scores, and save markers. Results remain dictionaries with the original JSON field names and extension values.
66
+ Pass a `MemoryGrant(user="read-write", project="read")` as `memory_grant` to apply explicit limits.
67
+ Without a grant, Intelligence applies its policy. Every Memory call requires the bare application user ID.
68
+
69
+ `annotate` records an annotation. Reuse `client_event_id` when retrying the same annotation.
70
+ The SDK raises `IntelligenceError` with an HTTP status but no private response body.
71
+ Requests have a 30-second timeout by default. The SDK does not retry writes or follow redirects.
72
+
73
+ Pass the same client to `IntelligenceRuntime(intelligence=intelligence, agents=agents, identify_user=identify_user)` to mount Runtime routes.
74
+ The Runtime borrows that client. Close the Runtime before leaving the SDK context.
75
+ If you supply an `httpx.AsyncClient`, you retain ownership of its pool.
76
+
77
+ ## Handle thread changes
78
+
79
+ Register synchronous listeners on the SDK:
80
+
81
+ ```python
82
+ unsubscribe = intelligence.on_thread_created(lambda thread: print(thread["id"]))
83
+ ```
84
+
85
+ `on_thread_created` receives the canonical thread after creation.
86
+ `on_thread_updated` receives the thread after an update or archive.
87
+ `on_thread_deleted` receives `threadId`, `userId`, and `agentId` after deletion.
88
+ Each registration returns an unsubscribe function. Call it to stop that listener.
89
+
90
+ Listeners receive changes from direct SDK calls and from a Runtime that shares the SDK.
91
+ Failed requests and concurrent-create conflicts emit no success event.
92
+ Listener exceptions do not stop other listeners or replace a successful platform response.
93
+ The SDK reports these exceptions through the standard Python logging module.
94
+
95
+ ## Read Inspector metadata
96
+
97
+ Read project display metadata from application code:
98
+
99
+ ```python
100
+ from copilotkit_intelligence import InspectorMetadata
101
+
102
+ metadata: InspectorMetadata | None = await intelligence.get_inspector_metadata()
103
+ if metadata is not None and "plan" in metadata:
104
+ print(metadata["plan"]["label"])
105
+ ```
106
+
107
+ The typed result contains supported identity, plan, license, action, and usage fields.
108
+ Each module is optional. The SDK removes unknown fields and unsafe action URLs.
109
+ Metadata describes the project. It does not grant access to a feature or resource.
110
+
111
+ The request uses the server API key and a five-second deadline, including the response body.
112
+ A shorter `request_timeout` also applies. Deadline expiry raises `TimeoutError`.
113
+ A 204, 404, or unsupported schema returns `None`.
114
+ Other provider errors raise `IntelligenceError` with the HTTP status. Invalid JSON uses status 502.
115
+
116
+ The Runtime exposes the same data at `GET /copilotkit/inspector-metadata`.
117
+ Like `/info`, this display endpoint does not require an application-user identity.
118
+ It never forwards browser credentials to Intelligence.
119
+ Responses use `Cache-Control: no-store, private`. Provider errors produce an empty 204 response.
120
+ The `/info` response advertises this route through `inspectorMetadata: true`.
121
+
122
+ ## Read Runtime entitlements
123
+
124
+ Read the Runtime grant from a script, worker, or application:
125
+
126
+ ```python
127
+ from copilotkit_intelligence import RuntimeEntitlementResponse
128
+
129
+ result: RuntimeEntitlementResponse = await intelligence.get_runtime_entitlements()
130
+ if result["status"] == "ready":
131
+ print(result["entitlement"]["active"])
132
+ else:
133
+ print(result["error"]["code"])
134
+ ```
135
+
136
+ A ready result contains the grant, features, and limits. Its `active` value determines Runtime access.
137
+ Other results have status `degraded`, `misconfigured`, or `unavailable` and contain a structured error.
138
+ The SDK accepts both current responses and legacy flat responses.
139
+
140
+ Concurrent calls share one HTTP request. Each caller receives a separate copy.
141
+ Active grants remain in the cache for 30 seconds. Other results and request errors remain for five seconds.
142
+ After expiry, the SDK requests a fresh result. A failed request does not return an expired grant.
143
+
144
+ The request deadline is 1.5 seconds, including the response body.
145
+ A shorter `request_timeout` also applies.
146
+ `RuntimeEntitlementError` extends `IntelligenceError` with a `retryable` flag.
147
+ Errors retain the HTTP status and retry guidance without transport messages or response bodies.
148
+ Invalid responses use status 502 with `retryable=False`. Timeouts use status 504 with `retryable=True`.
149
+
150
+ Caller cancellation does not interrupt other callers that await the same request.
151
+ When the last caller cancels, the SDK cancels the HTTP request.
152
+ SDK shutdown also cancels an active entitlement request and preserves a supplied HTTP client.
153
+
154
+ The Runtime uses this SDK method and cache for `/info`.
155
+ Configuration errors produce a non-retryable `misconfigured` result.
156
+ Retryable failures produce an `unavailable` result and an `unknown` compatibility license status.
157
+
158
+ ## Install and start
159
+
160
+ 1. From the repository root, install the package and an ASGI server:
161
+
162
+ ```sh
163
+ pip install ./packages/runtime-python
164
+ pip install uvicorn
165
+ ```
166
+
167
+ 2. Set `CPK_INTELLIGENCE_API_KEY`, `APP_AUTH_TOKEN`, and `APP_USER_ID` in your server environment.
168
+
169
+ This example binds one private application token to one application user.
170
+ `APP_AUTH_TOKEN` must differ from the Intelligence API key.
171
+
172
+ 3. Save this application as `app.py`:
173
+
174
+ ```python
175
+ import hmac
176
+ import os
177
+ from collections.abc import AsyncIterator
178
+ from typing import Any
179
+
180
+ from starlette.requests import Request
181
+
182
+ from copilotkit_runtime import IntelligenceRuntime, RuntimeConfig, User
183
+
184
+
185
+ class GreetingAgent:
186
+ description = "Returns a greeting"
187
+
188
+ async def run(self, input: dict[str, Any]) -> AsyncIterator[dict[str, Any]]:
189
+ yield {"type": "TEXT_MESSAGE_START", "messageId": "greeting", "role": "assistant"}
190
+ yield {"type": "TEXT_MESSAGE_CONTENT", "messageId": "greeting", "delta": "Hello"}
191
+ yield {"type": "TEXT_MESSAGE_END", "messageId": "greeting"}
192
+ yield {"type": "RUN_FINISHED"}
193
+
194
+
195
+ async def identify_user(request: Request) -> User | None:
196
+ expected = f"Bearer {os.environ['APP_AUTH_TOKEN']}".encode()
197
+ supplied = request.headers.get("authorization", "").encode()
198
+ if not hmac.compare_digest(supplied, expected):
199
+ return None
200
+ return User(id=os.environ["APP_USER_ID"], name="Application user")
201
+
202
+
203
+ app = IntelligenceRuntime(
204
+ RuntimeConfig(api_key=os.environ["CPK_INTELLIGENCE_API_KEY"]),
205
+ agents={"default": GreetingAgent()},
206
+ identify_user=identify_user,
207
+ )
208
+ ```
209
+
210
+ 4. Start the application:
211
+
212
+ ```sh
213
+ python -m uvicorn app:app --port 8000
214
+ ```
215
+
216
+ The runtime API is at `http://localhost:8000/copilotkit`.
217
+ `/copilotkit/info` describes the agents. The API also serves agent run/connect/stop routes, threads, memories, and annotations.
218
+ Authenticated requests use `Authorization: Bearer <APP_AUTH_TOKEN>` in this example.
219
+
220
+ ## Identify your application users
221
+
222
+ Replace the example token lookup with your application's session or token verification.
223
+ Return `User(id=..., name=...)` for the verified application user. Return `None` to deny access.
224
+ The callback can be synchronous or asynchronous.
225
+
226
+ The user ID identifies your application user, not an API-key owner or a control-plane user.
227
+ The runtime uses this identity for scoped platform requests. Stop requests recheck current ownership and use the platform's canonical thread ID.
228
+
229
+ Keep the Intelligence API key on the server. Do not accept a user ID from an unverified browser header.
230
+
231
+ ## Write an async agent
232
+
233
+ An agent has a `description` attribute and a `run(input)` method that returns an async iterator of AG-UI event dictionaries.
234
+ The runtime adds `RUN_STARTED` and stamps canonical thread and run IDs on each event.
235
+ Keep per-run mutable state inside `run`. Release open resources in `finally` blocks and allow cancellation to propagate.
236
+
237
+ Every agent must emit `RUN_FINISHED` or `RUN_ERROR`.
238
+ A missing terminal event produces `INCOMPLETE_STREAM`, including an HTTP stream that ends with EOF or `[DONE]`.
239
+ The runtime closes unfinished text and tool streams and adds missing tool results. An authorized stop ends with `RUN_FINISHED`.
240
+
241
+ For an HTTP AG-UI agent, replace `GreetingAgent()` with an `HttpAgent` instance:
242
+
243
+ ```python
244
+ from copilotkit_runtime import HttpAgent
245
+
246
+ agent = HttpAgent(
247
+ "http://localhost:8001/agent",
248
+ headers={"Authorization": "Bearer " + os.environ["AGENT_TOKEN"]},
249
+ timeout=120,
250
+ )
251
+ ```
252
+
253
+ `HttpAgent` uses server-owned headers. It does not forward browser authentication headers.
254
+
255
+ ## Configure the runtime and its lifecycle
256
+
257
+ `RuntimeConfig` contains the Intelligence endpoints, route prefix, CORS configuration, and transport limits:
258
+
259
+ ```python
260
+ config = RuntimeConfig(
261
+ api_key=os.environ["CPK_INTELLIGENCE_API_KEY"],
262
+ base_path="/copilotkit",
263
+ allowed_origins=("http://localhost:3000",),
264
+ request_timeout=30,
265
+ ack_timeout=10,
266
+ max_delivery_attempts=5,
267
+ lock_ttl_seconds=60,
268
+ lock_heartbeat_seconds=20,
269
+ shutdown_timeout=15,
270
+ )
271
+ ```
272
+
273
+ `api_url`, `runner_url`, and `client_url` select the HTTP API and the two WebSocket endpoints.
274
+ The defaults connect to the managed Intelligence service.
275
+
276
+ The runtime acquires a lock and joins the authenticated ingestion channel before it returns browser credentials.
277
+ Lock renewal starts before history loading and channel join. A lost lease cancels startup or agent work.
278
+
279
+ The producer queue holds at most 32 events. Negotiated batches contain at most 32 events.
280
+ Delivery retries preserve event IDs, sequences, and payloads. A permanent gateway rejection stops delivery.
281
+ The active batch must receive its ACK before normal lock cleanup.
282
+
283
+ The ASGI lifespan closes the runtime automatically. If your host manages lifespan separately, call `await app.aclose()` during shutdown.
284
+ Shutdown cancels pending startups and gives active runs `shutdown_timeout` seconds for cleanup. It then aborts their transports.
285
+ Application agents must cooperate with cancellation. An abrupt process exit can lose in-process events that lack an ACK.
286
+
287
+ ## Set memory and learning policies
288
+
289
+ Pass a trusted memory callback to `IntelligenceRuntime(memory_policy=...)`:
290
+
291
+ ```python
292
+ def memory_policy(user: User, request: Request) -> dict[str, str]:
293
+ return {"user": "read-write", "project": "read"}
294
+ ```
295
+
296
+ Each grant value is `none`, `read`, or `read-write`.
297
+ `None` or a grant with both values set to `none` denies access before a platform request.
298
+ The runtime rejects invalid grants and forwards valid server-owned grants to Intelligence.
299
+ Without a callback, Intelligence applies its default memory policy.
300
+
301
+ `learning_container(user, agent_id, input)` returns an optional Learning Container ID.
302
+ The runtime supplies that ID for thread creation and lock acquisition.
303
+ Both callbacks can return a value directly or through an awaitable.
304
+
305
+ ## Use MCP Apps and A2UI
306
+
307
+ Pass the UI configuration to the runtime constructor:
308
+
309
+ ```python
310
+ from copilotkit_runtime import A2UIConfig, MCPAppsConfig, MCPServer
311
+
312
+ app = IntelligenceRuntime(
313
+ RuntimeConfig(api_key=os.environ["CPK_INTELLIGENCE_API_KEY"]),
314
+ agents={"default": HttpAgent("http://localhost:8001/agent")},
315
+ identify_user=identify_user,
316
+ a2ui=A2UIConfig(
317
+ inject_tool=True,
318
+ agents=("default",),
319
+ default_catalog_id="https://example.com/my-catalog.json",
320
+ schema={"components": {"Text": {"required": ["text"]}}},
321
+ ),
322
+ mcp_apps=MCPAppsConfig(
323
+ servers=(
324
+ MCPServer(
325
+ url="https://example.com/mcp",
326
+ server_id="cards",
327
+ agent_id="default",
328
+ headers={"Authorization": "Bearer " + os.environ["MCP_SERVER_TOKEN"]},
329
+ ),
330
+ )
331
+ ),
332
+ )
333
+ ```
334
+
335
+ MCP Apps requires a Streamable HTTP server. The runtime uses the official Python MCP SDK and closes each session after its operation.
336
+ It discovers UI-enabled tools, adds their schemas to the agent input, and runs unresolved calls before `RUN_FINISHED`.
337
+ It publishes tool results and `mcp-apps` activity snapshots.
338
+
339
+ Browser reentry uses `forwardedProps.__proxiedMCPRequest` without another agent call.
340
+ The proxy permits configured servers and four methods: `tools/call`, `resources/read`, `notifications/message`, and `ping`.
341
+ Browser input cannot replace server authentication headers.
342
+
343
+ A2UI adds schema context and rendering tools. `inject_tool` accepts `True`, `False`, or a custom tool name.
344
+ `agents` limits A2UI to named agents. `enabled=False` disables it for every agent.
345
+ Action history comes from `forwardedProps.a2uiAction.userAction`.
346
+
347
+ A2UI validates complete component arrays before publication, then publishes cumulative data snapshots as array items arrive.
348
+ Validation covers IDs, component types, roots, catalog membership, required properties, references, and cycles.
349
+ The `schema` configuration describes A2UI components, not arbitrary JSON Schema validation.
350
+ Build, retry, error, and painted surface updates share one activity ID. The agent controls model retries.
351
+
352
+ ## Configure analytics and error reporting
353
+
354
+ Pass a telemetry instance to `IntelligenceRuntime(telemetry=...)`:
355
+
356
+ ```python
357
+ from copilotkit_runtime import Telemetry
358
+
359
+ telemetry = Telemetry(sample_rate=0.5, telemetry_id="my-application")
360
+ ```
361
+
362
+ Analytics use `https://telemetry.copilotkit.ai/ingest`. `Telemetry(url=...)` changes the endpoint.
363
+ `COPILOTKIT_TELEMETRY_URL` overrides the endpoint. The exporter does not follow redirects and has a three-second request deadline.
364
+
365
+ The default sample rate is `1`, so events are not sampled. `COPILOTKIT_TELEMETRY_SAMPLE_RATE` overrides `sample_rate`.
366
+ Rates must be finite and within `[0, 1]`.
367
+ Events include the sample rate, adjustment factor, weight, emitter, transport, and an integer Unix timestamp.
368
+ Analytics contain no prompts, user IDs, thread IDs, API keys, or raw errors.
369
+
370
+ `telemetry_id` supplies a standalone identity. `CPK_TELEMETRY_ID` supplies its fallback.
371
+ Identities accept 1–128 ASCII letters, digits, underscores, or hyphens, with optional spaces and tabs at each end.
372
+ The identity travels only in `X-CopilotKit-Telemetry-Id`. A standalone identity does not bypass sampling.
373
+
374
+ `Telemetry(license_token=...)` accepts a legacy analytics token. `COPILOTKIT_LICENSE_TOKEN` supplies the fallback for a blank configured token.
375
+ Without a standalone identity, a valid `telemetry_id` claim selects every event and sets `telemetry_identified` to true.
376
+ The exporter sends only the extracted identity. This claim does not verify a license signature or grant access.
377
+
378
+ `RuntimeConfig(telemetry_enabled=False)` disables default analytics. `Telemetry(enabled=False)` disables an explicit instance.
379
+ `DO_NOT_TRACK` or `COPILOTKIT_TELEMETRY_DISABLED` disables analytics with a value of `true` or `1`.
380
+ Opt-out takes precedence over license attribution.
381
+
382
+ The exporter holds at most 256 events and discards new events when the queue fills.
383
+ Requests do not wait for analytics delivery. `telemetry.stats` reports queue depth, sends, errors, discarded events, and sampling exclusions.
384
+ `await telemetry.flush()` waits at most three seconds. Runtime shutdown gives the exporter a separate bounded flush period.
385
+
386
+ `Telemetry(sink=async_callback)` supplies a custom sink with the same deadline and event contract.
387
+ `IntelligenceRuntime(on_error=async_callback)` supplies a separate application error handler.
388
+ The handler receives an exception and a fixed phase name. It has a three-second deadline, and its errors do not fail requests.
389
+ Both callbacks must support cancellation and must not block the event loop.
390
+
391
+ ## Develop in this repository
392
+
393
+ Run package checks from the repository root:
394
+
395
+ ```sh
396
+ NX_DAEMON=false pnpm nx run-many -t test,lint,typecheck,build -p runtime-python
397
+ ```
398
+
399
+ Run the shared integration cases:
400
+
401
+ ```sh
402
+ NX_DAEMON=false pnpm nx run runtime-conformance:conformance -- -- uv run --project packages/runtime-python python packages/runtime-python/examples/conformance.py
403
+ ```