snowflake-cortex-agent-sdk 0.0.2__tar.gz → 0.0.3__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.
- snowflake_cortex_agent_sdk-0.0.3/PKG-INFO +203 -0
- snowflake_cortex_agent_sdk-0.0.3/README.md +175 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/__init__.py +5 -1
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_base_client.py +64 -7
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_constants.py +5 -0
- snowflake_cortex_agent_sdk-0.0.3/cortex_agent_sdk/_partner_attribution.py +18 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_request_options.py +16 -1
- snowflake_cortex_agent_sdk-0.0.3/cortex_agent_sdk/_telemetry.py +24 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_transport.py +3 -2
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_version.py +1 -1
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/client.py +31 -5
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/conversation.py +217 -22
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/_internal/query.py +22 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/_internal/transport/subprocess_cli.py +10 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/client.py +28 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/types.py +11 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/resources/agent.py +62 -23
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/resources/coding_agent.py +17 -5
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/resources/feedback.py +17 -7
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/resources/runs.py +15 -7
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/resources/threads.py +52 -34
- snowflake_cortex_agent_sdk-0.0.3/cortex_agent_sdk/testing.py +98 -0
- snowflake_cortex_agent_sdk-0.0.3/cortex_agent_sdk/turn.py +192 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/views/async_run.py +20 -5
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/pyproject.toml +1 -1
- snowflake_cortex_agent_sdk-0.0.2/PKG-INFO +0 -118
- snowflake_cortex_agent_sdk-0.0.2/README.md +0 -90
- snowflake_cortex_agent_sdk-0.0.2/cortex_agent_sdk/turn.py +0 -85
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/.gitignore +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/LICENSE +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_generated/__init__.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_generated/agent_runs.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_generated/data_agent.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_generated/events.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_generated/lite_agent.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_generated/threads.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_resource.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_types.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/api.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/api_response.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/auth.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/constants.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/__init__.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/_errors.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/_internal/__init__.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/_internal/message_parser.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/_internal/transport/__init__.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/fork_session.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/py.typed +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/cortexcode/query.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/errors.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/models.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/origin.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/public_client.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/py.typed +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/resources/__init__.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/stream.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/streaming/__init__.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/streaming/parser.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/streaming/run_stream.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/threads_page.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/views/__init__.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/views/agent_response.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/views/content_view.py +0 -0
- {snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/views/thread_message.py +0 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: snowflake-cortex-agent-sdk
|
|
3
|
+
Version: 0.0.3
|
|
4
|
+
Summary: Python SDK for the Snowflake Cortex Agent REST API (agent:run streaming, threads, feedback)
|
|
5
|
+
Author-email: "Snowflake, Inc." <support@snowflake.com>
|
|
6
|
+
License: See LICENSE
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: cortex,cortex-agent,openapi,sdk,snowflake
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
11
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Requires-Dist: anyio>=4.0
|
|
14
|
+
Requires-Dist: httpx-sse>=0.4
|
|
15
|
+
Requires-Dist: httpx>=0.27
|
|
16
|
+
Requires-Dist: mcp<2,>=1.0
|
|
17
|
+
Requires-Dist: pydantic>=2.0
|
|
18
|
+
Requires-Dist: snowflake-connector-python[secure-local-storage]<5,>=4.7.1
|
|
19
|
+
Requires-Dist: typing-extensions>=4.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: datamodel-code-generator>=0.28; extra == 'dev'
|
|
22
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.20.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-timeout>=2.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# Snowflake Cortex Agent SDK for Python
|
|
30
|
+
|
|
31
|
+
Python SDK for the Snowflake Cortex Agent REST API. Covers the current public surface:
|
|
32
|
+
|
|
33
|
+
- Durable lite, data-agent, and coding-agent conversations
|
|
34
|
+
- Named + versioned data agents through the direct API client
|
|
35
|
+
- Coding-agent runs with sandbox, bash, skills, and workspace mounts
|
|
36
|
+
- Threads, background runs, streaming, and feedback through `cortex_agent_sdk.api`
|
|
37
|
+
- High-level `Conversation.send()` -> `Turn` abstraction
|
|
38
|
+
- Route-test helpers in `cortex_agent_sdk.testing` (see `docs/13-testing.md`)
|
|
39
|
+
- Curated `AgentResponse` content and usage view
|
|
40
|
+
- Synchronous and asyncio clients
|
|
41
|
+
- Claude-shaped local Cortex Code sessions via `cortex_agent_sdk.cortexcode`
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
[View `snowflake-cortex-agent-sdk` on PyPI](https://pypi.org/project/snowflake-cortex-agent-sdk/).
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install snowflake-cortex-agent-sdk
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Requires Python 3.10 or newer.
|
|
52
|
+
|
|
53
|
+
## Quickstart
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import os
|
|
57
|
+
from cortex_agent_sdk import (
|
|
58
|
+
AgentResponse,
|
|
59
|
+
Conversation,
|
|
60
|
+
ConversationMessage,
|
|
61
|
+
CortexAgentClient,
|
|
62
|
+
Turn,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
client: CortexAgentClient = CortexAgentClient(
|
|
66
|
+
account="my_account",
|
|
67
|
+
auth=os.environ["SNOWFLAKE_PAT"],
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
conversation: Conversation = client.conversations.create(
|
|
71
|
+
origin_application="cortex_agent_sdk",
|
|
72
|
+
agent={"type": "inline", "spec": {"models": {"orchestration": "claude-sonnet-4-5"}}},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
turn: Turn = conversation.send("What is Snowflake Arctic?")
|
|
76
|
+
print(f"run: {turn.id}")
|
|
77
|
+
|
|
78
|
+
answer: AgentResponse = turn.result()
|
|
79
|
+
print(answer.text)
|
|
80
|
+
|
|
81
|
+
history: list[ConversationMessage] = conversation.history()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Set a default agent when creating a conversation. A send can override it for one
|
|
85
|
+
turn when needed:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
inline_turn: Turn = conversation.send(
|
|
89
|
+
"Summarize the context.",
|
|
90
|
+
agent={"type": "inline", "spec": {"models": {"orchestration": "auto"}}},
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
data_turn: Turn = conversation.send(
|
|
94
|
+
"Which products grew fastest?",
|
|
95
|
+
agent={
|
|
96
|
+
"type": "data",
|
|
97
|
+
"spec": {"database": "ANALYTICS", "schema": "PUBLIC", "name": "SALES_AGENT"},
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
coding_turn: Turn = conversation.send(
|
|
102
|
+
"Fix the failing test.",
|
|
103
|
+
agent={
|
|
104
|
+
"type": "coding",
|
|
105
|
+
"spec": {
|
|
106
|
+
"models": {"orchestration": "claude-sonnet-4-5"},
|
|
107
|
+
"permission_policy": "always_allow",
|
|
108
|
+
"workspace_mounts": [{"name": "USER$MY_USER.PUBLIC.DEFAULT$"}],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use `turn.events()` for event-level progress and `turn.cancel()` to stop a run.
|
|
115
|
+
|
|
116
|
+
## Async
|
|
117
|
+
|
|
118
|
+
The asynchronous API mirrors the sync API:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from cortex_agent_sdk import AgentResponse, AsyncConversation, AsyncCortexAgentClient, AsyncTurn
|
|
122
|
+
|
|
123
|
+
async with AsyncCortexAgentClient(account="my_account", auth="<token>") as client:
|
|
124
|
+
conversation: AsyncConversation = await client.conversations.create(
|
|
125
|
+
origin_application="cortex_agent_sdk",
|
|
126
|
+
agent={"type": "inline", "spec": {"models": {"orchestration": "auto"}}},
|
|
127
|
+
)
|
|
128
|
+
turn: AsyncTurn = await conversation.send("Analyze this data.")
|
|
129
|
+
answer: AgentResponse = await turn.result()
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Cortex Code sessions (`cortex_agent_sdk.cortexcode`)
|
|
133
|
+
|
|
134
|
+
`cortex_agent_sdk.cortexcode` is the Cortex Code SDK for driving the local
|
|
135
|
+
`cortex` binary from Python. It exposes one-shot `query()` calls and long-lived
|
|
136
|
+
`CortexCodeSDKClient` sessions with permissions, hooks, MCP, plugins, structured
|
|
137
|
+
output, and session controls.
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
import asyncio
|
|
141
|
+
from cortex_agent_sdk.cortexcode import AssistantMessage, ResultMessage, query
|
|
142
|
+
|
|
143
|
+
async def main() -> None:
|
|
144
|
+
async for message in query(prompt="Summarize this repository"):
|
|
145
|
+
if isinstance(message, AssistantMessage):
|
|
146
|
+
for block in message.content:
|
|
147
|
+
if hasattr(block, "text"):
|
|
148
|
+
print(block.text, end="")
|
|
149
|
+
elif isinstance(message, ResultMessage):
|
|
150
|
+
print(f"\nDone: {message.subtype}")
|
|
151
|
+
|
|
152
|
+
asyncio.run(main())
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
This entry point runs the local Cortex Code CLI. For server-side integrations,
|
|
156
|
+
use the package-root `CortexAgentClient` with a coding-agent conversation
|
|
157
|
+
instead.
|
|
158
|
+
|
|
159
|
+
## Resources at a glance
|
|
160
|
+
|
|
161
|
+
| Resource | Purpose |
|
|
162
|
+
| --- | --- |
|
|
163
|
+
| `client.conversations` | Create, attach, list, and search conversations |
|
|
164
|
+
| `client.feedback` | Send feedback for a data-agent turn |
|
|
165
|
+
|
|
166
|
+
`Conversation` binds a thread to an inline, data, or coding agent and hides
|
|
167
|
+
message and run plumbing. `send()` returns a `Turn` with `id`, `result()`,
|
|
168
|
+
`events()`, and `cancel()`.
|
|
169
|
+
|
|
170
|
+
For direct REST request shapes, streaming modes, raw response wrappers, or SSE
|
|
171
|
+
parsing, import `CortexAgentClient` and related types from
|
|
172
|
+
`cortex_agent_sdk.api`.
|
|
173
|
+
|
|
174
|
+
Separate entry point, not a `client.*` resource:
|
|
175
|
+
|
|
176
|
+
| Entry point | Purpose |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| `cortex_agent_sdk.cortexcode` | Python SDK for the local Cortex Code CLI: permissions, hooks, MCP, plugins, and session controls |
|
|
179
|
+
|
|
180
|
+
## Auth at a glance
|
|
181
|
+
|
|
182
|
+
Authentication headers are rebuilt for every attempt. `refresh_auth` runs only
|
|
183
|
+
for recognized token/session expiry responses, including legacy `200` JSON error
|
|
184
|
+
envelopes; by default the SDK refreshes once
|
|
185
|
+
and replays the request once. SDK-generated errors do not include credential
|
|
186
|
+
values.
|
|
187
|
+
|
|
188
|
+
| Class | For | Header shape |
|
|
189
|
+
| --- | --- | --- |
|
|
190
|
+
| `PatAuth` (or string shorthand) | Programmatic Access Token | `Authorization: Bearer <token>` + `X-Snowflake-Authorization-Token-Type: PROGRAMMATIC_ACCESS_TOKEN` |
|
|
191
|
+
| `OAuthAuth` | External OAuth / Snowflake OAuth access tokens | `Authorization: Bearer <token>` + `X-Snowflake-Authorization-Token-Type: OAUTH` |
|
|
192
|
+
| `KeyPairJwtAuth` | Key-pair JWT auth | `Authorization: Bearer <token>` + `X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT` |
|
|
193
|
+
| `SnowflakeSessionTokenAuth` | `snowflake-connector-python` session tokens | `Authorization: Snowflake Token="<token>"` |
|
|
194
|
+
| `CallableAuth` | Lazy token minting | Bearer + configurable token-type header |
|
|
195
|
+
| Custom `Authenticator` | Anything else | You return the header map |
|
|
196
|
+
|
|
197
|
+
## Status
|
|
198
|
+
|
|
199
|
+
Preview. Expect breaking changes as the underlying API stabilizes.
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
See `LICENSE`. Use is governed by your Snowflake customer agreement.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Snowflake Cortex Agent SDK for Python
|
|
2
|
+
|
|
3
|
+
Python SDK for the Snowflake Cortex Agent REST API. Covers the current public surface:
|
|
4
|
+
|
|
5
|
+
- Durable lite, data-agent, and coding-agent conversations
|
|
6
|
+
- Named + versioned data agents through the direct API client
|
|
7
|
+
- Coding-agent runs with sandbox, bash, skills, and workspace mounts
|
|
8
|
+
- Threads, background runs, streaming, and feedback through `cortex_agent_sdk.api`
|
|
9
|
+
- High-level `Conversation.send()` -> `Turn` abstraction
|
|
10
|
+
- Route-test helpers in `cortex_agent_sdk.testing` (see `docs/13-testing.md`)
|
|
11
|
+
- Curated `AgentResponse` content and usage view
|
|
12
|
+
- Synchronous and asyncio clients
|
|
13
|
+
- Claude-shaped local Cortex Code sessions via `cortex_agent_sdk.cortexcode`
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
[View `snowflake-cortex-agent-sdk` on PyPI](https://pypi.org/project/snowflake-cortex-agent-sdk/).
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install snowflake-cortex-agent-sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Requires Python 3.10 or newer.
|
|
24
|
+
|
|
25
|
+
## Quickstart
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
import os
|
|
29
|
+
from cortex_agent_sdk import (
|
|
30
|
+
AgentResponse,
|
|
31
|
+
Conversation,
|
|
32
|
+
ConversationMessage,
|
|
33
|
+
CortexAgentClient,
|
|
34
|
+
Turn,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
client: CortexAgentClient = CortexAgentClient(
|
|
38
|
+
account="my_account",
|
|
39
|
+
auth=os.environ["SNOWFLAKE_PAT"],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
conversation: Conversation = client.conversations.create(
|
|
43
|
+
origin_application="cortex_agent_sdk",
|
|
44
|
+
agent={"type": "inline", "spec": {"models": {"orchestration": "claude-sonnet-4-5"}}},
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
turn: Turn = conversation.send("What is Snowflake Arctic?")
|
|
48
|
+
print(f"run: {turn.id}")
|
|
49
|
+
|
|
50
|
+
answer: AgentResponse = turn.result()
|
|
51
|
+
print(answer.text)
|
|
52
|
+
|
|
53
|
+
history: list[ConversationMessage] = conversation.history()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Set a default agent when creating a conversation. A send can override it for one
|
|
57
|
+
turn when needed:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
inline_turn: Turn = conversation.send(
|
|
61
|
+
"Summarize the context.",
|
|
62
|
+
agent={"type": "inline", "spec": {"models": {"orchestration": "auto"}}},
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
data_turn: Turn = conversation.send(
|
|
66
|
+
"Which products grew fastest?",
|
|
67
|
+
agent={
|
|
68
|
+
"type": "data",
|
|
69
|
+
"spec": {"database": "ANALYTICS", "schema": "PUBLIC", "name": "SALES_AGENT"},
|
|
70
|
+
},
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
coding_turn: Turn = conversation.send(
|
|
74
|
+
"Fix the failing test.",
|
|
75
|
+
agent={
|
|
76
|
+
"type": "coding",
|
|
77
|
+
"spec": {
|
|
78
|
+
"models": {"orchestration": "claude-sonnet-4-5"},
|
|
79
|
+
"permission_policy": "always_allow",
|
|
80
|
+
"workspace_mounts": [{"name": "USER$MY_USER.PUBLIC.DEFAULT$"}],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Use `turn.events()` for event-level progress and `turn.cancel()` to stop a run.
|
|
87
|
+
|
|
88
|
+
## Async
|
|
89
|
+
|
|
90
|
+
The asynchronous API mirrors the sync API:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from cortex_agent_sdk import AgentResponse, AsyncConversation, AsyncCortexAgentClient, AsyncTurn
|
|
94
|
+
|
|
95
|
+
async with AsyncCortexAgentClient(account="my_account", auth="<token>") as client:
|
|
96
|
+
conversation: AsyncConversation = await client.conversations.create(
|
|
97
|
+
origin_application="cortex_agent_sdk",
|
|
98
|
+
agent={"type": "inline", "spec": {"models": {"orchestration": "auto"}}},
|
|
99
|
+
)
|
|
100
|
+
turn: AsyncTurn = await conversation.send("Analyze this data.")
|
|
101
|
+
answer: AgentResponse = await turn.result()
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Cortex Code sessions (`cortex_agent_sdk.cortexcode`)
|
|
105
|
+
|
|
106
|
+
`cortex_agent_sdk.cortexcode` is the Cortex Code SDK for driving the local
|
|
107
|
+
`cortex` binary from Python. It exposes one-shot `query()` calls and long-lived
|
|
108
|
+
`CortexCodeSDKClient` sessions with permissions, hooks, MCP, plugins, structured
|
|
109
|
+
output, and session controls.
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
import asyncio
|
|
113
|
+
from cortex_agent_sdk.cortexcode import AssistantMessage, ResultMessage, query
|
|
114
|
+
|
|
115
|
+
async def main() -> None:
|
|
116
|
+
async for message in query(prompt="Summarize this repository"):
|
|
117
|
+
if isinstance(message, AssistantMessage):
|
|
118
|
+
for block in message.content:
|
|
119
|
+
if hasattr(block, "text"):
|
|
120
|
+
print(block.text, end="")
|
|
121
|
+
elif isinstance(message, ResultMessage):
|
|
122
|
+
print(f"\nDone: {message.subtype}")
|
|
123
|
+
|
|
124
|
+
asyncio.run(main())
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This entry point runs the local Cortex Code CLI. For server-side integrations,
|
|
128
|
+
use the package-root `CortexAgentClient` with a coding-agent conversation
|
|
129
|
+
instead.
|
|
130
|
+
|
|
131
|
+
## Resources at a glance
|
|
132
|
+
|
|
133
|
+
| Resource | Purpose |
|
|
134
|
+
| --- | --- |
|
|
135
|
+
| `client.conversations` | Create, attach, list, and search conversations |
|
|
136
|
+
| `client.feedback` | Send feedback for a data-agent turn |
|
|
137
|
+
|
|
138
|
+
`Conversation` binds a thread to an inline, data, or coding agent and hides
|
|
139
|
+
message and run plumbing. `send()` returns a `Turn` with `id`, `result()`,
|
|
140
|
+
`events()`, and `cancel()`.
|
|
141
|
+
|
|
142
|
+
For direct REST request shapes, streaming modes, raw response wrappers, or SSE
|
|
143
|
+
parsing, import `CortexAgentClient` and related types from
|
|
144
|
+
`cortex_agent_sdk.api`.
|
|
145
|
+
|
|
146
|
+
Separate entry point, not a `client.*` resource:
|
|
147
|
+
|
|
148
|
+
| Entry point | Purpose |
|
|
149
|
+
| --- | --- |
|
|
150
|
+
| `cortex_agent_sdk.cortexcode` | Python SDK for the local Cortex Code CLI: permissions, hooks, MCP, plugins, and session controls |
|
|
151
|
+
|
|
152
|
+
## Auth at a glance
|
|
153
|
+
|
|
154
|
+
Authentication headers are rebuilt for every attempt. `refresh_auth` runs only
|
|
155
|
+
for recognized token/session expiry responses, including legacy `200` JSON error
|
|
156
|
+
envelopes; by default the SDK refreshes once
|
|
157
|
+
and replays the request once. SDK-generated errors do not include credential
|
|
158
|
+
values.
|
|
159
|
+
|
|
160
|
+
| Class | For | Header shape |
|
|
161
|
+
| --- | --- | --- |
|
|
162
|
+
| `PatAuth` (or string shorthand) | Programmatic Access Token | `Authorization: Bearer <token>` + `X-Snowflake-Authorization-Token-Type: PROGRAMMATIC_ACCESS_TOKEN` |
|
|
163
|
+
| `OAuthAuth` | External OAuth / Snowflake OAuth access tokens | `Authorization: Bearer <token>` + `X-Snowflake-Authorization-Token-Type: OAUTH` |
|
|
164
|
+
| `KeyPairJwtAuth` | Key-pair JWT auth | `Authorization: Bearer <token>` + `X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT` |
|
|
165
|
+
| `SnowflakeSessionTokenAuth` | `snowflake-connector-python` session tokens | `Authorization: Snowflake Token="<token>"` |
|
|
166
|
+
| `CallableAuth` | Lazy token minting | Bearer + configurable token-type header |
|
|
167
|
+
| Custom `Authenticator` | Anything else | You return the header map |
|
|
168
|
+
|
|
169
|
+
## Status
|
|
170
|
+
|
|
171
|
+
Preview. Expect breaking changes as the underlying API stabilizes.
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
See `LICENSE`. Use is governed by your Snowflake customer agreement.
|
{snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/__init__.py
RENAMED
|
@@ -55,6 +55,7 @@ from .conversation import (
|
|
|
55
55
|
ConversationMessage,
|
|
56
56
|
DataAgentSpec,
|
|
57
57
|
InlineAgentSpec,
|
|
58
|
+
PermissionDecision,
|
|
58
59
|
)
|
|
59
60
|
from .errors import (
|
|
60
61
|
APIConnectionAbortedError,
|
|
@@ -74,7 +75,7 @@ from .errors import (
|
|
|
74
75
|
UnprocessableEntityError,
|
|
75
76
|
)
|
|
76
77
|
from .public_client import AsyncCortexAgentClient, CortexAgentClient
|
|
77
|
-
from .turn import AsyncTurn, Turn
|
|
78
|
+
from .turn import AsyncTurn, ClientToolUse, PermissionRequest, Turn
|
|
78
79
|
from .views.agent_response import AgentResponseView as AgentResponse
|
|
79
80
|
|
|
80
81
|
__all__ = [
|
|
@@ -89,6 +90,7 @@ __all__ = [
|
|
|
89
90
|
"ConversationInput",
|
|
90
91
|
"ConversationMessage",
|
|
91
92
|
"CodingAgentSpec",
|
|
93
|
+
"ClientToolUse",
|
|
92
94
|
"DataAgentSpec",
|
|
93
95
|
"InlineAgentSpec",
|
|
94
96
|
"CortexAgentClient",
|
|
@@ -101,6 +103,8 @@ __all__ = [
|
|
|
101
103
|
"KeyPairJwtAuth",
|
|
102
104
|
"OAuthAuth",
|
|
103
105
|
"PatAuth",
|
|
106
|
+
"PermissionRequest",
|
|
107
|
+
"PermissionDecision",
|
|
104
108
|
"SnowflakeSessionTokenAuth",
|
|
105
109
|
"SnowflakeTokenAuth",
|
|
106
110
|
"SnowflakeTokenType",
|
|
@@ -24,6 +24,7 @@ import platform
|
|
|
24
24
|
import random
|
|
25
25
|
import time
|
|
26
26
|
from collections.abc import Mapping
|
|
27
|
+
from dataclasses import replace
|
|
27
28
|
from typing import Any
|
|
28
29
|
from urllib.parse import urlparse
|
|
29
30
|
|
|
@@ -31,6 +32,7 @@ import httpx
|
|
|
31
32
|
|
|
32
33
|
from ._constants import (
|
|
33
34
|
DEFAULT_MAX_RETRIES,
|
|
35
|
+
DEFAULT_STREAM_READ_TIMEOUT,
|
|
34
36
|
DEFAULT_TIMEOUT,
|
|
35
37
|
INITIAL_RETRY_DELAY,
|
|
36
38
|
MAX_RETRY_AFTER_DELAY,
|
|
@@ -39,7 +41,9 @@ from ._constants import (
|
|
|
39
41
|
RETRY_STATUSES,
|
|
40
42
|
SHOULD_RETRY_HEADER,
|
|
41
43
|
)
|
|
44
|
+
from ._partner_attribution import validate_partner_application
|
|
42
45
|
from ._request_options import RequestOptions, RequestOptionsLike, normalize_options
|
|
46
|
+
from ._telemetry import SDK_OPERATION_HEADER, identity_headers
|
|
43
47
|
from ._transport import (
|
|
44
48
|
AuthRefreshContext,
|
|
45
49
|
RetryPolicy,
|
|
@@ -47,7 +51,7 @@ from ._transport import (
|
|
|
47
51
|
is_transport_retry_safe_by_default,
|
|
48
52
|
merge_retry_policies,
|
|
49
53
|
)
|
|
50
|
-
from ._types import NotGiven, Omit, given_or
|
|
54
|
+
from ._types import NotGiven, Omit, given_or, is_given, not_given
|
|
51
55
|
from ._version import __version__
|
|
52
56
|
from .api_response import APIResponse
|
|
53
57
|
from .auth import Authenticator, coerce_authenticator
|
|
@@ -78,11 +82,14 @@ class BaseClient:
|
|
|
78
82
|
base_url: str | None,
|
|
79
83
|
auth: str | Authenticator | Any,
|
|
80
84
|
timeout: float | httpx.Timeout | None | NotGiven,
|
|
85
|
+
stream_read_timeout: float | None | NotGiven = not_given,
|
|
81
86
|
retry_policy: RetryPolicy | None,
|
|
82
87
|
refresh_auth: Any,
|
|
83
88
|
auth_refresh_max_retries: int,
|
|
84
89
|
default_headers: Mapping[str, str] | None,
|
|
85
90
|
default_query: Mapping[str, Any] | None,
|
|
91
|
+
partner_application: str | None = None,
|
|
92
|
+
sdk_surface: str = "agent",
|
|
86
93
|
) -> None:
|
|
87
94
|
if base_url is None and account is None:
|
|
88
95
|
raise CortexAgentError("Either `account` or `base_url` is required.")
|
|
@@ -102,7 +109,37 @@ class BaseClient:
|
|
|
102
109
|
self.refresh_auth = refresh_auth
|
|
103
110
|
self.auth_refresh_max_retries = auth_refresh_max_retries
|
|
104
111
|
self.timeout: float | httpx.Timeout | None = given_or(timeout, DEFAULT_TIMEOUT)
|
|
105
|
-
|
|
112
|
+
# ``None`` disables the gap timeout. Omitted uses the 10-minute default.
|
|
113
|
+
self.stream_read_timeout: float | None = given_or(
|
|
114
|
+
stream_read_timeout, DEFAULT_STREAM_READ_TIMEOUT
|
|
115
|
+
)
|
|
116
|
+
identity = identity_headers(surface=sdk_surface)
|
|
117
|
+
application = validate_partner_application(partner_application)
|
|
118
|
+
configured_user_agent = next(
|
|
119
|
+
(
|
|
120
|
+
value
|
|
121
|
+
for name, value in (default_headers or {}).items()
|
|
122
|
+
if name.lower() == "user-agent"
|
|
123
|
+
),
|
|
124
|
+
None,
|
|
125
|
+
)
|
|
126
|
+
if (
|
|
127
|
+
application is not None
|
|
128
|
+
and configured_user_agent is not None
|
|
129
|
+
and configured_user_agent != application
|
|
130
|
+
):
|
|
131
|
+
raise CortexAgentError(
|
|
132
|
+
"Configure partner attribution with `partner_application`, not a "
|
|
133
|
+
"conflicting `default_headers['User-Agent']`."
|
|
134
|
+
)
|
|
135
|
+
attribution_headers = {"User-Agent": application} if application else {}
|
|
136
|
+
self.partner_application = application
|
|
137
|
+
self.sdk_surface = sdk_surface
|
|
138
|
+
self.default_headers: dict[str, str] = {
|
|
139
|
+
**identity,
|
|
140
|
+
**attribution_headers,
|
|
141
|
+
**dict(default_headers or {}),
|
|
142
|
+
}
|
|
106
143
|
self.default_query: dict[str, Any] = dict(default_query or {})
|
|
107
144
|
# Kept for copy()/with_options(), which must reproduce the original args.
|
|
108
145
|
self._account = account
|
|
@@ -146,6 +183,8 @@ class BaseClient:
|
|
|
146
183
|
headers.update(opts.headers)
|
|
147
184
|
if opts.extra_headers:
|
|
148
185
|
headers.update(opts.extra_headers)
|
|
186
|
+
if is_given(opts.sdk_operation):
|
|
187
|
+
headers[SDK_OPERATION_HEADER] = str(opts.sdk_operation)
|
|
149
188
|
if has_body:
|
|
150
189
|
headers.setdefault("Content-Type", "application/json")
|
|
151
190
|
# `omit` removes a header the SDK would otherwise send.
|
|
@@ -178,13 +217,14 @@ class BaseClient:
|
|
|
178
217
|
base = given_or(opts.timeout, self.timeout)
|
|
179
218
|
if not stream:
|
|
180
219
|
return base
|
|
181
|
-
# A long-running SSE response legitimately has long gaps between chunks
|
|
182
|
-
#
|
|
220
|
+
# A long-running SSE response legitimately has long gaps between chunks.
|
|
221
|
+
# `read` uses the client default (10 minutes) unless this request sets
|
|
222
|
+
# `stream_read_timeout`. Explicit ``None`` waits indefinitely.
|
|
183
223
|
connect = base.connect if isinstance(base, httpx.Timeout) else base
|
|
184
224
|
return httpx.Timeout(
|
|
185
225
|
None,
|
|
186
226
|
connect=connect,
|
|
187
|
-
read=given_or(opts.stream_read_timeout,
|
|
227
|
+
read=given_or(opts.stream_read_timeout, self.stream_read_timeout),
|
|
188
228
|
write=connect,
|
|
189
229
|
)
|
|
190
230
|
|
|
@@ -287,7 +327,11 @@ class BaseClient:
|
|
|
287
327
|
) -> AuthRefreshContext | None:
|
|
288
328
|
if self.refresh_auth is None or attempt > self.auth_refresh_max_retries:
|
|
289
329
|
return None
|
|
290
|
-
|
|
330
|
+
# A successful SSE response is a live stream; only a non-SSE 200 can
|
|
331
|
+
# be the legacy JSON expired-session envelope.
|
|
332
|
+
if stream and response.status_code == 200 and _is_sse_response(response):
|
|
333
|
+
return None
|
|
334
|
+
if response.status_code not in {200, 401, 403}:
|
|
291
335
|
return None
|
|
292
336
|
response_body = self._read_response_body(response)
|
|
293
337
|
if not is_auth_expired_response(response.status_code, response_body):
|
|
@@ -313,7 +357,11 @@ class BaseClient:
|
|
|
313
357
|
) -> AuthRefreshContext | None:
|
|
314
358
|
if self.refresh_auth is None or attempt > self.auth_refresh_max_retries:
|
|
315
359
|
return None
|
|
316
|
-
|
|
360
|
+
# A successful SSE response is a live stream; only a non-SSE 200 can
|
|
361
|
+
# be the legacy JSON expired-session envelope.
|
|
362
|
+
if stream and response.status_code == 200 and _is_sse_response(response):
|
|
363
|
+
return None
|
|
364
|
+
if response.status_code not in {200, 401, 403}:
|
|
317
365
|
return None
|
|
318
366
|
response_body = await self._aread_response_body(response)
|
|
319
367
|
if not is_auth_expired_response(response.status_code, response_body):
|
|
@@ -362,6 +410,8 @@ class BaseClient:
|
|
|
362
410
|
) -> tuple[RequestOptions, dict[str, Any], _ResolvedRetryPolicy, Any, Any]:
|
|
363
411
|
"""Resolve options once, before the retry loop."""
|
|
364
412
|
opts = normalize_options(options)
|
|
413
|
+
if not is_given(opts.sdk_operation):
|
|
414
|
+
opts = replace(opts, sdk_operation="client.request")
|
|
365
415
|
return (
|
|
366
416
|
opts,
|
|
367
417
|
self._build_query(params, opts),
|
|
@@ -400,11 +450,14 @@ class BaseClient:
|
|
|
400
450
|
"base_url": self.base_url,
|
|
401
451
|
"auth": self.auth,
|
|
402
452
|
"timeout": self.timeout,
|
|
453
|
+
"stream_read_timeout": self.stream_read_timeout,
|
|
403
454
|
"retry_policy": self.retry_policy,
|
|
404
455
|
"refresh_auth": self.refresh_auth,
|
|
405
456
|
"auth_refresh_max_retries": self.auth_refresh_max_retries,
|
|
406
457
|
"default_headers": self.default_headers,
|
|
407
458
|
"default_query": self.default_query,
|
|
459
|
+
"partner_application": self.partner_application,
|
|
460
|
+
"sdk_surface": self.sdk_surface,
|
|
408
461
|
}
|
|
409
462
|
|
|
410
463
|
|
|
@@ -742,6 +795,10 @@ def _is_local_host(hostname: str | None) -> bool:
|
|
|
742
795
|
return hostname in _LOCAL_HOSTS or (hostname is not None and hostname.endswith(".local"))
|
|
743
796
|
|
|
744
797
|
|
|
798
|
+
def _is_sse_response(response: httpx.Response) -> bool:
|
|
799
|
+
return "text/event-stream" in response.headers.get("content-type", "").lower()
|
|
800
|
+
|
|
801
|
+
|
|
745
802
|
def _validate_base_url(base_url: str) -> str:
|
|
746
803
|
"""Reject a base URL that would put the credential on the wire in clear text.
|
|
747
804
|
|
{snowflake_cortex_agent_sdk-0.0.2 → snowflake_cortex_agent_sdk-0.0.3}/cortex_agent_sdk/_constants.py
RENAMED
|
@@ -16,6 +16,11 @@ import httpx
|
|
|
16
16
|
#: ``APITimeoutError``s; a short *connect* timeout still fails fast on a bad host.
|
|
17
17
|
DEFAULT_TIMEOUT: Final = httpx.Timeout(600.0, connect=5.0)
|
|
18
18
|
|
|
19
|
+
#: Max gap between SSE chunks before a stream fails. Matches the 10-minute
|
|
20
|
+
#: total timeout: long enough for a quiet tool call, short enough that a dead
|
|
21
|
+
#: socket does not wait forever. Pass ``stream_read_timeout=None`` to disable.
|
|
22
|
+
DEFAULT_STREAM_READ_TIMEOUT: Final = 600.0
|
|
23
|
+
|
|
19
24
|
DEFAULT_MAX_RETRIES: Final = 2
|
|
20
25
|
|
|
21
26
|
#: First retry delay, doubled per attempt up to :data:`MAX_RETRY_DELAY`.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Partner attribution helpers for REST requests."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .errors import CortexAgentError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def validate_partner_application(value: str | None) -> str | None:
|
|
9
|
+
if value is None:
|
|
10
|
+
return None
|
|
11
|
+
if not value:
|
|
12
|
+
raise CortexAgentError("`partner_application` must not be empty.")
|
|
13
|
+
if "\r" in value or "\n" in value:
|
|
14
|
+
raise CortexAgentError("`partner_application` must not contain CR or LF characters.")
|
|
15
|
+
return value
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
__all__ = ["validate_partner_application"]
|
|
@@ -72,6 +72,9 @@ class RequestOptions:
|
|
|
72
72
|
#: next event boundary. The async client uses task cancellation instead.
|
|
73
73
|
cancel: threading.Event | None | NotGiven = field(default=not_given, repr=False)
|
|
74
74
|
|
|
75
|
+
#: Internal stable, low-cardinality public SDK operation name.
|
|
76
|
+
sdk_operation: str | NotGiven = field(default=not_given, repr=False)
|
|
77
|
+
|
|
75
78
|
def merge(self, other: RequestOptions | None) -> RequestOptions:
|
|
76
79
|
"""A copy with every *given* field of ``other`` layered on top."""
|
|
77
80
|
if other is None:
|
|
@@ -155,4 +158,16 @@ def with_overrides(
|
|
|
155
158
|
return replace(base, **overrides) if overrides else base
|
|
156
159
|
|
|
157
160
|
|
|
158
|
-
|
|
161
|
+
def with_sdk_operation(options: RequestOptionsLike, operation: str) -> RequestOptions:
|
|
162
|
+
"""Set the semantic operation unless an outer SDK wrapper already set it."""
|
|
163
|
+
base = normalize_options(options)
|
|
164
|
+
return base if is_given(base.sdk_operation) else replace(base, sdk_operation=operation)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
__all__ = [
|
|
168
|
+
"RequestOptions",
|
|
169
|
+
"RequestOptionsLike",
|
|
170
|
+
"normalize_options",
|
|
171
|
+
"with_overrides",
|
|
172
|
+
"with_sdk_operation",
|
|
173
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Bounded request metadata used for SDK telemetry."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from ._version import __version__
|
|
6
|
+
|
|
7
|
+
SDK_OPERATION_HEADER = "x-cortex-agent-sdk-operation"
|
|
8
|
+
SDK_SURFACE_HEADER = "x-cortex-agent-sdk-surface"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def identity_headers(*, surface: str = "agent") -> dict[str, str]:
|
|
12
|
+
return {
|
|
13
|
+
"User-Agent": f"cortex-agent-sdk-python/{__version__}",
|
|
14
|
+
"x-cortex-agent-sdk-lang": "python",
|
|
15
|
+
"x-cortex-agent-sdk-version": __version__,
|
|
16
|
+
SDK_SURFACE_HEADER: surface,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"SDK_OPERATION_HEADER",
|
|
22
|
+
"SDK_SURFACE_HEADER",
|
|
23
|
+
"identity_headers",
|
|
24
|
+
]
|