Metadata-Version: 2.3
Name: dagent
Version: 0.0.4
Summary: AI Agents as DAGs - Directed Acyclic Graphs
Author-email: Parth Sareen <parth@extensible.dev>
Requires-Python: >=3.8
Requires-Dist: litellm>=1.44.0
Description-Content-Type: text/markdown

# DAGent - Directed Acyclic Graphs (DAGs) as AI Agents
![Dagent Logo](DagentLogo.png)

*DAGent is a Python library to create AI Agents quickly*

## How to Use

### Dagent Diagram
![DAGent Diagram](dagent/examples/diagram.jpeg)

The idea behind dagent is to structure AI agents in to a workflow. This is done through setting each function up as a node in a graph. 

The agentic behavior is through the inferring of what function to run through the use of LLMs which is abstracted by a "Decision Node".


### DAGent basics 

`DecisionNode`
- This is where the llm picks a function to run from given options
- The `.compile()` method autogenerates and saves tool descriptions run with param `force_load=True` if there are errors or if an option of tool changes

`FunctionNode`
- Runs a python function
- Can be attached to a `DecisionNode` to be treated as a tool and allow an LLM to choose what to run

### Install the lib 
`pip install dagent`


### Example Usage
See [dagent/examples/simple_agent.py](dagent/examples/simple_agent.py) for more info

1. Put all functions to be run into nodes

```python
def add_two_nums(a: int, b: int) -> int:
    return a + b

add_two_nums_node = FunctionNode(func=add_two_nums)
```
2. If you want any decision making steps, each needs to be a node

```python
decision_node1 = DecisionNode()
# decision_node2 = DecisionNode()
```

2. Link the appropriate nodes together

The compile method will link it appropriately

```python
decision_node1.next_nodes = [
    add_two_nums_node,
    multiply_two_nums_node,
]
```

3. Run the `.compile()` method

- Make sure to run this on the first function, the rest will get compiled as well
- It will save json for the tools it has compiled for the attached functions
```python
decision_node1.compile()
```

4. Run the entry function
```python
decision_node1.run()
```


### Other things to know

- `prev_output` is needed in the function signature if you want to use the value from the prior function's value. Obviously the prior function should have returned something for this to work
- Args can be overriden at any time using the following (this merges the kwargs in the background with priority to the user):
```python
add_two_nums_node.user_params = {
    a : 10
}
```

#### Side Effects
<!-- TODO -->


## Motivation

- I found it difficult to use existing libraries and spend the extra time learning a framework to build an "agent"
- Was spending too much time reading their docs and writing agents manually was just faster
- So I built a framework to deal with all the things I didn't like about agents and help me structure code to be build agents quickly


## Things I am looking into (I have lots of opinions)
- [ ] Use "layers" to track next nodes instead of linkedlist style - not gonna do this prematurely :)
- [ ] Probably need a way to return a value directly from a top level run function
- [ ] Look if things run in memory and how to isolate for large workflows -> e.g. funcA(funcB(...)) -> funcA(...) -> funcB(...)
- [ ] Side effects/mutations
- [ ] Creating a data model for communication between functions + schema validation -> autogenerate? 
- [ ] Logging
- [ ] Alerting on error
- [x] Add a compile method to derive data models and tool descriptions
- [ ] Docker
- [ ] LLM error
- [ ] Ollama
- [ ] Groq
- [ ] Param passing
- [ ] simple memory

## Acks
Shoutout to:
- [@omkizzy](https://x.com/omkizzy)
- [@kaelan](https://github.com/Oasixer)
