Create a Python library for trigger-driven bots on top of the OpenAI Responses API, with decorator-based actions, trigger templates, a bounded tool-call runner, and modular memory management. Include README documentation and unit tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|---|---|---|
| src/openai_trigger_bot | ||
| tests | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
openai-trigger-bot
openai-trigger-bot is a small Python framework for building bots around OpenAI's Responses API in a strict trigger -> action style:
- developers define callable tools with
@action(...) - tools are exposed to the model through the Responses API
- the model's direct text is ignored
- only tool calls can cause side effects
- triggers define the prompt, data, default action, and which hidden actions are allowed
- the runtime uses
previous_response_idfor efficient tool-call loops andprompt_cache_keyto improve caching
Installation
pip install openai-trigger-bot
Quick example
from openai import OpenAI
from openai_trigger_bot import (
Bot,
BotSettings,
FileMemoryStore,
MemoryManager,
MemoryRequest,
OpenAIEmbedder,
action,
)
client = OpenAI()
memory = MemoryManager(
store=FileMemoryStore("bot-memory.json"),
embedder=OpenAIEmbedder(client),
)
@action(global_action=True)
def send_message(chat_id: str, text: str) -> dict[str, str]:
"""Send a chat message.
Args:
chat_id: The destination chat identifier.
text: The message body to deliver.
"""
print(f"[{chat_id}] {text}")
return {"status": "sent"}
@action()
def remember_fact(scope: str, fact: str) -> dict[str, str]:
"""Store a fact in long-term memory.
Args:
scope: The memory scope, such as `global` or `user:alice`.
fact: The fact that should be remembered.
"""
memory.remember(fact, scope=scope, kind="fact", source="remember_fact")
return {"status": "stored"}
bot = Bot(
name="support-bot",
client=client,
settings=BotSettings(
model="gpt-5.2",
system_prompt="You are a support bot. Direct text output is ignored.",
max_model_calls=6,
),
memory=memory,
)
bot.register_actions(send_message, remember_fact)
@bot.trigger(
"reply-to-chat",
prompt="Read the chat state and decide what to do.",
default_action=send_message,
hidden_actions=[remember_fact],
memory_request=MemoryRequest(
scopes=("global", "chat:support", "user:alice"),
query="Recent support conversation state and user preferences",
recent_limit=4,
semantic_limit=6,
),
)
def reply_to_chat(chat_id: str, messages: list[dict[str, str]]) -> dict[str, object]:
return {
"chat_id": chat_id,
"messages": messages,
}
result = bot.run(reply_to_chat("support", [{"role": "user", "content": "Can you help me?"}]))
print(result.model_calls)
print(result.action_calls)
Core ideas
Actions
Actions are normal Python callables decorated with @action(...).
- hidden by default
- global when
global_action=True - converted into OpenAI function tools from:
- function name
- docstring summary
- parameter names
- Python type hints
- docstring parameter descriptions
Unsupported signatures such as *args, **kwargs, and positional-only parameters are rejected because they cannot be expressed cleanly as JSON tool arguments.
Triggers
Each trigger defines:
- a name
- a prompt
- a default action
- some data
- optional hidden actions
- optional memory retrieval rules
The runtime strongly nudges the model toward the default action in instructions, but still leaves room for the model to skip it when truly necessary.
Memory
The package ships with a modular memory system:
SQLiteMemoryStorefor persistent local storageOpenAIEmbedderfor semantic retrieval with OpenAI embeddingsMemoryManagerfor selection, prompt injection, and optional automatic capture of trigger/action history
You can keep memory scoped however you like, for example:
globalchat:123user:aliceteam:ops
At runtime, a MemoryRequest pulls a bounded mix of:
- recent memories
- semantically relevant memories
- only the requested scopes
This keeps prompts smaller than dumping full history.
OpenAI features used deliberately
The framework is built around official Responses API capabilities and tries to use token-saving or automation-friendly features when possible:
- Responses API tools for action execution
previous_response_idfor iterative tool loops without resending the full conversation every timeprompt_cache_keyfor better prompt caching behavior- OpenAI embeddings for semantic memory retrieval
Running tests
python -m unittest discover -s tests -v