ghostdrive1 commited on
Commit
c2c9236
·
verified ·
1 Parent(s): fb91a77

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. README.md +3 -224
  2. main.py +34 -18
README.md CHANGED
@@ -1,6 +1,6 @@
1
  ---
2
  title: Logic Engine
3
- emoji: 🧠
4
  colorFrom: blue
5
  colorTo: indigo
6
  sdk: docker
@@ -8,227 +8,6 @@ pinned: false
8
  app_port: 7860
9
  ---
10
 
11
- <a href="https://kayba.ai"><img src="assets/kayba-banner.png" alt="Kayba - Stop fixing agents by hand" width="1080"/></a>
12
 
13
- # Agentic Context Engine (ACE)
14
-
15
- [![GitHub stars](https://img.shields.io/github/stars/kayba-ai/agentic-context-engine)](https://github.com/kayba-ai/agentic-context-engine/stargazers)
16
- [![Kayba Website](https://img.shields.io/badge/kayba.ai-6B8BA8?style=flat&logo=data:image/png;base64,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&logoColor=white)](https://kayba.ai)
17
- [![Discord](https://img.shields.io/discord/1429935408145236131?label=Discord&logo=discord&logoColor=white&color=5865F2)](https://discord.gg/mqCqH7sTyK)
18
- [![Twitter Follow](https://img.shields.io/twitter/follow/kaybaai?style=social)](https://twitter.com/kaybaai)
19
- [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://kayba-ai.github.io/agentic-context-engine/latest/)
20
-
21
- > [!TIP]
22
- > ACE is the open-source engine behind [Kayba](https://kayba.ai). If you'd rather have the whole loop managed for you, from failure investigation to fixes shipped as PRs, [get a demo](https://kayba.ai).
23
-
24
- ---
25
-
26
- **AI agents don't learn from experience.** They repeat the same mistakes every session, forget what worked, and ignore what failed. ACE is the open-source engine that adds a persistent learning loop. It also powers [Kayba](https://kayba.ai), the managed service that does this for your production agents automatically.
27
-
28
- <img src="examples/seahorse-emoji-ace.gif" alt="ACE learns from mistakes in real time" width="70%"/>
29
-
30
- > The agent claims a seahorse emoji exists. ACE reflects on the error, and on the next attempt, the agent responds correctly — without human intervention.
31
-
32
- ---
33
-
34
- ## Proven Results
35
-
36
- | Metric | Result | Context |
37
- |:-------|:-------|:--------|
38
- | **2x consistency** | Doubles pass^4 on Tau2 airline benchmark | 15 learned strategies, no reward signals |
39
- | **49% token reduction** | Browser automation costs cut nearly in half | 10-run learning curve |
40
- | **$1.50 learning cost** | Claude Code translated 14k lines to TypeScript | Zero build errors, all tests passing |
41
-
42
- ---
43
-
44
- ## Quick Start
45
-
46
- ```bash
47
- uv add ace-framework
48
- ```
49
-
50
- **Option A** — Interactive setup (recommended):
51
-
52
- ```bash
53
- ace setup # Walks you through model selection, API keys, and connection validation
54
- ```
55
-
56
- **Option B** — Manual configuration:
57
-
58
- ```bash
59
- export OPENAI_API_KEY="your-key" # or ANTHROPIC_API_KEY, or any of 100+ supported providers
60
- ```
61
-
62
- Then use it:
63
-
64
- ```python
65
- from ace import ACELiteLLM
66
-
67
- agent = ACELiteLLM(model="gpt-4o-mini")
68
-
69
- # First attempt — the agent may hallucinate
70
- answer = agent.ask("Is there a seahorse emoji?")
71
-
72
- # Feed a correction — ACE extracts a strategy and updates the Skillbook
73
- agent.learn_from_feedback("There is no seahorse emoji in Unicode.")
74
-
75
- # Subsequent calls benefit from the learned strategy
76
- answer = agent.ask("Is there a seahorse emoji?")
77
-
78
- # Inspect what the agent has learned
79
- print(agent.get_strategies())
80
- ```
81
-
82
- No fine-tuning, no training data, no vector database.
83
-
84
- [-> Quick Start Guide](https://kayba-ai.github.io/agentic-context-engine/latest/getting-started/quick-start/) | [-> Setup Guide](https://kayba-ai.github.io/agentic-context-engine/latest/getting-started/setup/) | [-> Hosted API: Where Do Traces Come From?](https://kayba-ai.github.io/agentic-context-engine/latest/integrations/hosted-api/#where-do-traces-come-from)
85
-
86
- ---
87
-
88
- ## How It Works
89
-
90
- ACE maintains a **Skillbook** — a persistent collection of strategies that evolves with every task. Three specialized roles manage the learning loop:
91
-
92
- | Role | Responsibility |
93
- |:-----|:---------------|
94
- | **Agent** | Executes tasks, enhanced with Skillbook strategies |
95
- | **Reflector** | Analyzes execution traces to extract what worked and what failed |
96
- | **SkillManager** | Curates the Skillbook — adds, refines, and removes strategies |
97
-
98
- The **Recursive Reflector** is the key innovation: instead of summarizing traces in a single pass, it writes and executes Python code in a sandboxed environment to programmatically search for patterns, isolate errors, and iterate until it finds actionable insights.
99
-
100
- ```mermaid
101
- flowchart LR
102
- Skillbook[(Skillbook)]
103
- Start([Task]) --> Agent[Agent]
104
- Agent <--> Environment[Environment]
105
- Environment -- Trace --> Reflector[Reflector]
106
- Reflector --> SkillManager[SkillManager]
107
- SkillManager -- Updates --> Skillbook
108
- Skillbook -. Strategies .-> Agent
109
- ```
110
-
111
- All roles are backed by [PydanticAI](https://ai.pydantic.dev/) agents with structured output validation. PydanticAI routes to 100+ LLM providers through its LiteLLM integration, with native support for OpenAI, Anthropic, Google, Bedrock, Groq, and more.
112
-
113
- *Based on the [ACE paper](https://arxiv.org/abs/2510.04618) (Stanford & SambaNova) and [Dynamic Cheatsheet](https://arxiv.org/abs/2504.07952).*
114
-
115
- ---
116
-
117
- ## Runners
118
-
119
- | Runner | Class | Description |
120
- |:-------|:------|:------------|
121
- | **LiteLLM** | `ACELiteLLM` | Batteries-included agent with `.ask()`, `.learn()`, `.save()` — accepts any [LiteLLM model string](https://docs.litellm.ai/docs/providers) |
122
- | **Core** | `ACE` | Full learning loop with batch epochs and evaluation |
123
- | **Trace Analyser** | `TraceAnalyser` | Learn from pre-recorded traces without re-running tasks |
124
- | **browser-use** | `BrowserUse` | Browser automation that improves with each run |
125
- | **LangChain** | `LangChain` | Wrap any LangChain chain or agent with learning |
126
- | **Claude Code** | `ClaudeCode` | Claude Code CLI tasks with learning |
127
-
128
- ```bash
129
- uv add 'ace-framework[browser-use]' # Browser automation
130
- uv add 'ace-framework[langchain]' # LangChain
131
- uv add 'ace-framework[logfire]' # Observability (auto-instruments PydanticAI)
132
- uv add 'ace-framework[mcp]' # MCP server for IDE integration
133
- uv add 'ace-framework[deduplication]' # Embedding-based skill deduplication
134
- ```
135
-
136
- Have existing agent logs? Extract strategies from them directly:
137
-
138
- ```python
139
- from ace import ACELiteLLM
140
-
141
- agent = ACELiteLLM(model="gpt-4o-mini")
142
- agent.learn_from_traces(your_existing_traces)
143
- print(agent.get_strategies())
144
- ```
145
-
146
- [-> Examples](examples/)
147
-
148
- ---
149
-
150
- ## Benchmarks
151
-
152
- ### Tau2 — Multi-Step Agentic Tasks
153
-
154
- [tau2-bench](https://github.com/sierra-research/tau2-bench) by Sierra Research: airline domain tasks requiring tool use and policy adherence. Claude Haiku 4.5 agent, strategies learned on the train split with no reward signals, evaluated on the held-out test split.
155
-
156
- <img src="benchmarks/tasks/tau_bench/Tau2Benchmark Result Haiku4.5.png" alt="Tau2 Benchmark — ACE doubles consistency at pass^4" width="35%"/>
157
-
158
- *pass^k = probability all k independent attempts succeed. ACE doubles consistency at pass^4 with 15 learned strategies.*
159
-
160
- ### Claude Code — Autonomous Translation
161
-
162
- ACE + Claude Code translated this library from Python to TypeScript with zero supervision:
163
-
164
- | Metric | Result |
165
- |:-------|:-------|
166
- | Duration | ~4 hours |
167
- | Commits | 119 |
168
- | Lines written | ~14,000 |
169
- | Build errors | 0 |
170
- | Tests | All passing |
171
- | Learning cost | ~$1.50 |
172
-
173
- ---
174
-
175
- ## Pipeline Architecture
176
-
177
- ACE is built on a composable pipeline engine. Each step declares what it requires and what it produces:
178
-
179
- ```
180
- AgentStep -> EvaluateStep -> ReflectStep -> UpdateStep -> DeduplicateStep
181
- ```
182
-
183
- Use `learning_tail()` for the standard learning sequence, or compose custom pipelines:
184
-
185
- ```python
186
- from ace import Pipeline, AgentStep, EvaluateStep, learning_tail
187
-
188
- steps = [AgentStep(agent, skillbook), EvaluateStep(env)] + learning_tail(reflector, skill_manager, skillbook)
189
- pipeline = Pipeline(steps)
190
- ```
191
-
192
- The pipeline engine ([`pipeline/`](pipeline/)) is framework-agnostic with `requires`/`provides` contracts, immutable context, and error isolation. See [Pipeline Design](docs/design/PIPELINE_DESIGN.md) and [Architecture](docs/design/ACE_ARCHITECTURE.md).
193
-
194
- ---
195
-
196
- ## CLI
197
-
198
- | Command | Description |
199
- |:--------|:------------|
200
- | `ace setup` | Interactive setup — model selection, API keys, connection validation |
201
- | `ace models <query>` | Search available models with pricing |
202
- | `ace validate <model>` | Test a model connection |
203
- | `ace config` | Show current configuration |
204
- | `kayba` | Cloud CLI — upload traces, fetch insights, manage prompts |
205
- | `ace-mcp` | MCP server for IDE integration |
206
-
207
- ---
208
-
209
- ## Documentation
210
-
211
- - [Full Documentation](https://kayba-ai.github.io/agentic-context-engine/latest/) — Guides, API reference, examples
212
- - [Quick Start](https://kayba-ai.github.io/agentic-context-engine/latest/getting-started/quick-start/) — 5-minute setup
213
- - [Setup Guide](https://kayba-ai.github.io/agentic-context-engine/latest/getting-started/setup/) — Configuration and providers
214
- - [Hosted API Guide](https://kayba-ai.github.io/agentic-context-engine/latest/integrations/hosted-api/) — Hosted CLI, trace upload, prompt install
215
- - [Architecture](docs/design/ACE_ARCHITECTURE.md) — Core concepts and system design
216
- - [Code Reference](docs/design/ACE_REFERENCE.md) — Implementations, API, usage examples
217
- - [Design Decisions](docs/design/ACE_DECISIONS.md) — Rejected alternatives and rationale
218
- - [Pipeline Engine](docs/design/PIPELINE_DESIGN.md) — Step composition and context flow
219
- - [Examples](examples/) — Runnable demos
220
- - [Changelog](CHANGELOG.md) — Version history
221
-
222
- ---
223
-
224
- ## Contributing
225
-
226
- Contributions are welcome. See [Contributing Guidelines](CONTRIBUTING.md).
227
-
228
- ---
229
-
230
- <div align="center">
231
-
232
- **Built by [Kayba](https://kayba.ai) and the open-source community.**
233
-
234
- </div>
 
1
  ---
2
  title: Logic Engine
3
+ emoji: 🤖
4
  colorFrom: blue
5
  colorTo: indigo
6
  sdk: docker
 
8
  app_port: 7860
9
  ---
10
 
11
+ # Logic Engine - Node 2
12
 
13
+ FastAPI backend for the Manus UI Clone. Exposes a /chat endpoint.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
main.py CHANGED
@@ -16,44 +16,58 @@ app.add_middleware(
16
 
17
  class ChatRequest(BaseModel):
18
  prompt: str
19
- model: str = "gpt-4o-mini"
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  @app.get("/")
22
  def root():
23
  return {"status": "Logic Engine is running", "endpoints": ["/chat", "/health"]}
24
 
25
-
26
  @app.post("/chat")
27
  async def chat_endpoint(request: ChatRequest):
28
- api_key = os.environ.get("OPENAI_API_KEY") or os.environ.get("GROQ_API_KEY")
 
 
 
 
 
29
 
30
  if not api_key:
31
- # Graceful fallback when no API key is configured
32
  return {
33
  "response": (
34
- f"[Logic Engine] Received your message: \"{request.prompt}\"\n\n"
35
- "No LLM API key is configured yet. Please add OPENAI_API_KEY or GROQ_API_KEY "
36
- "via the Providers panel in the UI or in the Space Secrets settings on Hugging Face."
37
  ),
38
  "doc": True
39
  }
40
 
41
- try:
42
- # Use OpenAI-compatible API via httpx (works with OpenAI & Groq)
43
- base_url = "https://api.groq.com/openai/v1" if os.environ.get("GROQ_API_KEY") else "https://api.openai.com/v1"
44
- chosen_key = os.environ.get("GROQ_API_KEY") or os.environ.get("OPENAI_API_KEY")
45
- model = "llama-3.1-8b-instant" if os.environ.get("GROQ_API_KEY") else request.model
46
 
47
- async with httpx.AsyncClient(timeout=30) as client:
 
48
  resp = await client.post(
49
  f"{base_url}/chat/completions",
50
- headers={"Authorization": f"Bearer {chosen_key}", "Content-Type": "application/json"},
 
 
 
51
  json={
52
- "model": model,
53
  "messages": [
54
- {"role": "system", "content": "You are Manus, a helpful autonomous AI agent."},
55
- {"role": "user", "content": request.prompt}
56
- ]
 
57
  }
58
  )
59
  resp.raise_for_status()
@@ -61,6 +75,8 @@ async def chat_endpoint(request: ChatRequest):
61
  reply = data["choices"][0]["message"]["content"]
62
  return {"response": reply, "doc": True}
63
 
 
 
64
  except Exception as e:
65
  raise HTTPException(status_code=500, detail=str(e))
66
 
 
16
 
17
  class ChatRequest(BaseModel):
18
  prompt: str
19
+ model: str = "llama-3.1-8b-instant"
20
+ api_key: str = ""
21
+ provider: str = "Groq"
22
+
23
+ PROVIDER_BASES = {
24
+ "OpenAI": "https://api.openai.com/v1",
25
+ "Anthropic": "https://api.anthropic.com/v1",
26
+ "Groq": "https://api.groq.com/openai/v1",
27
+ "HuggingFace": "https://api-inference.huggingface.co/v1",
28
+ "OpenRouter": "https://openrouter.ai/api/v1",
29
+ "Nvidia": "https://integrate.api.nvidia.com/v1",
30
+ }
31
 
32
  @app.get("/")
33
  def root():
34
  return {"status": "Logic Engine is running", "endpoints": ["/chat", "/health"]}
35
 
 
36
  @app.post("/chat")
37
  async def chat_endpoint(request: ChatRequest):
38
+ # Priority: key from frontend → env vars
39
+ api_key = (
40
+ request.api_key.strip()
41
+ or os.environ.get("GROQ_API_KEY", "")
42
+ or os.environ.get("OPENAI_API_KEY", "")
43
+ )
44
 
45
  if not api_key:
 
46
  return {
47
  "response": (
48
+ f'[Logic Engine] Received: "{request.prompt}"\n\n'
49
+ "No API key configured. Please add your key via the Providers panel."
 
50
  ),
51
  "doc": True
52
  }
53
 
54
+ base_url = PROVIDER_BASES.get(request.provider, PROVIDER_BASES["Groq"])
 
 
 
 
55
 
56
+ try:
57
+ async with httpx.AsyncClient(timeout=60) as client:
58
  resp = await client.post(
59
  f"{base_url}/chat/completions",
60
+ headers={
61
+ "Authorization": f"Bearer {api_key}",
62
+ "Content-Type": "application/json",
63
+ },
64
  json={
65
+ "model": request.model,
66
  "messages": [
67
+ {"role": "system", "content": "You are Manus, a helpful and concise autonomous AI agent."},
68
+ {"role": "user", "content": request.prompt},
69
+ ],
70
+ "temperature": 0.7,
71
  }
72
  )
73
  resp.raise_for_status()
 
75
  reply = data["choices"][0]["message"]["content"]
76
  return {"response": reply, "doc": True}
77
 
78
+ except httpx.HTTPStatusError as e:
79
+ raise HTTPException(status_code=e.response.status_code, detail=f"Provider error: {e.response.text}")
80
  except Exception as e:
81
  raise HTTPException(status_code=500, detail=str(e))
82