feat: vibed out some slop over here

This commit is contained in:
h
2026-05-19 11:18:37 +02:00
commit 52e7528b86
60 changed files with 9176 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
"""Minimal end-to-end example: load config, send a chat completion, stream one.
Prerequisites:
1. `raycast-api init` has been run (so `config.json` exists next to this file
or at the path you point `--config` to). See the README.
2. `RAYCAST_BEARER` is exported (your Raycast OAuth access token, `rca_...`).
3. `RAYCAST_DEVICE_ID` is exported (any stable 64-hex string; the CLI mints
one on first `ask` and persists it to `~/.config/raycast-api/device_id`,
so a one-liner is: `export RAYCAST_DEVICE_ID=$(cat ~/.config/raycast-api/device_id)`).
Run:
python examples/basic_usage.py
"""
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from raycast_api import Client, Config, Message
CONFIG_PATH = Path(os.environ.get("RAYCAST_CONFIG", "config.json"))
MODEL = os.environ.get("RAYCAST_MODEL", "Claude Sonnet 4.6")
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")
config = Config.load(CONFIG_PATH)
async with Client(
config=config, bearer_token=bearer, device_id=device_id
) as client:
result = await client.chat.complete(
model=MODEL, messages=[Message.user("Reply with the single word: OK")]
)
print(f"[complete] {result.text!r}")
print("[stream] ", end="", flush=True)
async for chunk in client.chat.stream(
model=MODEL, messages=[Message.user("Write a one-line haiku about HMAC.")]
):
if chunk.text:
print(chunk.text, end="", flush=True)
print()
if __name__ == "__main__":
asyncio.run(main())
+103
View File
@@ -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())
+53
View File
@@ -0,0 +1,53 @@
"""Remote tool example — ask something that needs fresh info from the web.
Raycast's `web_search` is server-routed: pass `RemoteTool.WEB_SEARCH` in
`tools=` and that's it. The model decides when to invoke it, the server
runs the search, and the assistant streams the synthesised answer back.
Nothing for the client to execute.
Prerequisites: same as basic_usage.py (config.json, RAYCAST_BEARER,
RAYCAST_DEVICE_ID).
Run:
python examples/web_search.py
"""
from __future__ import annotations
import asyncio
import os
import sys
from pathlib import Path
from raycast_api import Client, Config, Message, RemoteTool
CONFIG_PATH = Path(os.environ.get("RAYCAST_CONFIG", "config.json"))
MODEL = os.environ.get("RAYCAST_MODEL", "Claude Sonnet 4.6")
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")
async with Client(
config=Config.load(CONFIG_PATH), bearer_token=bearer, device_id=device_id
) as client:
result = await client.chat.complete(
model=MODEL,
messages=[
Message.user(
"What's the most recent stable Python release? "
"Reply with just the version number."
)
],
tools=[RemoteTool.WEB_SEARCH],
)
print(result.text)
if __name__ == "__main__":
asyncio.run(main())