diff --git a/CHANGELOG.md b/CHANGELOG.md index 8646771..5d714ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,14 @@ adheres to [Semantic Versioning](https://semver.org/). - **pi extensions** (`plugins/pi/pi-extensions-adapter.ts`): the tools and tool policies of [pi](https://github.com/earendil-works/pi) coding-agent extensions, loaded unchanged with pi's own loader, as one yoagent handler following pi 1.1.0's semantics. `registerTool` → tools (pi's activation and first-registration-wins, `prepareArguments` and validation before the policies, only the judged arguments run), `setActiveTools` → an enforced allowlist, `tool_call` → `before_tool` (yoagent's built-ins under pi's names, arguments translated both ways, relative paths resolved where the policies look; an override of a built-in is enforced; `terminate` stops the run), `tool_result` → `after_tool` (a failing handler withholds the result), `input` → `on_input`, `before_agent_start` additions → a turn note. Fails closed: a load error, a failing `session_start`, an unfired deciding event (`context`, `message_end`, ...; unless `allowUnmapped`) or a pi tool named like a yoagent built-in (unless `withoutBuiltins`) refuses the load; other unmapped API (observer and session events, commands, renderers, providers, MCP servers) is reported, or refuses with `strict`. Example `pi_extensions` (any extension files; `--live` with DeepSeek; `--without`), test `pi_test`. `ctx.executeTool` runs pi tools as nested calls (pi's pipeline; never rejects); a deciding event registered mid-run stops that run; adapter warnings reach the host's logs. `pi.appendEntry` / `pi.sendMessage` are recorded in the adapter's in-memory session instead of throwing (pi tools that record their result this way no longer fail after the work). CI: a weekly `pi latest` job runs the adapter's tests against the newest pi. - **Images in tool results, across ecosystems.** TypeScript and Python handlers' `call_tool` results and `after_tool` edits take `content` blocks in yoagent's JSON shape (`{"type": "image", "data": , "mimeType"}` next to text blocks) instead of `text`, so pictures cross the bridge both ways (`after_tool` already saw `output.content`). The dsh adapter turns dsh image blocks (references into dsh's attachment store) into yoagent images through the `attachments` service when one is loaded; the rutis-agent example reads a runner's `{"content": [...]}` value as blocks (rutis-agent results are otherwise text). Rust handlers already returned full yoagent tool results. Tests: `content_blocks` unit test, TypeScript/Python round trip in `languages_test`, dsh with and without a store in `dsh_test`. - **Plugin logs reach the host.** The `yoagent` service gains `log(level, message, { run_id }?)`: a TypeScript/Python plugin's diagnostics go to the host's `tracing` output (target `yoagent_rutis::plugin`, with the run as a `run_id` field) instead of the runtime process's stderr. It never rejects (a rejected, uncaught call would end the plugin's runtime): any message, extra context fields ignored. In Python it is a coroutine to `await`. The dsh adapter uses it. Test: `tests/plugin_log_test.rs`. -- **Docs: one contract, other ecosystems.** The extensions guide shows DSH and rutis-agent plugging in through `Extension` and the bridge with no core change (pi in review, #265); the bridge README states the adapter contract (map what the host honours, refuse what would decide unenforced, deny on failing policies, withhold on failing redactions, report what is ignored). CI now also runs the rutis-agent example. +- **Docs: one contract, other ecosystems.** The extensions guide shows DSH and rutis-agent plugging in through `Extension` and the bridge with no core change (pi too, since #265); the bridge README states the adapter contract (map what the host honours, refuse what would decide unenforced, deny on failing policies, withhold on failing redactions, report what is ignored). CI now also runs the rutis-agent example. - Test fix: `dsh_test` no longer reads the abort file mid-write (empty) as the result. +### Docs + +- **Design philosophy** (`docs/design-philosophy.md`): why yoagent is a loop library and not an agent, the one `Extension` contract, fail-closed rules, plugins and ecosystems outside the core, what it costs, and a checklist for what belongs in the core. Linked from the introduction and the README. +- The yoagent-rutis adapter guide gives dated npm package counts for the pi and DSH ecosystems (packages, not plugins that run through the adapters). + ## 0.25.0 (2026-10-08) ### Added diff --git a/README.md b/README.md index 3868b6d..a813045 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,7 @@ Built something on yoagent? [Open a PR](CONTRIBUTING.md) and add it here — we' Each line links to its chapter in [the book](https://yologdev.github.io/yoagent/). - **The loop** — a full event stream, parallel / sequential / batched tools, steering and follow-ups, execution limits, retry with backoff and jitter, and the original hooks (`ToolMiddleware`, input filters, `TurnHook`, lifecycle callbacks). [Agent loop](https://yologdev.github.io/yoagent/concepts/agent-loop.html) · [Events](https://yologdev.github.io/yoagent/concepts/messages-events.html) · [Retry](https://yologdev.github.io/yoagent/concepts/retry.html) · [Callbacks & hooks](https://yologdev.github.io/yoagent/concepts/callbacks.html) -- **Extensions** — one plug-in contract for the whole run: add tools, check input, gate and rewrite tool calls, redact results, verify the final answer, enforce a dollar `Budget`, audit events, and cover sub-agents with host policy. The [`yoagent-rutis`](integrations/yoagent-rutis/) bridge (not yet on crates.io) installs [rutis](https://crates.io/crates/rutis) plugins, in Rust, TypeScript or Python, as one extension. [Extensions](https://yologdev.github.io/yoagent/concepts/extensions.html) +- **Extensions** — one plug-in contract for the whole run: add tools, check input, gate and rewrite tool calls, redact results, verify the final answer, enforce a dollar `Budget`, audit events, and cover sub-agents with host policy. The [`yoagent-rutis`](integrations/yoagent-rutis/) bridge installs [rutis](https://crates.io/crates/rutis) plugins, in Rust, TypeScript or Python, as one extension, and plugs in other agent ecosystems (DSH tool plugins, pi extensions) through small adapters with no core change. [Extensions](https://yologdev.github.io/yoagent/concepts/extensions.html) - **Providers** — 7 native protocols (Anthropic, OpenAI Completions and Responses, Azure, Gemini, Vertex, Bedrock) reaching 20+ providers, with thinking controls, prompt-cache hints and centralised context-overflow detection. [Providers](https://yologdev.github.io/yoagent/providers/overview.html) · [Prompt caching](https://yologdev.github.io/yoagent/concepts/prompt-caching.html) - **Tools** — built-in `bash`, file read/write/edit, `list_files` and `search` (native), custom tools via one trait, MCP over stdio or HTTP, OpenAPI specs, and per-run `ToolSource`s. [Tools](https://yologdev.github.io/yoagent/concepts/tools.html) · [MCP](https://yologdev.github.io/yoagent/guides/mcp.html) · [OpenAPI](https://yologdev.github.io/yoagent/guides/openapi.html) - **Sub-agents and shared state** — delegate to child loops with their own model and tools; pass large artifacts by reference. [Sub-agents](https://yologdev.github.io/yoagent/concepts/sub-agents.html) @@ -228,6 +228,7 @@ in [CONTRIBUTING](CONTRIBUTING.md). ## Documentation - **[The book](https://yologdev.github.io/yoagent/)** — concepts, guides, a page per provider, and the [architecture and module map](https://yologdev.github.io/yoagent/architecture/overview.html) ([source](docs/)) +- **[Design philosophy](https://yologdev.github.io/yoagent/design-philosophy.html)** — why yoagent is a loop library, the one extension contract, and what that costs - **[API reference](https://docs.rs/yoagent)** — built with all features enabled - **[CHANGELOG](CHANGELOG.md)** — every release - **[CONTRIBUTING](CONTRIBUTING.md)** — how to build, test, and send a PR diff --git a/docs/concepts/extensions.md b/docs/concepts/extensions.md index 736801a..68dc0fb 100644 --- a/docs/concepts/extensions.md +++ b/docs/concepts/extensions.md @@ -171,7 +171,7 @@ So is the [`yoagent-rutis`](https://github.com/yologdev/yoagent/tree/main/integr |---|---|---|---| | [DSH](https://github.com/yologdev/yoagent/tree/main/integrations/yoagent-rutis#dsh-deepseek-harness-tool-plugins) (DeepSeek Harness) | Cordis plugins in Node | a small adapter over DSH's own tool registry (`plugins/dsh/`) | tools (images included), the system-prompt sections plugins add (as a turn note), cancellation | | [rutis-agent](https://github.com/yologdev/yoagent/tree/main/integrations/yoagent-rutis#rutis-agent-tools) | Rust tools in a rutis registry | a Rust rutis plugin (`examples/rutis-agent-tools/`) | tools (images by convention), hot-added tools, cancellation | -| [pi](https://github.com/earendil-works/pi) | TypeScript extensions written against pi's `ExtensionAPI` | an adapter that loads them with pi's own loader ([`plugins/pi/`](https://github.com/yologdev/yoagent/tree/main/integrations/yoagent-rutis#pi-extensions-tools-and-tool-policies), experimental) | tools, tool policies, input checks, prompt additions, images | +| [pi](https://github.com/earendil-works/pi) | TypeScript extensions written against pi's `ExtensionAPI` | an adapter that loads them with pi's own loader ([`plugins/pi/`](https://github.com/yologdev/yoagent/tree/main/integrations/yoagent-rutis#pi-extensions-tools-and-tool-policies)) | tools, tool policies, input checks, prompt additions, images | What the bridge gives every ecosystem alike: TypeScript and Python handlers next to Rust ones, one registration order, **image** tool results both ways (`content` blocks), **plugin logs** in the host's `tracing` output (`yoagent.log`, with the run they belong to), and failures that deny rather than allow. What stays outside the loop on purpose — commands, dialogs, session history, a UI — belongs to the app that hosts the agent. diff --git a/docs/design-philosophy.md b/docs/design-philosophy.md index 809fdfe..8ac2d5f 100644 --- a/docs/design-philosophy.md +++ b/docs/design-philosophy.md @@ -81,7 +81,7 @@ That bridge is how other agent ecosystems reach yoagent. DSH's tool plugins, rut Two consequences: -- **The contract is the claim, not the adapters.** That three foreign ecosystems fit through one `Extension` is the evidence the contract is general. The adapters themselves follow other projects' releases and need app services (commands, dialogs, sessions) to be complete; they live in the companion crate, marked experimental, and are expected to move to the app that hosts them. +- **The contract is the claim, not the adapters.** That three foreign ecosystems fit through one `Extension` is the evidence the contract is general. The adapters themselves follow other projects' releases, and the parts of those ecosystems that need app services (commands, dialogs, sessions) are left to the app that hosts the agent. - **What crosses the bridge is what every ecosystem gets:** images in tool results both ways, plugin logs in the host's `tracing`, tagged with their `run_id` so a recorder such as [GASP](concepts/gasp.md) can attribute them, and the fail-closed rules. ## 6. Correct over clever — and honest about cost and cache diff --git a/integrations/yoagent-rutis/README.md b/integrations/yoagent-rutis/README.md index 2ce79ad..1269b27 100644 --- a/integrations/yoagent-rutis/README.md +++ b/integrations/yoagent-rutis/README.md @@ -4,7 +4,7 @@ Extend [yoagent](https://crates.io/crates/yoagent) agents at runtime with [rutis](https://crates.io/crates/rutis) plugins — in Rust, TypeScript or Python — through one yoagent `Extension`. -**Status:** 0.1.0, not yet on crates.io; needs yoagent's `Extension` (0.25). +**Status:** on [crates.io](https://crates.io/crates/yoagent-rutis); needs yoagent's `Extension` (0.25). The DSH and pi adapters below cover tools, tool policies, input checks, prompt additions and images; commands, dialogs and UI belong to the app and are not mapped. rutis (a Rust port of the [Cordis](https://github.com/shigma/cordis) plugin kernel) loads, unloads, reloads and hot-updates plugins, and tears down @@ -353,10 +353,11 @@ cargo run --manifest-path examples/rutis-agent-tools/Cargo.toml [-- --live] ### pi extensions (tools and tool policies) -> **Experimental.** The pi and DSH adapters live here for now, and are -> expected to move to the yo app (or their own packages) once it hosts -> plugins: completing them needs app services — commands, dialogs, -> sessions — that a loop library does not have. The bridge itself stays. +> **Scope.** The adapter maps what an agent loop can honour: tools, tool +> policies, input checks, prompt additions and images. Commands, dialogs, +> UI and session history belong to the app hosting the agent and are not +> mapped (reported, or refused when they would decide something). It is +> pinned to pi 1.1.0 and tested weekly against the latest pi. [pi](https://github.com/earendil-works/pi) extensions are TypeScript modules written against pi's `ExtensionAPI`. diff --git a/integrations/yoagent-rutis/src/lib.rs b/integrations/yoagent-rutis/src/lib.rs index e834110..236b214 100644 --- a/integrations/yoagent-rutis/src/lib.rs +++ b/integrations/yoagent-rutis/src/lib.rs @@ -26,6 +26,14 @@ //! yoagent itself knows nothing about rutis; the bridge uses only yoagent's //! public API. //! +//! TypeScript and Python handlers (features `node`, `python`, `websocket`) +//! can return images in tool results and write logs into the host's +//! `tracing` output (target `yoagent_rutis::plugin`). Plugins from other +//! agent ecosystems — DSH tool plugins, pi extensions — plug in through +//! adapters shipped in the repository's `plugins/` directory; +//! see the [README](https://github.com/yologdev/yoagent/tree/main/integrations/yoagent-rutis) +//! and its adapter contract. +//! //! # Host //! //! ```no_run