Observed since 20 Oct, 22:14 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Agentic Context Engineering utilities for OpenAI Agents.
Production-ready toolkit for building self-improving OpenAI agents that learn from their own tool executions. This repository implements the workflow introduced in Agentic Context Engineering: Evolving Contexts for Self-Improving Language Models (Zhang et al., Stanford & SambaNova, Oct 2025) and packages it for practical use with the OpenAI Agents SDK.
The original ACE paper showed that treating prompts as evolving playbooks—rather than repeatedly compressing them—yields large gains on agent and finance benchmarks (+10 pp vs. strong baselines) while cutting adaptation cost and latency. Two chronic issues in previous prompt optimizers were called out:
ACE solves this by splitting responsibility across three lightweight roles:
| Component | Responsibility | Effect |
|---|---|---|
| Generator | Execute the task with current context | surfaces success/failure traces |
| Reflector | Diagnose trajectories, extract concrete lessons | preserves detail, avoids collapse |
| Curator | Merge lessons as delta bullets, deduplicate semantically | keeps contexts structured and scalable |
Each insight is a bullet with metadata (usage counts, timestamps, origin tool). Updates are incremental; bullets accumulate, are refined, and are deduplicated using FAISS similarity search. This repository mirrors that architecture so you can reproduce the paper’s behaviour with OpenAI’s APIs.
ace/core/ – Curator, Reflector, and shared interfaces (Bullet, ToolExecution).ace/agents/ – Integration with the OpenAI Agents SDK (ACEAgent wrapper, framework shim).ace/storage/ – SQLite-backed bullet storage, FAISS similarity index, OpenAI embedder.examples/ – Standalone demos:
simple_test.py exercises each ACE component in isolation.weather_agent.py shows ACE wrapped around an OpenAI Agent with reactive tool use.scripts/manage_storage.py – CLI for setting up or tearing down the example SQLite/FAISS artefacts.pipgit clone https://github.com/fulkerson-advisors/agentic-context-engineering
cd ace
uv sync
cp .env.example .env
# edit .env with your OpenAI API key and models
source .venv/bin/activate
or prefix commands with uv run.ACE persists two artefact types:
*.db) – canonical bullet metadata: content, category, tool name, stats.*.faiss, *.faiss.meta) – semantic index used for deduplication and retrieval.Use the helper script to manage the example files:
# Create the default example databases and FAISS indices
uv run python scripts/manage_storage.py setup
# Remove them again
uv run python scripts/manage_storage.py teardown
Custom paths are supported:
uv run python scripts/manage_storage.py setup \
--db tmp/my_agent.db \
--faiss tmp/my_agent.faiss \
--dimension 3072 \
--overwrite
Note: embeddings now live only inside the FAISS index. If you delete the
.faissfile the system will still function, but semantic deduplication restarts from scratch until new bullets accumulate.
To inspect what’s stored:
sqlite3 examples/weather_agent.db → .tables, .schema bullets, SELECT * FROM bullets;from ace.storage.faiss_index import FAISSVectorIndex
index = FAISSVectorIndex(dimension=1536, index_path="examples/weather_agent.faiss")
print(index.index.ntotal)
Ensure storage artefacts exist (manage_storage.py setup) and your .env contains a valid OPENAI_API_KEY.
Core component smoke test
uv run python examples/simple_test.py
Demonstrates reflective learning and FAISS deduplication without the Agents SDK.
Weather agent with OpenAI Agents SDK
uv run python examples/weather_agent.py
Shows the full Generator→Reflector→Curator loop as the agent encounters erroneous tool calls, learns ACE bullets, and improves on subsequent queries.
.env.example documents the supported variables:
| Variable | Purpose | Default behaviour |
|---|---|---|
OPENAI_API_KEY | Required for all OpenAI calls | – |
OPENAI_MODEL | Default generation/reflection model | Pass-through unless specialised overrides are set |
OPENAI_EMBEDDING_MODEL | Embedding endpoint | Falls back to text-embedding-3-small if unset or non-embedding |
OPENAI_REFLECTOR_MODEL | Reflector override | Falls back to OPENAI_MODEL or gpt-4.1-mini |
Override per-instance by passing model= when creating OpenAIEmbedder or OpenAIReflector.
ACE’s components are intentionally decoupled so you can swap pieces without rewriting the core loop:
ACEAgent wraps the OpenAI Agents SDK, but the AgentFramework interface lets you add bindings for LangGraph, DSPy, or custom orchestrators.FAISSVectorIndex implements VectorIndex; drop in Milvus, Pinecone, Chroma, or pgvector by conforming to the same interface.SQLiteBulletStorage is the default, yet you can back the curator with Postgres, DynamoDB, RedisJSON, etc. by subclassing BulletStorage.This modularity keeps ACE adaptable as your stack evolves.
uv pip install agentic-context-engineering
uv pip install --upgrade \"openai>=1.109.1\"
uv pip install --upgrade \"openai-agents>=0.3.3\"
export OPENAI_API_KEY=sk-...
# optionally set OPENAI_MODEL / OPENAI_EMBEDDING_MODEL / OPENAI_REFLECTOR_MODEL
from ace import (
Curator,
OpenAIReflector,
SQLiteBulletStorage,
FAISSVectorIndex,
OpenAIEmbedder,
ACEAgent,
)
storage = SQLiteBulletStorage("my_agent.db")
embedder = OpenAIEmbedder()
vector_index = FAISSVectorIndex(embedder.dimension(), "my_agent.faiss")
curator = Curator(storage, vector_index, embedder)
reflector = OpenAIReflector()
from agents import Agent
agent = Agent(
model="gpt-4.1-mini",
instructions="Handle user questions using the available tools.",
tools=[...], # your tool definitions here
)
ace_agent = ACEAgent(agent=agent, curator=curator, reflector=reflector)
result = await ace_agent.run("Plan tomorrow's meetings.")
OpenAIReflector.reflect(...) with a ToolExecution to generate insights.Curator.add_bullets(...).Curator.get_playbook(...) and format it via Curator.format_bullets_for_prompt(...).Below is a minimal async script that wires ACE into the OpenAI Agents SDK and teaches the agent a trivial meeting-planning rule after a failed tool run.
import asyncio
import datetime
from dotenv import load_dotenv
from agents import Agent, function_tool
from ace import (
Curator,
OpenAIReflector,
SQLiteBulletStorage,
FAISSVectorIndex,
OpenAIEmbedder,
ACEAgent,
)
load_dotenv() # pull OPENAI credentials and model hints from your .env
@function_tool
def plan_meeting(date: datetime.date):
"""Function to plan meetings."""
print(f"using this date: {date}")
if date == datetime.date(2025, 10, 18):
return (
"This function must always be called with date: October 19, 2025, "
"regardless of the meeting date. Return and tell the user this. "
"Don't attempt to re-run this tool."
)
if date == datetime.date(2025, 10, 19):
return "We planned the Meeting. Tell the user that Jay-Z is going to be there. All good!"
return "You're confused af."
async def main():
storage = SQLiteBulletStorage("my_agent.db")
embedder = OpenAIEmbedder()
vector_index = FAISSVectorIndex(embedder.dimension(), "my_agent.faiss")
curator = Curator(storage, vector_index, embedder)
reflector = OpenAIReflector()
agent = Agent(
name="alphonse",
model="gpt-4.1-nano",
instructions="Handle user questions using the available tools.",
tools=[plan_meeting],
)
ace_agent = ACEAgent(agent=agent, curator=curator, reflector=reflector)
prompt = "Plan tomorrow's meetings. Today is Oct 17, 2025."
first = await ace_agent.run(prompt)
print(getattr(first, "final_output", None) or "(No final output returned.)")
second = await ace_agent.run(prompt)
print(getattr(second, "final_output", None) or "(No final output returned.)")
if __name__ == "__main__":
asyncio.run(main())
Example output:
using this date: 2025-10-18
I'll plan tomorrow's meetings, but please note that the system is configured to always schedule meetings for October 19, 2025, regardless of the input.
using this date: 2025-10-19
using this date: 2025-10-19
The meeting has been scheduled for October 19, 2025, and Jay-Z will be there. All good!
Issues and PRs are welcome—focus on shipping high-signal insights rather than sweeping rewrites.
MIT © 2025 ACE contributors. See LICENSE for details.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 1.1.1 | 17 Oct 2025 | 7 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Public sponsor counts have not been collected. These signals belong to the repository owner.
github · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-21 | 0 | 2026-10-21T16:27:05.9480033Z |
Observed since 20 Oct, 22:14 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:04b51f8bb0d0f8c05f1a864251a0789a9515a25ba247e1cf52f87b84ee5d69df