Skip to content

Commit 047a9e3

Browse files
feat: add simple tools
1 parent 6c1396e commit 047a9e3

6 files changed

Lines changed: 1060 additions & 127 deletions

File tree

README.md

Lines changed: 156 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Edgee Gateway SDK
22

3-
Lightweight Python SDK for Edgee AI Gateway.
3+
Lightweight Python SDK for Edgee AI Gateway with built-in tool execution support.
44

55
## Installation
66

@@ -11,6 +11,7 @@ pip install edgee
1111
## Usage
1212

1313
```python
14+
import os
1415
from edgee import Edgee
1516

1617
edgee = Edgee(os.environ.get("EDGEE_API_KEY"))
@@ -41,7 +42,100 @@ response = edgee.send(
4142
)
4243
```
4344

44-
### With Tools
45+
## Tools
46+
47+
The SDK supports two modes for working with tools:
48+
49+
### Simple Mode: Automatic Tool Execution
50+
51+
Use the `Tool` class with Pydantic models for automatic tool execution. The SDK will handle the entire agentic loop for you:
52+
53+
```python
54+
from pydantic import BaseModel
55+
from edgee import Edgee, Tool
56+
57+
edgee = Edgee(os.environ.get("EDGEE_API_KEY"))
58+
59+
# Define tool parameters with Pydantic
60+
class WeatherParams(BaseModel):
61+
location: str
62+
63+
# Define the tool handler
64+
def get_weather(params: WeatherParams) -> dict:
65+
# Your implementation here
66+
return {"temperature": 22, "condition": "sunny", "location": params.location}
67+
68+
# Create the tool
69+
weather_tool = Tool(
70+
name="get_weather",
71+
description="Get the current weather for a location",
72+
schema=WeatherParams,
73+
handler=get_weather,
74+
)
75+
76+
# The SDK automatically:
77+
# 1. Sends the request with tools
78+
# 2. Executes tools when the model requests them
79+
# 3. Sends results back to the model
80+
# 4. Returns the final response
81+
response = edgee.send(
82+
model="gpt-4o",
83+
input="What's the weather in Paris?",
84+
tools=[weather_tool],
85+
)
86+
87+
print(response.text)
88+
# "The weather in Paris is sunny with a temperature of 22°C."
89+
```
90+
91+
#### Multiple Tools
92+
93+
```python
94+
from typing import Literal
95+
from pydantic import BaseModel
96+
97+
class CalculatorParams(BaseModel):
98+
operation: Literal["add", "subtract", "multiply", "divide"]
99+
a: float
100+
b: float
101+
102+
def calculate(params: CalculatorParams) -> dict:
103+
ops = {
104+
"add": params.a + params.b,
105+
"subtract": params.a - params.b,
106+
"multiply": params.a * params.b,
107+
"divide": params.a / params.b if params.b != 0 else "Error: division by zero",
108+
}
109+
return {"result": ops[params.operation]}
110+
111+
calculator_tool = Tool(
112+
name="calculate",
113+
description="Perform arithmetic operations",
114+
schema=CalculatorParams,
115+
handler=calculate,
116+
)
117+
118+
response = edgee.send(
119+
model="gpt-4o",
120+
input="What's 25 * 4, and what's the weather in London?",
121+
tools=[weather_tool, calculator_tool],
122+
)
123+
```
124+
125+
#### Configuration Options
126+
127+
```python
128+
response = edgee.send(
129+
model="gpt-4o",
130+
input="Complex query requiring multiple tool calls",
131+
tools=[tool1, tool2],
132+
max_tool_iterations=15, # Default: 10
133+
)
134+
```
135+
136+
### Advanced Mode: Manual Tool Handling
137+
138+
For full control over tool execution, use the advanced mode with raw tool definitions:
45139

46140
```python
47141
response = edgee.send(
@@ -67,13 +161,13 @@ response = edgee.send(
67161
},
68162
)
69163

164+
# Handle tool calls manually
70165
if response.tool_calls:
71166
print(response.tool_calls)
167+
# Execute tools and send results back...
72168
```
73169

74-
### Streaming
75-
76-
Access chunk properties for streaming:
170+
## Streaming
77171

78172
```python
79173
for chunk in edgee.stream(model="gpt-4o", input="Tell me a story"):
@@ -89,45 +183,41 @@ for chunk in edgee.send(model="gpt-4o", input="Tell me a story", stream=True):
89183
print(chunk.text, end="", flush=True)
90184
```
91185

92-
#### Accessing Full Chunk Data
93-
94-
When you need complete access to the streaming response:
95-
96-
```python
97-
for chunk in edgee.stream(model="gpt-4o", input="Hello"):
98-
if chunk.role:
99-
print(f"Role: {chunk.role}")
100-
if chunk.text:
101-
print(chunk.text, end="", flush=True)
102-
if chunk.finish_reason:
103-
print(f"\nFinish: {chunk.finish_reason}")
104-
```
105-
106186
## Response
107187

108188
```python
109189
@dataclass
110190
class SendResponse:
111191
choices: list[Choice]
112-
usage: Optional[Usage]
192+
usage: Usage | None
113193

114-
# Convenience properties for easy access
115-
text: str | None # Shortcut for choices[0].message["content"]
116-
message: dict | None # Shortcut for choices[0].message
117-
finish_reason: str | None # Shortcut for choices[0].finish_reason
118-
tool_calls: list | None # Shortcut for choices[0].message["tool_calls"]
194+
# Convenience properties
195+
text: str | None # choices[0].message["content"]
196+
message: dict | None # choices[0].message
197+
finish_reason: str | None # choices[0].finish_reason
198+
tool_calls: list | None # choices[0].message["tool_calls"]
119199

120200
@dataclass
121201
class Choice:
122202
index: int
123203
message: dict # {"role": str, "content": str | None, "tool_calls": list | None}
124204
finish_reason: str | None
125205

206+
@dataclass
207+
class InputTokenDetails:
208+
cached_tokens: int
209+
210+
@dataclass
211+
class OutputTokenDetails:
212+
reasoning_tokens: int
213+
126214
@dataclass
127215
class Usage:
128216
prompt_tokens: int
129217
completion_tokens: int
130218
total_tokens: int
219+
input_tokens_details: InputTokenDetails
220+
output_tokens_details: OutputTokenDetails
131221
```
132222

133223
### Streaming Response
@@ -137,10 +227,10 @@ class Usage:
137227
class StreamChunk:
138228
choices: list[StreamChoice]
139229

140-
# Convenience properties for easy access
141-
text: str | None # Shortcut for choices[0].delta.content
142-
role: str | None # Shortcut for choices[0].delta.role
143-
finish_reason: str | None # Shortcut for choices[0].finish_reason
230+
# Convenience properties
231+
text: str | None # choices[0].delta.content
232+
role: str | None # choices[0].delta.role
233+
finish_reason: str | None # choices[0].finish_reason
144234

145235
@dataclass
146236
class StreamChoice:
@@ -150,9 +240,44 @@ class StreamChoice:
150240

151241
@dataclass
152242
class StreamDelta:
153-
role: str | None # Only present in first chunk
243+
role: str | None
154244
content: str | None
155245
tool_calls: list[dict] | None
156246
```
157247

158-
To learn more about this SDK, please refer to the [dedicated documentation](https://www.edgee.cloud/docs/sdk/python).
248+
## API Reference
249+
250+
### `Tool` Class
251+
252+
```python
253+
from pydantic import BaseModel
254+
from edgee import Tool
255+
256+
class MyParams(BaseModel):
257+
param1: str
258+
param2: int
259+
260+
tool = Tool(
261+
name="my_tool", # Unique tool name
262+
description="...", # Tool description for the model
263+
schema=MyParams, # Pydantic model for parameters
264+
handler=my_function, # Function to execute
265+
)
266+
267+
# Methods
268+
tool.to_dict() # Convert to OpenAI tool format
269+
tool.execute(args) # Validate and execute handler
270+
```
271+
272+
### `create_tool` Helper
273+
274+
```python
275+
from edgee import create_tool
276+
277+
tool = create_tool(
278+
name="my_tool",
279+
schema=MyParams,
280+
handler=my_function,
281+
description="...",
282+
)
283+
```

0 commit comments

Comments
 (0)