toolstream 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.
- toolstream/__init__.py +44 -0
- toolstream/_agent.py +215 -0
- toolstream/_builtin_tools.py +115 -0
- toolstream/_context.py +14 -0
- toolstream/_direct.py +292 -0
- toolstream/_invoke.py +126 -0
- toolstream/_protocol.py +87 -0
- toolstream/_schema.py +259 -0
- toolstream/_session.py +176 -0
- toolstream/_tools.py +109 -0
- toolstream/config.py +26 -0
- toolstream/events.py +63 -0
- toolstream/py.typed +0 -0
- toolstream-0.1.0.dist-info/METADATA +7 -0
- toolstream-0.1.0.dist-info/RECORD +16 -0
- toolstream-0.1.0.dist-info/WHEEL +4 -0
toolstream/_tools.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Tool registration system for toolstream.
|
|
2
|
+
|
|
3
|
+
Provides the @tool decorator for marking functions as LLM-callable tools,
|
|
4
|
+
and collect_tools() for discovering decorated functions across modules.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import inspect
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from typing import Callable
|
|
12
|
+
|
|
13
|
+
from ._schema import _generate_schema
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class Tool:
|
|
18
|
+
"""Metadata for a registered tool function."""
|
|
19
|
+
|
|
20
|
+
name: str
|
|
21
|
+
description: str
|
|
22
|
+
input_schema: dict
|
|
23
|
+
handler: Callable
|
|
24
|
+
inject: list[str]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def tool(
|
|
28
|
+
*,
|
|
29
|
+
name: str | None = None,
|
|
30
|
+
description: str | None = None,
|
|
31
|
+
inject: list[str] | None = None,
|
|
32
|
+
) -> Callable:
|
|
33
|
+
"""Decorator factory that attaches Tool metadata to a function.
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
@tool()
|
|
37
|
+
def my_func(x: int) -> str:
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
@tool(inject=["ctx"])
|
|
41
|
+
def my_func(ctx, x: int) -> str:
|
|
42
|
+
...
|
|
43
|
+
|
|
44
|
+
The decorated function is returned unchanged -- this decorator only
|
|
45
|
+
attaches a _tool attribute, it does not wrap the function.
|
|
46
|
+
"""
|
|
47
|
+
inject_list = inject or []
|
|
48
|
+
|
|
49
|
+
def decorator(fn: Callable) -> Callable:
|
|
50
|
+
# Validate that every injected param exists in the signature
|
|
51
|
+
sig = inspect.signature(fn)
|
|
52
|
+
for param_name in inject_list:
|
|
53
|
+
if param_name not in sig.parameters:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"inject parameter {param_name!r} not found in "
|
|
56
|
+
f"signature of {fn.__name__}(). "
|
|
57
|
+
f"Available: {list(sig.parameters.keys())}"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Resolve name
|
|
61
|
+
tool_name = name if name is not None else fn.__name__
|
|
62
|
+
|
|
63
|
+
# Resolve description from first line of docstring
|
|
64
|
+
if description is not None:
|
|
65
|
+
tool_description = description
|
|
66
|
+
elif fn.__doc__:
|
|
67
|
+
tool_description = fn.__doc__.strip().split("\n")[0].strip()
|
|
68
|
+
else:
|
|
69
|
+
tool_description = ""
|
|
70
|
+
|
|
71
|
+
# Generate input schema, excluding injected params
|
|
72
|
+
input_schema = _generate_schema(fn, inject=set(inject_list))
|
|
73
|
+
|
|
74
|
+
fn._tool = Tool(
|
|
75
|
+
name=tool_name,
|
|
76
|
+
description=tool_description,
|
|
77
|
+
input_schema=input_schema,
|
|
78
|
+
handler=fn,
|
|
79
|
+
inject=inject_list,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return fn
|
|
83
|
+
|
|
84
|
+
return decorator
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def collect_tools(*modules) -> list[Tool]:
|
|
88
|
+
"""Discover all @tool-decorated functions across the given modules.
|
|
89
|
+
|
|
90
|
+
Raises ValueError if two tools share the same name.
|
|
91
|
+
"""
|
|
92
|
+
tools: list[Tool] = []
|
|
93
|
+
seen_names: dict[str, str] = {} # name -> module name for error messages
|
|
94
|
+
|
|
95
|
+
for module in modules:
|
|
96
|
+
module_name = getattr(module, "__name__", repr(module))
|
|
97
|
+
for attr_name in dir(module):
|
|
98
|
+
obj = getattr(module, attr_name)
|
|
99
|
+
if callable(obj) and hasattr(obj, "_tool"):
|
|
100
|
+
t: Tool = obj._tool
|
|
101
|
+
if t.name in seen_names:
|
|
102
|
+
raise ValueError(
|
|
103
|
+
f"Tool name collision: {t.name!r} found in both "
|
|
104
|
+
f"{seen_names[t.name]} and {module_name}"
|
|
105
|
+
)
|
|
106
|
+
seen_names[t.name] = module_name
|
|
107
|
+
tools.append(t)
|
|
108
|
+
|
|
109
|
+
return tools
|
toolstream/config.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from ._agent import AgentSandbox
|
|
8
|
+
from ._context import ToolContext
|
|
9
|
+
from ._tools import Tool
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class SessionConfig:
|
|
14
|
+
model: str
|
|
15
|
+
api_key: str
|
|
16
|
+
base_url: str
|
|
17
|
+
system_prompt: str
|
|
18
|
+
cwd: str | None = None
|
|
19
|
+
env: dict[str, str] = field(default_factory=dict)
|
|
20
|
+
agent: str | None = None
|
|
21
|
+
tools: list[Tool] | None = None
|
|
22
|
+
tool_context: ToolContext | None = None
|
|
23
|
+
tool_env: dict[str, str] = field(default_factory=dict)
|
|
24
|
+
max_completion_tokens: int = 16384
|
|
25
|
+
sandbox: AgentSandbox | None = None
|
|
26
|
+
metadata: dict[str, str] | None = None
|
toolstream/events.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True)
|
|
7
|
+
class StepStart:
|
|
8
|
+
session_id: str
|
|
9
|
+
message_id: str
|
|
10
|
+
timestamp: int
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class Text:
|
|
15
|
+
session_id: str
|
|
16
|
+
message_id: str
|
|
17
|
+
text: str
|
|
18
|
+
timestamp: int
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass(frozen=True)
|
|
22
|
+
class ToolUse:
|
|
23
|
+
session_id: str
|
|
24
|
+
message_id: str
|
|
25
|
+
tool: str
|
|
26
|
+
call_id: str
|
|
27
|
+
status: str # "completed", "error", etc.
|
|
28
|
+
input: dict
|
|
29
|
+
output: str
|
|
30
|
+
title: str
|
|
31
|
+
timestamp: int
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True)
|
|
35
|
+
class StepFinish:
|
|
36
|
+
session_id: str
|
|
37
|
+
message_id: str
|
|
38
|
+
reason: str # "stop", "tool-calls"
|
|
39
|
+
input_tokens: int
|
|
40
|
+
output_tokens: int
|
|
41
|
+
reasoning_tokens: int
|
|
42
|
+
cache_read_tokens: int
|
|
43
|
+
cache_write_tokens: int
|
|
44
|
+
cost: float
|
|
45
|
+
timestamp: int
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass(frozen=True)
|
|
49
|
+
class Error:
|
|
50
|
+
session_id: str
|
|
51
|
+
name: str
|
|
52
|
+
message: str
|
|
53
|
+
data: dict
|
|
54
|
+
timestamp: int
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@dataclass(frozen=True)
|
|
58
|
+
class Result:
|
|
59
|
+
session_id: str
|
|
60
|
+
total_input_tokens: int
|
|
61
|
+
total_output_tokens: int
|
|
62
|
+
total_cost: float
|
|
63
|
+
steps: int
|
toolstream/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
toolstream/__init__.py,sha256=Lt50_6y_ZOnxWSSQEsoRPbbfBau_ZPAKvR5MqAxrABU,915
|
|
2
|
+
toolstream/_agent.py,sha256=l3FipLcg_0QszIcekBrq-ORzGbnl2vBcu3fgGOZE7Ls,6550
|
|
3
|
+
toolstream/_builtin_tools.py,sha256=tGYC0iteb1_F_X4iNW20frtucwkBwGCyP7PREk1FCTA,4107
|
|
4
|
+
toolstream/_context.py,sha256=KMFlPW5xqHDLAyps_UfnZOhHA_3lNsWT4UfRxkhNUts,366
|
|
5
|
+
toolstream/_direct.py,sha256=qBCfBjCVLyeFUiCUpo4UP62Jagn453x70kR-r1ny6ho,10300
|
|
6
|
+
toolstream/_invoke.py,sha256=pmvprfovXhzWOWVh0j7ArvAU122HESEmEWohCDT2LW4,3912
|
|
7
|
+
toolstream/_protocol.py,sha256=-hqqJX-xCg7bqQXMCHrjZ4FnWGKsiQ4QdLFQKdXBBII,2514
|
|
8
|
+
toolstream/_schema.py,sha256=qG2zLGXGFU5IYfF6YJRoV-TPEkjjJFQ016DWmNFBuxo,8382
|
|
9
|
+
toolstream/_session.py,sha256=ka5EKQloyYvnQO9_UarVWWWK5HY1brx_f7LOlRDb__0,5724
|
|
10
|
+
toolstream/_tools.py,sha256=nmNKs9l9FwY6v0FTXB1J2gd841pYQafOExbNLADOp2A,3201
|
|
11
|
+
toolstream/config.py,sha256=Gmt_0BTaymbdtQAZaYM_C0LtN9J1l44e4VIMFUE1yB0,711
|
|
12
|
+
toolstream/events.py,sha256=1ECr9gKTBX5JW7XfvuKFNkMABuAk3N9a2yMi3TdNSxQ,1070
|
|
13
|
+
toolstream/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
toolstream-0.1.0.dist-info/METADATA,sha256=zcA1Lg05a1mZhCva9-AoYUvOinJjnbDsvC82nL2PVI4,171
|
|
15
|
+
toolstream-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
16
|
+
toolstream-0.1.0.dist-info/RECORD,,
|