tau-coding-agent 0.1.0__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.
- tau/__init__.py +0 -0
- tau/agent/__init__.py +11 -0
- tau/agent/prompt/__init__.py +10 -0
- tau/agent/prompt/builder.py +302 -0
- tau/agent/prompt/types.py +33 -0
- tau/agent/service.py +369 -0
- tau/agent/types.py +61 -0
- tau/auth/manager.py +247 -0
- tau/auth/storage.py +82 -0
- tau/auth/types.py +41 -0
- tau/builtins/__init__.py +4 -0
- tau/builtins/__pycache__/__init__.cpython-313.pyc +0 -0
- tau/builtins/__pycache__/__init__.cpython-314.pyc +0 -0
- tau/builtins/commands/__init__.py +41 -0
- tau/builtins/commands/__pycache__/__init__.cpython-313.pyc +0 -0
- tau/builtins/commands/__pycache__/__init__.cpython-314.pyc +0 -0
- tau/builtins/commands/__pycache__/clear.cpython-313.pyc +0 -0
- tau/builtins/commands/__pycache__/clear.cpython-314.pyc +0 -0
- tau/builtins/commands/__pycache__/compact.cpython-313.pyc +0 -0
- tau/builtins/commands/__pycache__/compact.cpython-314.pyc +0 -0
- tau/builtins/commands/__pycache__/reload.cpython-313.pyc +0 -0
- tau/builtins/commands/__pycache__/reload.cpython-314.pyc +0 -0
- tau/builtins/commands/__pycache__/session.cpython-313.pyc +0 -0
- tau/builtins/commands/__pycache__/session.cpython-314.pyc +0 -0
- tau/builtins/commands/clear.py +16 -0
- tau/builtins/commands/compact.py +28 -0
- tau/builtins/commands/reload.py +27 -0
- tau/builtins/commands/session.py +19 -0
- tau/builtins/extensions/footer/__init__.py +76 -0
- tau/builtins/extensions/footer/__pycache__/__init__.cpython-313.pyc +0 -0
- tau/builtins/extensions/footer/__pycache__/git.cpython-313.pyc +0 -0
- tau/builtins/extensions/footer/__pycache__/model.cpython-313.pyc +0 -0
- tau/builtins/extensions/footer/__pycache__/utils.cpython-313.pyc +0 -0
- tau/builtins/extensions/footer/git.py +26 -0
- tau/builtins/extensions/footer/model.py +69 -0
- tau/builtins/extensions/footer/utils.py +44 -0
- tau/builtins/extensions/header/__init__.py +18 -0
- tau/builtins/extensions/header/__pycache__/__init__.cpython-313.pyc +0 -0
- tau/builtins/models/__init__.py +0 -0
- tau/builtins/models/__pycache__/__init__.cpython-313.pyc +0 -0
- tau/builtins/models/__pycache__/text.cpython-313.pyc +0 -0
- tau/builtins/models/audio.py +43 -0
- tau/builtins/models/image.py +43 -0
- tau/builtins/models/text.py +482 -0
- tau/builtins/models/video.py +40 -0
- tau/builtins/prompts/commit.md +7 -0
- tau/builtins/prompts/docs.md +7 -0
- tau/builtins/prompts/explain.md +7 -0
- tau/builtins/prompts/fix.md +7 -0
- tau/builtins/prompts/refactor.md +7 -0
- tau/builtins/prompts/review.md +7 -0
- tau/builtins/prompts/test.md +7 -0
- tau/builtins/providers/__init__.py +0 -0
- tau/builtins/providers/__pycache__/__init__.cpython-313.pyc +0 -0
- tau/builtins/providers/__pycache__/text.cpython-313.pyc +0 -0
- tau/builtins/providers/audio.py +10 -0
- tau/builtins/providers/image.py +9 -0
- tau/builtins/providers/text.py +33 -0
- tau/builtins/providers/video.py +6 -0
- tau/builtins/skills/code-review/SKILL.md +4 -0
- tau/builtins/skills/debug/SKILL.md +4 -0
- tau/builtins/skills/git-commit/SKILL.md +4 -0
- tau/builtins/themes/dark.yaml +1 -0
- tau/builtins/themes/light.yaml +46 -0
- tau/builtins/tools/__init__.py +73 -0
- tau/builtins/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/bash.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/bash.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/edit.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/edit.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/glob.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/glob.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/grep.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/grep.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/ls.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/ls.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/read.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/read.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/terminal.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/terminal.cpython-314.pyc +0 -0
- tau/builtins/tools/__pycache__/write.cpython-313.pyc +0 -0
- tau/builtins/tools/__pycache__/write.cpython-314.pyc +0 -0
- tau/builtins/tools/edit.py +215 -0
- tau/builtins/tools/glob.py +112 -0
- tau/builtins/tools/grep.py +146 -0
- tau/builtins/tools/ls.py +135 -0
- tau/builtins/tools/read.py +122 -0
- tau/builtins/tools/terminal.py +150 -0
- tau/builtins/tools/write.py +105 -0
- tau/commands/__init__.py +10 -0
- tau/commands/registry.py +71 -0
- tau/commands/types.py +33 -0
- tau/console/__init__.py +0 -0
- tau/console/cli.py +266 -0
- tau/console/commands/__init__.py +0 -0
- tau/console/commands/auth.py +193 -0
- tau/console/commands/packages.py +104 -0
- tau/console/commands/update.py +76 -0
- tau/core/__init__.py +0 -0
- tau/core/registry.py +102 -0
- tau/engine/__init__.py +47 -0
- tau/engine/service.py +768 -0
- tau/engine/types.py +163 -0
- tau/extensions/__init__.py +28 -0
- tau/extensions/api.py +928 -0
- tau/extensions/context.py +462 -0
- tau/extensions/events.py +70 -0
- tau/extensions/loader.py +386 -0
- tau/extensions/runtime.py +184 -0
- tau/extensions/settings.py +137 -0
- tau/hooks/__init__.py +112 -0
- tau/hooks/engine.py +237 -0
- tau/hooks/inference.py +21 -0
- tau/hooks/runtime.py +126 -0
- tau/hooks/service.py +121 -0
- tau/hooks/session.py +117 -0
- tau/hooks/tui.py +61 -0
- tau/hooks/types.py +72 -0
- tau/inference/__init__.py +180 -0
- tau/inference/api/__init__.py +0 -0
- tau/inference/api/audio/__init__.py +0 -0
- tau/inference/api/audio/base.py +29 -0
- tau/inference/api/audio/builtins.py +15 -0
- tau/inference/api/audio/elevenlabs_audio.py +183 -0
- tau/inference/api/audio/gemini_audio.py +95 -0
- tau/inference/api/audio/openai_audio.py +159 -0
- tau/inference/api/audio/registry.py +15 -0
- tau/inference/api/audio/sarvam_audio.py +163 -0
- tau/inference/api/audio/service.py +103 -0
- tau/inference/api/audio/utils.py +47 -0
- tau/inference/api/image/__init__.py +0 -0
- tau/inference/api/image/base.py +17 -0
- tau/inference/api/image/builtins.py +8 -0
- tau/inference/api/image/gemini_image.py +77 -0
- tau/inference/api/image/openai_image.py +103 -0
- tau/inference/api/image/openrouter.py +144 -0
- tau/inference/api/image/registry.py +15 -0
- tau/inference/api/image/service.py +71 -0
- tau/inference/api/registry.py +82 -0
- tau/inference/api/text/__init__.py +0 -0
- tau/inference/api/text/anthropic_claude_code.py +222 -0
- tau/inference/api/text/anthropic_messages.py +196 -0
- tau/inference/api/text/base.py +40 -0
- tau/inference/api/text/builtins.py +19 -0
- tau/inference/api/text/gemini_generate.py +234 -0
- tau/inference/api/text/github_copilot_chat.py +172 -0
- tau/inference/api/text/google_antigravity.py +522 -0
- tau/inference/api/text/mistral_chat.py +284 -0
- tau/inference/api/text/ollama_chat.py +200 -0
- tau/inference/api/text/openai_codex_responses.py +497 -0
- tau/inference/api/text/openai_completions.py +227 -0
- tau/inference/api/text/openai_responses.py +235 -0
- tau/inference/api/text/registry.py +50 -0
- tau/inference/api/text/service.py +297 -0
- tau/inference/api/text/types.py +7 -0
- tau/inference/api/text/utils.py +228 -0
- tau/inference/api/video/__init__.py +0 -0
- tau/inference/api/video/base.py +26 -0
- tau/inference/api/video/builtins.py +7 -0
- tau/inference/api/video/fal_video.py +119 -0
- tau/inference/api/video/openrouter_video.py +142 -0
- tau/inference/api/video/registry.py +15 -0
- tau/inference/api/video/service.py +72 -0
- tau/inference/model/__init__.py +0 -0
- tau/inference/model/registry.py +102 -0
- tau/inference/model/types.py +65 -0
- tau/inference/provider/__init__.py +0 -0
- tau/inference/provider/oauth/__init__.py +35 -0
- tau/inference/provider/oauth/anthropic_claude_code.py +286 -0
- tau/inference/provider/oauth/github_copilot.py +333 -0
- tau/inference/provider/oauth/google_antigravity.py +258 -0
- tau/inference/provider/oauth/openai_codex.py +309 -0
- tau/inference/provider/oauth/pkce.py +14 -0
- tau/inference/provider/oauth/types.py +46 -0
- tau/inference/provider/oauth/utils.py +154 -0
- tau/inference/provider/registry.py +141 -0
- tau/inference/provider/types.py +114 -0
- tau/inference/types.py +549 -0
- tau/inference/utils.py +219 -0
- tau/message/__init__.py +0 -0
- tau/message/types.py +482 -0
- tau/message/utils.py +178 -0
- tau/packages/__init__.py +11 -0
- tau/packages/manager.py +190 -0
- tau/packages/types.py +20 -0
- tau/packages/utils.py +67 -0
- tau/prompts/expand.py +58 -0
- tau/prompts/loader.py +69 -0
- tau/prompts/registry.py +45 -0
- tau/prompts/types.py +24 -0
- tau/rpc/__init__.py +8 -0
- tau/rpc/mode.py +783 -0
- tau/rpc/types.py +252 -0
- tau/runtime/service.py +759 -0
- tau/runtime/types.py +303 -0
- tau/session/branch_summarization.py +312 -0
- tau/session/compaction.py +646 -0
- tau/session/manager.py +652 -0
- tau/session/types.py +188 -0
- tau/session/utils.py +233 -0
- tau/settings/manager.py +1077 -0
- tau/settings/paths.py +150 -0
- tau/settings/storage.py +63 -0
- tau/settings/types.py +173 -0
- tau/settings/utils.py +25 -0
- tau/skills/loader.py +91 -0
- tau/skills/registry.py +70 -0
- tau/skills/types.py +25 -0
- tau/themes/loader.py +238 -0
- tau/themes/registry.py +108 -0
- tau/themes/types.py +19 -0
- tau/tool/__init__.py +3 -0
- tau/tool/registry.py +117 -0
- tau/tool/render.py +21 -0
- tau/tool/types.py +244 -0
- tau/trust/__init__.py +13 -0
- tau/trust/manager.py +80 -0
- tau/trust/types.py +14 -0
- tau/trust/utils.py +72 -0
- tau/tui/__init__.py +54 -0
- tau/tui/agent_hooks.py +346 -0
- tau/tui/ansi.py +330 -0
- tau/tui/app.py +540 -0
- tau/tui/autocomplete.py +33 -0
- tau/tui/capabilities.py +119 -0
- tau/tui/commands/__init__.py +3 -0
- tau/tui/commands/appearance.py +498 -0
- tau/tui/commands/auth.py +232 -0
- tau/tui/commands/context.py +38 -0
- tau/tui/commands/misc.py +82 -0
- tau/tui/commands/model.py +118 -0
- tau/tui/commands/session.py +464 -0
- tau/tui/component.py +268 -0
- tau/tui/components/__init__.py +0 -0
- tau/tui/components/autocomplete_manager.py +267 -0
- tau/tui/components/autocomplete_picker.py +143 -0
- tau/tui/components/box.py +90 -0
- tau/tui/components/command_palette.py +144 -0
- tau/tui/components/dynamic_border.py +19 -0
- tau/tui/components/file_picker.py +233 -0
- tau/tui/components/image.py +181 -0
- tau/tui/components/inline_selector.py +71 -0
- tau/tui/components/layout.py +1194 -0
- tau/tui/components/message_list.py +692 -0
- tau/tui/components/modal.py +97 -0
- tau/tui/components/model_palette.py +204 -0
- tau/tui/components/picker_overlay.py +174 -0
- tau/tui/components/prompt_overlay.py +236 -0
- tau/tui/components/resume_modal.py +372 -0
- tau/tui/components/select_list.py +222 -0
- tau/tui/components/settings_modal.py +274 -0
- tau/tui/components/settings_schema.py +203 -0
- tau/tui/components/spinner.py +119 -0
- tau/tui/components/text_input.py +396 -0
- tau/tui/components/text_prompt.py +82 -0
- tau/tui/components/tree_select_list.py +580 -0
- tau/tui/components/trust_screen.py +97 -0
- tau/tui/diff.py +114 -0
- tau/tui/fuzzy.py +99 -0
- tau/tui/input.py +496 -0
- tau/tui/input_handler.py +716 -0
- tau/tui/keybindings.py +87 -0
- tau/tui/markdown.py +286 -0
- tau/tui/message_renderers.py +31 -0
- tau/tui/overlay.py +326 -0
- tau/tui/renderer.py +378 -0
- tau/tui/terminal.py +499 -0
- tau/tui/theme.py +148 -0
- tau/tui/tui.py +544 -0
- tau/tui/ui_context.py +768 -0
- tau/tui/utils.py +20 -0
- tau/utils/__init__.py +0 -0
- tau/utils/http_proxy.py +221 -0
- tau/utils/image_processing.py +172 -0
- tau/utils/secrets.py +59 -0
- tau/utils/version_check.py +60 -0
- tau_coding_agent-0.1.0.dist-info/METADATA +177 -0
- tau_coding_agent-0.1.0.dist-info/RECORD +283 -0
- tau_coding_agent-0.1.0.dist-info/WHEEL +5 -0
- tau_coding_agent-0.1.0.dist-info/entry_points.txt +2 -0
- tau_coding_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
- tau_coding_agent-0.1.0.dist-info/top_level.txt +1 -0
tau/inference/types.py
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Any, Callable, Optional, TYPE_CHECKING
|
|
6
|
+
import asyncio
|
|
7
|
+
import time
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from tau.message.types import LLMMessage, TextContent, ThinkingContent, ToolCallContent, ImageContent
|
|
14
|
+
from tau.tool.types import Tool
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ── Shared enums ──────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
class Transport(str, Enum):
|
|
20
|
+
"""Wire transport protocol used to reach the provider endpoint."""
|
|
21
|
+
|
|
22
|
+
Auto = "auto"
|
|
23
|
+
HTTP = "http"
|
|
24
|
+
WEBSOCKET = "websocket"
|
|
25
|
+
SSE = "sse"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class AuthType(str, Enum):
|
|
29
|
+
"""Authentication mechanism used by a provider."""
|
|
30
|
+
|
|
31
|
+
ApiKey = "api_key"
|
|
32
|
+
OAuth = "oauth"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class StopReason(str, Enum):
|
|
36
|
+
"""Normalised reason a model generation stopped."""
|
|
37
|
+
|
|
38
|
+
Stop = "stop"
|
|
39
|
+
Length = "length"
|
|
40
|
+
ToolCalls = "tool_calls"
|
|
41
|
+
ContentFilter = "content_filter"
|
|
42
|
+
Abort = "abort"
|
|
43
|
+
Error = "error"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ThinkingLevel(str, Enum):
|
|
47
|
+
"""Ordered thinking/reasoning intensity levels mapped to provider budgets."""
|
|
48
|
+
|
|
49
|
+
Off = "off"
|
|
50
|
+
Minimal = "minimal"
|
|
51
|
+
Low = "low"
|
|
52
|
+
Medium = "medium"
|
|
53
|
+
High = "high"
|
|
54
|
+
XHigh = "xhigh"
|
|
55
|
+
Max = "max"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class ThinkingBudgets:
|
|
60
|
+
"""Token budgets for providers that map ThinkingLevel to budget_tokens."""
|
|
61
|
+
minimal: Optional[int] = 1024
|
|
62
|
+
low: Optional[int] = 2048
|
|
63
|
+
medium: Optional[int] = 4096
|
|
64
|
+
high: Optional[int] = 8192
|
|
65
|
+
xhigh: Optional[int] = 16384
|
|
66
|
+
max: Optional[int] = 32768
|
|
67
|
+
|
|
68
|
+
def get(self, level: ThinkingLevel) -> int:
|
|
69
|
+
"""Return the budget_tokens value for the given ThinkingLevel, falling back to built-in defaults."""
|
|
70
|
+
_defaults = {
|
|
71
|
+
"minimal": 1024, "low": 2048, "medium": 4096,
|
|
72
|
+
"high": 8192, "xhigh": 16384, "max": 32768,
|
|
73
|
+
}
|
|
74
|
+
value = getattr(self, level.value, None)
|
|
75
|
+
return value if value is not None else _defaults[level.value]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
# ── LLM types ─────────────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
class LLMEventType(str, Enum):
|
|
81
|
+
"""Discriminant tag carried by every LLMEvent dataclass."""
|
|
82
|
+
|
|
83
|
+
Start = "start"
|
|
84
|
+
Retry = "retry"
|
|
85
|
+
Error = "error"
|
|
86
|
+
End = "end"
|
|
87
|
+
TextStart = "text_start"
|
|
88
|
+
TextDelta = "text_delta"
|
|
89
|
+
TextEnd = "text_end"
|
|
90
|
+
ThinkingStart = "thinking_start"
|
|
91
|
+
ThinkingDelta = "thinking_delta"
|
|
92
|
+
ThinkingEnd = "thinking_end"
|
|
93
|
+
ToolCallStart = "tool_call_start"
|
|
94
|
+
ToolCallDelta = "tool_call_delta"
|
|
95
|
+
ToolCallEnd = "tool_call_end"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
AbortSignal = asyncio.Event
|
|
99
|
+
PayloadCallback = Callable[[dict[str, Any]], Optional[dict[str, Any]]]
|
|
100
|
+
ResponseCallback = Callable[[Any], None]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class LLMOptions:
|
|
105
|
+
"""Runtime configuration passed to every BaseLLMAPI constructor and stream() call."""
|
|
106
|
+
|
|
107
|
+
api_key: Optional[str] = None
|
|
108
|
+
base_url: Optional[str] = None
|
|
109
|
+
headers: Optional[dict[str, str]] = None
|
|
110
|
+
max_retries: int = 3
|
|
111
|
+
retry_base_delay_ms: int = 1000
|
|
112
|
+
timeout: timedelta = field(default_factory=lambda: timedelta(seconds=60))
|
|
113
|
+
temperature: float = 1.0
|
|
114
|
+
max_tokens: Optional[int] = None
|
|
115
|
+
transport: Transport = Transport.HTTP
|
|
116
|
+
thinking_level: Optional[ThinkingLevel] = None
|
|
117
|
+
thinking_budgets: Optional[ThinkingBudgets] = None
|
|
118
|
+
signal: Optional[AbortSignal] = None
|
|
119
|
+
extra_params: Optional[dict[str, Any]] = None
|
|
120
|
+
on_payload: Optional[PayloadCallback] = None
|
|
121
|
+
on_response: Optional[ResponseCallback] = None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class StructuredResponseFormat:
|
|
126
|
+
"""Normalised structured output spec (JSON schema + name + strict flag)."""
|
|
127
|
+
|
|
128
|
+
schema: dict[str, Any]
|
|
129
|
+
name: str = "response"
|
|
130
|
+
strict: bool = True
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
StructuredResponseInput = StructuredResponseFormat | type[Any] | dict[str, Any]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def normalize_structured_response_format(response_format: StructuredResponseInput | None) -> StructuredResponseFormat | None:
|
|
137
|
+
"""Coerce any supported response_format shape into a StructuredResponseFormat, or None."""
|
|
138
|
+
if response_format is None:
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
if isinstance(response_format, StructuredResponseFormat):
|
|
142
|
+
return response_format
|
|
143
|
+
|
|
144
|
+
if isinstance(response_format, type) and issubclass(response_format, BaseModel):
|
|
145
|
+
return StructuredResponseFormat(
|
|
146
|
+
name=response_format.__name__,
|
|
147
|
+
schema=response_format.model_json_schema(),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
if isinstance(response_format, dict):
|
|
151
|
+
schema = deepcopy(response_format)
|
|
152
|
+
if isinstance(schema.get("format"), dict):
|
|
153
|
+
schema = deepcopy(schema["format"])
|
|
154
|
+
if isinstance(schema.get("json_schema"), dict):
|
|
155
|
+
schema = deepcopy(schema["json_schema"])
|
|
156
|
+
name = str(schema.get("name") or schema.get("title") or "response")
|
|
157
|
+
strict = bool(schema.pop("strict", True))
|
|
158
|
+
if "schema" in schema and isinstance(schema["schema"], dict):
|
|
159
|
+
name = str(schema.pop("name", name))
|
|
160
|
+
schema = deepcopy(schema["schema"])
|
|
161
|
+
return StructuredResponseFormat(name=name, schema=schema, strict=strict)
|
|
162
|
+
|
|
163
|
+
raise TypeError("response_format must be a Pydantic model class, JSON schema dict, or StructuredResponseFormat")
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@dataclass
|
|
167
|
+
class LLMContext:
|
|
168
|
+
"""All inputs required to execute one LLM turn: messages, tools, and optional overrides."""
|
|
169
|
+
|
|
170
|
+
messages: list["LLMMessage"]
|
|
171
|
+
tools: list["Tool"] = field(default_factory=list)
|
|
172
|
+
system_prompt: Optional[str] = None
|
|
173
|
+
response_format: Optional[StructuredResponseInput] = None
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _default_text_event_data():
|
|
177
|
+
"""Return an empty TextContent; used as a field default_factory to avoid mutable defaults."""
|
|
178
|
+
from tau.message.types import TextContent
|
|
179
|
+
return TextContent(content="")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@dataclass
|
|
183
|
+
class TextEventData:
|
|
184
|
+
"""Mixin carrying a TextContent payload for text-phase events."""
|
|
185
|
+
|
|
186
|
+
text: "TextContent" = field(default_factory=_default_text_event_data)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@dataclass
|
|
190
|
+
class ThinkingEventData:
|
|
191
|
+
"""Mixin carrying an optional ThinkingContent payload for thinking-phase events."""
|
|
192
|
+
|
|
193
|
+
thinking: Optional["ThinkingContent"] = None
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass
|
|
197
|
+
class ToolCallEventData:
|
|
198
|
+
"""Mixin carrying an optional ToolCallContent payload for tool-call-phase events."""
|
|
199
|
+
|
|
200
|
+
tool_call: Optional["ToolCallContent"] = None
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@dataclass
|
|
204
|
+
class StartEvent:
|
|
205
|
+
"""Emitted once at the very beginning of a stream before any content."""
|
|
206
|
+
|
|
207
|
+
type: LLMEventType = field(default=LLMEventType.Start, init=False)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@dataclass
|
|
211
|
+
class RetryEvent:
|
|
212
|
+
"""Emitted before each retry attempt after a transient pre-stream failure."""
|
|
213
|
+
|
|
214
|
+
type: LLMEventType = field(default=LLMEventType.Retry, init=False)
|
|
215
|
+
attempt: int = 0
|
|
216
|
+
max_retries: int = 0
|
|
217
|
+
error: str = ""
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
@dataclass
|
|
221
|
+
class ErrorEvent:
|
|
222
|
+
"""Emitted when the stream terminates due to an error or cancellation."""
|
|
223
|
+
|
|
224
|
+
type: LLMEventType = field(default=LLMEventType.Error, init=False)
|
|
225
|
+
reason: StopReason = StopReason.Stop
|
|
226
|
+
error: str = ""
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@dataclass
|
|
230
|
+
class EndEvent:
|
|
231
|
+
"""Emitted once at the end of a stream carrying token usage and the stop reason."""
|
|
232
|
+
|
|
233
|
+
type: LLMEventType = field(default=LLMEventType.End, init=False)
|
|
234
|
+
reason: StopReason = StopReason.Stop
|
|
235
|
+
input_tokens: int = 0
|
|
236
|
+
output_tokens: int = 0
|
|
237
|
+
cache_read_tokens: int = 0
|
|
238
|
+
cache_write_tokens: int = 0
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@dataclass
|
|
242
|
+
class TextStartEvent:
|
|
243
|
+
"""Signals the opening of a new text content block."""
|
|
244
|
+
|
|
245
|
+
type: LLMEventType = field(default=LLMEventType.TextStart, init=False)
|
|
246
|
+
text: "TextContent"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
@dataclass
|
|
250
|
+
class TextDeltaEvent:
|
|
251
|
+
"""Carries an incremental text chunk within the active text block."""
|
|
252
|
+
|
|
253
|
+
type: LLMEventType = field(default=LLMEventType.TextDelta, init=False)
|
|
254
|
+
text: "TextContent"
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
@dataclass
|
|
258
|
+
class TextEndEvent:
|
|
259
|
+
"""Signals the close of a text block, carrying the fully accumulated text."""
|
|
260
|
+
|
|
261
|
+
type: LLMEventType = field(default=LLMEventType.TextEnd, init=False)
|
|
262
|
+
text: "TextContent"
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@dataclass
|
|
266
|
+
class ThinkingStartEvent:
|
|
267
|
+
"""Signals the opening of a thinking/reasoning content block."""
|
|
268
|
+
|
|
269
|
+
type: LLMEventType = field(default=LLMEventType.ThinkingStart, init=False)
|
|
270
|
+
thinking: Optional["ThinkingContent"] = None
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@dataclass
|
|
274
|
+
class ThinkingDeltaEvent:
|
|
275
|
+
"""Carries an incremental chunk of thinking/reasoning text."""
|
|
276
|
+
|
|
277
|
+
type: LLMEventType = field(default=LLMEventType.ThinkingDelta, init=False)
|
|
278
|
+
thinking: "ThinkingContent"
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@dataclass
|
|
282
|
+
class ThinkingEndEvent:
|
|
283
|
+
"""Signals the close of a thinking block, carrying the fully accumulated text."""
|
|
284
|
+
|
|
285
|
+
type: LLMEventType = field(default=LLMEventType.ThinkingEnd, init=False)
|
|
286
|
+
thinking: "ThinkingContent"
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@dataclass
|
|
290
|
+
class ToolCallStartEvent:
|
|
291
|
+
"""Signals that the model has started emitting a tool call (id and name known)."""
|
|
292
|
+
|
|
293
|
+
type: LLMEventType = field(default=LLMEventType.ToolCallStart, init=False)
|
|
294
|
+
tool_call: "ToolCallContent"
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
@dataclass
|
|
298
|
+
class ToolCallDeltaEvent:
|
|
299
|
+
"""Carries a partial JSON arguments chunk for an in-progress tool call."""
|
|
300
|
+
|
|
301
|
+
type: LLMEventType = field(default=LLMEventType.ToolCallDelta, init=False)
|
|
302
|
+
tool_call: "ToolCallContent"
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@dataclass
|
|
306
|
+
class ToolCallEndEvent:
|
|
307
|
+
"""Signals the completion of a tool call with the final parsed arguments."""
|
|
308
|
+
|
|
309
|
+
type: LLMEventType = field(default=LLMEventType.ToolCallEnd, init=False)
|
|
310
|
+
tool_call: "ToolCallContent"
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
LLMEvent = (
|
|
314
|
+
StartEvent
|
|
315
|
+
| RetryEvent
|
|
316
|
+
| ErrorEvent
|
|
317
|
+
| EndEvent
|
|
318
|
+
| TextStartEvent
|
|
319
|
+
| TextDeltaEvent
|
|
320
|
+
| TextEndEvent
|
|
321
|
+
| ThinkingStartEvent
|
|
322
|
+
| ThinkingDeltaEvent
|
|
323
|
+
| ThinkingEndEvent
|
|
324
|
+
| ToolCallStartEvent
|
|
325
|
+
| ToolCallDeltaEvent
|
|
326
|
+
| ToolCallEndEvent
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
# ── Image types ───────────────────────────────────────────────────────────────
|
|
331
|
+
|
|
332
|
+
class ImageStopReason(str, Enum):
|
|
333
|
+
"""Normalised reason an image generation run stopped."""
|
|
334
|
+
|
|
335
|
+
Stop = "stop"
|
|
336
|
+
Error = "error"
|
|
337
|
+
Abort = "abort"
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
@dataclass
|
|
341
|
+
class ImageOptions:
|
|
342
|
+
"""Runtime configuration for image generation API calls."""
|
|
343
|
+
|
|
344
|
+
api_key: Optional[str] = None
|
|
345
|
+
base_url: Optional[str] = None
|
|
346
|
+
headers: Optional[dict[str, str]] = None
|
|
347
|
+
timeout: timedelta = field(default_factory=lambda: timedelta(seconds=120))
|
|
348
|
+
max_retries: int = 3
|
|
349
|
+
on_payload: Optional[PayloadCallback] = None
|
|
350
|
+
on_response: Optional[ResponseCallback] = None
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
@dataclass
|
|
354
|
+
class ImageContext:
|
|
355
|
+
"""Inputs for a single image generation request."""
|
|
356
|
+
|
|
357
|
+
contents: list["TextContent | ImageContent"]
|
|
358
|
+
size: Optional[str] = None
|
|
359
|
+
quality: Optional[str] = None
|
|
360
|
+
n: int = 1
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@dataclass
|
|
364
|
+
class GeneratedImage:
|
|
365
|
+
"""Result of a completed image generation call."""
|
|
366
|
+
|
|
367
|
+
model_id: str
|
|
368
|
+
provider: str
|
|
369
|
+
output: list["TextContent | ImageContent"]
|
|
370
|
+
stop_reason: ImageStopReason
|
|
371
|
+
usage: Any = field(default_factory=lambda: __import__("tau.message.types", fromlist=["Usage"]).Usage())
|
|
372
|
+
error: str = ""
|
|
373
|
+
timestamp: float = field(default_factory=time.time)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
# ── Video types ───────────────────────────────────────────────────────────────
|
|
377
|
+
|
|
378
|
+
class VideoFormat(str, Enum):
|
|
379
|
+
"""Container format for generated video output."""
|
|
380
|
+
|
|
381
|
+
MP4 = "mp4"
|
|
382
|
+
WEBM = "webm"
|
|
383
|
+
MOV = "mov"
|
|
384
|
+
GIF = "gif"
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
class VideoStopReason(str, Enum):
|
|
388
|
+
"""Normalised reason a video generation job stopped."""
|
|
389
|
+
|
|
390
|
+
Stop = "stop"
|
|
391
|
+
Error = "error"
|
|
392
|
+
Abort = "abort"
|
|
393
|
+
Timeout = "timeout"
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
@dataclass
|
|
397
|
+
class VideoOptions:
|
|
398
|
+
"""Runtime configuration for video generation API calls."""
|
|
399
|
+
|
|
400
|
+
api_key: Optional[str] = None
|
|
401
|
+
base_url: Optional[str] = None
|
|
402
|
+
headers: Optional[dict[str, str]] = None
|
|
403
|
+
timeout: timedelta = field(default_factory=lambda: timedelta(seconds=600))
|
|
404
|
+
poll_interval: float = 3.0
|
|
405
|
+
max_retries: int = 3
|
|
406
|
+
on_payload: Optional[PayloadCallback] = None
|
|
407
|
+
on_response: Optional[ResponseCallback] = None
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@dataclass
|
|
411
|
+
class VideoContext:
|
|
412
|
+
"""Inputs for a single video generation request."""
|
|
413
|
+
|
|
414
|
+
prompt: str
|
|
415
|
+
image: Optional[bytes] = None
|
|
416
|
+
duration: Optional[float] = None
|
|
417
|
+
aspect_ratio: Optional[str] = None
|
|
418
|
+
resolution: Optional[str] = None
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
@dataclass
|
|
422
|
+
class GeneratedVideo:
|
|
423
|
+
"""Result of a completed video generation job."""
|
|
424
|
+
|
|
425
|
+
model_id: str
|
|
426
|
+
provider: str
|
|
427
|
+
url: Optional[str] = None
|
|
428
|
+
video: Optional[bytes] = None
|
|
429
|
+
format: VideoFormat = VideoFormat.MP4
|
|
430
|
+
duration: Optional[float] = None
|
|
431
|
+
stop_reason: VideoStopReason = VideoStopReason.Stop
|
|
432
|
+
usage: Any = None
|
|
433
|
+
error: str = ""
|
|
434
|
+
timestamp: float = field(default_factory=time.time)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
# ── Audio types ───────────────────────────────────────────────────────────────
|
|
438
|
+
|
|
439
|
+
class AudioFormat(str, Enum):
|
|
440
|
+
"""Audio codec/container format for TTS output or STT input."""
|
|
441
|
+
|
|
442
|
+
MP3 = "mp3"
|
|
443
|
+
WAV = "wav"
|
|
444
|
+
OPUS = "opus"
|
|
445
|
+
AAC = "aac"
|
|
446
|
+
FLAC = "flac"
|
|
447
|
+
PCM = "pcm"
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
class AudioStopReason(str, Enum):
|
|
451
|
+
"""Normalised reason an audio synthesis or transcription call stopped."""
|
|
452
|
+
|
|
453
|
+
Stop = "stop"
|
|
454
|
+
Error = "error"
|
|
455
|
+
Abort = "abort"
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
class TimestampGranularity(str, Enum):
|
|
459
|
+
"""Level of timestamp detail requested in a transcription response."""
|
|
460
|
+
|
|
461
|
+
Word = "word"
|
|
462
|
+
Segment = "segment"
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
@dataclass
|
|
466
|
+
class AudioOptions:
|
|
467
|
+
"""Runtime configuration for TTS and STT API calls."""
|
|
468
|
+
|
|
469
|
+
api_key: Optional[str] = None
|
|
470
|
+
base_url: Optional[str] = None
|
|
471
|
+
headers: Optional[dict[str, str]] = None
|
|
472
|
+
timeout: timedelta = field(default_factory=lambda: timedelta(seconds=120))
|
|
473
|
+
max_retries: int = 3
|
|
474
|
+
on_payload: Optional[PayloadCallback] = None
|
|
475
|
+
on_response: Optional[ResponseCallback] = None
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
@dataclass
|
|
479
|
+
class TTSContext:
|
|
480
|
+
"""Inputs for a single text-to-speech synthesis request."""
|
|
481
|
+
|
|
482
|
+
input: str
|
|
483
|
+
voice: str
|
|
484
|
+
speed: float = 1.0
|
|
485
|
+
response_format: AudioFormat = AudioFormat.MP3
|
|
486
|
+
language: Optional[str] = None
|
|
487
|
+
instructions: Optional[str] = None
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
@dataclass
|
|
491
|
+
class WordTimestamp:
|
|
492
|
+
"""Timing information for a single word in a transcription."""
|
|
493
|
+
|
|
494
|
+
word: str
|
|
495
|
+
start: float
|
|
496
|
+
end: float
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
@dataclass
|
|
500
|
+
class SegmentTimestamp:
|
|
501
|
+
"""Timing information for a sentence-level segment in a transcription."""
|
|
502
|
+
|
|
503
|
+
id: int
|
|
504
|
+
text: str
|
|
505
|
+
start: float
|
|
506
|
+
end: float
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
@dataclass
|
|
510
|
+
class STTContext:
|
|
511
|
+
"""Inputs for a single speech-to-text transcription request."""
|
|
512
|
+
|
|
513
|
+
audio: bytes
|
|
514
|
+
format: AudioFormat = AudioFormat.MP3
|
|
515
|
+
language: Optional[str] = None
|
|
516
|
+
temperature: float = 0.0
|
|
517
|
+
timestamp_granularities: list[TimestampGranularity] = field(default_factory=list)
|
|
518
|
+
prompt: Optional[str] = None
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
@dataclass
|
|
522
|
+
class SynthesizedAudio:
|
|
523
|
+
"""Result of a completed TTS synthesis call."""
|
|
524
|
+
|
|
525
|
+
model_id: str
|
|
526
|
+
provider: str
|
|
527
|
+
audio: bytes
|
|
528
|
+
format: AudioFormat
|
|
529
|
+
stop_reason: AudioStopReason
|
|
530
|
+
usage: Any = None
|
|
531
|
+
error: str = ""
|
|
532
|
+
timestamp: float = field(default_factory=time.time)
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
@dataclass
|
|
536
|
+
class TranscribedAudio:
|
|
537
|
+
"""Result of a completed STT transcription call."""
|
|
538
|
+
|
|
539
|
+
model_id: str
|
|
540
|
+
provider: str
|
|
541
|
+
text: str
|
|
542
|
+
language: Optional[str] = None
|
|
543
|
+
duration: Optional[float] = None
|
|
544
|
+
words: list[WordTimestamp] = field(default_factory=list)
|
|
545
|
+
segments: list[SegmentTimestamp] = field(default_factory=list)
|
|
546
|
+
stop_reason: AudioStopReason = AudioStopReason.Stop
|
|
547
|
+
usage: Any = None
|
|
548
|
+
error: str = ""
|
|
549
|
+
timestamp: float = field(default_factory=time.time)
|