mirror of
https://github.com/humanlayer/humanlayer.git
synced 2025-08-20 19:01:22 +03:00
Humanlayer (#19)
* black/ruff still fighting * wip * links and rename * wip to humanlayer * humanlayer
This commit is contained in:
@@ -20,6 +20,15 @@ repos:
|
||||
rev: "v3.0.3"
|
||||
hooks:
|
||||
- id: prettier
|
||||
- repo: https://github.com/tcort/markdown-link-check
|
||||
rev: "v3.12.2"
|
||||
hooks:
|
||||
- id: markdown-link-check
|
||||
args:
|
||||
[
|
||||
--quiet,
|
||||
--ignore=https://platform.openai.com/docs/guides/function-calling,
|
||||
]
|
||||
# - repo: https://github.com/psf/black-pre-commit-mirror
|
||||
# rev: 24.8.0
|
||||
# hooks:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Contributing to FunctionLayer
|
||||
# Contributing to HumanLayer
|
||||
|
||||
If you're looking to contribute, please:
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ RUN --mount=type=cache,target=/root/.cache/pypoetry/cache \
|
||||
poetry install --no-interaction --no-ansi --without dev
|
||||
|
||||
# Copy Python code to the Docker image
|
||||
COPY functionlayer-core /code/functionlayer-core
|
||||
COPY humanlayer /code/humanlayer
|
||||
|
||||
ENTRYPOINT ["functionlayer"]
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
Apache Software License 2.0
|
||||
|
||||
Copyright (c) 2024, functionlayer Authors
|
||||
Copyright (c) 2024, humanlayer Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
2
Makefile
2
Makefile
@@ -69,4 +69,4 @@ test-examples:
|
||||
:
|
||||
: 🧠 OpenAI
|
||||
:
|
||||
docker compose -f examples/openai_client/docker-compose.yaml run examples
|
||||
docker compose -f examples/openai_client/docker-compose.yaml run examples
|
||||
|
||||
48
README.md
48
README.md
@@ -1,12 +1,12 @@
|
||||
<div align="center">
|
||||
|
||||

|
||||

|
||||
|
||||
# **FunctionLayer**
|
||||
# **HumanLayer**
|
||||
|
||||
</div>
|
||||
|
||||
**FunctionLayer**: A python toolkit to enable AI agents to communicate with humans in tool-based and asynchronous workflows. By incorporating humans-in-the-loop, agentic tools can be given access to much more powerful and meaningful tool calls and tasks.
|
||||
**HumanLayer**: A python toolkit to enable AI agents to communicate with humans in tool-based and asynchronous workflows. By incorporating humans-in-the-loop, agentic tools can be given access to much more powerful and meaningful tool calls and tasks.
|
||||
|
||||
Bring your LLM (OpenAI, Llama, Claude, etc) and Framework (LangChain, CrewAI, etc) and start giving your AI agents safe access to the world.
|
||||
|
||||
@@ -14,11 +14,11 @@ Bring your LLM (OpenAI, Llama, Claude, etc) and Framework (LangChain, CrewAI, et
|
||||
|
||||
<h3>
|
||||
|
||||
[Homepage](https://www.functionlayer.ai/) | [Get Started](./docs/getting-started.md) | [Discord](https://discord.gg/KNATT2xK) | [Documentation](./docs) | [Examples](./examples)
|
||||
[Homepage](https://www.humanlayer.dev/) | [Get Started](./docs/getting-started.md) | [Discord](https://discord.gg/KNATT2xK) | [Documentation](./docs) | [Examples](./examples)
|
||||
|
||||
</h3>
|
||||
|
||||
[](https://github.com/functionlayer/functionlayer)
|
||||
[](https://github.com/humanlayer/humanlayer)
|
||||
[](https://opensource.org/licenses/Apache-2)
|
||||
|
||||
</div>
|
||||
@@ -26,7 +26,7 @@ Bring your LLM (OpenAI, Llama, Claude, etc) and Framework (LangChain, CrewAI, et
|
||||
## Table of contents
|
||||
|
||||
- [Getting Started](#getting-started)
|
||||
- [Why FunctionLayer?](#why-functionlayer)
|
||||
- [Why HumanLayer?](#why-humanlayer)
|
||||
- [Key Features](#key-features)
|
||||
- [Examples](#examples)
|
||||
- [Roadmap](#roadmap)
|
||||
@@ -37,29 +37,29 @@ Bring your LLM (OpenAI, Llama, Claude, etc) and Framework (LangChain, CrewAI, et
|
||||
|
||||
To get started, check out [Getting Started](./docs/getting-started.md), watch the [2:30 Getting Started Video](https://www.loom.com/share/97ead4e4a0b84b3dac4fec2ff1b410bf), or jump straight into one of the [Examples](./examples/):
|
||||
|
||||
- 🦜⛓️ [LangChain](./examples/langchain/math_example.py)
|
||||
- 🦜⛓️ [LangChain](./examples/langchain/01-math_example.py)
|
||||
- 🚣 [CrewAI](./examples/crewai/crewai_math.py)
|
||||
- 🦾 [ControlFlow](./examples/controlflow/controlflow_math.py)
|
||||
- 🧠 [Raw OpenAI Client](./examples/openai_client/math_example.py)
|
||||
|
||||
```shell
|
||||
pip install functionlayer-ai
|
||||
pip install humanlayer
|
||||
```
|
||||
|
||||
or for the bleeding edge
|
||||
|
||||
```shell
|
||||
pip install git+https://github.com/functionlayer/functionlayer
|
||||
pip install git+https://github.com/humanlayer/humanlayer-ai-llm-agents
|
||||
```
|
||||
|
||||
Set `FUNCTIONLAYER_API_TOKEN` and wrap your AI function in `require_approval()`
|
||||
Set `HUMANLAYER_API_TOKEN` and wrap your AI function in `require_approval()`
|
||||
|
||||
```python
|
||||
|
||||
from functionlayer import ApprovalMethod, FunctionLayer
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD) # or CLI
|
||||
from humanlayer import ApprovalMethod, HumanLayer
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD) # or CLI
|
||||
|
||||
@fl.require_approval()
|
||||
@hl.require_approval()
|
||||
def send_email(to: str, subject: str, body: str):
|
||||
"""Send an email to the customer"""
|
||||
...
|
||||
@@ -77,9 +77,9 @@ Then you can start manging LLM actions in slack, email, or whatever channel you
|
||||
|
||||
<div align="center"><img style="width: 400px" alt="A screenshot of slack showing a human replying to the bot" src="./docs/images/slack_approval_response.png"></div>
|
||||
|
||||
Check out the [FunctionLayer Docs](./docs/) and the [Getting Started Guide](./docs/getting-started.md) for more information.
|
||||
Check out the [HumanLayer Docs](./docs/) and the [Getting Started Guide](./docs/getting-started.md) for more information.
|
||||
|
||||
## Why FunctionLayer?
|
||||
## Why HumanLayer?
|
||||
|
||||
Functions and tools are a key part of [Agentic Workflows](https://www.deeplearning.ai/the-batch/how-agents-can-improve-llm-performance). They enable LLMs to interact meaningfully with the outside world and automate broad scopes of impactful work. Correct and accurate function calling is essential for AI agents that do meaningful things like book appointments, interact with customers, manage billing information, write+execute code, and more.
|
||||
|
||||
@@ -105,30 +105,30 @@ To better define what is meant by "high stakes", some examples:
|
||||
|
||||
The high stakes functions are the ones that are the most valuable and promise the most impact in automating away human workflows. The sooner teams can get Agents reliably and safely calling these tools, the sooner they can reap massive benefits.
|
||||
|
||||
FunctionLayer provides a set of tools to _deterministically_ guarantee human oversight of high stakes function calls. Even if the LLM makes a mistake or hallucinates, FunctionLayer is baked into the tool/function itself, guaranteeing a human in the loop.
|
||||
HumanLayer provides a set of tools to _deterministically_ guarantee human oversight of high stakes function calls. Even if the LLM makes a mistake or hallucinates, HumanLayer is baked into the tool/function itself, guaranteeing a human in the loop.
|
||||
|
||||
<div align="center"><img style="width: 400px" alt="Function Layer @require_approval decorator wrapping the Commnicate on my behalf function" src="./docs/images/function_layer_require_approval.png"></div>
|
||||
|
||||
<div align="center">
|
||||
<h3><blockquote>
|
||||
FunctionLayer provides a set of tools to *deterministically* guarantee human oversight of high stakes function calls
|
||||
HumanLayer provides a set of tools to *deterministically* guarantee human oversight of high stakes function calls
|
||||
</blockquote></h3>
|
||||
</div>
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Require Human Approval for Function Calls**: the `@fl.require_approval()` decorator blocks specifc function calls until a human has been consulted - upon denial, feedback will be passed to the LLM
|
||||
- **Require Human Approval for Function Calls**: the `@hl.require_approval()` decorator blocks specifc function calls until a human has been consulted - upon denial, feedback will be passed to the LLM
|
||||
- **Human as Tool**: generic `fl.human_as_tool()` allows for contacting a human for answers, advice, or feedback
|
||||
- **OmniChannel Contact**: Contact humans and collect responses across Slack, Email, Discord, and more
|
||||
- **Granular Routing**: Route approvals to specific teams or individuals
|
||||
- **Bring your own LLM + Framework**: Because FunctionLayer is implemented at tools layer, it supports any LLM and all major orchestration frameworks that support tool calling.
|
||||
- **Bring your own LLM + Framework**: Because HumanLayer is implemented at tools layer, it supports any LLM and all major orchestration frameworks that support tool calling.
|
||||
|
||||
## Examples
|
||||
|
||||
You can test different real life examples of FunctionLayer in the [examples folder](./examples/):
|
||||
You can test different real life examples of HumanLayer in the [examples folder](./examples/):
|
||||
|
||||
- 🦜⛓️ [LangChain Math](./examples/langchain/math_example.py)
|
||||
- 🦜⛓️ [LangChain Human As Tool](./examples/langchain/human_as_tool.py)
|
||||
- 🦜⛓️ [LangChain Math](./examples/langchain/01-math_example.py)
|
||||
- 🦜⛓️ [LangChain Human As Tool](./examples/langchain/03-human_as_tool.py)
|
||||
- 🚣 [CrewAI Math](./examples/crewai/crewai_math.py)
|
||||
- 🦾 [ControlFlow Math](./examples/controlflow/controlflow_math.py)
|
||||
- 🧠 [Raw OpenAI Client](./examples/openai_client/math_example.py)
|
||||
@@ -154,8 +154,8 @@ You can test different real life examples of FunctionLayer in the [examples fold
|
||||
|
||||
## Contributing
|
||||
|
||||
FunctionLayer is open-source and we welcome contributions in the form of issues, documentation, pull requests, and more. See [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
|
||||
HumanLayer is open-source and we welcome contributions in the form of issues, documentation, pull requests, and more. See [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
|
||||
|
||||
## License
|
||||
|
||||
The FunctionLayer SDK in this repo is licensed under the Apache 2 License.
|
||||
The HumanLayer SDK in this repo is licensed under the Apache 2 License.
|
||||
|
||||
4
Tiltfile
4
Tiltfile
@@ -1,4 +1,4 @@
|
||||
deps = [
|
||||
'functionlayer/',
|
||||
"humanlayer/",
|
||||
]
|
||||
local_resource('check', cmd='make check test', deps=deps, ignore='**/*pyc*')
|
||||
local_resource("check", cmd="make check test", deps=deps, ignore="**/*pyc*")
|
||||
|
||||
@@ -11,7 +11,7 @@ pip install functionlayer-ai
|
||||
Or, for the bleeding edge:
|
||||
|
||||
```bash
|
||||
pip install git+https://github.com/functionlayer/functionlayer
|
||||
pip install git+https://github.com/humanlayer/humanlayer
|
||||
```
|
||||
|
||||
### Choose an LLM Client and Write your first tool-calling agent
|
||||
@@ -20,10 +20,10 @@ You'll need a short python script that defines a function that you want to gate
|
||||
and an agent+prompt that will execute the function.
|
||||
There are a number of different examples you can start from, including:
|
||||
|
||||
- 🦜⛓️ [LangChain Math](./examples/langchain/math_example.py)
|
||||
- 🚣 [CrewAI Math](./examples/crewai/crewai_math.py)
|
||||
- 🦾 [ControlFlow Math](./examples/controlflow/controlflow_math.py)
|
||||
- 🧠 [Raw OpenAI Client](./examples/openai_client/math_example.py)
|
||||
- 🦜⛓️ [LangChain Math](../examples/langchain/01-math_example.py)
|
||||
- 🚣 [CrewAI Math](../examples/crewai/crewai_math.py)
|
||||
- 🦾 [ControlFlow Math](../examples/controlflow/controlflow_math.py)
|
||||
- 🧠 [Raw OpenAI Client](../examples/openai_client/math_example.py)
|
||||
|
||||
We'll use LangChain and OpenAI here since it's fairly succinct for this use case.
|
||||
|
||||
@@ -105,7 +105,7 @@ The result of multiplying 2 and 5, then adding 32 to the result, is 42.
|
||||
|
||||
```
|
||||
|
||||
### Wrap a function with functionlayer
|
||||
### Wrap a function with humanlayer
|
||||
|
||||
Once you've run the example and verified it works, it's time to wrap the function with FunctionLayer.
|
||||
Add the following to the top of your file:
|
||||
@@ -116,8 +116,8 @@ from langchain.agents import AgentType
|
||||
from langchain.tools import tool
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
+ from functionlayer import FunctionLayer
|
||||
+ fl = FunctionLayer()
|
||||
+ from humanlayer import HumanLayer
|
||||
+ hl = HumanLayer()
|
||||
|
||||
|
||||
@tool
|
||||
@@ -132,11 +132,11 @@ def multiply(x: int, y: int) -> int:
|
||||
return x * y
|
||||
```
|
||||
|
||||
and then wrap your `multiply` function with `@fl.require_approval()`:
|
||||
and then wrap your `multiply` function with `@hl.require_approval()`:
|
||||
|
||||
```diff
|
||||
from functionlayer import FunctionLayer
|
||||
fl = FunctionLayer()
|
||||
from humanlayer import HumanLayer
|
||||
hl = HumanLayer()
|
||||
|
||||
|
||||
@tool
|
||||
@@ -146,7 +146,7 @@ def add(x: int, y: int) -> int:
|
||||
|
||||
|
||||
@tool
|
||||
+ @fl.require_approval()
|
||||
+ @hl.require_approval()
|
||||
def multiply(x: int, y: int) -> int:
|
||||
"""multiply two numbers"""
|
||||
return x * y
|
||||
@@ -172,7 +172,7 @@ def add(x: int, y: int) -> int:
|
||||
|
||||
|
||||
@tool
|
||||
@fl.require_approval()
|
||||
@hl.require_approval()
|
||||
def multiply(x: int, y: int) -> int:
|
||||
"""multiply two numbers"""
|
||||
return x * y
|
||||
@@ -268,7 +268,7 @@ Navigate to the Approval Queue and click the Status button to approve the functi
|
||||
|
||||
### Connect Slack
|
||||
|
||||
Web approvals are a start, but FunctionLayer really shines when you connect your slack instance. See [configuring slack](./configuring_slack.md) for more information on how to do this, and then you can
|
||||
Web approvals are a start, but FunctionLayer really shines when you connect your slack instance. See [configuring slack](./configuring-slack.md) for more information on how to do this, and then you can
|
||||
|
||||
### Try a Human as tool
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
BIN
docs/images/humanlayer-logo.png
Normal file
BIN
docs/images/humanlayer-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -18,7 +18,7 @@ Table of Contents:
|
||||
- [Features](#features)
|
||||
- [Function Decorators](#function-decorators)
|
||||
- [Human as Tool](#human-as-tool)
|
||||
- [Functionlayer CLI](#functionlayer-cli)
|
||||
- [Functionlayer CLI](#cli-mode)
|
||||
- [Functionlayer Cloud](#functionlayer-cloud)
|
||||
- [Reference](#reference)
|
||||
|
||||
@@ -26,12 +26,12 @@ Table of Contents:
|
||||
|
||||
**[Getting Started Guide](./getting-started.md)**
|
||||
|
||||
To get started, check out [Getting Started](./getting-started.md) or jump straight into one of the [Examples](../examples/):
|
||||
To get started, check out [Getting Started](./getting-started.md) or jump straight into one of the [Examples](../examples):
|
||||
|
||||
- 🦜⛓️ [LangChain](./examples/langchain/math_example.py)
|
||||
- 🚣 [CrewAI](./examples/crewai/crewai_math.py)
|
||||
- 🦾 [ControlFlow](./examples/controlflow/controlflow_math.py)
|
||||
- 🧠 [Raw OpenAI Client](./examples/openai_client/math_example.py)
|
||||
- 🦜⛓️ [LangChain](../examples/langchain/)
|
||||
- 🚣 [CrewAI](../examples/crewai/)
|
||||
- 🦾 [ControlFlow](../examples/controlflow/)
|
||||
- 🧠 [Raw OpenAI Client](../examples/openai_client/)
|
||||
|
||||
## Concepts
|
||||
|
||||
@@ -98,7 +98,7 @@ The High stakes functions are the ones that are the most valuable and promise th
|
||||
FunctionLayer provides a set of decorators that can be used to add approval requirements to specific functions.
|
||||
|
||||
```python
|
||||
@fl.require_approval()
|
||||
@hl.require_approval()
|
||||
def send_email(to: str, subject: str, body: str):
|
||||
"""Send an email to the customer"""
|
||||
...
|
||||
@@ -119,7 +119,7 @@ In addition to gating function calls, FunctionLayer can also provide a more gene
|
||||
```python
|
||||
from functionlayer import ApprovalMethod, ContactChannel, FunctionLayer, SlackContactChannel
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
customer_success_direct_message = ContactChannel(
|
||||
slack=SlackContactChannel(
|
||||
@@ -185,17 +185,17 @@ fl_sales = FunctionLayer(
|
||||
contact_channel=dm_sales,
|
||||
)
|
||||
|
||||
@fl_default.require_approval() # uses project default contact channel
|
||||
@hl_default.require_approval() # uses project default contact channel
|
||||
def send_email(to: str, subject: str, body: str):
|
||||
"""Send an email to the customer"""
|
||||
...
|
||||
|
||||
@fl_sales.require_approval() # uses the sales contact channel
|
||||
@hl_sales.require_approval() # uses the sales contact channel
|
||||
def update_crm_record(opportunity_id: str, status: str):
|
||||
"""Update the CRM record for the opportunity"""
|
||||
...
|
||||
|
||||
@fl_default.require_approval(dm_engineering) # uses the engineering contact channel
|
||||
@hl_default.require_approval(dm_engineering) # uses the engineering contact channel
|
||||
def drop_production_database(database_name: str):
|
||||
"""Drop the specified database"""
|
||||
...
|
||||
@@ -230,9 +230,9 @@ import os
|
||||
|
||||
from functionlayer import FunctionLayer
|
||||
|
||||
fl = FunctionLayer(api_token=os.getenv("FUNCTIONLAYER_API_TOKEN"))
|
||||
hl = HumanLayer(api_token=os.getenv("FUNCTIONLAYER_API_TOKEN"))
|
||||
|
||||
@fl.require_approval()
|
||||
@hl.require_approval()
|
||||
def send_email_to_customer(email: str, subject: str, body: str) -> str:
|
||||
"""
|
||||
send an email to the customer
|
||||
@@ -257,7 +257,7 @@ head_of_sales = ContactChannel(
|
||||
)
|
||||
)
|
||||
|
||||
@fl.require_approval(head_of_sales)
|
||||
@hl.require_approval(head_of_sales)
|
||||
def send_email_to_customer(email: str, subject: str, body: str) -> str:
|
||||
...
|
||||
```
|
||||
@@ -268,7 +268,7 @@ In addition to blocking function execution based on human feedback, functionlaye
|
||||
|
||||
```python
|
||||
from functionlayer import ContactChannel, FunctionLayer, SlackContactChannel
|
||||
fl = FunctionLayer()
|
||||
hl = HumanLayer()
|
||||
|
||||
tools = [
|
||||
fl.human_as_tool(
|
||||
@@ -296,7 +296,7 @@ this builds a function that can be passed to `langchain.tools.StructuredTool.fro
|
||||
contact_human_in_a_dm_with_the_head_of_sales(msg: str) -> str
|
||||
```
|
||||
|
||||
See [Langchain Human as Tool Example](../examples/langchain_human_as_tool.py) for an example of how to use this in a Langchain context.
|
||||
See [Langchain Human as Tool Example](../examples/langchain/03-human_as_tool.py) for an example of how to use this in a Langchain context.
|
||||
|
||||
### Functionlayer Cloud
|
||||
|
||||
@@ -312,7 +312,7 @@ then initialize FunctionLayer with `ApprovalMethod.CLOUD`
|
||||
|
||||
```python
|
||||
from functionlayer import ApprovalMethod, FunctionLayer
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
```
|
||||
|
||||
See [Getting Started](./getting-started.md) for more information on how to set up and use FunctionLayer Cloud.
|
||||
@@ -333,14 +333,14 @@ to run in CLI mode, initialize FunctionLayer with `ApprovalMethod.CLI`
|
||||
|
||||
from functionlayer import FunctionLayer, ApprovalMethod
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLI)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLI)
|
||||
|
||||
```
|
||||
|
||||
Then, you can decorate your functions as normal.
|
||||
|
||||
```python
|
||||
@fl.require_approval()
|
||||
@hl.require_approval()
|
||||
def send_email_to_customer(email: str, subject: str, body: str) -> str:
|
||||
"""
|
||||
send an email to the customer
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
venv/
|
||||
.venv/
|
||||
.venv/
|
||||
|
||||
@@ -11,4 +11,4 @@ RUN pip install \
|
||||
COPY . /app
|
||||
|
||||
ENTRYPOINT ["python3"]
|
||||
CMD ["controlflow_math.py"]
|
||||
CMD ["controlflow_math.py"]
|
||||
|
||||
@@ -11,7 +11,6 @@ Activate a new virtualenv however you prefer
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
python controlflow_math.py
|
||||
```
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from functionlayer import ApprovalMethod, FunctionLayer
|
||||
from functionlayer import ApprovalMethod, HumanLayer
|
||||
|
||||
load_dotenv()
|
||||
|
||||
import controlflow as cf
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
|
||||
def add(x: int, y: int) -> int:
|
||||
@@ -15,7 +15,7 @@ def add(x: int, y: int) -> int:
|
||||
|
||||
|
||||
# multiply must be approved via email by a user in the admin group
|
||||
@fl.require_approval()
|
||||
@hl.require_approval()
|
||||
def multiply(x: int, y: int) -> int:
|
||||
"""multiply two numbers"""
|
||||
return x * y
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
version: '3.7'
|
||||
version: "3.7"
|
||||
services:
|
||||
examples:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- ./:/app
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
venv/
|
||||
.venv/
|
||||
.venv/
|
||||
|
||||
2
examples/crewai/.gitignore
vendored
2
examples/crewai/.gitignore
vendored
@@ -1 +1 @@
|
||||
emails.md
|
||||
emails.md
|
||||
|
||||
@@ -12,4 +12,4 @@ RUN pip install \
|
||||
COPY . /app
|
||||
|
||||
ENTRYPOINT ["python3"]
|
||||
CMD ["crewai_math.py"]
|
||||
CMD ["crewai_math.py"]
|
||||
|
||||
@@ -13,7 +13,6 @@ Activate a new virtualenv however you prefer
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
python crewai_math.py
|
||||
```
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
from crewai import Agent, Crew, Task
|
||||
from crewai_tools import tool
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from functionlayer import ApprovalMethod, HumanLayer
|
||||
|
||||
load_dotenv()
|
||||
|
||||
from functionlayer import ApprovalMethod, FunctionLayer
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
PROMPT = """multiply 2 and 5, then add 32 to the result"""
|
||||
|
||||
|
||||
@@ -1,40 +1,37 @@
|
||||
from crewai import Agent, Crew, Task
|
||||
from crewai_tools import tool
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
from functionlayer import ApprovalMethod, FunctionLayer
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
task_prompt = """
|
||||
|
||||
Your task is to check the list of recently signed up customers, get info about their onboarding progress,
|
||||
and send each one an email to encourage them to complete the onboarding process. You should
|
||||
and send each one an email to encourage them to complete the onboarding process. You should
|
||||
offer a meeting to help them where it makes sense.
|
||||
|
||||
If they are fully onboard, you should simply request feedback and offer a meeting.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@tool
|
||||
def get_recently_signed_up_customers() -> list[str]:
|
||||
"""get a list of customers that signed up recently"""
|
||||
return [
|
||||
"danny@metacorp.com",
|
||||
"terri@acmestuff.com"
|
||||
]
|
||||
return ["danny@metacorp.com", "terri@acmestuff.com"]
|
||||
|
||||
|
||||
@tool
|
||||
def get_info_about_customer(customer_email: str) -> str:
|
||||
"""get info about a customer"""
|
||||
if customer_email == "danny@metacorp.com":
|
||||
|
||||
return """
|
||||
This customer has completed most of the onboarding steps,
|
||||
but still needs to invite a few team members before they can be
|
||||
but still needs to invite a few team members before they can be
|
||||
considered fully onboarded
|
||||
"""
|
||||
else:
|
||||
@@ -47,23 +44,25 @@ def send_email(to: str, subject: str, body: str) -> str:
|
||||
"""Send an email to a user"""
|
||||
|
||||
# write to a local file so we can inspect after
|
||||
with open ("emails.md", "a") as f:
|
||||
f.write(f"""{subject}
|
||||
with open("emails.md", "a") as f:
|
||||
f.write(
|
||||
f"""{subject}
|
||||
=============
|
||||
|
||||
To: {to}
|
||||
* * *
|
||||
* * *
|
||||
|
||||
{body}
|
||||
|
||||
* * *\n\n\n\n""")
|
||||
* * *\n\n\n\n"""
|
||||
)
|
||||
|
||||
return f"Email sent to {to} with subject: {subject}"
|
||||
|
||||
|
||||
general_agent = Agent(
|
||||
role="Onboarding Agent",
|
||||
goal="""Ensure all customers of the SaaS product, SuperCI, are onboarded successfully and
|
||||
goal="""Ensure all customers of the SaaS product, SuperCI, are onboarded successfully and
|
||||
getting value from all features.""",
|
||||
backstory="""
|
||||
You are a seasoned customer success agent. You check on the progress customers
|
||||
@@ -85,9 +84,11 @@ task = Task(
|
||||
|
||||
crew = Crew(agents=[general_agent], tasks=[task], verbose=2)
|
||||
|
||||
|
||||
def main():
|
||||
return crew.kickoff()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = main()
|
||||
print("\n\n---------- RESULT ----------\n\n")
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
from channels import dm_with_head_of_marketing
|
||||
from crewai import Agent, Crew, Task
|
||||
from crewai_tools import tool
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from channels import dm_with_head_of_marketing
|
||||
|
||||
load_dotenv()
|
||||
|
||||
from functionlayer import ApprovalMethod, FunctionLayer
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
task_prompt = """
|
||||
|
||||
Your task is to check the list of recently signed up customers, get info about their onboarding progress,
|
||||
and send each one an email to encourage them to complete the onboarding process. You should
|
||||
and send each one an email to encourage them to complete the onboarding process. You should
|
||||
offer a meeting to help them where it makes sense.
|
||||
|
||||
If they are fully onboard, you should simply request feedback and offer a meeting.
|
||||
@@ -23,22 +21,20 @@ Get approval from the head of marketing before sending
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@tool
|
||||
def get_recently_signed_up_customers() -> list[str]:
|
||||
"""get a list of customers that signed up recently"""
|
||||
return [
|
||||
"danny@metacorp.com",
|
||||
"terri@acmestuff.com"
|
||||
]
|
||||
return ["danny@metacorp.com", "terri@acmestuff.com"]
|
||||
|
||||
|
||||
@tool
|
||||
def get_info_about_customer(customer_email: str) -> str:
|
||||
"""get info about a customer"""
|
||||
if customer_email == "danny@metacorp.com":
|
||||
|
||||
return """
|
||||
This customer has completed most of the onboarding steps,
|
||||
but still needs to invite a few team members before they can be
|
||||
but still needs to invite a few team members before they can be
|
||||
considered fully onboarded
|
||||
"""
|
||||
else:
|
||||
@@ -51,16 +47,18 @@ def send_email(to: str, subject: str, body: str) -> str:
|
||||
"""Send an email to a user"""
|
||||
|
||||
# write to a local file so we can inspect after
|
||||
with open ("emails.md", "a") as f:
|
||||
f.write(f"""{subject}
|
||||
with open("emails.md", "a") as f:
|
||||
f.write(
|
||||
f"""{subject}
|
||||
=============
|
||||
To: {to}
|
||||
* * *
|
||||
* * *
|
||||
|
||||
{body}
|
||||
|
||||
* * *
|
||||
""")
|
||||
* * *
|
||||
"""
|
||||
)
|
||||
|
||||
return f"Email sent to {to} with subject: {subject}"
|
||||
|
||||
@@ -93,9 +91,11 @@ task = Task(
|
||||
|
||||
crew = Crew(agents=[general_agent], tasks=[task], verbose=2)
|
||||
|
||||
|
||||
def main():
|
||||
return crew.kickoff()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = main()
|
||||
print("\n\n---------- RESULT ----------\n\n")
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
version: '3.7'
|
||||
version: "3.7"
|
||||
services:
|
||||
examples:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- ./:/app
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
venv/
|
||||
.venv/
|
||||
.venv/
|
||||
|
||||
2
examples/langchain/.gitignore
vendored
2
examples/langchain/.gitignore
vendored
@@ -1 +1 @@
|
||||
emails.md
|
||||
emails.md
|
||||
|
||||
@@ -13,7 +13,7 @@ from functionlayer import FunctionLayer
|
||||
|
||||
load_dotenv()
|
||||
|
||||
fl = FunctionLayer()
|
||||
hl = HumanLayer()
|
||||
|
||||
|
||||
@tool
|
||||
|
||||
@@ -8,11 +8,11 @@ from langchain.agents import AgentType, initialize_agent
|
||||
from langchain.tools import tool
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
from functionlayer.core.approval import ApprovalMethod, FunctionLayer
|
||||
from functionlayer.core.approval import ApprovalMethod, HumanLayer
|
||||
|
||||
load_dotenv()
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
|
||||
@tool
|
||||
@@ -39,10 +39,12 @@ agent = initialize_agent(
|
||||
handle_parsing_errors=True,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
result = agent.run("multiply 2 and 5, then add 32 to the result")
|
||||
print("\n\n----------Result----------\n\n")
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -8,11 +8,11 @@ from langchain.agents import AgentType, initialize_agent
|
||||
from langchain.tools import tool
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
from functionlayer import ApprovalMethod, FunctionLayer
|
||||
from functionlayer import ApprovalMethod, HumanLayer
|
||||
|
||||
load_dotenv()
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
|
||||
@tool
|
||||
|
||||
@@ -3,11 +3,16 @@ from dotenv import load_dotenv
|
||||
from langchain.agents import AgentType, initialize_agent
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
from functionlayer import ApprovalMethod, ContactChannel, FunctionLayer, SlackContactChannel
|
||||
from functionlayer import (
|
||||
ApprovalMethod,
|
||||
ContactChannel,
|
||||
HumanLayer,
|
||||
SlackContactChannel,
|
||||
)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
task_prompt = """
|
||||
figure out the wizard's favorite color,
|
||||
|
||||
@@ -3,19 +3,20 @@ from dotenv import load_dotenv
|
||||
from langchain.agents import AgentType, initialize_agent
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
from examples.langchain.channels import (
|
||||
dm_with_summer_intern,
|
||||
dm_with_head_of_marketing,
|
||||
dm_with_ceo,
|
||||
)
|
||||
from functionlayer.core.approval import (
|
||||
ApprovalMethod,
|
||||
FunctionLayer,
|
||||
)
|
||||
|
||||
from .channels import (
|
||||
dm_with_ceo,
|
||||
dm_with_head_of_marketing,
|
||||
dm_with_summer_intern,
|
||||
)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
task_prompt = """
|
||||
|
||||
@@ -37,7 +38,7 @@ def get_info_about_customer(customer_email: str) -> str:
|
||||
"""get info about a customer"""
|
||||
return """
|
||||
This customer has completed most of the onboarding steps,
|
||||
but still needs to invite a few team members before they can be
|
||||
but still needs to invite a few team members before they can be
|
||||
considered fully onboarded
|
||||
"""
|
||||
|
||||
|
||||
@@ -3,19 +3,20 @@ from dotenv import load_dotenv
|
||||
from langchain.agents import AgentType, initialize_agent
|
||||
from langchain_openai import ChatOpenAI
|
||||
|
||||
from examples.langchain.channels import (
|
||||
dm_with_ceo,
|
||||
dm_with_head_of_marketing,
|
||||
dm_with_summer_intern,
|
||||
)
|
||||
from functionlayer.core.approval import (
|
||||
from functionlayer import (
|
||||
ApprovalMethod,
|
||||
FunctionLayer,
|
||||
)
|
||||
|
||||
from .channels import (
|
||||
dm_with_ceo,
|
||||
dm_with_head_of_marketing,
|
||||
dm_with_summer_intern,
|
||||
)
|
||||
|
||||
load_dotenv()
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
task_prompt = """
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ load_dotenv()
|
||||
|
||||
override_bot_token = os.getenv("SLACK_BOT_TOKEN")
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
|
||||
task_prompt = """
|
||||
|
||||
@@ -12,4 +12,4 @@ RUN pip install \
|
||||
COPY . /app
|
||||
|
||||
ENTRYPOINT ["python3"]
|
||||
CMD ["01-math_example.py"]
|
||||
CMD ["01-math_example.py"]
|
||||
|
||||
@@ -32,4 +32,4 @@ docker compose run examples 01-math_example.py
|
||||
- [03-human_as_tool.py](03-human_as_tool.py) - A tou example of using functionlayer's `human_as_tool()` function to create a tool that the angent can use to contact a human for input
|
||||
- [04-human_as_tool_onboarding.py](04-human_as_tool_onboarding.py) - A more in-depth example of an agent that uses a human_as_tool channel to get feedback on emails that are to be sent to new customers
|
||||
- [05-approvals_and_humans_composite.py](05-approvals_and_humans_composite.py) - Wrapping a "contact a human call" with an approval step routed to another human
|
||||
- [06-custom_bot_token.py](06-custom_bot_token.py) - Example of how to override the default slack bot token for specific channels
|
||||
- [06-custom_bot_token.py](06-custom_bot_token.py) - Example of how to override the default slack bot token for specific channels
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
version: '3.7'
|
||||
version: "3.7"
|
||||
services:
|
||||
examples:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- ./:/app
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
venv/
|
||||
.venv/
|
||||
.venv/
|
||||
|
||||
@@ -11,4 +11,4 @@ RUN pip install \
|
||||
COPY . /app
|
||||
|
||||
ENTRYPOINT ["python3"]
|
||||
CMD ["math_example.py"]
|
||||
CMD ["math_example.py"]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
This is a straightforward and simple (albeit verbose) example of tool calling with a plain OpenAI Client -
|
||||
no frameworks are used to manage the tool calling loop. Among other things, this example serves as a good
|
||||
"look under the hood" for how frameworks generally implement tool calling.
|
||||
"look under the hood" for how frameworks generally implement tool calling.
|
||||
|
||||
In this example, as in others, the `multiply(x: int, y: int) -> int` function is wrapped with
|
||||
`@fl.require_approval`.
|
||||
@@ -39,4 +39,3 @@ INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions "HTTP/1
|
||||
INFO:__main__:last message led to 1 tool calls: [('multiply', '{"x":2,"y":5}')]
|
||||
INFO:__main__:CALL tool multiply with {'x': 2, 'y': 5}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
version: '3.7'
|
||||
version: "3.7"
|
||||
services:
|
||||
examples:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- ./:/app
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from functionlayer import ApprovalMethod, FunctionLayer
|
||||
|
||||
load_dotenv()
|
||||
|
||||
fl = FunctionLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
hl = HumanLayer(approval_method=ApprovalMethod.CLOUD)
|
||||
|
||||
PROMPT = "multiply 2 and 5, then add 32 to the result"
|
||||
|
||||
@@ -79,11 +79,16 @@ def run_chain(prompt: str, tools_openai: list[dict], tools_map: dict) -> str:
|
||||
response_message = response.choices[0].message
|
||||
tool_calls = response_message.tool_calls
|
||||
if tool_calls:
|
||||
messages.append(response_message) # extend conversation with assistant's reply
|
||||
messages.append(
|
||||
response_message
|
||||
) # extend conversation with assistant's reply
|
||||
logger.info(
|
||||
"last message led to %s tool calls: %s",
|
||||
len(tool_calls),
|
||||
[(tool_call.function.name, tool_call.function.arguments) for tool_call in tool_calls],
|
||||
[
|
||||
(tool_call.function.name, tool_call.function.arguments)
|
||||
for tool_call in tool_calls
|
||||
],
|
||||
)
|
||||
for tool_call in tool_calls:
|
||||
function_name = tool_call.function.name
|
||||
@@ -102,7 +107,11 @@ def run_chain(prompt: str, tools_openai: list[dict], tools_map: dict) -> str:
|
||||
}
|
||||
)
|
||||
|
||||
logger.info("tool %s responded with %s", function_name, function_response_json[:200])
|
||||
logger.info(
|
||||
"tool %s responded with %s",
|
||||
function_name,
|
||||
function_response_json[:200],
|
||||
)
|
||||
messages.append(
|
||||
{
|
||||
"tool_call_id": tool_call.id,
|
||||
|
||||
@@ -6,7 +6,7 @@ from dotenv import load_dotenv
|
||||
load_dotenv(dotenv_path=os.path.join(os.getcwd(), ".env"))
|
||||
|
||||
|
||||
@click.group(name="functionlayer")
|
||||
@click.group(name="humanlayer")
|
||||
def cli() -> None:
|
||||
pass
|
||||
|
||||
@@ -12,7 +12,7 @@ import requests
|
||||
import socketio # type: ignore
|
||||
from pydantic import BaseModel
|
||||
|
||||
from functionlayer.core.types import (
|
||||
from humanlayer.core.types import (
|
||||
ContactChannel,
|
||||
FunctionCall,
|
||||
FunctionCallSpec,
|
||||
@@ -27,11 +27,11 @@ R = TypeVar("R")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FunctionLayerError(Exception):
|
||||
class HumanLayerError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class UserDeniedError(FunctionLayerError):
|
||||
class UserDeniedError(HumanLayerError):
|
||||
pass
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class ApprovalMethod(Enum):
|
||||
CLOUD = "cloud"
|
||||
|
||||
|
||||
class FunctionLayerWrapper:
|
||||
class HumanLayerWrapper:
|
||||
def __init__(self, decorator: Callable) -> None:
|
||||
self.decorator = decorator
|
||||
|
||||
@@ -55,8 +55,8 @@ class FunctionLayerWrapper:
|
||||
return self.decorator(fn)
|
||||
|
||||
|
||||
class FunctionLayer(BaseModel):
|
||||
"""🧱 FunctionLayer"""
|
||||
class HumanLayer(BaseModel):
|
||||
"""🧱 HumanLayer"""
|
||||
|
||||
model_config = {"arbitrary_types_allowed": True}
|
||||
|
||||
@@ -64,9 +64,7 @@ class FunctionLayer(BaseModel):
|
||||
api_base_url: str | None = None
|
||||
ws_base_url: str | None = None
|
||||
run_id: str | None = None
|
||||
approval_method: ApprovalMethod = os.getenv(
|
||||
"FUNCTIONLAYER_APPROVAL_METHOD", ApprovalMethod.CLI
|
||||
)
|
||||
approval_method: ApprovalMethod | None
|
||||
sio: socketio.AsyncClient = socketio.AsyncClient()
|
||||
|
||||
CLI: ApprovalMethod = ApprovalMethod.CLI
|
||||
@@ -80,7 +78,7 @@ class FunctionLayer(BaseModel):
|
||||
)
|
||||
self.ws_base_url = self.ws_base_url or os.getenv("FUNCTIONLAYER_WS_BASE")
|
||||
self.approval_method = self.approval_method or os.getenv(
|
||||
"FUNCTIONLAYER_APPROVAL_METHOD"
|
||||
"FUNCTIONLAYER_APPROVAL_METHOD", ApprovalMethod.CLI
|
||||
)
|
||||
self.run_id = self.run_id or os.getenv("FUNCTIONLAYER_RUN_ID", genid("run"))
|
||||
if not self.api_key and self.approval_method is not ApprovalMethod.CLI:
|
||||
@@ -88,11 +86,11 @@ class FunctionLayer(BaseModel):
|
||||
raise ValueError(exception)
|
||||
|
||||
def __str__(self):
|
||||
return "FunctionLayer()"
|
||||
return "HumanLayer()"
|
||||
|
||||
def require_approval(
|
||||
self, contact_channel: ContactChannel | None = None
|
||||
) -> FunctionLayerWrapper:
|
||||
) -> HumanLayerWrapper:
|
||||
def decorator(fn):
|
||||
if self.approval_method is ApprovalMethod.CLI:
|
||||
return self._approve_cli(fn)
|
||||
@@ -102,7 +100,7 @@ class FunctionLayer(BaseModel):
|
||||
exception = f"Approval method {self.approval_method} not implemented"
|
||||
raise NotImplementedError(exception)
|
||||
|
||||
return FunctionLayerWrapper(decorator)
|
||||
return HumanLayerWrapper(decorator)
|
||||
|
||||
def _approve_cli(self, fn: Callable[[T], R]) -> Callable[[T], R]:
|
||||
@wraps(fn)
|
||||
@@ -27,7 +27,7 @@ class SlackContactChannel(BaseModel):
|
||||
|
||||
# a bot token to override the default contact channel
|
||||
# if you use a custom bot token, you must set your app's
|
||||
# slack webhook destination appropriately so your functionlayer server can receive them
|
||||
# slack webhook destination appropriately so your humanlayer server can receive them
|
||||
bot_token: str | None = None
|
||||
#
|
||||
# bot_token_ref: str | None
|
||||
@@ -1,12 +1,12 @@
|
||||
[tool.poetry]
|
||||
name = "functionlayer-ai"
|
||||
name = "humanlayer"
|
||||
version = "0.3.0"
|
||||
description = "functionlayer-ai"
|
||||
authors = ["functionlayer authors <dexter@metalytics.dev>"]
|
||||
repository = "https://github.com/functionlayer/functionlayer"
|
||||
description = "humanlayer"
|
||||
authors = ["humanlayer authors <dexter@metalytics.dev>"]
|
||||
repository = "https://github.com/humanlayer/humanlayer"
|
||||
readme = "README.md"
|
||||
packages = [
|
||||
{include = "functionlayer"}
|
||||
{include = "humanlayer"}
|
||||
]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
@@ -18,8 +18,8 @@ aiohttp = "3.10.2"
|
||||
requests = "2.32.3"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
fl = "functionlayer.cli.main:cli"
|
||||
functionlayer = "functionlayer.cli.main:cli"
|
||||
hl = "humanlayer.cli.main:cli"
|
||||
humanlayer = "humanlayer.cli.main:cli"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
pytest = "^7.2.0"
|
||||
@@ -40,7 +40,7 @@ requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.mypy]
|
||||
files = ["functionlayer"]
|
||||
files = ["humanlayer"]
|
||||
disallow_untyped_defs = "True"
|
||||
disallow_any_unimported = "True"
|
||||
no_implicit_optional = "True"
|
||||
@@ -109,13 +109,13 @@ skip_empty = true
|
||||
|
||||
[tool.coverage.run]
|
||||
branch = true
|
||||
source = ["functionlayer"]
|
||||
source = ["humanlayer"]
|
||||
|
||||
|
||||
[tool.ruff.per-file-ignores]
|
||||
"tests/*" = ["S101"]
|
||||
"functionlayer/cli/main.py" = ["TRY003"]
|
||||
"functionlayer/core/types.py" = ["TRY003"]
|
||||
"humanlayer/cli/main.py" = ["TRY003"]
|
||||
"humanlayer/core/types.py" = ["TRY003"]
|
||||
|
||||
[tool.ruff.mccabe]
|
||||
max-complexity = 12
|
||||
|
||||
Reference in New Issue
Block a user