@sapiom/agent-core
Advanced tools
+36
-0
| # @sapiom/orchestration-core | ||
| ## 0.13.2 | ||
| ### Patch Changes | ||
| - db81e32: Step code can now tell a local trace from a deployed run, and the stub Postgres DSN no longer points at a host that might answer. | ||
| `AgentExecutionContext` gains `isLocalTrace?: boolean` — `true` under `run_local`, and set by nothing else. The deployed step runner does not set it, so `input.dryRun ?? ctx.isLocalTrace` reads as live in production; the name is qualified precisely because that absence is load-bearing. | ||
| Use it for the I/O `run_local` cannot stub — a raw Postgres socket, third-party HTTP, any client holding its own connection. Resolve it once in the entry step and carry it in `ctx.shared`, since `input` downstream is the previous step's output: | ||
| ```ts | ||
| // entry step | ||
| const dryRun = input.dryRun ?? ctx.isLocalTrace ?? false; | ||
| ctx.shared.set("dryRun", dryRun); | ||
| ``` | ||
| An explicit `{ "dryRun": false }` still forces the live path. Capability calls (`ctx.sapiom.*`) are already stubbed locally and need no guard. | ||
| Separately, the stub `database.get` / `database.create` DSN now uses a host in the reserved `.invalid` TLD (RFC 6761) instead of `localhost`. A template that dialed the old DSN reached whatever Postgres happened to be listening on the author's own machine and failed with an opaque TLS error; it now fails at name resolution on any conforming resolver. Treat this as a backstop rather than a guard — a resolver that hijacks NXDOMAIN can still return an address — and gate the dial on `ctx.isLocalTrace`. | ||
| - 054f749: `sapiom-sandbox-preview` skill now teaches App Links. It says plainly that a | ||
| sandbox preview URL is temporary (it dies with the resource's `ttl`, along with | ||
| any bookmark or Slack message it was pasted into), and adds a "Make it durable / | ||
| share it" section that routes "share this", "send this to my team", "a permanent | ||
| link", "keep it alive", "my link died" to `sapiom_dev_app_publish` — with the | ||
| five facts an agent otherwise gets wrong: wake-on-demand cold start, org-scoped | ||
| by default (public needs `confirmPublic` + `dailySpendCapUsd`, so ask first), | ||
| republish-in-place on the same slug, text-only bundles, and the ~10 MiB cap. The | ||
| frontmatter `description` picks up the durability triggers so the skill fires on | ||
| a "link that won't die" ask. | ||
| - Updated dependencies [db81e32] | ||
| - Updated dependencies [9165f18] | ||
| - Updated dependencies [6fb3273] | ||
| - @sapiom/agent@0.12.2 | ||
| - @sapiom/tools@0.33.0 | ||
| ## 0.13.1 | ||
@@ -4,0 +40,0 @@ |
@@ -81,2 +81,3 @@ "use strict"; | ||
| sapiom, | ||
| isLocalTrace: true, | ||
| }; | ||
@@ -83,0 +84,0 @@ let stepInput = request.input; |
| export declare const VERSION_FALLBACK: { | ||
| readonly agent: "0.12.1"; | ||
| readonly tools: "0.32.0"; | ||
| readonly agent: "0.12.2"; | ||
| readonly tools: "0.33.0"; | ||
| }; |
@@ -5,4 +5,4 @@ "use strict"; | ||
| exports.VERSION_FALLBACK = { | ||
| agent: "0.12.1", | ||
| tools: "0.32.0", | ||
| agent: "0.12.2", | ||
| tools: "0.33.0", | ||
| }; |
@@ -78,2 +78,3 @@ import { InMemoryContextStore, StepInputValidationError, } from "@sapiom/agent"; | ||
| sapiom, | ||
| isLocalTrace: true, | ||
| }; | ||
@@ -80,0 +81,0 @@ let stepInput = request.input; |
| export declare const VERSION_FALLBACK: { | ||
| readonly agent: "0.12.1"; | ||
| readonly tools: "0.32.0"; | ||
| readonly agent: "0.12.2"; | ||
| readonly tools: "0.33.0"; | ||
| }; |
| export const VERSION_FALLBACK = { | ||
| agent: "0.12.1", | ||
| tools: "0.32.0", | ||
| agent: "0.12.2", | ||
| tools: "0.33.0", | ||
| }; |
+4
-4
| { | ||
| "name": "@sapiom/agent-core", | ||
| "version": "0.13.1", | ||
| "version": "0.13.2", | ||
| "description": "Pure, stateless core functions for scaffolding, validating, and operating Sapiom agents — shared by the CLI and MCP packages.", | ||
@@ -40,6 +40,6 @@ "license": "MIT", | ||
| "esbuild": "^0.28.1", | ||
| "@sapiom/agent": "^0.12.1", | ||
| "@sapiom/agent": "^0.12.2", | ||
| "@sapiom/agent-runtime": "^0.7.0", | ||
| "@sapiom/tools": "^0.32.0", | ||
| "@sapiom/analytics-core": "^0.2.1" | ||
| "@sapiom/analytics-core": "^0.2.1", | ||
| "@sapiom/tools": "^0.33.0" | ||
| }, | ||
@@ -46,0 +46,0 @@ "devDependencies": { |
@@ -274,2 +274,3 @@ --- | ||
| | `ctx.sapiom` | `Sapiom` | The typed capability client — the `Sapiom` interface from `@sapiom/tools`, installed in your `node_modules` (see "Capabilities" below) | | ||
| | `ctx.isLocalTrace` | `boolean \| undefined` | `true` under `run_local`; **absent** on a deployed run. Gate raw I/O `run_local` cannot stub (see "Testing with `run_local`") | | ||
| | `ctx.organizationId` | `string \| null` | Tenant org | | ||
@@ -602,2 +603,28 @@ | `ctx.tenantId` | `string \| null` | Tenant id | | ||
| ### Gate I/O the stub cannot see | ||
| `run_local` stubs `ctx.sapiom.*` and nothing else. Anything holding its own connection — a | ||
| `postgres` client, raw HTTP to a third party — still runs for real. `database.get` succeeds | ||
| and hands back a DSN, but that DSN's host is in the reserved `.invalid` TLD and does not | ||
| resolve, so dialing it fails. | ||
| Resolve a `dryRun` gate **once, in the entry step**, and carry it in `ctx.shared`: | ||
| ```ts | ||
| // entry step — `input` is the execution's entry input | ||
| const dryRun = input.dryRun ?? ctx.isLocalTrace ?? false; | ||
| ctx.shared.set("dryRun", dryRun); | ||
| if (!dryRun) { | ||
| // raw sockets, third-party HTTP — the things run_local cannot stub | ||
| } | ||
| // any later step: `input` is the previous step's output, so re-deriving it here | ||
| // would read live on a deployed run the caller asked to be dry. | ||
| const dryRun = ctx.shared.get("dryRun") ?? false; | ||
| ``` | ||
| `ctx.isLocalTrace` is absent on a deployed run, so `?? ctx.isLocalTrace` supplies the default | ||
| without changing production behaviour — and an explicit `{ "dryRun": false }` still forces the | ||
| live path when you want to exercise it. | ||
| `run_local` works with **no stubs** — capabilities return sensible defaults. Add | ||
@@ -604,0 +631,0 @@ `.sapiom-dev/stubs.json` overrides only when a step branches on a specific result: |
| --- | ||
| name: sapiom-sandbox-preview | ||
| description: Deploy a live preview of a web app from the current project to a | ||
| Sapiom sandbox. Use when the user wants to preview, host, or deploy a web | ||
| app, dev server, API, or static site to a live URL ("preview this app", | ||
| "give me a live link", "host this server"), or mentions sapiom.json sandbox | ||
| resources. Do NOT use for deploying Sapiom agents (that's | ||
| sapiom_dev_agents_deploy) or for one-off capability calls. | ||
| description: Deploy a web app from the current project to a live Sapiom URL — | ||
| either a throwaway sandbox preview or a durable App Link. Use when the user | ||
| wants to preview, host, deploy, or share a web app, dashboard, dev server, | ||
| API, or static site ("preview this app", "give me a live link", "host this | ||
| server"), and especially when they want that link to last ("a permanent | ||
| link", "something I can share with my team", "keep it alive", "my link | ||
| died"), or mentions sapiom.json sandbox resources or App Links. Do NOT use | ||
| for deploying Sapiom agents (that's sapiom_dev_agents_deploy) or for one-off | ||
| capability calls. | ||
| --- | ||
| # Sandbox Previews | ||
| # Sandbox Previews & App Links | ||
| Deploy the web app in the current project directory to a Sapiom **sandbox** and get a | ||
| **live public URL** — provisioned, uploaded, built, and started in one tool call. Driven | ||
| by the sapiom-dev MCP (`npx -y @sapiom/mcp`; see the [Get Started guide](https://docs.sapiom.ai/) | ||
| if it isn't connected). | ||
| Two ways to put the web app in the current project on a live URL, both driven by the | ||
| sapiom-dev MCP (`npx -y @sapiom/mcp`; see the [Get Started guide](https://docs.sapiom.ai/) | ||
| if it isn't connected) and both reading the same `sapiom.json` resource: | ||
| **This is not agent deployment.** Sapiom *agents* deploy with `sapiom_dev_agents_deploy`; | ||
| sandbox previews host an ordinary app (Node server, static site, API) from your working | ||
| directory. | ||
| | You want | Tool | The URL | | ||
| | --------------------------------------------- | ---------------------------- | --------------------------------------------------- | | ||
| | To look at it now, iterate, throw it away | `sapiom_dev_sandbox_preview` | **Temporary** — dies with the sandbox's `ttl` | | ||
| | A link that lasts, or that someone else opens | `sapiom_dev_app_publish` | **Durable** — `https://apps.sapiom.ai/{org}/{slug}` | | ||
| **This is not agent deployment.** Sapiom _agents_ deploy with `sapiom_dev_agents_deploy`; | ||
| both tools here host an ordinary app (Node server, static site, API, dashboard) from your | ||
| working directory. | ||
| ## Prerequisite | ||
| Run `sapiom_authenticate` once (browser login; caches a key in `~/.sapiom/credentials.json`). | ||
| `sapiom_dev_sandbox_preview` returns a structured not-authenticated error otherwise; | ||
| `configure` and `check` only touch local files and work signed-out. Check with | ||
| `sapiom_status`. | ||
| `sapiom_dev_sandbox_preview` and `sapiom_dev_app_publish` return a structured | ||
| not-authenticated error otherwise; `configure` and `check` only touch local files and work | ||
| signed-out. Check with `sapiom_status`. | ||
@@ -35,3 +42,3 @@ ## The lifecycle | ||
| the stored config. | ||
| 2. **`sapiom_dev_sandbox_check`** *(optional)* — statically validates the resources without | ||
| 2. **`sapiom_dev_sandbox_check`** _(optional)_ — statically validates the resources without | ||
| deploying. Returns `{ ok, sandboxes, issues }`; fix any `issues` before previewing. | ||
@@ -42,2 +49,3 @@ 3. **`sapiom_dev_sandbox_preview`** — reads `sapiom.json`, provisions the sandbox if | ||
| resource. | ||
| 4. **`sapiom_dev_app_publish`** — when the link needs to outlive the sandbox. See below. | ||
@@ -48,2 +56,45 @@ **A `failed` status is not an error** — it carries the build/start logs so you can fix the | ||
| **The preview URL is temporary.** It belongs to a sandbox that expires with the resource's | ||
| `ttl` (default `1h`), and it goes away with it — along with any bookmark, Slack message, or | ||
| doc anyone pasted it into. Say so when you hand it over, and reach for | ||
| `sapiom_dev_app_publish` instead whenever the link is meant to survive. | ||
| ## Make it durable / share it | ||
| Route to **`sapiom_dev_app_publish`** whenever the ask is about the link lasting or leaving | ||
| your machine — "share this", "send this to my team", "a permanent link", "keep it alive", | ||
| "can I bookmark this", "put this somewhere", "my link died", "the URL stopped working". | ||
| ``` | ||
| sapiom_dev_app_publish { slug: "dash", name: "Dash" } | ||
| → { url: "https://apps.sapiom.ai/{org}/dash", appLinkId, bundleSha256, manifest } | ||
| ``` | ||
| It reads the **same** `sapiom.json` sandbox resource (source dir, `start`, `port`, optional | ||
| `build`/`env`), uploads the source as a stored bundle, and activates it. What to know: | ||
| - **Wake on demand, not always-on.** Nothing runs until someone visits. The first visit | ||
| after a publish cold-starts the app — tens of seconds behind a "Starting…" page — then | ||
| it's fast until it idles out again. Tell the user that, so a slow first load doesn't read | ||
| as broken. | ||
| - **Org-scoped by default.** Only logged-in members of the organization can open it. | ||
| `visibility: "public"` (anyone with the link) additionally needs `confirmPublic: true` | ||
| and a `dailySpendCapUsd` — the org pays for every wake, so **ask the user before setting | ||
| either**. | ||
| - **Republish in place.** Publishing the same `slug` again replaces the app at the _same_ | ||
| URL and returns a new `bundleSha256`. That is how you ship an update; never mint a second | ||
| slug for v2. | ||
| - **Text-only bundles.** UTF-8 files only — no images, fonts, or archives. A binary is | ||
| rejected **by name** before anything is uploaded; drop it, or use inline SVG, a data URL, | ||
| or a CDN reference. `node_modules`, `.git`, dotfiles, symlinks and the project's own | ||
| `sapiom.json` are never uploaded, so install dependencies at wake with the resource's | ||
| `build` command. | ||
| - **~10 MiB** per bundle over this path, checked locally before the upload. Drop generated | ||
| output (`dist`, build artifacts, vendored assets) rather than shipping it. | ||
| - Pass `resource` only when the project defines more than one sandbox resource. `slug` | ||
| (`[a-z0-9-]{1,63}`) is the app's identity; `name` is what the "Starting…" page shows. | ||
| The canonical link is the identity — share `https://apps.sapiom.ai/{org}/{slug}`, never the | ||
| sandbox address the browser lands on after a wake. | ||
| ## The `sapiom.json` resource | ||
@@ -66,11 +117,11 @@ | ||
| | Field | Required | Notes | | ||
| |---|---|---| | ||
| | `source` | yes | `{ "kind": "upload", "path"? }` (upload the local dir) or `{ "kind": "git", "slug", "path"? }` (server checks out a Sapiom repo) | | ||
| | `start` | yes | The server command (e.g. `node server.js`) | | ||
| | `port` | yes | 1–65535 — the port your app listens on | | ||
| | `build` | no | Build command run before start (e.g. `npm run build`) | | ||
| | `tier` | no | Sandbox size: `xs` \| `s` \| `m` \| `l` \| `xl` | | ||
| | `ttl` | no | Sandbox lifetime, e.g. `"1h"`, `"24h"`, `"7d"` | | ||
| | `env` | no | Environment variables (string map) | | ||
| | Field | Required | Notes | | ||
| | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `source` | yes | `{ "kind": "upload", "path"? }` (upload the local dir) or `{ "kind": "git", "slug", "path"? }` (server checks out a Sapiom repo) | | ||
| | `start` | yes | The server command (e.g. `node server.js`) | | ||
| | `port` | yes | 1–65535 — the port your app listens on | | ||
| | `build` | no | Build command run before start (e.g. `npm run build`) | | ||
| | `tier` | no | Sandbox size: `xs` \| `s` \| `m` \| `l` \| `xl` | | ||
| | `ttl` | no | Sandbox lifetime, e.g. `"1h"`, `"24h"`, `"7d"` — **preview only**; an App Link's URL is not bounded by it | | ||
| | `env` | no | Environment variables (string map) | | ||
@@ -77,0 +128,0 @@ Uploads skip `node_modules`, `.git`, and dotfiles — dependencies install in the sandbox at |
@@ -274,2 +274,3 @@ --- | ||
| | `ctx.sapiom` | `Sapiom` | The typed capability client — the `Sapiom` interface from `@sapiom/tools`, installed in your `node_modules` (see "Capabilities" below) | | ||
| | `ctx.isLocalTrace` | `boolean \| undefined` | `true` under `run_local`; **absent** on a deployed run. Gate raw I/O `run_local` cannot stub (see "Testing with `run_local`") | | ||
| | `ctx.organizationId` | `string \| null` | Tenant org | | ||
@@ -602,2 +603,28 @@ | `ctx.tenantId` | `string \| null` | Tenant id | | ||
| ### Gate I/O the stub cannot see | ||
| `run_local` stubs `ctx.sapiom.*` and nothing else. Anything holding its own connection — a | ||
| `postgres` client, raw HTTP to a third party — still runs for real. `database.get` succeeds | ||
| and hands back a DSN, but that DSN's host is in the reserved `.invalid` TLD and does not | ||
| resolve, so dialing it fails. | ||
| Resolve a `dryRun` gate **once, in the entry step**, and carry it in `ctx.shared`: | ||
| ```ts | ||
| // entry step — `input` is the execution's entry input | ||
| const dryRun = input.dryRun ?? ctx.isLocalTrace ?? false; | ||
| ctx.shared.set("dryRun", dryRun); | ||
| if (!dryRun) { | ||
| // raw sockets, third-party HTTP — the things run_local cannot stub | ||
| } | ||
| // any later step: `input` is the previous step's output, so re-deriving it here | ||
| // would read live on a deployed run the caller asked to be dry. | ||
| const dryRun = ctx.shared.get("dryRun") ?? false; | ||
| ``` | ||
| `ctx.isLocalTrace` is absent on a deployed run, so `?? ctx.isLocalTrace` supplies the default | ||
| without changing production behaviour — and an explicit `{ "dryRun": false }` still forces the | ||
| live path when you want to exercise it. | ||
| `run_local` works with **no stubs** — capabilities return sensible defaults. Add | ||
@@ -604,0 +631,0 @@ `.sapiom-dev/stubs.json` overrides only when a step branches on a specific result: |
@@ -274,2 +274,3 @@ --- | ||
| | `ctx.sapiom` | `Sapiom` | The typed capability client — the `Sapiom` interface from `@sapiom/tools`, installed in your `node_modules` (see "Capabilities" below) | | ||
| | `ctx.isLocalTrace` | `boolean \| undefined` | `true` under `run_local`; **absent** on a deployed run. Gate raw I/O `run_local` cannot stub (see "Testing with `run_local`") | | ||
| | `ctx.organizationId` | `string \| null` | Tenant org | | ||
@@ -602,2 +603,28 @@ | `ctx.tenantId` | `string \| null` | Tenant id | | ||
| ### Gate I/O the stub cannot see | ||
| `run_local` stubs `ctx.sapiom.*` and nothing else. Anything holding its own connection — a | ||
| `postgres` client, raw HTTP to a third party — still runs for real. `database.get` succeeds | ||
| and hands back a DSN, but that DSN's host is in the reserved `.invalid` TLD and does not | ||
| resolve, so dialing it fails. | ||
| Resolve a `dryRun` gate **once, in the entry step**, and carry it in `ctx.shared`: | ||
| ```ts | ||
| // entry step — `input` is the execution's entry input | ||
| const dryRun = input.dryRun ?? ctx.isLocalTrace ?? false; | ||
| ctx.shared.set("dryRun", dryRun); | ||
| if (!dryRun) { | ||
| // raw sockets, third-party HTTP — the things run_local cannot stub | ||
| } | ||
| // any later step: `input` is the previous step's output, so re-deriving it here | ||
| // would read live on a deployed run the caller asked to be dry. | ||
| const dryRun = ctx.shared.get("dryRun") ?? false; | ||
| ``` | ||
| `ctx.isLocalTrace` is absent on a deployed run, so `?? ctx.isLocalTrace` supplies the default | ||
| without changing production behaviour — and an explicit `{ "dryRun": false }` still forces the | ||
| live path when you want to exercise it. | ||
| `run_local` works with **no stubs** — capabilities return sensible defaults. Add | ||
@@ -604,0 +631,0 @@ `.sapiom-dev/stubs.json` overrides only when a step branches on a specific result: |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
585503
1.86%6257
0.03%- Removed
Updated
Updated