diff --git a/vendor/actors/docs/AGENTS.md b/vendor/actors/docs/AGENTS.md deleted file mode 120000 index 681311eb..00000000 --- a/vendor/actors/docs/AGENTS.md +++ /dev/null @@ -1 +0,0 @@ -CLAUDE.md \ No newline at end of file diff --git a/vendor/actors/docs/CLAUDE.md b/vendor/actors/docs/CLAUDE.md deleted file mode 100644 index 2d6ae04c..00000000 --- a/vendor/actors/docs/CLAUDE.md +++ /dev/null @@ -1,125 +0,0 @@ -# Docs Bundle CLAUDE.md - -Rules for the docs in this repo. These pages are **not** rendered here — they are -published on [rivet.dev](https://rivet.dev) by the -[rivet-website](https://github.com/rivet-dev/website) repo, which symlinks -this directory in. Everything below exists so a page written here renders -correctly there. - -## Layout - -``` -docs/ - sidebar.json navigation for the two tabs - content/ - docs/**.mdx -> /{product}/docs/... - tutorials/**.mdx -> /{product}/tutorials/... -``` - -The website links `docs/content` into its content collection, so **only real -pages belong under `content/`**. Anything else (scripts, fixtures, notes) goes -elsewhere in the repo or it will be published as a docs page. - -## Frontmatter - -Every page needs `title` and `description`. Both are used for SEO and the -sidebar falls back to `title` when a sidebar entry omits one. - -```mdx ---- -title: "In-Memory State" -description: "Actors store state in memory for instant reads and writes." ---- -``` - -## sidebar.json - -Navigation for this product's Documentation and Tutorials tabs. Icons travel as -Font Awesome **export names**, not objects, so this repo needs no dependency on -the website's icon package. - -```json -{ - "docs": [ - { "title": "General", "pages": [ - { "title": "Introduction", "href": "/actors/docs", "icon": "faSquareInfo" } - ]} - ], - "tutorials": [] -} -``` - -- `href` is the full site path, including the product segment. -- Adding a page to `content/` does not add it to the nav. Add it here too. -- The Self-Host tab is **not** in this file. It is generated by the website. - -## Code - -- **Never inline a fenced TypeScript block.** Real examples live in `examples/` - and are embedded with ``, so they are type-checked and cannot rot. - A snippet that fails to compile fails the website build. -- Snippet paths are relative to **this repo's root**, so the same path works both - here and on rivet.dev: - ```mdx - - ``` -- Embed part of a file with `region="name"`, delimited in the source by - `// docs:start name` / `// docs:end name`. -- Shell commands, YAML, Dockerfiles, and terminal output **may** be inline fenced - blocks. The no-inline rule exists for type checking, which only applies to - TypeScript. -- Every TypeScript snippet must include its imports and define everything it - references. Use `@nocheck` only for API that does not exist on this branch yet. -- Use `` for examples spanning multiple files, with each - file as its own ``. - -## What does not belong here - -- **Marketing pages.** They live in the website repo. -- **Deploy and self-hosting guides.** They are written once in the website repo - and templated across every product. Do not write a per-product copy. -- **Website components.** Do not import from the website by relative path or - alias; a page must render from the components the site already provides. - -## Terminology - -Applies to everything published on the website. - -- The service that routes, schedules, and persists is the **control plane**. - Never "engine", "server", or "orchestrator". -- A process running user code with the Rivet SDK is a **worker**. Never "envoy", - "runner", "node", "compute", or "data plane". -- **Never use "agent" as a deployment noun.** Rivet ships agentOS and Actors is - "where agents live"; the collision is unrecoverable. -- **"envoy" never appears in docs.** Envoy Proxy is a top-tier CNCF project. - Internal code keeps its own names. -- **"Rivet Compute" is retired.** Where prose must name the managed offering it - is **Rivet Cloud**, and it links to . -- Spell the product `agentOS`, never `AgentOS`. Capitalize **Rivet Actor** as a - proper noun, lowercase generic "actor". -- Always `rivet.dev`, never `rivet.gg`. - -## Writing - -- Write comments and prose as complete sentences. **Never use em dashes**; use - periods instead. -- Do not document deltas. A reader who never saw the old version gains nothing - from "this was renamed". - -## Previewing locally - -Clone the website next to this repo and run it. It detects the sibling -automatically and serves this directory's pages live: - -```sh -git clone https://github.com/rivet-dev/website -cd rivet-website && pnpm install && pnpm dev -``` - -`pnpm assemble` prints which checkout each product resolved to. To point at a -different checkout, repoint the symlink; it is gitignored and assemble leaves an -existing one alone: - -```sh -ln -sfn /path/to/this/repo/docs/content src/content/docs/ -``` diff --git a/vendor/actors/docs/content/docs/limits.mdx b/vendor/actors/docs/content/docs/limits.mdx index 28bc3c1f..16a0bae2 100644 --- a/vendor/actors/docs/content/docs/limits.mdx +++ b/vendor/actors/docs/content/docs/limits.mdx @@ -56,6 +56,12 @@ These limits affect actions that do not use `.connect()` and [low-level HTTP req | Max response body size | — | 20 MiB | Maximum size of HTTP response bodies. | | Request timeout | 60 seconds | — | Maximum time for an `onRequest` handler to complete. Defaults to `actionTimeout`; configure with `actionTimeout`. | +### Actions + +| Name | Soft Limit | Hard Limit | Description | +|------|------------|------------|-------------| +| Max actions per actor | 128 | None | Maximum number of action handlers defined on one actor. Nested action groups count each leaf handler. Configurable via `maxActions`. | + ### Networking | Name | Soft Limit | Hard Limit | Description | diff --git a/vendor/actors/docs/content/docs/sqlite-profiling.mdx b/vendor/actors/docs/content/docs/sqlite-profiling.mdx new file mode 100644 index 00000000..4caef10e --- /dev/null +++ b/vendor/actors/docs/content/docs/sqlite-profiling.mdx @@ -0,0 +1,232 @@ +--- +title: "SQLite Profiling" +description: "Profile SQLite statements and transactions in Rivet Actors using bounded metrics and sampled diagnostics." +skill: true +--- + +Profiling helps you find slow queries, transaction contention, and unnecessary storage activity. + +## Logging slow queries + +RivetKit logs slow or failed SQLite statements and transactions. Logs include the fingerprint, outcome, timing breakdown, and storage activity; statement logs also include rows and bytes, while transaction logs include the statement count. + +Search actor logs for `sampled SQLite operation profile` for statements or `sampled SQLite transaction profile` for transactions. + +## Identify operations + +### Transaction names + +Transaction names provide a stable identity for profiling transactions. Use a short, static name to correlate metrics. + +Pass `{ name: "complete-order" }` as the options argument to `db.transaction()`. + +Without a name, RivetKit falls back to a fingerprint of the transaction's statement sequence. Branches and different loop counts can therefore produce separate fingerprints. + +### Statement fingerprints + +RivetKit hashes each SQL statement exactly as provided. The fingerprint groups metrics without putting SQL text in a Prometheus label. + +For example, repeated `SELECT * FROM orders WHERE id = ?` calls share one fingerprint regardless of the bound ID. + +### Find the SQL for a fingerprint + +RivetKit logs the SQL statement or transaction name for each tracked fingerprint. + +For example, suppose a Prometheus result contains `fingerprint="select-a1b2c3d4e5f60718"`: + +1. Copy the fingerprint: `select-a1b2c3d4e5f60718`. +2. Search the actor logs for `sqlite fingerprint catalog` and `select-a1b2c3d4e5f60718`. +3. Read `identity` from the matching log line: + + ```text + sqlite fingerprint catalog fingerprint="select-a1b2c3d4e5f60718" identity="SELECT value FROM items WHERE id = ?" + ``` + +## Query metrics + +Collect [Prometheus metrics from each worker](/actors/self-host/workers/prometheus-metrics/) to use the queries below. + +### Slowest statements and transactions + +Find the statements and transactions with the highest 95th-percentile latency. + +```promql +histogram_quantile( + 0.95, + sum by (le, actor_name, type, fingerprint) ( + rate(rivet_rivetkit_sqlite_duration_seconds_bucket[5m]) + ) +) +``` + +### Slowest latency phases + +Break down slow operations to see whether they spend time waiting, executing SQL, or accessing storage. + +- `transaction_wait`: waiting for another transaction on the actor to finish. +- `worker_wait`: waiting for earlier SQLite work on the actor to finish. +- `storage`: loading or saving SQLite data. +- `local_work`: executing SQL and preparing results, excluding storage time. +- `application_time`: time the transaction stays open between SQL calls. +- `commit`: saving changes at the end of a transaction. + +```promql +histogram_quantile( + 0.95, + sum by (le, actor_name, type, fingerprint, phase) ( + rate(rivet_rivetkit_sqlite_phase_duration_seconds_bucket[5m]) + ) +) +``` + +### Non-success outcomes + +Find statements and transactions that fail, roll back, expire, or lose their connection. + +```promql +sum by (actor_name, type, fingerprint, outcome) ( + rate(rivet_rivetkit_sqlite_outcome_total{outcome!="success"}[5m]) +) +``` + +### Transaction contention + +See whether transactions are waiting for other transactions on the same actor. + +```promql +max by (actor_name) ( + max_over_time(rivet_rivetkit_sqlite_coordinator_queue_depth[5m]) +) +``` + +### Native worker saturation + +See whether SQLite operations are backing up on an actor. A sustained queue means work is arriving faster than SQLite can finish it, while `worker_inflight` shows how often SQLite is busy. + +```promql +max by (actor_name) ( + max_over_time(rivet_rivetkit_sqlite_worker_queue_depth[5m]) +) +``` + +```promql +avg by (actor_name) ( + avg_over_time(rivet_rivetkit_sqlite_worker_inflight[5m]) +) +``` + +### Transactions with the most statements + +Find transactions that execute many SQL statements before finishing. Large counts can identify loops or oversized units of work; use a static transaction name to keep its fingerprint stable. + +```promql +histogram_quantile( + 0.95, + sum by (le, actor_name, fingerprint) ( + rate(rivet_rivetkit_sqlite_transaction_statement_count_bucket[5m]) + ) +) +``` + +### Average storage round trips per operation + +See how many times each operation contacts storage on average. High counts can indicate a missing index, a large scan, or ineffective prefetching. + +```promql +sum by (actor_name, type, fingerprint) ( + rate(rivet_rivetkit_sqlite_get_pages_round_trips_sum[5m]) +) +/ +sum by (actor_name, type, fingerprint) ( + rate(rivet_rivetkit_sqlite_get_pages_round_trips_count[5m]) +) +``` + +### Pages per physical storage request + +See how many pages each storage request asks for and returns. Compare `response_present` with `demand_requested` to find response amplification; `overflow_expansion_extra` shows overflow-chain reads, and `prefetch_requested` shows speculative reads. + +```promql +sum by (actor_name, request_ordinal, page_kind) ( + rate(rivet_rivetkit_sqlite_get_pages_pages_sum[5m]) +) +/ +sum by (actor_name, request_ordinal, page_kind) ( + rate(rivet_rivetkit_sqlite_get_pages_pages_count[5m]) +) +``` + +### Large storage responses + +Find storage requests that return unusually large amounts of SQLite data. + +```promql +histogram_quantile( + 0.95, + sum by (le, actor_name, request_ordinal) ( + rate(rivet_rivetkit_sqlite_get_pages_response_bytes_bucket[5m]) + ) +) +``` + +### Missing response pages + +Find storage requests that could not return every requested page. + +```promql +sum by (actor_name, request_ordinal) ( + rate(rivet_rivetkit_sqlite_get_pages_missing_pages_total[5m]) +) +``` + +### SQLite page usage by kind + +Break down the pages used for each kind of SQLite activity. High page counts can indicate a missing index or a large scan. + +```promql +sum by (actor_name, type, page_kind) ( + rate(rivet_rivetkit_sqlite_local_pages_total[5m]) +) +``` + +### SQLite data volume by kind + +Compare bytes used by query parameters, results, storage reads, and writes. + +```promql +sum by (actor_name, type, byte_kind) ( + rate(rivet_rivetkit_sqlite_local_bytes_total[5m]) +) +``` + +## Configure profiling + +Profiling is enabled by default and most applications do not need to configure it. The entire profiling configuration surface is experimental and subject to change without notice. Set `profiling.slowOperationThresholdMs` or `profiling.baselineSampleRate` on the database provider when needed. + +Increase fingerprint limits only when `other` is hiding frequently repeated operations. Prometheus series remain allocated for the life of the process after admission. + +## Troubleshooting + +### Most results are `other` + +Fast statements initially appear under `other`, while overflow metrics show when a fingerprint limit was reached. Increase limits only for useful operations that repeat regularly. + +### Too many fingerprints + +Statement fingerprints use the exact query text. Keep formatting and query structure static, and pass dynamic values as bindings instead of constructing SQL strings. + +### Transactions are hard to identify + +Unnamed transactions are grouped by their statement sequence, which can vary across branches. Add a static `name` to each important transaction. + +### Storage activity is high + +Use the storage queries above to compare page counts, response bytes, and round trips by actor name. Large scans or missing indexes are common causes. + +### Diagnostics are missing + +Diagnostic events are sampled and bounded. Check `rivet_rivetkit_sqlite_event_dropped_total` for rate limiting or backpressure; aggregate Prometheus metrics continue reporting when events are dropped. + +### No profiling metrics appear + +Confirm profiling was not disabled in the database provider. Profiling currently applies to native actor-local SQLite, not remote or wasm SQLite. diff --git a/vendor/actors/docs/content/docs/sqlite.mdx b/vendor/actors/docs/content/docs/sqlite.mdx index 0fd4241a..a0dbcc43 100644 --- a/vendor/actors/docs/content/docs/sqlite.mdx +++ b/vendor/actors/docs/content/docs/sqlite.mdx @@ -88,13 +88,16 @@ const rows = await c.db.execute( Use transactions when multiple writes must succeed or fail together. ```ts @nocheck -await c.db.transaction(async (tx) => { - await tx.execute("INSERT INTO todos (title) VALUES (?)", title); - await tx.execute( - "INSERT INTO comments (todo_id, body) VALUES (last_insert_rowid(), ?)", - body, - ); -}); +await c.db.transaction( + async (tx) => { + await tx.execute("INSERT INTO todos (title) VALUES (?)", title); + await tx.execute( + "INSERT INTO comments (todo_id, body) VALUES (last_insert_rowid(), ?)", + body, + ); + }, + { name: "create-todo" }, +); ``` RivetKit commits when the callback resolves and rolls back when it throws. Other transactions and ordinary actor SQL queue in FIFO order until the callback finishes. Transactions have a 60-second safety timeout by default; increase it for legitimately long work with `{ timeout: 120_000 }`. @@ -103,6 +106,8 @@ Always use the callback's `tx` value inside the transaction. Starting another tr Manual `BEGIN`/`COMMIT` calls remain supported for compatibility, but cannot protect against interleaving callers. RivetKit logs a warning recommending `db.transaction()`. Set `warnOnManualTransactions: false` in `db(...)` to disable the warning; the warning itself mentions this flag. +Use a static transaction name for profiling, never a request ID or other dynamic value. + ## Queues It's recommended to use queues for mutations and actions for read-only queries. This is the same code structure as the basic setup, but mutation writes are routed through queues. @@ -121,6 +126,10 @@ It's recommended to use queues for mutations and actions for read-only queries. - Keep a small read-only action for quick query verification while debugging. - In non-dev mode, inspector endpoints require authorization. +## Profiling + +See [SQLite Profiling](/actors/docs/sqlite-profiling) to understand query fingerprints, transaction names, metrics, and diagnostics. + ## Recommendations - Keep schema creation and migration steps in `onMigrate`; RivetKit runs them atomically inside a SQLite savepoint. diff --git a/vendor/actors/docs/sidebar.json b/vendor/actors/docs/sidebar.json index f72d3bc4..c6aafcd6 100644 --- a/vendor/actors/docs/sidebar.json +++ b/vendor/actors/docs/sidebar.json @@ -172,6 +172,10 @@ "title": "SQLite + Drizzle", "href": "/actors/docs/sqlite-drizzle" }, + { + "title": "SQLite Profiling", + "href": "/actors/docs/sqlite-profiling" + }, { "title": "Logging", "href": "/actors/docs/general/logging" diff --git a/vendor/actors/examples/docs/actors-limits/actor-options.ts b/vendor/actors/examples/docs/actors-limits/actor-options.ts index 25c3b69c..2aa44fbb 100644 --- a/vendor/actors/examples/docs/actors-limits/actor-options.ts +++ b/vendor/actors/examples/docs/actors-limits/actor-options.ts @@ -2,6 +2,7 @@ import { actor } from "rivetkit"; const myActor = actor({ options: { + maxActions: 128, maxQueueSize: 1000, actionTimeout: 60_000, stateSaveInterval: 1_000, diff --git a/vendor/actors/rivetkit-typescript/artifacts/actor-config.json b/vendor/actors/rivetkit-typescript/artifacts/actor-config.json index 5d4a3d85..6b0ce929 100644 --- a/vendor/actors/rivetkit-typescript/artifacts/actor-config.json +++ b/vendor/actors/rivetkit-typescript/artifacts/actor-config.json @@ -63,7 +63,7 @@ "description": "Called for raw WebSocket connections to /actors/{name}/websocket/* endpoints." }, "actions": { - "description": "Map of action name to handler function. Defaults to an empty object.", + "description": "Tree of action names or nested groups to handler functions. Nested paths use dot-separated low-level action names. Defaults to an empty object.", "type": "object", "propertyNames": { "type": "string" @@ -71,7 +71,7 @@ "additionalProperties": {} }, "actionInputSchemas": { - "description": "Optional schema map for validating action argument tuples in native runtimes.", + "description": "Optional schemas for validating action argument tuples in native runtimes. May mirror nested action groups or use dot-separated low-level action names.", "type": "object", "propertyNames": { "type": "string" @@ -109,6 +109,12 @@ "description": "Icon for the actor in the Inspector UI. Can be an emoji (e.g., '🚀') or FontAwesome icon name (e.g., 'rocket').", "type": "string" }, + "maxActions": { + "description": "Maximum number of action handlers that may be defined on this actor. Default: 128", + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, "enableActorRuntimeSocket": { "description": "Enables the experimental Actor Runtime Socket for this actor. Default: false", "type": "boolean" @@ -173,6 +179,12 @@ "description": "Maximum number of queue messages before rejecting new messages. Default: 1000", "type": "number" }, + "maxSchedules": { + "description": "Maximum pending one-shot and recurring schedules before rejecting new schedules. Default: 1000", + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, "maxQueueMessageSize": { "description": "Maximum size of each queue message in bytes. Default: 65536", "type": "number" @@ -187,4 +199,4 @@ }, "additionalProperties": false, "title": "RivetKit Actor Configuration" -} +} \ No newline at end of file diff --git a/vendor/actors/rivetkit-typescript/packages/rivetkit/package.json b/vendor/actors/rivetkit-typescript/packages/rivetkit/package.json index 4f52492c..b95a85b3 100644 --- a/vendor/actors/rivetkit-typescript/packages/rivetkit/package.json +++ b/vendor/actors/rivetkit-typescript/packages/rivetkit/package.json @@ -1,6 +1,6 @@ { "name": "rivetkit", - "version": "2.3.7", + "version": "2.3.11", "description": "Lightweight libraries for building stateful actors on edge platforms", "license": "Apache-2.0", "keywords": [ @@ -136,6 +136,16 @@ "default": "./dist/tsup/inspector/mod.cjs" } }, + "./experimental/inspector/workflow": { + "import": { + "types": "./dist/tsup/inspector/workflow.d.ts", + "default": "./dist/tsup/inspector/workflow.js" + }, + "require": { + "types": "./dist/tsup/inspector/workflow.d.cts", + "default": "./dist/tsup/inspector/workflow.cjs" + } + }, "./inspector-tab": { "import": { "types": "./dist/tsup/inspector-tab/mod.d.ts", @@ -181,7 +191,7 @@ "./dist/tsup/chunk-*.cjs" ], "scripts": { - "build": "tsup src/mod.ts src/client/mod.ts src/common/log.ts src/common/websocket.ts src/actor/errors.ts src/utils.ts src/workflow/mod.ts src/test/mod.ts src/inspector/mod.ts src/inspector-tab/mod.ts src/db/mod.ts src/db/drizzle.ts src/dynamic/mod.ts src/unstable/migrations.ts && tsup src/agent-os/index.ts --no-clean --out-dir dist/tsup/agent-os", + "build": "tsup src/mod.ts src/client/mod.ts src/common/log.ts src/common/websocket.ts src/actor/errors.ts src/utils.ts src/workflow/mod.ts src/test/mod.ts src/inspector/mod.ts src/inspector/workflow.ts src/inspector-tab/mod.ts src/db/mod.ts src/db/drizzle.ts src/dynamic/mod.ts src/unstable/migrations.ts && tsup src/agent-os/index.ts --no-clean --out-dir dist/tsup/agent-os && node scripts/check-built-commonjs.mjs", "build:browser": "tsup --config tsup.browser.config.ts", "check-types": "tsc --noEmit", "lint": "biome check . && pnpm run check:test-skips && pnpm run check:wait-for-comments",