mirror of
https://github.com/aljazceru/goose.git
synced 2025-12-18 14:44:21 +01:00
This builds a prototype FFI for goose rust library which only supports initializing goose agent and sending message, there is no support for tool calling yet in this library.
117 lines
3.5 KiB
Python
117 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Python example for using the Goose FFI interface.
|
|
|
|
This example demonstrates how to:
|
|
1. Load the Goose FFI library
|
|
2. Create an agent with a provider
|
|
3. Add a tool extension
|
|
4. Send messages to the agent
|
|
5. Handle tool calls and responses
|
|
"""
|
|
|
|
import ctypes
|
|
import os
|
|
import platform
|
|
from ctypes import c_char_p, c_bool, c_uint32, c_void_p, Structure, POINTER
|
|
|
|
class ProviderType:
|
|
DATABRICKS = 0
|
|
|
|
# Platform-specific dynamic lib name
|
|
if platform.system() == "Darwin":
|
|
LIB_NAME = "libgoose_ffi.dylib"
|
|
elif platform.system() == "Linux":
|
|
LIB_NAME = "libgoose_ffi.so"
|
|
elif platform.system() == "Windows":
|
|
LIB_NAME = "goose_ffi.dll"
|
|
else:
|
|
raise RuntimeError("Unsupported platform")
|
|
|
|
# Adjust to your actual build output directory
|
|
LIB_PATH = os.path.join(os.path.dirname(__file__), "../../..", "target", "debug", LIB_NAME)
|
|
|
|
# Load library
|
|
goose = ctypes.CDLL(LIB_PATH)
|
|
|
|
# Forward declaration for goose_Agent
|
|
class goose_Agent(Structure):
|
|
pass
|
|
|
|
# Agent pointer type
|
|
goose_AgentPtr = POINTER(goose_Agent)
|
|
|
|
# C struct mappings
|
|
class ProviderConfig(Structure):
|
|
_fields_ = [
|
|
("provider_type", c_uint32),
|
|
("api_key", c_char_p),
|
|
("model_name", c_char_p),
|
|
("host", c_char_p),
|
|
]
|
|
|
|
class AsyncResult(Structure):
|
|
_fields_ = [
|
|
("succeeded", c_bool),
|
|
("error_message", c_char_p),
|
|
]
|
|
|
|
# Function signatures
|
|
goose.goose_agent_new.argtypes = [POINTER(ProviderConfig)]
|
|
goose.goose_agent_new.restype = goose_AgentPtr
|
|
|
|
goose.goose_agent_free.argtypes = [goose_AgentPtr]
|
|
goose.goose_agent_free.restype = None
|
|
|
|
goose.goose_agent_send_message.argtypes = [goose_AgentPtr, c_char_p]
|
|
goose.goose_agent_send_message.restype = c_void_p
|
|
|
|
goose.goose_free_string.argtypes = [c_void_p]
|
|
goose.goose_free_string.restype = None
|
|
|
|
goose.goose_free_async_result.argtypes = [POINTER(AsyncResult)]
|
|
goose.goose_free_async_result.restype = None
|
|
|
|
class GooseAgent:
|
|
def __init__(self, provider_type=ProviderType.DATABRICKS, api_key=None, model_name=None, host=None):
|
|
self.config = ProviderConfig(
|
|
provider_type=provider_type,
|
|
api_key=api_key.encode("utf-8") if api_key else None,
|
|
model_name=model_name.encode("utf-8") if model_name else None,
|
|
host=host.encode("utf-8") if host else None,
|
|
)
|
|
self.agent = goose.goose_agent_new(ctypes.byref(self.config))
|
|
if not self.agent:
|
|
raise RuntimeError("Failed to create Goose agent")
|
|
|
|
def __del__(self):
|
|
if getattr(self, "agent", None):
|
|
goose.goose_agent_free(self.agent)
|
|
|
|
def send_message(self, message: str) -> str:
|
|
msg = message.encode("utf-8")
|
|
response_ptr = goose.goose_agent_send_message(self.agent, msg)
|
|
if not response_ptr:
|
|
return "Error or NULL response from agent"
|
|
response = ctypes.string_at(response_ptr).decode("utf-8")
|
|
# Free the string using the proper C function provided by the library
|
|
# This correctly releases memory allocated by the Rust side
|
|
goose.goose_free_string(response_ptr)
|
|
return response
|
|
|
|
def main():
|
|
api_key = os.getenv("DATABRICKS_API_KEY")
|
|
host = os.getenv("DATABRICKS_HOST")
|
|
agent = GooseAgent(api_key=api_key, model_name="claude-3-7-sonnet", host=host)
|
|
|
|
print("Type a message (or 'quit' to exit):")
|
|
while True:
|
|
user_input = input("> ")
|
|
if user_input.lower() in ("quit", "exit"):
|
|
break
|
|
reply = agent.send_message(user_input)
|
|
print(f"Agent: {reply}\n")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|