Add README and update API URL in Kortix class

- Introduced a new README.md file for the Kortix SDK, detailing installation instructions, quick start examples, and environment setup.
- Updated the default API URL in the Kortix class constructor from `http://localhost:8000/api` to `https://suna.so/api`, ensuring consistency with the production environment.
This commit is contained in:
mykonos-ibiza 2025-08-01 03:30:25 +05:30
parent c94a0becd9
commit 403561f823
6 changed files with 203 additions and 1 deletions

1
sdk/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.kvstore.json

View File

@ -0,0 +1,72 @@
# Kortix SDK
[![Python](https://img.shields.io/badge/python-3.11+-blue.svg)](https://python.org)
A Python SDK that enables you to create, manage, and interact with AI agents on [Suna](https://suna.so).
## 📦 Installation
Install directly from the GitHub repository:
```bash
pip install "kortix @ git+https://github.com/kortix/suna.git@main#subdirectory=sdk"
```
Or using uv:
```bash
uv add "kortix @ git+https://github.com/kortix/suna.git@main#subdirectory=sdk"
```
## 🔧 Quick Start
```python
import asyncio
from kortix import kortix
async def main():
mcp_tools = kortix.MCPTools(
"http://localhost:4000/mcp/", # Point to any HTTP MCP server
"Kortix",
)
await mcp_tools.initialize()
# Initialize the client
client = kortix.Kortix(api_key="your-api-key")
# Create an agent
agent = await client.Agent.create(
name="My Assistant",
system_prompt="You are a helpful AI assistant.",
mcp_tools=[mcp_tools],
allowed_tools=["get_wind_direction"],
)
# Create a conversation thread
thread = await client.Thread.create()
# Run the agent
run = await agent.run("Hello, how are you?", thread)
# Stream the response
stream = await run.get_stream()
async for chunk in stream:
print(chunk, end="")
if __name__ == "__main__":
asyncio.run(main())
```
## 🔑 Environment Setup
Get your API key from [https://suna.so/settings/api-keys](https://suna.so/settings/api-keys)
## 🧪 Running Examples
```bash
# Install dependencies
uv sync
# Run the main example
PYTHONPATH=$(pwd) uv run example/example.py
```

69
sdk/example/example.py Normal file
View File

@ -0,0 +1,69 @@
# Run with `PYTHONPATH=$(pwd) uv run example/example.py`
import asyncio
import os
from kortix import kortix
from kortix.utils import print_stream
from .kv import kv
from .mcp_server import mcp
async def main():
"""
Please ignore the asyncio.exceptions.CancelledError that is thrown when the MCP server is stopped. I couldn't fix it.
"""
# Start the MCP server in the background
asyncio.create_task(
mcp.run_http_async(
show_banner=False, log_level="error", host="0.0.0.0", port=4000
)
)
# Create the MCP tools client with the URL of the MCP server that's accessible by the Suna instance
mcp_tools = kortix.MCPTools(
"http://localhost:4000/mcp/", # Since we are running Suna locally, we can use the local URL
"Kortix",
allowed_tools=["get_wind_direction"],
)
await mcp_tools.initialize()
kortix_client = kortix.Kortix(
os.getenv("KORTIX_API_KEY", "pk_xxx:sk_xxx"),
"http://localhost:8000/api",
)
# Setup the agent
agent_id = kv.get("agent_id")
if not agent_id:
agent = await kortix_client.Agent.create(
name="Generic Agent",
system_prompt="You are a generic agent. You can use the tools provided to you to answer questions.",
mcp_tools=[mcp_tools],
allowed_tools=["get_weather"],
)
kv.set("agent_id", agent._agent_id)
else:
agent = await kortix_client.Agent.get(agent_id)
await agent.update(allowed_tools=["get_weather"])
# Setup the thread
thread_id = kv.get("thread_id")
if not thread_id:
thread = await kortix_client.Thread.create()
kv.set("thread_id", thread._thread_id)
else:
thread = await kortix_client.Thread.get(thread_id)
# Run the agent
agent_run = await agent.run("What is the wind direction in Bangalore?", thread)
stream = await agent_run.get_stream()
await print_stream(stream)
if __name__ == "__main__":
asyncio.run(main())

47
sdk/example/kv.py Normal file
View File

@ -0,0 +1,47 @@
import json
import os
from typing import Any, Optional
from dotenv import load_dotenv
load_dotenv("./.env")
# Local key-value store for storing agent and thread IDs
class LocalKVStore:
def __init__(self, filename: str = ".kvstore.json"):
self.filename = filename
self._data = {}
self._load()
def _load(self):
if os.path.exists(self.filename):
try:
with open(self.filename, "r", encoding="utf-8") as f:
self._data = json.load(f)
except Exception:
self._data = {}
else:
self._data = {}
def _save(self):
with open(self.filename, "w", encoding="utf-8") as f:
json.dump(self._data, f, indent=2)
def get(self, key: str, default: Optional[Any] = None) -> Any:
return self._data.get(key, default)
def set(self, key: str, value: Any):
self._data[key] = value
self._save()
def delete(self, key: str):
if key in self._data:
del self._data[key]
self._save()
def clear(self):
self._data = {}
self._save()
kv = LocalKVStore()

13
sdk/example/mcp_server.py Normal file
View File

@ -0,0 +1,13 @@
from fastmcp import FastMCP
mcp = FastMCP(name="Kortix")
@mcp.tool
async def get_weather(city: str) -> str:
return f"The weather in {city} is windy."
@mcp.tool
async def get_wind_direction(city: str) -> str:
return f"The wind direction in {city} is from the north."

View File

@ -5,7 +5,7 @@ from .tools import AgentPressTools, MCPTools
class Kortix:
def __init__(self, api_key: str, api_url="http://localhost:8000/api"):
def __init__(self, api_key: str, api_url="https://suna.so/api"):
self._agents_client = agents.create_agents_client(api_url, api_key)
self._threads_client = threads.create_threads_client(api_url, api_key)