openvibers/openvibe.actor Commits
Actor: README sections the docs-currency checker requires (Purpose, Depends on, Capabilities, Acceptance) (#12)
Changes
@@@ -7,6 +7,10 @@**Plan:** T17 (owner direction 2026-10-08: OpenVibe's own general agent, competing with the big labs' agents while able to use theirs; an OpenRouter for agents; cheap self-hosted browser and desktop agents). Decisions: [ADR-044](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-044-actor-runtime.md) (proposed).**License:** AGPL-3.0 (same as every OpenVibe service).++## Purpose++++Actor is OpenVibe's own general agent and the router for agent work: it takes a task in plain words, sends it to the best agent system for it, streams the steps, has a model of another family check the answer, and gives back the result with its cost and the reason it went where it did. People use it in the browser at openvibe.actor with their OpenVibe.Network account. Apps, agents and services use the same API with a Network token for audience `openvibe.actor` and an `actor.task.*` grant.++## How a task runs1. **Sort it** ([server/agents/classify.js](server/agents/classify.js)): an answer, a lookup (a domain, address or site), research (pages it names, or OpenVibe's content), a live web search, or code. A cheap model decides, or a free heuristic in private mode, so the text never leaves OpenVibe there.@@@ -75,6 +79,26 @@ Rate cards are typed in by a person from each provider's price page, with the pa- Accounts, apps and grants: **OpenVibe.Network** and **OpenVibe.Services**.- The tools the runtime uses: **OpenVibe.Tools**. Search: **OpenVibe.Search**.++## Depends on++++**Services it calls at runtime** (base URLs in [server/config.js](server/config.js)):++++- **OpenVibe.Network** (`OV_NETWORK_URL`, `OV_NETWORK_INTERNAL_URL`): sign-in (OAuth2 + PKCE, client `actor`), the JWKS that verifies session and app tokens, and the internal routes (with this service's own client-credentials token) where account export parts and deletion confirmations are pushed.++- **OpenVibe.Search** (`ACTOR_SEARCH_URL`): content across the network, for the runtime's `search_openvibe` tool.++- **OpenVibe.Tools** (`ACTOR_TOOLS_URL`): the catalog, the run API and the page reader, for `find_tools`, `run_tool` and `read_page`. Called as any anonymous caller would.++- **OpenVibe.Events** (`ACTOR_EVENTS_URL`): the two ADR-033 subscriptions created at boot, and delivery to the loopback `/internal/events`.++- **The model providers**: DeepSeek (`ACTOR_DEEPSEEK_API_KEY`, `api.deepseek.com`), OpenAI (`ACTOR_OPENAI_API_KEY`, `api.openai.com/v1`) for the web-search agent and the cross-family check, and an OpenAI-compatible local server (`ACTOR_LOCAL_LLM_URL`) for private mode.++++**Data:** PostgreSQL (openvibe-sdk/db, `DATABASE_URL` / `DATABASE_DIRECT_URL`) holds tasks, their events and daily spend; Valkey (`VALKEY_URL`) holds the shared per-caller limit counters. A provider or service without its key or URL is listed unavailable, never invented.++++**Libraries:** openvibe-contracts (contract validation, problem responses, service-token verification, capability checks); openvibe-sdk (`placement` for routing, `auth`, `db`, `limits`, `account-data`, `valkey`, `service`); openvibe-shared (`serve`, `cache-policy`, `frame`, `shell`, `showcase`, `seo`, `legal`, `release`, `metrics`, `ready`); express, helmet, express-rate-limit, cookie-parser, pg, iovalkey.++++## Capabilities++++- **Required on this API:** `actor.task.create` (create a task, cancel one), `actor.task.read` (one task, its live stream), `actor.task.list` (list your tasks). A person acting for themself needs no capability; an app, agent or service token for audience `openvibe.actor` needs the one the route names, granted on OpenVibe.Services. `actor.agent.read` is the code's name for the catalog and the dry run, which are public.++- **Held on other services:** a client-credentials token for audience `openvibe.events`, scope `events.subscription.manage`, creates the two ADR-033 subscriptions at OpenVibe.Events; the same `actor` principal's token pushes account export parts and deletion confirmations to OpenVibe.Network's internal routes.++- **Not held:** the runtime presents no grant to OpenVibe.Search or OpenVibe.Tools — it uses only what any anonymous caller may call.++## What comes next1. Browser and desktop agents on OpenVibe's own cheap servers (Run workers with a headless browser and a virtual desktop), watchable live and taken over by the owner.@@@ -98,6 +122,24 @@ Readiness requires the database and at least one available agent.- **Rollback:** ovhost puts the previous sha back by itself when `/api/ready` does not answer after the restart.- **A stop:** running tasks are stopped and recorded as `actor.task.interrupted`. They are never re-run behind the person's back.++## Acceptance++++Run the suite with Node 22 (the Development block below):++++- `npm test` — every [test/*.test.js](test/) in its own process on temp PGlite databases, with in-process mocks of OpenVibe.Network, OpenVibe.Events and OpenVibe.Media and stand-in model providers; nothing needs the network or a running site.++- `npm run test:pg` — the same suite against PostgreSQL instead of PGlite.++- `npm test -- <word>` runs only files whose name contains a word; `npm test -- --strict` makes a skipped test fail the run.++++What the main tests prove:++++- [test/tasks.test.js](test/tasks.test.js): a task end to end through the API and the real adapters — classified, routed, run, checked, delivered as `platform.task@1` with its cost and explanation; hand-off to the next agent on an error or a failed check; private mode never sending the text outside OpenVibe; hard budgets and the free tier; idempotency; cancel; the live stream replaying and ending; nobody seeing another person's task.++- [test/contracts.test.js](test/contracts.test.js): the released `actor` service manifest and its four capability manifests match the routes, guards and response shapes in the code.++- [test/account-data.test.js](test/account-data.test.js): the ADR-033 export and deletion through the signed `/internal/events` route carry only the person's rows; a redelivery erases nothing twice, and a bad signature or a forwarded request is refused.++- [test/caller-limits.test.js](test/caller-limits.test.js): one caller past its limit gets 429 before any work while another passes; the budgets and the `actor_rate_limited_total` metric are pinned.++- [test/security-ssrf.test.js](test/security-ssrf.test.js), [test/security-secrets.test.js](test/security-secrets.test.js) and [test/security-session.test.js](test/security-session.test.js): Actor never fetches a URL from a request or a task, outbound requests reach only configured bases, no secret leaves in a body or a log, and a FedCM assertion is not a session.++++The remaining files cover sign-in (PKCE, state, redirect safety), the Network JWKS, the pages and layout, crawl artifacts, asset caching, per-file size budgets, graceful stop and the nginx sign-in limits.++## Development```bash
@@ -7,6 +7,10 @@
@@ -7,6 +7,10 @@
**Plan:** T17 (owner direction 2026-10-08: OpenVibe's own general agent, competing with the big labs' agents while able to use theirs; an OpenRouter for agents; cheap self-hosted browser and desktop agents). Decisions: [ADR-044](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-044-actor-runtime.md) (proposed).
**Plan:** T17 (owner direction 2026-10-08: OpenVibe's own general agent, competing with the big labs' agents while able to use theirs; an OpenRouter for agents; cheap self-hosted browser and desktop agents). Decisions: [ADR-044](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-044-actor-runtime.md) (proposed).
**License:** AGPL-3.0 (same as every OpenVibe service).
**License:** AGPL-3.0 (same as every OpenVibe service).
+## Purpose
+
+Actor is OpenVibe's own general agent and the router for agent work: it takes a task in plain words, sends it to the best agent system for it, streams the steps, has a model of another family check the answer, and gives back the result with its cost and the reason it went where it did. People use it in the browser at openvibe.actor with their OpenVibe.Network account. Apps, agents and services use the same API with a Network token for audience `openvibe.actor` and an `actor.task.*` grant.
+
## How a task runs
## How a task runs
1. **Sort it** ([server/agents/classify.js](server/agents/classify.js)): an answer, a lookup (a domain, address or site), research (pages it names, or OpenVibe's content), a live web search, or code. A cheap model decides, or a free heuristic in private mode, so the text never leaves OpenVibe there.
1. **Sort it** ([server/agents/classify.js](server/agents/classify.js)): an answer, a lookup (a domain, address or site), research (pages it names, or OpenVibe's content), a live web search, or code. A cheap model decides, or a free heuristic in private mode, so the text never leaves OpenVibe there.
@@ -75,6 +79,26 @@ Rate cards are typed in by a person from each provider's price page, with the pa
@@ -75,6 +79,26 @@ Rate cards are typed in by a person from each provider's price page, with the pa
- Accounts, apps and grants: **OpenVibe.Network** and **OpenVibe.Services**.
- Accounts, apps and grants: **OpenVibe.Network** and **OpenVibe.Services**.
- The tools the runtime uses: **OpenVibe.Tools**. Search: **OpenVibe.Search**.
- The tools the runtime uses: **OpenVibe.Tools**. Search: **OpenVibe.Search**.
+## Depends on
+
+**Services it calls at runtime** (base URLs in [server/config.js](server/config.js)):
+
+- **OpenVibe.Network** (`OV_NETWORK_URL`, `OV_NETWORK_INTERNAL_URL`): sign-in (OAuth2 + PKCE, client `actor`), the JWKS that verifies session and app tokens, and the internal routes (with this service's own client-credentials token) where account export parts and deletion confirmations are pushed.
+- **OpenVibe.Search** (`ACTOR_SEARCH_URL`): content across the network, for the runtime's `search_openvibe` tool.
+- **OpenVibe.Tools** (`ACTOR_TOOLS_URL`): the catalog, the run API and the page reader, for `find_tools`, `run_tool` and `read_page`. Called as any anonymous caller would.
+- **OpenVibe.Events** (`ACTOR_EVENTS_URL`): the two ADR-033 subscriptions created at boot, and delivery to the loopback `/internal/events`.
+- **The model providers**: DeepSeek (`ACTOR_DEEPSEEK_API_KEY`, `api.deepseek.com`), OpenAI (`ACTOR_OPENAI_API_KEY`, `api.openai.com/v1`) for the web-search agent and the cross-family check, and an OpenAI-compatible local server (`ACTOR_LOCAL_LLM_URL`) for private mode.
+
+**Data:** PostgreSQL (openvibe-sdk/db, `DATABASE_URL` / `DATABASE_DIRECT_URL`) holds tasks, their events and daily spend; Valkey (`VALKEY_URL`) holds the shared per-caller limit counters. A provider or service without its key or URL is listed unavailable, never invented.
+
+**Libraries:** openvibe-contracts (contract validation, problem responses, service-token verification, capability checks); openvibe-sdk (`placement` for routing, `auth`, `db`, `limits`, `account-data`, `valkey`, `service`); openvibe-shared (`serve`, `cache-policy`, `frame`, `shell`, `showcase`, `seo`, `legal`, `release`, `metrics`, `ready`); express, helmet, express-rate-limit, cookie-parser, pg, iovalkey.
+
+## Capabilities
+
+- **Required on this API:** `actor.task.create` (create a task, cancel one), `actor.task.read` (one task, its live stream), `actor.task.list` (list your tasks). A person acting for themself needs no capability; an app, agent or service token for audience `openvibe.actor` needs the one the route names, granted on OpenVibe.Services. `actor.agent.read` is the code's name for the catalog and the dry run, which are public.
+- **Held on other services:** a client-credentials token for audience `openvibe.events`, scope `events.subscription.manage`, creates the two ADR-033 subscriptions at OpenVibe.Events; the same `actor` principal's token pushes account export parts and deletion confirmations to OpenVibe.Network's internal routes.
+- **Not held:** the runtime presents no grant to OpenVibe.Search or OpenVibe.Tools — it uses only what any anonymous caller may call.
+
## What comes next
## What comes next
1. Browser and desktop agents on OpenVibe's own cheap servers (Run workers with a headless browser and a virtual desktop), watchable live and taken over by the owner.
1. Browser and desktop agents on OpenVibe's own cheap servers (Run workers with a headless browser and a virtual desktop), watchable live and taken over by the owner.
@@ -98,6 +122,24 @@ Readiness requires the database and at least one available agent.
@@ -98,6 +122,24 @@ Readiness requires the database and at least one available agent.
- **Rollback:** ovhost puts the previous sha back by itself when `/api/ready` does not answer after the restart.
- **Rollback:** ovhost puts the previous sha back by itself when `/api/ready` does not answer after the restart.
- **A stop:** running tasks are stopped and recorded as `actor.task.interrupted`. They are never re-run behind the person's back.
- **A stop:** running tasks are stopped and recorded as `actor.task.interrupted`. They are never re-run behind the person's back.
+## Acceptance
+
+Run the suite with Node 22 (the Development block below):
+
+- `npm test` — every [test/*.test.js](test/) in its own process on temp PGlite databases, with in-process mocks of OpenVibe.Network, OpenVibe.Events and OpenVibe.Media and stand-in model providers; nothing needs the network or a running site.
+- `npm run test:pg` — the same suite against PostgreSQL instead of PGlite.
+- `npm test -- <word>` runs only files whose name contains a word; `npm test -- --strict` makes a skipped test fail the run.
+
+What the main tests prove:
+
+- [test/tasks.test.js](test/tasks.test.js): a task end to end through the API and the real adapters — classified, routed, run, checked, delivered as `platform.task@1` with its cost and explanation; hand-off to the next agent on an error or a failed check; private mode never sending the text outside OpenVibe; hard budgets and the free tier; idempotency; cancel; the live stream replaying and ending; nobody seeing another person's task.
+- [test/contracts.test.js](test/contracts.test.js): the released `actor` service manifest and its four capability manifests match the routes, guards and response shapes in the code.
+- [test/account-data.test.js](test/account-data.test.js): the ADR-033 export and deletion through the signed `/internal/events` route carry only the person's rows; a redelivery erases nothing twice, and a bad signature or a forwarded request is refused.
+- [test/caller-limits.test.js](test/caller-limits.test.js): one caller past its limit gets 429 before any work while another passes; the budgets and the `actor_rate_limited_total` metric are pinned.
+- [test/security-ssrf.test.js](test/security-ssrf.test.js), [test/security-secrets.test.js](test/security-secrets.test.js) and [test/security-session.test.js](test/security-session.test.js): Actor never fetches a URL from a request or a task, outbound requests reach only configured bases, no secret leaves in a body or a log, and a FedCM assertion is not a session.
+
+The remaining files cover sign-in (PKCE, state, redirect safety), the Network JWKS, the pages and layout, crawl artifacts, asset caching, per-file size budgets, graceful stop and the nginx sign-in limits.
+
## Development
## Development
```bash
```bash