Spaces:
Runtime error
Runtime error
refactor: update grammar, remove unused project files, and clean up workspace configuration
Browse files- .codex/config.toml +0 -3
- .gitignore +2 -0
- app.py +15 -3
- field_notes.md +33 -21
- grammar.gbnf +1 -1
- hackathon.md +0 -19
- scratch/test_models.py +0 -29
- static/index.html +0 -125
.codex/config.toml
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
[features]
|
| 2 |
-
memories = true
|
| 3 |
-
codex_git_commit = true
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
CHANGED
|
@@ -6,3 +6,5 @@ models/
|
|
| 6 |
.venv/pyvenv.cfg
|
| 7 |
.venv/pyvenv.cfg
|
| 8 |
*.log
|
|
|
|
|
|
|
|
|
| 6 |
.venv/pyvenv.cfg
|
| 7 |
.venv/pyvenv.cfg
|
| 8 |
*.log
|
| 9 |
+
scratch/
|
| 10 |
+
.codex/
|
app.py
CHANGED
|
@@ -192,7 +192,7 @@ async def generate_atomic_task(goal: str, previous_failures: int, history: list
|
|
| 192 |
prompt,
|
| 193 |
max_tokens=64,
|
| 194 |
temperature=0.3,
|
| 195 |
-
stop=["\n", "<extra_id_1>"],
|
| 196 |
grammar=grammar # Enforcing grammar here!
|
| 197 |
)
|
| 198 |
raw_content = response['choices'][0]['text'].strip()
|
|
@@ -283,7 +283,8 @@ async def apply_activation_style(task: str, style="direct") -> str:
|
|
| 283 |
)
|
| 284 |
content = response['choices'][0]['message']['content'].strip()
|
| 285 |
print(f"MINICPM RAW OUT: {content}", flush=True)
|
| 286 |
-
|
|
|
|
| 287 |
|
| 288 |
# --- GRADIO UI ---
|
| 289 |
|
|
@@ -331,6 +332,8 @@ footer { display: none !important; }
|
|
| 331 |
#goal-input textarea:focus { border-bottom: 2px solid white !important; }
|
| 332 |
|
| 333 |
/* Buttons */
|
|
|
|
|
|
|
| 334 |
#btn-done { background-color: #16a34a !important; color: white !important; font-weight: bold; font-size: 1.25rem !important; }
|
| 335 |
#btn-skip { background-color: #4b5563 !important; color: white !important; font-weight: bold; font-size: 1.25rem !important; }
|
| 336 |
#btn-hard { background-color: #1f2937 !important; color: #d1d5db !important; font-weight: bold; font-size: 1.25rem !important; }
|
|
@@ -438,7 +441,7 @@ with gr.Blocks(css=custom_css, js="() => { document.documentElement.classList.ad
|
|
| 438 |
container=False
|
| 439 |
)
|
| 440 |
|
| 441 |
-
start_btn = gr.Button("Start", variant="primary", elem_classes="mt-8 mx-auto w-48")
|
| 442 |
|
| 443 |
with gr.Column(visible=False) as screen_task:
|
| 444 |
breadcrumbs_display = gr.HTML(elem_id="breadcrumbs-container")
|
|
@@ -452,6 +455,7 @@ with gr.Blocks(css=custom_css, js="() => { document.documentElement.classList.ad
|
|
| 452 |
with gr.Row(elem_classes="justify-center mt-4 gap-4"):
|
| 453 |
btn_trace = gr.Button("Export Trace", elem_id="btn-trace")
|
| 454 |
btn_push = gr.Button("Push to Hub", elem_id="btn-trace")
|
|
|
|
| 455 |
|
| 456 |
trace_download = gr.File(visible=False)
|
| 457 |
hub_status = gr.HTML(visible=False, elem_classes="text-center text-sm text-gray-400 mt-2")
|
|
@@ -573,5 +577,13 @@ with gr.Blocks(css=custom_css, js="() => { document.documentElement.classList.ad
|
|
| 573 |
outputs=[hub_status]
|
| 574 |
)
|
| 575 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 576 |
if __name__ == "__main__":
|
| 577 |
app.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
|
| 192 |
prompt,
|
| 193 |
max_tokens=64,
|
| 194 |
temperature=0.3,
|
| 195 |
+
stop=["\n", "<extra_id_1>", "Completed Tasks", "Goal:", "User:", "Assistant:", "<extra_id_"],
|
| 196 |
grammar=grammar # Enforcing grammar here!
|
| 197 |
)
|
| 198 |
raw_content = response['choices'][0]['text'].strip()
|
|
|
|
| 283 |
)
|
| 284 |
content = response['choices'][0]['message']['content'].strip()
|
| 285 |
print(f"MINICPM RAW OUT: {content}", flush=True)
|
| 286 |
+
cleaned_content, is_valid = clean_and_validate_task(content, [], [])
|
| 287 |
+
return cleaned_content or content.strip('"\' ,.-1234567890)')
|
| 288 |
|
| 289 |
# --- GRADIO UI ---
|
| 290 |
|
|
|
|
| 332 |
#goal-input textarea:focus { border-bottom: 2px solid white !important; }
|
| 333 |
|
| 334 |
/* Buttons */
|
| 335 |
+
#btn-start { background-color: #16a34a !important; color: white !important; font-weight: bold; font-size: 1.25rem !important; border: none !important; }
|
| 336 |
+
#btn-start:hover { background-color: #15803d !important; }
|
| 337 |
#btn-done { background-color: #16a34a !important; color: white !important; font-weight: bold; font-size: 1.25rem !important; }
|
| 338 |
#btn-skip { background-color: #4b5563 !important; color: white !important; font-weight: bold; font-size: 1.25rem !important; }
|
| 339 |
#btn-hard { background-color: #1f2937 !important; color: #d1d5db !important; font-weight: bold; font-size: 1.25rem !important; }
|
|
|
|
| 441 |
container=False
|
| 442 |
)
|
| 443 |
|
| 444 |
+
start_btn = gr.Button("Start", variant="primary", elem_classes="mt-8 mx-auto w-48", elem_id="btn-start")
|
| 445 |
|
| 446 |
with gr.Column(visible=False) as screen_task:
|
| 447 |
breadcrumbs_display = gr.HTML(elem_id="breadcrumbs-container")
|
|
|
|
| 455 |
with gr.Row(elem_classes="justify-center mt-4 gap-4"):
|
| 456 |
btn_trace = gr.Button("Export Trace", elem_id="btn-trace")
|
| 457 |
btn_push = gr.Button("Push to Hub", elem_id="btn-trace")
|
| 458 |
+
btn_reset = gr.Button("Start Over", elem_id="btn-trace")
|
| 459 |
|
| 460 |
trace_download = gr.File(visible=False)
|
| 461 |
hub_status = gr.HTML(visible=False, elem_classes="text-center text-sm text-gray-400 mt-2")
|
|
|
|
| 577 |
outputs=[hub_status]
|
| 578 |
)
|
| 579 |
|
| 580 |
+
def handle_reset():
|
| 581 |
+
return {}, gr.Column(visible=True), gr.Column(visible=False), ""
|
| 582 |
+
|
| 583 |
+
btn_reset.click(
|
| 584 |
+
fn=handle_reset,
|
| 585 |
+
outputs=[session_state, screen_start, screen_task, goal_input]
|
| 586 |
+
)
|
| 587 |
+
|
| 588 |
if __name__ == "__main__":
|
| 589 |
app.launch(server_name="0.0.0.0", server_port=7860)
|
field_notes.md
CHANGED
|
@@ -2,13 +2,13 @@
|
|
| 2 |
|
| 3 |
Step-Zero is a local-first "Cognitive Pacemaker" application designed to break down overwhelming goals into atomic physical actions to overcome executive dysfunction.
|
| 4 |
|
| 5 |
-
|
| 6 |
|
| 7 |
---
|
| 8 |
|
| 9 |
## 1. System Architecture
|
| 10 |
|
| 11 |
-
|
| 12 |
|
| 13 |
```
|
| 14 |
┌──────────────────────┐
|
|
@@ -30,29 +30,40 @@ The core of Step-Zero is a **dual-model orchestrator** that runs entirely locall
|
|
| 30 |
└──────────────────────┘ └───────────────────────┘
|
| 31 |
```
|
| 32 |
|
| 33 |
-
1. **Primary Model (Nemotron-Mini-4B):** Fine-tuned
|
| 34 |
-
2. **Fallback Model (MiniCPM-3-4B):** An instruction-following model used for stylistic
|
| 35 |
|
| 36 |
---
|
| 37 |
|
| 38 |
-
## 2. Technical Alignments &
|
| 39 |
|
| 40 |
-
|
| 41 |
|
| 42 |
-
|
| 43 |
-
We defined a GBNF grammar (`[a-zA-Z0-9 ,.!?'-]+`) to force the models to generate raw plain text rather than markdown lists, JSON objects, or verbose chat commentary. This bypasses the need for complex output parser libraries.
|
| 44 |
|
| 45 |
-
###
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
-
|
| 52 |
-
Instead of exact string matching, we implemented a sliding-window overlap check. If a newly generated action has >70% word overlap with the user's recent history or skipped tasks, the system intercepts it as a repetition loop and routes it to MiniCPM to generate a novel alternative.
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
---
|
| 58 |
|
|
@@ -60,12 +71,13 @@ If the user indicates a task is "Too Hard" three times consecutively, the app tr
|
|
| 60 |
|
| 61 |
To support the cognitive design of the pacemaker (which aims to reduce cognitive load), the app features a minimal, custom dark theme. By leveraging Gradio's CSS custom properties on `:root` and `.dark`, we overrode Gradio's standard elements to deliver a clean, borderless dark UI styled like a game interface:
|
| 62 |
- **Fog of War:** Completed history is styled with low opacity (`opacity: 0.3`) and blurred (`filter: blur(2px)`) to keep the user's attention anchored on the single next step.
|
| 63 |
-
- **
|
|
|
|
| 64 |
|
| 65 |
---
|
| 66 |
|
| 67 |
## 4. Key Takeaways & Small Model Constraints
|
| 68 |
|
| 69 |
-
1. **
|
| 70 |
-
2. **
|
| 71 |
-
3. **
|
|
|
|
| 2 |
|
| 3 |
Step-Zero is a local-first "Cognitive Pacemaker" application designed to break down overwhelming goals into atomic physical actions to overcome executive dysfunction.
|
| 4 |
|
| 5 |
+
Running small language models (≤4B parameters) entirely on consumer hardware forces you to confront the "Alignment Tax" head-on. Here is the honest developer log of the design decisions, engineering failures, and breakthroughs we encountered.
|
| 6 |
|
| 7 |
---
|
| 8 |
|
| 9 |
## 1. System Architecture
|
| 10 |
|
| 11 |
+
Step-Zero uses a **dual-model orchestrator** executing locally on CPU/laptop hardware via the `llama.cpp` runtime.
|
| 12 |
|
| 13 |
```
|
| 14 |
┌──────────────────────┐
|
|
|
|
| 30 |
└──────────────────────┘ └───────────────────────┘
|
| 31 |
```
|
| 32 |
|
| 33 |
+
1. **Primary Model (Nemotron-Mini-4B):** Fine-tuned using Unsloth SFT specifically on daily goal breakdown datasets (`verbs.jsonl`) to produce atomic, physical next-step instructions.
|
| 34 |
+
2. **Fallback Model (MiniCPM-3-4B):** An instruction-following model used for stylistic tone adjustments (Calm vs. Encouraging), semantic repetition loops, and simplifying tasks when a user signals "Too Hard".
|
| 35 |
|
| 36 |
---
|
| 37 |
|
| 38 |
+
## 2. Technical Alignments & The GBNF Stop-Token Deadlock
|
| 39 |
|
| 40 |
+
During testing under real model inference, we noticed that Nemotron-Mini-4B suffered from severe over-generation, outputting long paragraphs containing prompt template headers, formatting guidelines, and repeat sentences. Every single task triggered our validation filters and fell back to MiniCPM, causing a 25-second latency penalty.
|
| 41 |
|
| 42 |
+
Here are the two breakthroughs that solved this:
|
|
|
|
| 43 |
|
| 44 |
+
### Breakthrough A: Resolving the GBNF Sampler Deadlock
|
| 45 |
+
We originally constrained the model using a GBNF grammar:
|
| 46 |
+
```gbnf
|
| 47 |
+
root ::= [a-zA-Z0-9 ,.!?'-]+
|
| 48 |
+
```
|
| 49 |
+
We also specified a stop token of `\n` in the inference call (`stop=["\n"]`) to terminate the action after the first sentence.
|
| 50 |
+
|
| 51 |
+
**The Failure:** The GBNF grammar restricted the allowed character set to letters, numbers, and basic punctuation. Crucially, it did *not* include the newline character `\n`. Because GBNF constraints are enforced at the sampler level, the model's probability of selecting `\n` was set to exactly zero.
|
| 52 |
|
| 53 |
+
As a result, the model was mathematically forbidden from generating the stop token. It kept generating sentence after sentence until it hit the hard limit of `max_tokens=64`, leading to severe paragraph bloating and prompt echoing.
|
|
|
|
| 54 |
|
| 55 |
+
**The Fix:** We updated the GBNF grammar to permit newline characters:
|
| 56 |
+
```gbnf
|
| 57 |
+
root ::= [a-zA-Z0-9 ,.!?\n'-]+
|
| 58 |
+
```
|
| 59 |
+
This allowed the model to output a newline character as soon as it finished the task, instantly triggering the `stop=["\n"]` check and terminating generation after the first sentence. The model now outputs exactly 6 to 8 words, saving massive CPU latency.
|
| 60 |
+
|
| 61 |
+
### Breakthrough B: Token-Level Early Stopping for Prompt Echoing
|
| 62 |
+
Small models are highly susceptible to "prompt echoing" (repeating headers like `Completed Tasks:` or `Goal:` when prompted). Rather than waiting for the model to generate a full 64-token sequence of echoed prompt template text before filtering it out in Python, we added the headers directly to the llama.cpp stop-words:
|
| 63 |
+
```python
|
| 64 |
+
stop=["\n", "<extra_id_1>", "Completed Tasks", "Goal:", "User:", "Assistant:"]
|
| 65 |
+
```
|
| 66 |
+
If the model begins echoing the prompt template, it hits a stop word within 1 or 2 tokens and halts generation immediately. This terminates failed inference loops in under 50ms, allowing an instantaneous fallback to MiniCPM.
|
| 67 |
|
| 68 |
---
|
| 69 |
|
|
|
|
| 71 |
|
| 72 |
To support the cognitive design of the pacemaker (which aims to reduce cognitive load), the app features a minimal, custom dark theme. By leveraging Gradio's CSS custom properties on `:root` and `.dark`, we overrode Gradio's standard elements to deliver a clean, borderless dark UI styled like a game interface:
|
| 73 |
- **Fog of War:** Completed history is styled with low opacity (`opacity: 0.3`) and blurred (`filter: blur(2px)`) to keep the user's attention anchored on the single next step.
|
| 74 |
+
- **Start Button Theme:** Overrode Gradio's default primary orange buttons to match the deep forest green theme of the interface.
|
| 75 |
+
- **Timer and Recovery:** Included a clean "Start Over" action flow to allow user recovery once the circuit breaker fires.
|
| 76 |
|
| 77 |
---
|
| 78 |
|
| 79 |
## 4. Key Takeaways & Small Model Constraints
|
| 80 |
|
| 81 |
+
1. **Syntax Constraints are Sampler Constraints:** Constraining text syntax with GBNF without matching stop criteria can lead to sampler deadlocks. Always align your grammar's allowed character space with your engine's stop sequences.
|
| 82 |
+
2. **LoRA Fine-tuning is Highly Sensitive:** A 4B parameter model is highly sensitive to format drift. Minor discrepancies between fine-tuning prompt structure and inference structure will cause formatting breakdowns.
|
| 83 |
+
3. **Optimized CPU Execution:** With optimized GGUF quantizations and proper early stopping, both models run under 50ms per token on consumer CPU laptop hardware, making fully offline cognitive assistance viable.
|
grammar.gbnf
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
root ::= [a-zA-Z0-9 ,.!?'-]+
|
|
|
|
| 1 |
+
root ::= [a-zA-Z0-9 ,.!?\n'-]+
|
hackathon.md
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
can they win the hackathon tho? this one:
|
| 2 |
-
Hosted by Gradio · Hugging Face Anchor Sponsors OpenBMB · OpenAI · NVIDIA · Modal Cash & Prizes $48k+ Our Trail Partners Backed by the best in AI. The folks making this adventure possible — the full roster, locked in.
|
| 3 |
-
From Your Hosts Hugging Face Logo Hugging Face $15,000 into the cash prize pool, plus $20 in Hugging Face credits for every participant. We're not just hosting the trail — we're packing the provisions too. Anchor Sponsors OpenAI Logo $10,000 in cash prizes, plus $100 in Codex credits for the first 1,000 participants.
|
| 4 |
-
NVIDIA Logo Two RTX 5080 GPUs🔥 as physical prizes.
|
| 5 |
-
Modal Logo $250 in Modal credits for every participant, plus $20,000 in credits for the winners.
|
| 6 |
-
OpenBMB Logo $10,000 in special category prizes — split across both tracks for the standout OpenBMB picks.
|
| 7 |
-
Supporting Sponsors Cohere Logo Cohere $5,000 in cash prize contribution to the pool. JetBrains Logo JetBrains $5,000 in cash prize contribution to the pool. Black Forest Labs Logo Black Forest Labs $3,000 in cash prize contribution to the pool. Total Prize Pool $48,000+ in cash & physical prizes across both tracks — plus per-participant credits ($100 Codex · $250 Modal · $20 Hugging Face) Registrations are closed — and the trail is open! Sign-ups wrapped on June 3, 2026. Registered builders — the hack window is live, June 5–15. Hop into the Discord, find your teammates, and start building. → Join the Discord ← ❋ Chapter Zero — Why this exists The pace of AI over the last year has been anxiety-inducing. Labs release larger and larger models that do more of the things that make us feel human — writing, drawing, speaking, coding. No wonder more than half of us think the risks of AI outweigh the benefits.
|
| 8 |
-
We're sponsoring a hackathon to take things back to how they felt in 2021 — when models were small enough to tinker with, and the vibe was fun and hopeful about how this technology could improve our lives. This hackathon is different. Rather than using a giant LLM to ship yet another B2B SaaS, we want you to think small. Armed with only 32 billion parameters, solve a problem someone you know is facing — or build something whimsical.
|
| 9 |
-
❋ Two Tracks · Pick your trail Choose your own adventure. Chapter One 🏡 Backyard AI Solve a real problem for someone you actually know. Pick a person — a neighbor, a parent, a small-business owner on your street — and build something that makes their day measurably better.
|
| 10 |
-
Judged on Problem is specific and real The person actually used it Honest fit between problem and the small-model constraint Polish of the Gradio app Chapter Two 🍄 An Adventure in Thousand Token Wood Build something delightful that wouldn't exist without AI. Wander somewhere weirder. A toy, a tiny game, a strange interactive story, an art experiment that surprises you. The AI should be doing the fun thing — not just helping you build it. Strange is good. Joyful is the bar.
|
| 11 |
-
Judged on Genuinely delightful (would you show a friend?) AI is load-bearing for the experience Originality of concept Polish of the Gradio app ❋ The Constraints — Three rules of the trail Pack light. 1 Small Models Only Total parameters must be ≤ 32 billion. The model fits on a laptop. So should your ambition.
|
| 12 |
-
2 Built on Gradio Your app must be a Gradio app, hosted as a Hugging Face Space. That's the canvas.
|
| 13 |
-
3 Show, Don't Tell A short demo video and a social-media post are part of the submission. Make it sing.
|
| 14 |
-
❋ Bonus Quests · Six earnable merit badges Stack 'em on your sash. None required. Each one grants extra points for your submission. Hover a patch to see it lift.
|
| 15 |
-
🔌 Off the Grid No cloud APIs. The whole thing runs on the model in front of you. Local-first 🎯 Well-Tuned Your app uses a fine-tuned model you've published on Hugging Face. Fine-tuned 🎨 Off-Brand A custom frontend that pushes past the default Gradio look (Hint: see gr.Server). Custom UI 🦙 Llama Champion Your model runs through the llama.cpp runtime. llama.cpp 📡 Sharing is Caring You shared your agent trace on the Hub for everyone to learn from. Open trace 📓 Field Notes You wrote a blog post or report about what you built and what you learned. Tentative ❋ The Awards · What you're competing for The trophy cabinet. Every submission to a main track competes for that track's podium. Sponsor and special awards are separate categories on top — one great app can take home more than one.
|
| 16 |
-
Main Track Awards · $18,000 🏡 Backyard AI Top four submissions on this trail. 1st First Place $4,000 2nd Second Place $2,500 3rd Third Place $1,500 4th Fourth Place $1,000 🍄 Thousand Token Wood Top four submissions on this trail. 1st First Place $4,000 2nd Second Place $2,500 3rd Third Place $1,500 4th Fourth Place $1,000 🗳️ Community Choice — by Hugging Face One winner, voted by the community. The app the trail itself loved most. $2,000 Sponsor Awards 🏮 OpenBMB Awards $10,000 total — three prizes in each of the two tracks for the standout OpenBMB picks. 1st First, per track $2,500 2nd Second, per track $1,500 3rd Third, per track $1,000 🌀 OpenAI Track $10,000 total — OpenAI's own podium across all submissions. 1st First Place $5,000 2nd Second Place $3,000 3rd Third Place $2,000 🟩 NVIDIA Nemotron Quest Two physical GPUs for the standout Nemotron builds. ×2 Winners RTX 5080 each 🟢 Modal Awards $20,000 in Modal credits for the top Modal-powered apps. 1st First Place $10,000 credits 2nd Second Place $7,000 credits 3rd Third Place $3,000 credits Special Awards · $8,000 $2,000 🎖️ Bonus Quest Champion The most merit badges stacked on a single sash. Collect 'em all. $1,500 🎨 Off-Brand Award The best custom UI pushing past the default Gradio look. gr.Server is your friend. $1,500 🐜 Tiny Titan The best app built on a genuinely tiny model — think ≤4B parameters. $1,000 🎬 Best Demo The full package: great app, great demo video, great social post. $1,000 🤖 Best Agent The best agentic app — all under the 32B cap, of course. $1,000 🃏 Judges' Wildcard For the entry that's amazing but fits no category. We know you're out there.
|
| 17 |
-
brainstorm, we need to win. to be eligible for OpenBMB Awards we need to use their models, for OpenAI Track we need to have codex-attributed commits that will be judged by codex itself, for nvda nemotron questsame thing we need to use their models, for modal awards we also need to use it if we care about credits but this is less priority for me.
|
| 18 |
-
|
| 19 |
-
disclaimer: the <=4 model req is for each model used in the project.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scratch/test_models.py
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
from llama_cpp import Llama, LlamaGrammar
|
| 2 |
-
import os
|
| 3 |
-
|
| 4 |
-
grammar = LlamaGrammar.from_file("grammar.gbnf")
|
| 5 |
-
nemotron = Llama(model_path="./models/step-zero-nemotron-finetuned.gguf", n_ctx=1024, verbose=False)
|
| 6 |
-
|
| 7 |
-
system_msg = "You are a cognitive pacemaker. Break down goals into extremely tiny, atomic physical actions under 8 words."
|
| 8 |
-
|
| 9 |
-
goals = [
|
| 10 |
-
"I want to study",
|
| 11 |
-
"I want to clean my room",
|
| 12 |
-
"I need to write a python script"
|
| 13 |
-
]
|
| 14 |
-
|
| 15 |
-
for goal in goals:
|
| 16 |
-
prompt = f"<extra_id_0>System\n{system_msg}\n\n"
|
| 17 |
-
prompt += f"<extra_id_1>User\nGoal: {goal}\nCompleted Tasks: None\nFailures: 0\nOutput the NEXT step.\n"
|
| 18 |
-
prompt += f"<extra_id_1>Assistant\n"
|
| 19 |
-
|
| 20 |
-
response = nemotron(
|
| 21 |
-
prompt,
|
| 22 |
-
max_tokens=64,
|
| 23 |
-
temperature=0.3,
|
| 24 |
-
stop=["\n", "<extra_id_1>"],
|
| 25 |
-
grammar=grammar
|
| 26 |
-
)
|
| 27 |
-
print(f"Goal: {goal}")
|
| 28 |
-
print(f"Response: {response['choices'][0]['text']}")
|
| 29 |
-
print("-" * 40)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/index.html
DELETED
|
@@ -1,125 +0,0 @@
|
|
| 1 |
-
<!DOCTYPE html>
|
| 2 |
-
<html lang="en">
|
| 3 |
-
<head>
|
| 4 |
-
<meta charset="UTF-8">
|
| 5 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>Step-Zero</title>
|
| 7 |
-
<script src="https://cdn.tailwindcss.com"></script>
|
| 8 |
-
<style>
|
| 9 |
-
body { background-color: #0a0a0a; color: #ffffff; font-family: 'Helvetica Neue', sans-serif; overflow: hidden;}
|
| 10 |
-
.fog { opacity: 0.3; filter: blur(2px); transition: all 0.5s ease; }
|
| 11 |
-
.fade-in { animation: fadeIn 0.5s ease-in forwards; }
|
| 12 |
-
@keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
|
| 13 |
-
</style>
|
| 14 |
-
</head>
|
| 15 |
-
<body class="h-screen w-screen flex flex-col items-center justify-center p-6">
|
| 16 |
-
|
| 17 |
-
<div id="breadcrumbs" class="absolute top-10 left-10 text-gray-500 fog text-sm space-y-2"></div>
|
| 18 |
-
|
| 19 |
-
<div id="input-screen" class="w-full max-w-2xl text-center fade-in">
|
| 20 |
-
<h1 class="text-4xl font-bold mb-8">What is paralyzing you?</h1>
|
| 21 |
-
<input type="text" id="goal-input" class="w-full bg-transparent border-b-2 border-gray-600 focus:border-white outline-none text-2xl pb-2 text-center" placeholder="e.g. Write my thesis..." autocomplete="off">
|
| 22 |
-
<div class="mt-8 flex justify-center gap-3" role="group" aria-label="Activation style">
|
| 23 |
-
<button type="button" class="style-btn px-4 py-2 border border-white text-white bg-white/10 rounded" data-style="direct">Direct</button>
|
| 24 |
-
<button type="button" class="style-btn px-4 py-2 border border-gray-700 text-gray-400 rounded" data-style="calm">Calm</button>
|
| 25 |
-
<button type="button" class="style-btn px-4 py-2 border border-gray-700 text-gray-400 rounded" data-style="encouraging">Encouraging</button>
|
| 26 |
-
</div>
|
| 27 |
-
</div>
|
| 28 |
-
|
| 29 |
-
<div id="task-screen" class="hidden w-full max-w-4xl text-center flex-col items-center justify-center fade-in">
|
| 30 |
-
<div id="current-task" class="text-5xl md:text-7xl font-extrabold tracking-tight mb-16 min-h-[150px] flex items-center justify-center">
|
| 31 |
-
</div>
|
| 32 |
-
|
| 33 |
-
<div id="controls" class="flex gap-6 justify-center w-full">
|
| 34 |
-
<button id="btn-done" class="px-8 py-4 bg-green-600 hover:bg-green-500 text-white font-bold rounded-lg text-xl transition-colors">I DID THIS</button>
|
| 35 |
-
<button id="btn-hard" class="px-8 py-4 bg-gray-800 hover:bg-gray-700 text-gray-300 font-bold rounded-lg text-xl transition-colors">TOO HARD</button>
|
| 36 |
-
</div>
|
| 37 |
-
<button id="btn-trace" class="mt-8 text-xs uppercase tracking-widest text-gray-600 hover:text-gray-300 transition-colors">Export Trace</button>
|
| 38 |
-
</div>
|
| 39 |
-
|
| 40 |
-
<script>
|
| 41 |
-
const ws = new WebSocket(`ws://${window.location.host}/ws`);
|
| 42 |
-
let currentTaskText = "";
|
| 43 |
-
let currentStyle = "direct";
|
| 44 |
-
let latestTrace = [];
|
| 45 |
-
|
| 46 |
-
const inputScreen = document.getElementById('input-screen');
|
| 47 |
-
const taskScreen = document.getElementById('task-screen');
|
| 48 |
-
const goalInput = document.getElementById('goal-input');
|
| 49 |
-
const currentTaskEl = document.getElementById('current-task');
|
| 50 |
-
const breadcrumbsEl = document.getElementById('breadcrumbs');
|
| 51 |
-
const controlsEl = document.getElementById('controls');
|
| 52 |
-
const styleButtons = document.querySelectorAll('.style-btn');
|
| 53 |
-
|
| 54 |
-
styleButtons.forEach((button) => {
|
| 55 |
-
button.addEventListener('click', () => {
|
| 56 |
-
currentStyle = button.dataset.style;
|
| 57 |
-
styleButtons.forEach((item) => {
|
| 58 |
-
const isActive = item.dataset.style === currentStyle;
|
| 59 |
-
item.className = isActive
|
| 60 |
-
? 'style-btn px-4 py-2 border border-white text-white bg-white/10 rounded'
|
| 61 |
-
: 'style-btn px-4 py-2 border border-gray-700 text-gray-400 rounded';
|
| 62 |
-
});
|
| 63 |
-
});
|
| 64 |
-
});
|
| 65 |
-
|
| 66 |
-
// Handle Enter key on input
|
| 67 |
-
goalInput.addEventListener('keypress', (e) => {
|
| 68 |
-
if (e.key === 'Enter' && goalInput.value.trim() !== '') {
|
| 69 |
-
ws.send(JSON.stringify({ action: "start", goal: goalInput.value, style: currentStyle }));
|
| 70 |
-
inputScreen.classList.add('hidden');
|
| 71 |
-
taskScreen.classList.remove('hidden');
|
| 72 |
-
currentTaskEl.innerHTML = '<span class="text-gray-600 animate-pulse">Calculating constraint...</span>';
|
| 73 |
-
controlsEl.classList.add('hidden');
|
| 74 |
-
}
|
| 75 |
-
});
|
| 76 |
-
|
| 77 |
-
// WebSocket Messages
|
| 78 |
-
ws.onmessage = (event) => {
|
| 79 |
-
const data = JSON.parse(event.data);
|
| 80 |
-
currentTaskText = data.task;
|
| 81 |
-
latestTrace = data.trace || latestTrace;
|
| 82 |
-
|
| 83 |
-
// Re-render task with fade-in
|
| 84 |
-
currentTaskEl.classList.remove('fade-in');
|
| 85 |
-
void currentTaskEl.offsetWidth; // Trigger reflow
|
| 86 |
-
currentTaskEl.innerText = data.task;
|
| 87 |
-
currentTaskEl.classList.add('fade-in');
|
| 88 |
-
|
| 89 |
-
// Show controls, hide if circuit breaker triggered
|
| 90 |
-
if(data.is_breaker) {
|
| 91 |
-
controlsEl.classList.add('hidden');
|
| 92 |
-
setTimeout(() => { controlsEl.classList.remove('hidden'); }, 3000); // 3 sec demo timeout
|
| 93 |
-
} else {
|
| 94 |
-
controlsEl.classList.remove('hidden');
|
| 95 |
-
}
|
| 96 |
-
|
| 97 |
-
// Update Breadcrumbs
|
| 98 |
-
breadcrumbsEl.innerHTML = data.history.map(t => `<div>✓ ${t}</div>`).join('');
|
| 99 |
-
};
|
| 100 |
-
|
| 101 |
-
// Button Clicks
|
| 102 |
-
document.getElementById('btn-done').addEventListener('click', () => {
|
| 103 |
-
currentTaskEl.innerHTML = '<span class="text-gray-600 animate-pulse">Loading next step...</span>';
|
| 104 |
-
controlsEl.classList.add('hidden');
|
| 105 |
-
ws.send(JSON.stringify({ action: "done", last_task: currentTaskText }));
|
| 106 |
-
});
|
| 107 |
-
|
| 108 |
-
document.getElementById('btn-hard').addEventListener('click', () => {
|
| 109 |
-
currentTaskEl.innerHTML = '<span class="text-gray-600 animate-pulse">Recalculating friction...</span>';
|
| 110 |
-
controlsEl.classList.add('hidden');
|
| 111 |
-
ws.send(JSON.stringify({ action: "too_hard" }));
|
| 112 |
-
});
|
| 113 |
-
|
| 114 |
-
document.getElementById('btn-trace').addEventListener('click', () => {
|
| 115 |
-
const blob = new Blob([JSON.stringify(latestTrace, null, 2)], { type: 'application/json' });
|
| 116 |
-
const url = URL.createObjectURL(blob);
|
| 117 |
-
const link = document.createElement('a');
|
| 118 |
-
link.href = url;
|
| 119 |
-
link.download = 'step-zero-agent-trace.json';
|
| 120 |
-
link.click();
|
| 121 |
-
URL.revokeObjectURL(url);
|
| 122 |
-
});
|
| 123 |
-
</script>
|
| 124 |
-
</body>
|
| 125 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|