feat: vibed out some slop over here
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
"""Local tool-calling example with token-by-token streaming.
|
||||
|
||||
Flow:
|
||||
1. Declare a `get_weather(city)` tool with a JSON Schema.
|
||||
2. First turn: stream the chat. Print every text delta as it arrives;
|
||||
feed each chunk into `ChatResult.add(chunk)` so tool_calls merge
|
||||
correctly across the chunked wire format.
|
||||
3. If the assistant called a tool, execute it locally and append a
|
||||
`tool` message to history.
|
||||
4. Second turn: stream again — this time the text reply is what we want
|
||||
to see token-by-token.
|
||||
|
||||
Prerequisites: same as basic_usage.py (config.json, RAYCAST_BEARER,
|
||||
RAYCAST_DEVICE_ID).
|
||||
|
||||
Run:
|
||||
python examples/local_tool.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from raycast_api import ChatResult, Client, Config, Message, Tool
|
||||
|
||||
CONFIG_PATH = Path(os.environ.get("RAYCAST_CONFIG", "config.json"))
|
||||
MODEL = os.environ.get("RAYCAST_MODEL", "Claude Sonnet 4.6")
|
||||
|
||||
WEATHER_TOOL = Tool.local(
|
||||
name="get_weather",
|
||||
description="Look up the current weather for a city.",
|
||||
parameters={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {"type": "string", "description": "City name, e.g. 'Tokyo'."},
|
||||
},
|
||||
"required": ["city"],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def get_weather(city: str) -> dict[str, str]:
|
||||
return {"city": city, "temp_c": "18", "conditions": "light rain"}
|
||||
|
||||
|
||||
async def stream_turn(client: Client, history: list[Message]) -> ChatResult:
|
||||
"""Stream one turn, printing text deltas live. Returns the merged result."""
|
||||
result = ChatResult()
|
||||
async for chunk in client.chat.stream(
|
||||
model=MODEL, messages=history, tools=[WEATHER_TOOL]
|
||||
):
|
||||
if chunk.text:
|
||||
print(chunk.text, end="", flush=True)
|
||||
result.add(chunk)
|
||||
print()
|
||||
return result
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
bearer = os.environ.get("RAYCAST_BEARER")
|
||||
device_id = os.environ.get("RAYCAST_DEVICE_ID")
|
||||
if not bearer or not device_id:
|
||||
sys.exit("set RAYCAST_BEARER and RAYCAST_DEVICE_ID before running")
|
||||
if not CONFIG_PATH.is_file():
|
||||
sys.exit(f"no config at {CONFIG_PATH} — run `raycast-api init` first")
|
||||
|
||||
history: list[Message] = [
|
||||
Message.user("What's the weather like in Tokyo right now?")
|
||||
]
|
||||
|
||||
async with Client(
|
||||
config=Config.load(CONFIG_PATH), bearer_token=bearer, device_id=device_id
|
||||
) as client:
|
||||
print("--- turn 1 ---")
|
||||
first = await stream_turn(client, history)
|
||||
|
||||
if not first.tool_calls:
|
||||
return
|
||||
|
||||
for tc in first.tool_calls:
|
||||
print(f" → tool_call: {tc.name}({tc.arguments})")
|
||||
|
||||
history.append(first.to_assistant_message())
|
||||
for call in first.tool_calls:
|
||||
args = json.loads(call.arguments or "{}")
|
||||
if call.name == "get_weather":
|
||||
result: object = get_weather(**args)
|
||||
else:
|
||||
result = {"error": f"unknown tool: {call.name}"}
|
||||
history.append(
|
||||
Message.tool(tool_call_id=call.id, name=call.name, result=result)
|
||||
)
|
||||
|
||||
print("--- turn 2 ---")
|
||||
await stream_turn(client, history)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user