惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
I
InfoQ
B
Blog RSS Feed
D
Docker
GbyAI
GbyAI
N
Netflix TechBlog - Medium
Y
Y Combinator Blog
F
Fortinet All Blogs
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
人人都是产品经理
人人都是产品经理
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
M
MIT News - Artificial intelligence
C
Check Point Blog
Vercel News
Vercel News
云风的 BLOG
云风的 BLOG
博客园 - Franky
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
Last Week in AI
Last Week in AI
L
LangChain Blog

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw LinkedIn™ 职位抓取工具 - Chrome 应用商店
GitHub - hsaghir/looplet: The tool-calling loop for LLM a...
hsaghir · 2026-04-30 · via Hacker News: Show HN

demo — 4-tool data-cleanup loop with a DebugHook trace and a human approval pause

CI codecov PyPI version Python 3.11+ License: Apache 2.0 Status: Beta

looplet exposes the agent loop as an iterator, makes every step observable, and lets you compose behavior with hooks. Build LLM agents that call tools in a loop while you keep ordinary Python control over every step — no graph DSL, no subclassing, no vendor lock-in. Zero runtime dependencies.

Elevator pitch: looplet is the tiny agent loop you can actually own. Yield every tool call, inspect every result, intercept any decision, and grow from a 30-line prototype to a production agent without switching frameworks.

from looplet import composable_loop

for step in composable_loop(llm=llm, tools=tools, task=task, config=cfg, state=state):
    print(step.pretty())          # → "#1 ✓ search(query='…') → 12 items [182ms]"
    if step.tool_result.error:
        break                     # your loop, your control flow
pip install looplet               # core — zero third-party packages pulled in
pip install "looplet[openai]"     # works with OpenAI, Ollama, Together, Groq, vLLM, …
pip install "looplet[anthropic]"  # or Anthropic directly

The simple story

Every looplet agent turn is the same small mechanism:

  1. The LLM proposes a tool call.
  2. The registry validates and dispatches it.
  3. Hooks observe or steer the turn.
  4. State records the step.
  5. The loop yields a Step back to your for loop.

That is the whole mental model. Presets, skills, cartridges, provenance, native tool calling, and evals are useful layers around this mechanism; they do not replace it.

for step in composable_loop(llm=llm, tools=tools, state=state, config=config, hooks=hooks):
  print(step.pretty())

Start with ordinary Python code when you want full control. Start with a cartridge when you want to run or share a packaged capability:

python -m looplet run ./skills/coder "Fix the tests" --workspace .
python -m looplet blueprint ./skills/coder --workspace .
python -m looplet export-code ./skills/coder coder_agent.py

Why it exists

Most agent frameworks give you agent.run(task) and a black box. When the agent does something wrong at step 7, you can't step in between step 6 and step 8. You end up forking the library or writing a second agent to babysit the first.

looplet does the opposite: the loop is the product, and hooks are the extension API. Every tool call is a Step object you can print, save, or diff. Every decision the loop makes — what goes in the next prompt, whether to compact context, whether to dispatch a dangerous tool, whether to stop — is a Protocol method you implement in a few lines. Hooks compose without inheritance. Nothing is hidden.

That one design choice is where the library's three practical superpowers come from:

  • Shape agent behaviour without forking — a 10-line hook can redact PII from every prompt, inject retrieved docs, rewrite tool arguments, or rate-limit calls to a single tool. Hooks are the extension point the framework can't close off because the loop itself is built on them.
  • Manage context on your termscompact_chain(Prune, Summarize, Truncate) is three hooks you wire together. Swap the strategy, change the budget, fire on a different threshold — no monkey-patching.
  • Debug and eval without a second toolstep.pretty() is a human-readable trace, ProvenanceSink dumps every prompt the LLM saw plus every tool result into a diff-friendly directory, and pytest-style eval_* functions turn that trace into a regression suite. Your debug output is your eval harness.

That is the differentiation: looplet is not trying to be a complete agent product. It is the control plane for people building one.


The mental model — one picture

looplet is a for loop you own. The LLM proposes a tool call, the registry dispatches it, hooks observe or steer, state records the result, and the loop yields a Step. The diagram below expands that simple story into the hook points you can customize:

%%{init: {"theme":"base","themeVariables":{
  "fontFamily":"ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, sans-serif",
  "fontSize":"15px",
  "lineColor":"#94a3b8"
}}}%%
flowchart LR
    you(["<b>your code</b><br/><span style='font-size:11px;opacity:.75'>for&nbsp;step&nbsp;in&nbsp;loop(...)</span>"]):::you

    h1["<b>pre_prompt</b><br/><span style='font-size:11px;opacity:.9'>redact&nbsp;·&nbsp;inject&nbsp;·&nbsp;compact</span>"]:::hookBlue
    h2["<b>pre_dispatch</b><br/><span style='font-size:11px;opacity:.9'>permissions&nbsp;·&nbsp;approval&nbsp;·&nbsp;rewrite</span>"]:::hookAmber
    h3["<b>post_dispatch</b><br/><span style='font-size:11px;opacity:.9'>trace&nbsp;·&nbsp;metrics&nbsp;·&nbsp;checkpoint</span>"]:::hookAmber
    h4["<b>check_done</b><br/><span style='font-size:11px;opacity:.9'>stop&nbsp;rules&nbsp;·&nbsp;budgets</span>"]:::hookGreen

    subgraph loop[" "]
      direction LR
      prompt(["<b>PROMPT</b><br/><span style='font-size:11px;opacity:.85'>build&nbsp;·&nbsp;call&nbsp;LLM</span>"]):::phaseBlue
      dispatch(["<b>DISPATCH</b><br/><span style='font-size:11px;opacity:.85'>validate&nbsp;·&nbsp;run&nbsp;tool</span>"]):::phaseAmber
      done{{"<b>DONE?</b>"}}:::phaseGreen
      prompt -- "tool call" --> dispatch
      dispatch -- "observation" --> done
      done -- "no" --> prompt
    end

    step[/"<b>Step</b><br/><span style='font-size:11px;opacity:.85'>prompt&nbsp;·&nbsp;call&nbsp;·&nbsp;result&nbsp;·&nbsp;usage</span>"/]:::step

    you == "task" ==> prompt
    done == "yes" ==> step
    step == "yield" ==> you

    h1 -.-> prompt
    h2 -.-> dispatch
    h3 -.-> dispatch
    h4 -.-> done

    linkStyle 0,1,2 stroke:#94a3b8,stroke-width:2px
    linkStyle 3 stroke:#475569,stroke-width:3px
    linkStyle 4 stroke:#059669,stroke-width:3px
    linkStyle 5 stroke:#475569,stroke-width:3px
    linkStyle 6 stroke:#3b82f6,stroke-width:1.5px
    linkStyle 7 stroke:#f59e0b,stroke-width:1.5px
    linkStyle 8 stroke:#f59e0b,stroke-width:1.5px
    linkStyle 9 stroke:#10b981,stroke-width:1.5px

    classDef you        fill:#0f172a,stroke:#334155,stroke-width:2px,color:#f8fafc;
    classDef phaseBlue  fill:#dbeafe,stroke:#2563eb,stroke-width:2.5px,color:#1e3a8a;
    classDef phaseAmber fill:#fef3c7,stroke:#d97706,stroke-width:2.5px,color:#78350f;
    classDef phaseGreen fill:#d1fae5,stroke:#059669,stroke-width:2.5px,color:#064e3b;
    classDef step       fill:#eef2ff,stroke:#4338ca,stroke-width:2.5px,color:#312e81;
    classDef hookBlue   fill:#eff6ff,stroke:#3b82f6,stroke-width:1.5px,color:#1e40af;
    classDef hookAmber  fill:#fffbeb,stroke:#f59e0b,stroke-width:1.5px,color:#92400e;
    classDef hookGreen  fill:#ecfdf5,stroke:#10b981,stroke-width:1.5px,color:#065f46;

    style loop fill:#f8fafc,stroke:#cbd5e1,stroke-width:2px,stroke-dasharray:10 6,color:#1e293b;
Loading

Every amber box is a Protocol method. A hook is any object that implements one or more of them — no base class, no inheritance:

class RedactPII:
    def pre_prompt(self, state, log, ctx, step):
        return _scrub_emails(ctx)          # mutates the next LLM prompt

class RetryFlakyTool:
    def pre_dispatch(self, state, log, tc, step):
        if tc.tool == "web_search" and state.last_error:
            return Deny("retry with backoff", retry=True)

for step in composable_loop(..., hooks=[RedactPII(), RetryFlakyTool()]):
    ...

Ship-ready hooks already wired in: ApprovalHook, PermissionHook, CheckpointHook, ContextPressureHook, ThresholdCompactHook, ProvenanceSink, TracingHook, MetricsHook, EvalHook, plus the compact_chain(Prune, Summarize, Truncate) context strategy. Use any, all, or none — and drop in your own in 10 lines.


Your first agent (60 seconds)

from looplet import BaseToolRegistry, OpenAIBackend, composable_loop
from looplet.tools import register_done_tool

llm = OpenAIBackend.from_env(model="gpt-4o-mini")  # reads OPENAI_API_KEY etc

tools = BaseToolRegistry()


@tools.tool
def greet(name: str) -> dict:
    """Greet someone by name."""
    return {"greeting": f"Hello, {name}!"}


register_done_tool(tools)

for step in composable_loop(
    llm=llm,
    tools=tools,
    task={"goal": "Greet Alice and Bob, then finish."},
    max_steps=5,
):
    print(step.pretty())

Works out of the box with any OpenAI-compatible endpoint. No Claude-only SDK, no pydantic schema gymnastics, no LangChain memory objects.

Try it on your laptop against a local Ollama in three lines:

OPENAI_BASE_URL=http://127.0.0.1:11434/v1 \
OPENAI_API_KEY=ollama OPENAI_MODEL=llama3.1 \
python -m looplet.examples.hello_world

When should you reach for looplet?

Use it when you want to build your own agent loop and actually own the details. Concretely:

  • You need to insert logic at an exact phase of the loop — before the prompt is built, before a tool is dispatched, after a tool returns — without forking a framework.
  • You need to swap context-management strategy at runtime (prune, summarize, truncate, your own) without losing the rest of your stack.
  • You need the loop to pause for human approval, then resume where it left off when approval arrives.
  • You want first-class debugging and evaluation — a printable Step, a prompt-level provenance dump, pytest-style eval_* functions — without bolting on a second tool.
  • You want zero runtime dependencies and a loop that cold-imports in ~300 ms (numbers in docs/benchmarks.md).

Don't reach for looplet if you want agent.run(task) to handle everything and return a string, or if you want a visual graph DSL — a higher-level framework will feel more natural and the overlap in features won't be worth the extra control looplet gives you.


Examples

Real-LLM examples read OPENAI_BASE_URL, OPENAI_API_KEY, and OPENAI_MODEL from the environment. Point them at Ollama or any OpenAI-compatible endpoint, or use --scripted where available for a deterministic no-model run.

python -m looplet.examples.hello_world                            # 30-line starter
python -m looplet.examples.hello_world --scripted                 # no model required
python -m looplet.examples.coding_agent "implement fizzbuzz"      # bash/read/write/edit/grep
python -m looplet.examples.coding_agent --trace ./traces/         # save full trajectory
python -m looplet.examples.coding_agent "implement add" --scripted --workspace /tmp/demo
python -m looplet.examples.data_agent --clean                     # approval + compact + checkpoints
python -m looplet.examples.data_agent --resume                    # resume from last checkpoint
python -m looplet.examples.data_agent --scripted --auto-approve   # no model required

Runnable cartridges package the same primitives behind a portable folder:

python -m looplet list-bundles examples/coder --json
python -m looplet run examples/coder/skill "Create a tiny add function with tests" --scripted --workspace /tmp/demo
python -m looplet export-code examples/coder/skill /tmp/coder_agent.py  # exact local wrapper
python -m looplet package my_agent:build ./skills/my-agent --name my-agent --description "Run my agent."
python -m looplet wrap-claude-skill ./claude-skills/pdf ./skills/pdf

For a memorable custom agent, start with Dependency Doctor: point it at a repo and it audits dependency files for security, license, and maintenance risk, then produces a report card. It is concrete enough to be useful, broad enough that most developers understand the pain, and it shows looplet's core value: the user can watch every evidence-gathering step and add guardrails without rewriting the agent.

OPENAI_BASE_URL=http://127.0.0.1:11434/v1 \
OPENAI_API_KEY=ollama OPENAI_MODEL=llama3.1 \
python examples/dep_doctor/agent.py /path/to/project

# No model required: deterministic local dogfood run
python examples/dep_doctor/agent.py examples/dep_doctor/demo_project --scripted

Other example directions that show off the same infrastructure: examples/git_detective/ for repo-health analysis, examples/threat_intel/ for local-first security briefings, and examples/coder/ for a coding agent with bash/read/write/edit/test tools.

# More no-model dogfood runs
python -m looplet.examples.hello_world --scripted
python -m looplet.examples.ollama_hello --scripted
python examples/git_detective/agent.py . --scripted
python examples/threat_intel/agent.py --scripted
python examples/coder/agent.py "Create a tiny add function with tests" --scripted
python -m looplet.examples.coding_agent "Implement add" --scripted --workspace /tmp/demo
python -m looplet.examples.data_agent --scripted --auto-approve --clean

Plus scripted_demo.py — a scripted MockLLMBackend run used only to record the GIF above. Not a usage reference.


Learn more

Doc What's in it
docs/tutorial.md Build your first agent in 5 steps
docs/hooks.md Writing and composing hooks
docs/skills.md Lazy skills, runnable cartridges, blueprints, and Claude Skill wrapping
docs/evals.md pytest-style agent evaluation
docs/provenance.md Capturing prompts + trajectories
docs/recipes.md Ollama, OTel, MCP, cost accounting, checkpoints
docs/benchmarks.md Cold-import time & dep footprint vs alternatives
docs/faq.md FAQ, including "why not LangGraph?"
ROADMAP.md What's planned, what's frozen, what's out of scope
CONTRIBUTING.md Dev setup, conventions, PR checklist
CHANGELOG.md Release notes

Stability

looplet follows SemVer. Pre-1.0, minor versions may introduce breaking changes as the design stabilises — pin conservatively:

looplet>=0.1.8,<0.2

See ROADMAP.md § v1.0 API contract for the frozen surface and the path to 1.0.

Contributors

Thanks to everyone who has contributed to looplet:

See CONTRIBUTING.md for how to get started.

Contributing

Contributions welcome: bug reports, docs, backends, examples, evals. Start with CONTRIBUTING.md and docs/good-first-issues.md. Security issues go through SECURITY.md.

License

Apache 2.0. See LICENSE.