No description
Find a file
Padawan-GM 12d0044446 Add OpenAI trigger bot library
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>
2026-05-19 18:25:45 +02:00
src/openai_trigger_bot Add OpenAI trigger bot library 2026-05-19 18:25:45 +02:00
tests Add OpenAI trigger bot library 2026-05-19 18:25:45 +02:00
.gitignore Add OpenAI trigger bot library 2026-05-19 18:25:45 +02:00
pyproject.toml Add OpenAI trigger bot library 2026-05-19 18:25:45 +02:00
README.md Add OpenAI trigger bot library 2026-05-19 18:25:45 +02:00

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_id for efficient tool-call loops and prompt_cache_key to 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:

  • SQLiteMemoryStore for persistent local storage
  • OpenAIEmbedder for semantic retrieval with OpenAI embeddings
  • MemoryManager for selection, prompt injection, and optional automatic capture of trigger/action history

You can keep memory scoped however you like, for example:

  • global
  • chat:123
  • user:alice
  • team:ops

At runtime, a MemoryRequest pulls a bounded mix of:

  1. recent memories
  2. semantically relevant memories
  3. 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_id for iterative tool loops without resending the full conversation every time
  • prompt_cache_key for better prompt caching behavior
  • OpenAI embeddings for semantic memory retrieval

Running tests

python -m unittest discover -s tests -v