# GAME SDK

## Overview

This library enables the creation of AI agents, in which actions are defined by the creator/developer. These agents can be used:
- Worker Mode: to autonomously execute tasks through interaction with the agent. User interaction and tasks is required for the agent to execute tasks. For example, "Bring me some fruits and then go sit on the chair".
- Agent Mode: to autonomously function in an open-ended manner by just providing a general goal. The agent independently and continuously decides tasks for itself in an open-ended manner, and attempts to complete them.


## Core Features

### 1. Functions and Executables

Functions define available actions for the agent:

```python
my_function = Function(
    fn_name="action_name",
    fn_description="Description of action",
    args=[Argument(name="param", type="type", description="param description")],
    executable=function_implementation
)
```
Executable functions must return a tuple of:
- FunctionResultStatus
- Message string
- Additional info dictionary


### 2. State Management

Easy and flexible way to define the state management, what the agent sees and how that changes.

```python
def get_state_fn(function_result: FunctionResult, current_state: dict) -> dict:
    """
    Updates state based on function execution results
    
    Args:
        function_result: Result from last executed function
        current_state: Current state dictionary or None for initialization
        
    Returns:
        Updated state dictionary
    """
    if current_state is None:
        return initial_state
    
    # Update state based on function_result.info
    new_state = update_state(current_state, function_result)
    return new_state
```

Key features:
- Can be shared or unique per worker
- Processes function execution results to update state

### 3. Workers
Workers are simple interactiable agents that execute the tasks defined by the user. They can be specialized agents with defined capabilities:

```python
worker = Worker(
    api_key="your_api_key",
    description="Worker description",
    instruction="Default instructions",
    get_state_fn=state_function,
    action_space=[list_of_functions]
)

worker.run("Bring me some fruits")
```



### 4. Agents

Agents are used to autonomously function in an open-ended manner by just providing a general goal. Tasks are generated by the agent itself continuously, and the agent will attempt to complete them. You can provide many workers to the agent, and they will be used to execute the tasks.

```python
agent = Agent(
    api_key="your_api_key",
    name="Agent Name",
    agent_goal="Primary goal",
    agent_description="Description",
    get_agent_state_fn=agent_state_function,
    workers=[worker1, worker2]
)

# Compile and run
agent.compile()
agent.run()
```

Use WorkerConfig for agent composition:

```python
worker_config = WorkerConfig(
    id="worker_id",
    worker_description="Description",
    get_state_fn=state_function,
    action_space=[function1, function2]
)
```

You can also access and obtain an individual worker from the agent:

```python
worker = agent.get_worker("worker_id")

worker.run("Bring me some fruits")
```

### 5. Chat Agents

Chat Agents enable interactive conversations with AI agents that can execute functions. They are simpler to use than full Agents and are ideal for chatbot-like interactions where the agent can perform actions.

```python
# Initialize the chat agent
chat_agent = ChatAgent(
    prompt="You are helpful assistant",
    api_key="your_api_key"
)

# Define functions
```python
def generate_picture(prompt: str):
    # Implementation
    return FunctionResultStatus.DONE, "Picture generated", {}

action_space = [
    Function(
        fn_name="generate_picture",
        fn_description="Generate a picture",
        args=[Argument(name="prompt", description="The prompt for the picture")],
        executable=generate_picture
    )
]

# Create a chat session
chat = chat_agent.create_chat(
    partner_id="user123",
    partner_name="User Name",
    action_space=[list_of_functions],  # Optional
    get_state_fn=lambda: {...}  # Optional, allows to push state of the environment to the agent
)

# Run conversation
chat_continue = True
while chat_continue:
    user_message = input("Enter a message: ")
    response = chat.next(user_message)
    ...
    if response.is_finished:
        chat_continue = False

# End chat
chat.end("Optional ending message")
```

### Chat Termination

The chat can be terminated in two ways:

1. **Agent-initiated**: The agent may decide to end the chat on its own when it determines the conversation is complete. In this case, `chat.next()` will return `False`.

2. **Client-initiated**: The client can manually end the chat at any time by calling:
```python
chat.end("Optional farewell message")
```

### Chat Memory

ChatAgent maintains a simple short-term memory by keeping track of recent messages in the conversation. This allows the agent to maintain context and provide coherent responses based on the conversation history. The memory is temporary and limited to the current chat session.

