tars-sdk 0.1.1__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.
tars_sdk/__init__.py ADDED
@@ -0,0 +1,219 @@
1
+ """tars-sdk — the Python client for TARS.
2
+
3
+ from tars_sdk import TarsClient, TextDeltaEvent
4
+
5
+ async with TarsClient(api_key="tars_sk_…", base_url="https://your-tars-host") as tars:
6
+ agent = await tars.agents.create(name="assistant", system="You are helpful.")
7
+ session = await tars.sessions.create(agent_id=agent.id)
8
+ async for ev in session.send("Hello!"):
9
+ if isinstance(ev, TextDeltaEvent):
10
+ print(ev.text, end="")
11
+ """
12
+
13
+ from importlib.metadata import PackageNotFoundError, version as _version
14
+
15
+ from ._wire import UNSET
16
+ from .client import (
17
+ DEFAULT_BASE_URL,
18
+ KEYED_PROVIDERS,
19
+ AdminClient,
20
+ AgentsClient,
21
+ ApiKeysClient,
22
+ CompletionsClient,
23
+ FilesClient,
24
+ McpClient,
25
+ McpCredentialsClient,
26
+ SessionsClient,
27
+ SkillsClient,
28
+ TarsClient,
29
+ UsageClient,
30
+ )
31
+ from .errors import TarsApiError
32
+ from .events import (
33
+ AGENT_ERROR_CODES,
34
+ SESSION_EVENT_TYPES,
35
+ CompactionEvent,
36
+ ConnectRequiredEvent,
37
+ ErrorEvent,
38
+ McpConnectEvent,
39
+ MessageAttachment,
40
+ OutputFileEvent,
41
+ SessionEvent,
42
+ StatusEvent,
43
+ TextDeltaEvent,
44
+ TextEndEvent,
45
+ TextStartEvent,
46
+ ToolCallEvent,
47
+ ToolResultEvent,
48
+ TurnEndEvent,
49
+ TurnStartEvent,
50
+ TurnUsage,
51
+ UnknownEvent,
52
+ UserMessageEvent,
53
+ parse_event,
54
+ )
55
+ from .models import (
56
+ Agent,
57
+ AgentEnvironment,
58
+ AgentPackages,
59
+ AgentStatusResult,
60
+ AgentVersion,
61
+ ApiKeyInfo,
62
+ AttachResult,
63
+ BearerCredential,
64
+ BuiltinToolInfo,
65
+ ClientIdentity,
66
+ ClientTool,
67
+ ClientToolDeclaration,
68
+ CompactResult,
69
+ CompletionResult,
70
+ CompletionUsage,
71
+ CreatedApiKey,
72
+ CreatedTenant,
73
+ DailyUsageRow,
74
+ FileMeta,
75
+ InterruptResult,
76
+ McpCredential,
77
+ McpCredentialStatus,
78
+ McpServer,
79
+ McpServerTools,
80
+ McpToolAnnotations,
81
+ McpToolInfo,
82
+ ModelInfo,
83
+ ModelPricing,
84
+ MountResult,
85
+ OAuthCredential,
86
+ OkResult,
87
+ PlatformStats,
88
+ PlatformUsageTotals,
89
+ ProviderStatus,
90
+ ProviderStatusReport,
91
+ ReasoningConfig,
92
+ SessionClientTool,
93
+ SessionEventsPage,
94
+ SessionInfo,
95
+ SessionListItem,
96
+ SessionsPage,
97
+ SessionToolSurface,
98
+ SessionUsage,
99
+ SessionUsageFigures,
100
+ SessionUsageRow,
101
+ Skill,
102
+ SkillPin,
103
+ SkillVersion,
104
+ SkillVersionPushed,
105
+ Tenant,
106
+ TenantCounts,
107
+ TenantDetail,
108
+ TenantFirstKey,
109
+ TenantStats,
110
+ ToolHandler,
111
+ UsageBreakdownRow,
112
+ UsageSummary,
113
+ UsageTotals,
114
+ )
115
+ from .session import TarsSession
116
+
117
+ try:
118
+ __version__ = _version("tars-sdk")
119
+ except PackageNotFoundError: # running from a source checkout
120
+ __version__ = "0.0.0"
121
+
122
+ __all__ = [
123
+ "AGENT_ERROR_CODES",
124
+ "DEFAULT_BASE_URL",
125
+ "KEYED_PROVIDERS",
126
+ "SESSION_EVENT_TYPES",
127
+ "UNSET",
128
+ "AdminClient",
129
+ "Agent",
130
+ "AgentEnvironment",
131
+ "AgentPackages",
132
+ "AgentStatusResult",
133
+ "AgentVersion",
134
+ "AgentsClient",
135
+ "ApiKeyInfo",
136
+ "ApiKeysClient",
137
+ "AttachResult",
138
+ "BearerCredential",
139
+ "BuiltinToolInfo",
140
+ "ClientIdentity",
141
+ "ClientTool",
142
+ "ClientToolDeclaration",
143
+ "CompactResult",
144
+ "CompactionEvent",
145
+ "CompletionResult",
146
+ "CompletionUsage",
147
+ "CompletionsClient",
148
+ "ConnectRequiredEvent",
149
+ "CreatedApiKey",
150
+ "CreatedTenant",
151
+ "DailyUsageRow",
152
+ "ErrorEvent",
153
+ "FileMeta",
154
+ "FilesClient",
155
+ "InterruptResult",
156
+ "McpClient",
157
+ "McpConnectEvent",
158
+ "McpCredential",
159
+ "McpCredentialStatus",
160
+ "McpCredentialsClient",
161
+ "McpServer",
162
+ "McpServerTools",
163
+ "McpToolAnnotations",
164
+ "McpToolInfo",
165
+ "MessageAttachment",
166
+ "ModelInfo",
167
+ "ModelPricing",
168
+ "MountResult",
169
+ "OAuthCredential",
170
+ "OkResult",
171
+ "OutputFileEvent",
172
+ "PlatformStats",
173
+ "PlatformUsageTotals",
174
+ "ProviderStatus",
175
+ "ProviderStatusReport",
176
+ "ReasoningConfig",
177
+ "SessionClientTool",
178
+ "SessionEvent",
179
+ "SessionEventsPage",
180
+ "SessionInfo",
181
+ "SessionListItem",
182
+ "SessionToolSurface",
183
+ "SessionUsage",
184
+ "SessionUsageFigures",
185
+ "SessionUsageRow",
186
+ "SessionsClient",
187
+ "SessionsPage",
188
+ "Skill",
189
+ "SkillPin",
190
+ "SkillVersion",
191
+ "SkillVersionPushed",
192
+ "SkillsClient",
193
+ "StatusEvent",
194
+ "TarsApiError",
195
+ "TarsClient",
196
+ "TarsSession",
197
+ "Tenant",
198
+ "TenantCounts",
199
+ "TenantDetail",
200
+ "TenantFirstKey",
201
+ "TenantStats",
202
+ "TextDeltaEvent",
203
+ "TextEndEvent",
204
+ "TextStartEvent",
205
+ "ToolCallEvent",
206
+ "ToolHandler",
207
+ "ToolResultEvent",
208
+ "TurnEndEvent",
209
+ "TurnStartEvent",
210
+ "TurnUsage",
211
+ "UnknownEvent",
212
+ "UsageBreakdownRow",
213
+ "UsageClient",
214
+ "UsageSummary",
215
+ "UsageTotals",
216
+ "UserMessageEvent",
217
+ "__version__",
218
+ "parse_event",
219
+ ]
tars_sdk/_sse.py ADDED
@@ -0,0 +1,33 @@
1
+ """Minimal SSE reader for the session streams.
2
+
3
+ TARS writes ``id: <seq>\\ndata: <json>\\n\\n`` per event (``backend/src/http/sse.ts``);
4
+ the seq is also inside the JSON, so ``id:`` is ignored. ``data:`` lines of one
5
+ frame are joined, a blank line ends the frame, EOF flushes a frame the server
6
+ closed without a blank line.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ from collections.abc import AsyncIterator
13
+
14
+ import httpx
15
+
16
+ from .events import SessionEvent, parse_event
17
+
18
+
19
+ async def read_events(response: httpx.Response) -> AsyncIterator[SessionEvent]:
20
+ data: list[str] = []
21
+ async for line in response.aiter_lines():
22
+ if line == "":
23
+ if data:
24
+ yield parse_event(json.loads("".join(data)))
25
+ data = []
26
+ continue
27
+ if line.startswith("data: "):
28
+ data.append(line[6:])
29
+ elif line.startswith("data:"):
30
+ data.append(line[5:])
31
+ # id:, event:, retry:, comments — not used by this stream.
32
+ if data:
33
+ yield parse_event(json.loads("".join(data)))
tars_sdk/_wire.py ADDED
@@ -0,0 +1,49 @@
1
+ """Request-body helpers.
2
+
3
+ ``UNSET`` lets a method tell "the caller did not pass this" from "the caller
4
+ passed ``None``": for a PATCH that is "leave it" versus "clear it". ``body()``
5
+ drops the SDK's own unset/None fields; the caller's data inside them (tool
6
+ outputs, input schemas, metadata) is passed through verbatim.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from typing import Any, Final
12
+
13
+
14
+ class _Unset:
15
+ __slots__ = ()
16
+
17
+ def __repr__(self) -> str:
18
+ return "UNSET"
19
+
20
+ def __bool__(self) -> bool:
21
+ return False
22
+
23
+
24
+ UNSET: Final = _Unset()
25
+ """Default for optional update fields: not sent. Pass ``None`` to clear a field."""
26
+
27
+
28
+ def body(**fields: Any) -> dict[str, Any]:
29
+ """The SDK's own top-level fields, minus the ones left ``None``/``UNSET``."""
30
+ return {k: v for k, v in fields.items() if v is not None and v is not UNSET}
31
+
32
+
33
+ def patch(**fields: Any) -> dict[str, Any]:
34
+ """Like :func:`body`, but a ``None`` is kept (sent as JSON ``null``); only ``UNSET`` is dropped."""
35
+ return {k: v for k, v in fields.items() if v is not UNSET}
36
+
37
+
38
+ def iso(at: Any) -> str:
39
+ """UTC ISO 8601 with milliseconds and ``Z``, the shape the API expects."""
40
+ from datetime import datetime, timezone
41
+
42
+ if isinstance(at, str):
43
+ return at
44
+ if not isinstance(at, datetime):
45
+ raise TypeError(f"expected a datetime or ISO string, got {type(at).__name__}")
46
+ if at.tzinfo is None:
47
+ at = at.replace(tzinfo=timezone.utc)
48
+ at = at.astimezone(timezone.utc)
49
+ return at.strftime("%Y-%m-%dT%H:%M:%S.") + f"{at.microsecond // 1000:03d}Z"