@nylorun/runtime 0.28.0-beta → 0.30.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -1
- package/README.md +1 -1
- package/dist/api/components.d.ts +109 -2
- package/dist/api/http/define.d.ts +4 -0
- package/dist/api/http/define.js +20 -9
- package/dist/api/http/routes/agent-manifests.d.ts +1 -1
- package/dist/api/http/routes/agent-manifests.js +1 -1
- package/dist/api/http/routes/agents.js +6 -6
- package/dist/api/http/routes/reads.js +29 -4
- package/dist/api/http/routes/tenant.js +5 -2
- package/dist/api/http/routes/triggers.js +15 -12
- package/dist/api/openapi.js +3 -3
- package/dist/gates/egress-credentials.js +2 -13
- package/dist/gates/handler.js +2 -1
- package/dist/gates/http-tool.js +1 -1
- package/dist/gates/in-process.d.ts +9 -0
- package/dist/gates/in-process.js +21 -0
- package/dist/gates/meter.js +16 -0
- package/dist/gates/tenant-vaults.d.ts +1 -1
- package/dist/host/config-for.d.ts +2 -0
- package/dist/host/config-for.js +1 -0
- package/dist/host/main.js +3 -0
- package/dist/host/stack-config.d.ts +10 -0
- package/dist/host/stack-config.js +36 -0
- package/dist/management-openapi.json +492 -80
- package/dist/mcp/connect.d.ts +36 -7
- package/dist/mcp/connect.js +76 -15
- package/dist/mcp/gateway-outcomes.d.ts +14 -0
- package/dist/mcp/gateway-outcomes.js +46 -0
- package/dist/mcp/pool.js +5 -0
- package/dist/model/call-headers.d.ts +15 -0
- package/dist/model/call-headers.js +9 -0
- package/dist/model/models.d.ts +7 -0
- package/dist/model/models.js +3 -0
- package/dist/model/pi-model.d.ts +6 -0
- package/dist/model/pi-model.js +36 -3
- package/dist/openapi.json +331 -215
- package/dist/store/postgres/drizzle/0037_model_usage_cost_split.sql +4 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +7 -0
- package/dist/store/postgres/reads.js +31 -1
- package/dist/store/postgres/schema.d.ts +78 -5
- package/dist/store/postgres/schema.js +12 -3
- package/dist/tenant/agents.js +7 -3
- package/dist/tenant/transcript.d.ts +8 -0
- package/dist/tenant/transcript.js +2 -0
- package/dist/tenant/types.d.ts +5 -0
- package/dist/vault/headers.d.ts +8 -0
- package/dist/vault/headers.js +25 -0
- package/dist/vault/host-model.js +8 -5
- package/dist/vault/service.d.ts +12 -5
- package/dist/vault/service.js +43 -6
- package/dist/vault/sources.js +22 -1
- package/dist/vault/workload-token.d.ts +16 -0
- package/dist/vault/workload-token.js +58 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.30.0-beta
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- fce0c9b: Headers for a custom model endpoint (#493). A custom endpoint's `settings` (`PUT /v1/tenant/model`) take `headers`, sent on every call, and `callHeaders`, whose values the Runtime resolves per call from the calling Agent: one of its labels (`{ from: "agent.label", key: "org" }`), its id (`agent.id`) or the session's owner when it is a person (`session.owner`). A source with no value sends no header. A Runtime that serves several orgs' Agents can then send each call's org (`x-nylorun-org` from the `org` label), so a model gateway attributes and budgets it while the call is made, in process and through the gates service alike. They are settings, read back by `GET /v1/tenant/model`: neither map may set `authorization`, a hop-by-hop or transport header, or `Nylorun-*`, and a name appears once across both. Studio keeps them when it saves the model.
|
|
8
|
+
- ab7c08a: A gateway's tool prefix (#494, Host feature `gateway-credentials`). A `bearer` or `headers` credential with `via`, written to an Agent's vault, may add `toolPrefix`: what the gateway at `via` puts before each tool name it lists, such as LiteLLM's `github-`. The Runtime lists the server's tools without it, so tool names (`github__create_issue`), a manifest's `tools` settings and tool policy rules name the server's own tools whether or not a gateway is in between, and calls each tool by the name the gateway listed. A listed tool that lacks the prefix keeps its name, and the server's `mcp.discovered` message names it. `toolPrefix` needs `via`, and secret views carry it. It is the installation's routing, never a manifest's: a manifest's secret slot cannot name it, and a slot's value write (`{ headers, toolPrefix }`) adds it. A fork keeps it while the new slot keeps `via`. No protocol change.
|
|
9
|
+
- 4a563e7: The workload token (#496). A Runtime given `NYLORUN_WORKLOAD_TOKEN_FILE`, a token a platform rotates through a file, reads it at each use and keeps nothing, so a rotation applies to the next request with no restart; a missing, unreadable or empty file fails the request, naming the variable, and nothing is sent without it. A custom model with `auth: { type: "workload" }` sends it as the endpoint's bearer. A new credential type, `workload` (`{ url, via, identity?, toolPrefix? }`, no value), sends `Authorization: Bearer <token>` to its `via` only, and only when `via`'s origin is in `NYLORUN_WORKLOAD_TOKEN_ORIGINS`, since an Agent's writer chooses `via`. A gateway's `401` is `credential_rejected` with `gateway`, its origin. The token stays in the process that makes the call: never in a sandbox, the model, an event or a log. Studio shows the credential and the model's auth.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 8c82ed9: An MCP gateway's report of an upstream `401` is `credential_rejected` (#495). Through a credential's `via`, a gateway that answers HTTP 200 but reports that the server behind it answered `401` is read like a `401`. LiteLLM does this for a token the provider revoked: a `tools/list` with no tools and `"auth_required"` for the server in `_meta["litellm.ai/server_outcomes"]` makes the server's `mcp.discovered` outcome `failed` ("MCP server returned 401"), and a tool error carrying that outcome, or LiteLLM's `HTTPStatusError: Client error '401 Unauthorized'` text, completes as `credential_rejected` with `retryable: false`, naming the server. A server reached without `via` is read as before.
|
|
14
|
+
- Pin core to the tested release.
|
|
15
|
+
- Pin harness to the tested release.
|
|
16
|
+
- Updated dependencies [fce0c9b]
|
|
17
|
+
- Updated dependencies [ab7c08a]
|
|
18
|
+
- Updated dependencies [4a563e7]
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- @nylorun/core@0.26.0-beta
|
|
21
|
+
- @nylorun/harness@0.29.2-beta
|
|
22
|
+
|
|
23
|
+
## 0.29.0-beta
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- eeb6294: Session usage as one ledger (protocol 18). The usage ledger keeps each model call's cost by token kind (uncached input, cache read, cache write, output) at the prices the adapter applied (migration 0037). For a protocol 18 client, `GET /v1/sessions/{id}/calls/model` returns each call's `startedAt`, `endedAt` and `usage.costSplit` (null for a call recorded before), and `GET /v1/sessions/{id}/usage` adds `costSplit` with `splitCalls`, and the calls' durations added up as `modelTimeMs` with `timedCalls`. A protocol 16 or 17 client reads usage as before. Studio's Usage tab is rebuilt on them: a Session card with one tokens bar and a ledger of tokens and cost by kind adding up to a total row, then the model calls grouped by turn with the same columns (cached, uncached, output, total, time, cost), and a row menu whose View event opens the call's event in the Events tab.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- ed08ba8: Credential failures name the session's Agent, not its Environment: an HTTP tool's `http.credential` failure says "The session's Agent holds no credential '…' for …", and an MCP server's `credential_rejected` says the credential came from, or is missing in, the session's Agent.
|
|
32
|
+
- ed08ba8: A flow's HTTP stage or HTTP verifier, and an HTTP tool of an agent the harness section embeds (a flow's `agents`, or an agent used as a tool), now has its `credential` checked when the manifest is saved, as an agent's own HTTP tool has: it must name a `bearer` or `headers` slot of `runtime.secrets` bound to its URL, or the save is `422 manifest_inconsistent` naming it (`harness.root stage "refund" http.credential "checks" is not a secret slot in runtime.secrets`). Before, such a manifest saved and each call failed at run time with `http.credential`.
|
|
33
|
+
- ed08ba8: The Runtime API's Agent manifests tag no longer says a save changes no Agent: a save moves every Agent that tracks the manifest to the new version, and a pinned one stays.
|
|
34
|
+
- ed08ba8: Public text names no internal roadmap codes: the OpenAPI documents' descriptions, the type comments of `@nylorun/core`, `@nylorun/agents` and `@nylorun/admin`, and the CLI's help, README and generated compose file. A Runtime test fails when either OpenAPI document names one.
|
|
35
|
+
- ed08ba8: Webhook URLs name the Runtime's public URL. A trigger's `webhookUrl` is at `NYLORUN_PUBLIC_URL`, else the origin the request reached, so behind a reverse proxy that rewrites `Host` to `localhost:<port>` it is the proxy's URL, not `http://localhost:<port>`; the Runtime API's `401` challenges name it too. `nylorun start` passes `NYLORUN_PUBLIC_URL` from its shell to the runtime container (default `http://localhost:<port>`).
|
|
36
|
+
- ed08ba8: The tool policy's documentation matches how rules match: `tool` is the tool's identity (an MCP tool's own name on its `server`, or an HTTP tool's declared name), never the model-facing `server__tool`, which is refused; `agent` is the agent manifest's name, or the id of an agent used as a tool or of a flow's agent. `PUT /v1/tenant/tool-policy` describes each selector, and `GET` documents its `409` for a stored rule it cannot apply.
|
|
37
|
+
- ed08ba8: `POST /v1/webhooks/{endpointId}` takes no credential and ignores one that is sent: a delivery with an `Authorization` header is no longer checked against the Tenant's keys, since its Standard Webhooks signature is its grant. The OpenAPI document says so: `security: []`, no `Nylorun-*` headers, and `webhook-id`, `webhook-timestamp` and `webhook-signature` required.
|
|
38
|
+
- Pin core to the tested release.
|
|
39
|
+
- Pin harness to the tested release.
|
|
40
|
+
- Updated dependencies [ed08ba8]
|
|
41
|
+
- Updated dependencies [ed08ba8]
|
|
42
|
+
- Updated dependencies [ed08ba8]
|
|
43
|
+
- Updated dependencies [eeb6294]
|
|
44
|
+
- Updated dependencies [ed08ba8]
|
|
45
|
+
- Updated dependencies
|
|
46
|
+
- @nylorun/core@0.25.0-beta
|
|
47
|
+
- @nylorun/harness@0.29.1-beta
|
|
48
|
+
|
|
3
49
|
## 0.28.0-beta
|
|
4
50
|
|
|
5
51
|
### Minor Changes
|
|
@@ -12,7 +58,7 @@
|
|
|
12
58
|
|
|
13
59
|
- 1ded443: Track T3, Agents that evolve: an Agent moves between versions of its manifest in place, with its id, disk, vault and sessions. `PUT /v1/agents/{id}` with another version moves it (`?dryRun=true` answers the plan, `AgentMovePlan`), and saving a manifest moves every Agent that tracks it. A harness-only change applies at once; a runtime change a pod applies only when it starts (image, resources, network, setup, files) leaves the Agent outdated (`targetVersion`, `waitingFor: "start"`) until its pod's next start, on the same volume; a version that adds a required secret waits for its value (`waitingFor: "secrets"`, state `input_required`). Its manifest's name, kind, harness and storage are fixed: `409 agent_fixed_field` replaces `409 agent_upgrade_unavailable`. Only secrets that fill a slot of the running version are used; others stay in the vault, dormant. New events `agent.outdated` and `agent.version_changed`, `GET /v1/agents?outdated=true`, and the save plan's `moves` and `agents_move` warning. Migration 0033 adds the Agent's target and failed versions and its start check.
|
|
14
60
|
- 76dcd11: Track T3, the next start and its check: a pod Agent's start on a new version is checked until the new pod's harness joins (`startCheck` on the Agent). A failed setup, a failed pod, or a start slower than the Host's `tenant.upgradeStartMs` (10 minutes) takes the Agent back to the version it ran, its definition and not its disk, records `agent.start_failed`, and names the version `failedVersion` (state `failing`), which a tracking Agent does not move to again. A new version's setup runs on the same volume when its commands or files changed (`setupHash` in the setup plan and the volume's marker). While a pod waits to start on a new version it idles at most `tenant.upgradeIdleMs` (1 minute). `POST /v1/agents/{id}/restart` applies a pending version now; `retry: true` tries the failed version again.
|
|
15
|
-
- 4fa160d: Agent memory, storage and API (track T5, D72). An agent manifest's `harness.memory` (`access`: `read_write` or `read_only`; `instructions`, at most 4,096 characters) turns on the Agent's memory: Markdown files under `/memories` it keeps across sessions, wakes and upgrades. The Runtime keeps them in Postgres (`memories`, `memory_versions`, migration 0036) with a version per change and who made it. `GET /v1/agents/{id}/memories` lists them (`pathPrefix`), `GET`, `PUT` (whole content, with an optional `contentSha256` precondition: `409 memory_conflict`) and `DELETE /v1/agents/{id}/memories/{path}` read, write and delete one (or a folder), and `GET /v1/agents/{id}/memory_versions` and `.../memory_versions/{versionId}` page the versions. A fork copies the memories (the fork plan adds `memories`); a delete removes them. `@nylorun/core` adds `memoryPathOf`, `memoryDescriptionOf` and the memory contracts; new Runtime limits `memoryBytes` (100
|
|
61
|
+
- 4fa160d: Agent memory, storage and API (track T5, D72). An agent manifest's `harness.memory` (`access`: `read_write` or `read_only`; `instructions`, at most 4,096 characters) turns on the Agent's memory: Markdown files under `/memories` it keeps across sessions, wakes and upgrades. The Runtime keeps them in Postgres (`memories`, `memory_versions`, migration 0036) with a version per change and who made it. `GET /v1/agents/{id}/memories` lists them (`pathPrefix`), `GET`, `PUT` (whole content, with an optional `contentSha256` precondition: `409 memory_conflict`) and `DELETE /v1/agents/{id}/memories/{path}` read, write and delete one (or a folder), and `GET /v1/agents/{id}/memory_versions` and `.../memory_versions/{versionId}` page the versions. A fork copies the memories (the fork plan adds `memories`); a delete removes them. `@nylorun/core` adds `memoryPathOf`, `memoryDescriptionOf` and the memory contracts; new Runtime limits `memoryBytes` (100 KiB) and `memoriesPerAgent` (10,000); new error code `memory_conflict`. The SDK adds `client.agents.memories`; the CLI adds `nylorun agents memories ls|cat|put|rm|versions`. The model's `memory` tool arrives in the next steps of T5.
|
|
16
62
|
- 9fed948: The `memory` tool's calls (track T5, D72). A new effect target, `{kind: "runtime", operation: "memory"}` (additive on Harness API 5), carries Anthropic's memory tool input (`command`: `view`, `create`, `str_replace`, `insert`, `delete`, `rename`, and its parameters); core serves it in the intent's own transaction, so a replayed turn applies a write once. A malformed call fails with text for the model and changes nothing; a write from a `read_only` agent or a sub-agent is `memory.forbidden`. Each write is a memory version naming the turn's manifest version, session, turn and the trigger run that started the turn, with a new session event `memory.updated` and Agent event `agent.memory_updated`. `turn.start.memory` (`TurnMemorySchema`) carries the Agent's memory access, instructions and the index a harness pins, newest first, within the new Runtime limits `memoryIndexLines` (200) and `memoryIndexBytes` (25 KiB).
|
|
17
63
|
- ffeb3bb: `schedule_wake` (track T4, D77). An agent manifest's `runtime.selfWake: true` offers the agent `schedule_wake`: `{in | at, note}` books its session's next turn, replacing the booking before, and `{cancel: true}` removes it. The Runtime serves the call in its own transaction (a new effect target, `{kind: "runtime", operation: "schedule_wake"}`, additive on Harness API 5; `turn.start.agent.selfWake` tells a harness to offer it), so a replayed turn books once. The booking fires as a trigger run of kind `wake`, its note the turn's message with `cause.kind: "self"`. New session events `wake.booked` and `wake.cancelled`, tool call kind `runtime`, and Runtime limits `wakeMaxAheadMs` and `wakeNoteChars`.
|
|
18
64
|
- 9e60e40: Protocol 17, a queue per session (track T4, D76). A message sent while the session's turn runs or waits is queued (`{status: "queued", queuedMessageId, position}`, `message.queued`) and starts the next turn when this one ends, with every queued message, each its own user message (`queue.taken`); a cancel ends the turn, not the queue. `delivery: "reject"` keeps the refusal, now `409 session_busy`, and a protocol 16 client's messages default to it, so the Host serves protocol 16 and 17. The queue holds at most the Runtime limit `sessionQueuedMessages` (`429 queue_full`), and session reads count `queuedMessages`. Our engine takes `{kind: "messages", messages}` as a turn's input. The SDK's `input` and `inputParts` take `delivery`, and the CLI's `sessions send` takes `--reject-if-busy`. See MIGRATION.md.
|
package/README.md
CHANGED
|
@@ -295,7 +295,7 @@ Postgres transactions persist session checkpoints, command receipts, individual
|
|
|
295
295
|
effects, waits and the record of session events — in the Tenant's database; history is
|
|
296
296
|
read from Durable Streams (S2). An advance owns its session through a lease with
|
|
297
297
|
an epoch; a Worker that takes over after a crash marks in-flight model effects
|
|
298
|
-
`uncertain`, and sends an interrupted MCP or HTTP tool call again with the same key
|
|
298
|
+
`uncertain`, and sends an interrupted MCP or HTTP tool call again with the same key. Vault ciphertext needs that Tenant's own KEK.
|
|
299
299
|
|
|
300
300
|
A session that names an Environment of kind `virtual` or `pod` gets a sandbox, its spec pinned
|
|
301
301
|
on the session: our harness offers the sandbox tools and `save_artifact` and writes their notes
|
package/dist/api/components.d.ts
CHANGED
|
@@ -897,6 +897,7 @@ export declare const PutAgentSecretValueRequest: z.ZodObject<{
|
|
|
897
897
|
requestId: z.ZodOptional<z.ZodString>;
|
|
898
898
|
value: z.ZodOptional<z.ZodString>;
|
|
899
899
|
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
900
|
+
toolPrefix: z.ZodOptional<z.ZodString>;
|
|
900
901
|
}, z.core.$strict>;
|
|
901
902
|
export declare const AgentSnapshot: z.ZodObject<{
|
|
902
903
|
agentId: z.ZodString;
|
|
@@ -4447,6 +4448,7 @@ export declare const SessionEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
4447
4448
|
code: z.ZodString;
|
|
4448
4449
|
message: z.ZodString;
|
|
4449
4450
|
server: z.ZodOptional<z.ZodString>;
|
|
4451
|
+
gateway: z.ZodOptional<z.ZodString>;
|
|
4450
4452
|
retryable: z.ZodOptional<z.ZodBoolean>;
|
|
4451
4453
|
}, z.core.$loose>>;
|
|
4452
4454
|
redacted: z.ZodOptional<z.ZodNumber>;
|
|
@@ -7179,6 +7181,7 @@ export declare const SessionEvent: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
7179
7181
|
code: z.ZodString;
|
|
7180
7182
|
message: z.ZodString;
|
|
7181
7183
|
server: z.ZodOptional<z.ZodString>;
|
|
7184
|
+
gateway: z.ZodOptional<z.ZodString>;
|
|
7182
7185
|
retryable: z.ZodOptional<z.ZodBoolean>;
|
|
7183
7186
|
}, z.core.$loose>>;
|
|
7184
7187
|
redacted: z.ZodOptional<z.ZodNumber>;
|
|
@@ -9914,6 +9917,7 @@ export declare const SessionItemsResponse: z.ZodObject<{
|
|
|
9914
9917
|
code: z.ZodString;
|
|
9915
9918
|
message: z.ZodString;
|
|
9916
9919
|
server: z.ZodOptional<z.ZodString>;
|
|
9920
|
+
gateway: z.ZodOptional<z.ZodString>;
|
|
9917
9921
|
retryable: z.ZodOptional<z.ZodBoolean>;
|
|
9918
9922
|
}, z.core.$loose>>;
|
|
9919
9923
|
redacted: z.ZodOptional<z.ZodNumber>;
|
|
@@ -12646,6 +12650,7 @@ export declare const SessionItemsResponse: z.ZodObject<{
|
|
|
12646
12650
|
code: z.ZodString;
|
|
12647
12651
|
message: z.ZodString;
|
|
12648
12652
|
server: z.ZodOptional<z.ZodString>;
|
|
12653
|
+
gateway: z.ZodOptional<z.ZodString>;
|
|
12649
12654
|
retryable: z.ZodOptional<z.ZodBoolean>;
|
|
12650
12655
|
}, z.core.$loose>>;
|
|
12651
12656
|
redacted: z.ZodOptional<z.ZodNumber>;
|
|
@@ -13224,6 +13229,7 @@ export declare const TenantStatus: z.ZodObject<{
|
|
|
13224
13229
|
authType: z.ZodEnum<{
|
|
13225
13230
|
api_key: "api_key";
|
|
13226
13231
|
oauth: "oauth";
|
|
13232
|
+
workload: "workload";
|
|
13227
13233
|
}>;
|
|
13228
13234
|
baseUrl: z.ZodOptional<z.ZodString>;
|
|
13229
13235
|
settings: z.ZodOptional<z.ZodObject<{
|
|
@@ -13239,6 +13245,15 @@ export declare const TenantStatus: z.ZodObject<{
|
|
|
13239
13245
|
video: "video";
|
|
13240
13246
|
}>>>;
|
|
13241
13247
|
compat: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
13248
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13249
|
+
callHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13250
|
+
from: z.ZodLiteral<"agent.label">;
|
|
13251
|
+
key: z.ZodString;
|
|
13252
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13253
|
+
from: z.ZodLiteral<"agent.id">;
|
|
13254
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13255
|
+
from: z.ZodLiteral<"session.owner">;
|
|
13256
|
+
}, z.core.$strict>], "from">>>;
|
|
13242
13257
|
}, z.core.$strict>>;
|
|
13243
13258
|
}, z.core.$strict>]>;
|
|
13244
13259
|
agents: z.ZodArray<z.ZodObject<{
|
|
@@ -13357,6 +13372,15 @@ export declare const SeedTenantConfigRequest: z.ZodObject<{
|
|
|
13357
13372
|
video: "video";
|
|
13358
13373
|
}>>>;
|
|
13359
13374
|
compat: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
13375
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13376
|
+
callHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13377
|
+
from: z.ZodLiteral<"agent.label">;
|
|
13378
|
+
key: z.ZodString;
|
|
13379
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13380
|
+
from: z.ZodLiteral<"agent.id">;
|
|
13381
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13382
|
+
from: z.ZodLiteral<"session.owner">;
|
|
13383
|
+
}, z.core.$strict>], "from">>>;
|
|
13360
13384
|
}, z.core.$strict>>;
|
|
13361
13385
|
auth: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13362
13386
|
type: z.ZodLiteral<"api_key">;
|
|
@@ -13367,7 +13391,9 @@ export declare const SeedTenantConfigRequest: z.ZodObject<{
|
|
|
13367
13391
|
refresh: z.ZodString;
|
|
13368
13392
|
access: z.ZodString;
|
|
13369
13393
|
expires: z.ZodNumber;
|
|
13370
|
-
}, z.core.$loose
|
|
13394
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
13395
|
+
type: z.ZodLiteral<"workload">;
|
|
13396
|
+
}, z.core.$strict>], "type">;
|
|
13371
13397
|
}, z.core.$strict>>;
|
|
13372
13398
|
fixtureModel: z.ZodOptional<z.ZodLiteral<true>>;
|
|
13373
13399
|
}, z.core.$strict>;
|
|
@@ -13626,6 +13652,7 @@ export declare const ListProvidersResponse: z.ZodObject<{
|
|
|
13626
13652
|
authType: z.ZodEnum<{
|
|
13627
13653
|
api_key: "api_key";
|
|
13628
13654
|
oauth: "oauth";
|
|
13655
|
+
workload: "workload";
|
|
13629
13656
|
}>;
|
|
13630
13657
|
baseUrl: z.ZodOptional<z.ZodString>;
|
|
13631
13658
|
settings: z.ZodOptional<z.ZodObject<{
|
|
@@ -13641,6 +13668,15 @@ export declare const ListProvidersResponse: z.ZodObject<{
|
|
|
13641
13668
|
video: "video";
|
|
13642
13669
|
}>>>;
|
|
13643
13670
|
compat: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
13671
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13672
|
+
callHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13673
|
+
from: z.ZodLiteral<"agent.label">;
|
|
13674
|
+
key: z.ZodString;
|
|
13675
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13676
|
+
from: z.ZodLiteral<"agent.id">;
|
|
13677
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13678
|
+
from: z.ZodLiteral<"session.owner">;
|
|
13679
|
+
}, z.core.$strict>], "from">>>;
|
|
13644
13680
|
}, z.core.$strict>>;
|
|
13645
13681
|
inputs: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
13646
13682
|
audio: "audio";
|
|
@@ -13663,6 +13699,7 @@ export declare const HostModelView: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
13663
13699
|
authType: z.ZodEnum<{
|
|
13664
13700
|
api_key: "api_key";
|
|
13665
13701
|
oauth: "oauth";
|
|
13702
|
+
workload: "workload";
|
|
13666
13703
|
}>;
|
|
13667
13704
|
baseUrl: z.ZodOptional<z.ZodString>;
|
|
13668
13705
|
settings: z.ZodOptional<z.ZodObject<{
|
|
@@ -13678,6 +13715,15 @@ export declare const HostModelView: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
13678
13715
|
video: "video";
|
|
13679
13716
|
}>>>;
|
|
13680
13717
|
compat: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
13718
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13719
|
+
callHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13720
|
+
from: z.ZodLiteral<"agent.label">;
|
|
13721
|
+
key: z.ZodString;
|
|
13722
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13723
|
+
from: z.ZodLiteral<"agent.id">;
|
|
13724
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13725
|
+
from: z.ZodLiteral<"session.owner">;
|
|
13726
|
+
}, z.core.$strict>], "from">>>;
|
|
13681
13727
|
}, z.core.$strict>>;
|
|
13682
13728
|
}, z.core.$strict>]>;
|
|
13683
13729
|
export declare const PutHostModelRequest: z.ZodObject<{
|
|
@@ -13699,6 +13745,15 @@ export declare const PutHostModelRequest: z.ZodObject<{
|
|
|
13699
13745
|
video: "video";
|
|
13700
13746
|
}>>>;
|
|
13701
13747
|
compat: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
13748
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13749
|
+
callHeaders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13750
|
+
from: z.ZodLiteral<"agent.label">;
|
|
13751
|
+
key: z.ZodString;
|
|
13752
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13753
|
+
from: z.ZodLiteral<"agent.id">;
|
|
13754
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13755
|
+
from: z.ZodLiteral<"session.owner">;
|
|
13756
|
+
}, z.core.$strict>], "from">>>;
|
|
13702
13757
|
}, z.core.$strict>>;
|
|
13703
13758
|
auth: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
13704
13759
|
type: z.ZodLiteral<"api_key">;
|
|
@@ -13709,7 +13764,9 @@ export declare const PutHostModelRequest: z.ZodObject<{
|
|
|
13709
13764
|
refresh: z.ZodString;
|
|
13710
13765
|
access: z.ZodString;
|
|
13711
13766
|
expires: z.ZodNumber;
|
|
13712
|
-
}, z.core.$loose
|
|
13767
|
+
}, z.core.$loose>, z.ZodObject<{
|
|
13768
|
+
type: z.ZodLiteral<"workload">;
|
|
13769
|
+
}, z.core.$strict>], "type">;
|
|
13713
13770
|
}, z.core.$strict>;
|
|
13714
13771
|
export declare const SelectHostModelRequest: z.ZodObject<{
|
|
13715
13772
|
requestId: z.ZodString;
|
|
@@ -13740,6 +13797,7 @@ export declare const PutAgentSecretRequest: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
13740
13797
|
type: z.ZodLiteral<"bearer">;
|
|
13741
13798
|
url: z.ZodString;
|
|
13742
13799
|
value: z.ZodString;
|
|
13800
|
+
toolPrefix: z.ZodOptional<z.ZodString>;
|
|
13743
13801
|
}, z.core.$strict>, z.ZodObject<{
|
|
13744
13802
|
via: z.ZodOptional<z.ZodString>;
|
|
13745
13803
|
identity: z.ZodOptional<z.ZodObject<{
|
|
@@ -13749,6 +13807,16 @@ export declare const PutAgentSecretRequest: z.ZodDiscriminatedUnion<[z.ZodObject
|
|
|
13749
13807
|
type: z.ZodLiteral<"headers">;
|
|
13750
13808
|
url: z.ZodString;
|
|
13751
13809
|
headers: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
13810
|
+
toolPrefix: z.ZodOptional<z.ZodString>;
|
|
13811
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
13812
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
13813
|
+
type: z.ZodLiteral<"workload">;
|
|
13814
|
+
url: z.ZodString;
|
|
13815
|
+
via: z.ZodString;
|
|
13816
|
+
identity: z.ZodOptional<z.ZodObject<{
|
|
13817
|
+
header: z.ZodString;
|
|
13818
|
+
}, z.core.$strict>>;
|
|
13819
|
+
toolPrefix: z.ZodOptional<z.ZodString>;
|
|
13752
13820
|
}, z.core.$strict>], "type">;
|
|
13753
13821
|
export declare const AgentSecretView: z.ZodObject<{
|
|
13754
13822
|
name: z.ZodString;
|
|
@@ -13757,6 +13825,7 @@ export declare const AgentSecretView: z.ZodObject<{
|
|
|
13757
13825
|
environment_secret: "environment_secret";
|
|
13758
13826
|
environment_variable: "environment_variable";
|
|
13759
13827
|
headers: "headers";
|
|
13828
|
+
workload: "workload";
|
|
13760
13829
|
}>;
|
|
13761
13830
|
binding: z.ZodObject<{
|
|
13762
13831
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -13768,6 +13837,7 @@ export declare const AgentSecretView: z.ZodObject<{
|
|
|
13768
13837
|
}, z.core.$strict>;
|
|
13769
13838
|
headerNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13770
13839
|
via: z.ZodOptional<z.ZodString>;
|
|
13840
|
+
toolPrefix: z.ZodOptional<z.ZodString>;
|
|
13771
13841
|
identity: z.ZodOptional<z.ZodObject<{
|
|
13772
13842
|
header: z.ZodString;
|
|
13773
13843
|
}, z.core.$strict>>;
|
|
@@ -13782,6 +13852,7 @@ export declare const ListAgentSecretsResponse: z.ZodObject<{
|
|
|
13782
13852
|
environment_secret: "environment_secret";
|
|
13783
13853
|
environment_variable: "environment_variable";
|
|
13784
13854
|
headers: "headers";
|
|
13855
|
+
workload: "workload";
|
|
13785
13856
|
}>;
|
|
13786
13857
|
binding: z.ZodObject<{
|
|
13787
13858
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -13793,6 +13864,7 @@ export declare const ListAgentSecretsResponse: z.ZodObject<{
|
|
|
13793
13864
|
}, z.core.$strict>;
|
|
13794
13865
|
headerNames: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
13795
13866
|
via: z.ZodOptional<z.ZodString>;
|
|
13867
|
+
toolPrefix: z.ZodOptional<z.ZodString>;
|
|
13796
13868
|
identity: z.ZodOptional<z.ZodObject<{
|
|
13797
13869
|
header: z.ZodString;
|
|
13798
13870
|
}, z.core.$strict>>;
|
|
@@ -13964,6 +14036,8 @@ export declare const ModelCall: z.ZodObject<{
|
|
|
13964
14036
|
provider: z.ZodNullable<z.ZodString>;
|
|
13965
14037
|
model: z.ZodNullable<z.ZodString>;
|
|
13966
14038
|
at: z.ZodString;
|
|
14039
|
+
startedAt: z.ZodNullable<z.ZodString>;
|
|
14040
|
+
endedAt: z.ZodNullable<z.ZodString>;
|
|
13967
14041
|
outcome: z.ZodEnum<{
|
|
13968
14042
|
completed: "completed";
|
|
13969
14043
|
failed: "failed";
|
|
@@ -13979,6 +14053,12 @@ export declare const ModelCall: z.ZodObject<{
|
|
|
13979
14053
|
duplicate: z.ZodBoolean;
|
|
13980
14054
|
tokensReported: z.ZodNullable<z.ZodBoolean>;
|
|
13981
14055
|
costKnown: z.ZodNullable<z.ZodBoolean>;
|
|
14056
|
+
costSplit: z.ZodNullable<z.ZodObject<{
|
|
14057
|
+
input: z.ZodNumber;
|
|
14058
|
+
cacheRead: z.ZodNumber;
|
|
14059
|
+
cacheWrite: z.ZodNumber;
|
|
14060
|
+
output: z.ZodNumber;
|
|
14061
|
+
}, z.core.$strict>>;
|
|
13982
14062
|
}, z.core.$strict>>;
|
|
13983
14063
|
}, z.core.$strict>;
|
|
13984
14064
|
export declare const SessionPage: z.ZodObject<{
|
|
@@ -16202,6 +16282,7 @@ export declare const HistoryPage: z.ZodObject<{
|
|
|
16202
16282
|
code: z.ZodString;
|
|
16203
16283
|
message: z.ZodString;
|
|
16204
16284
|
server: z.ZodOptional<z.ZodString>;
|
|
16285
|
+
gateway: z.ZodOptional<z.ZodString>;
|
|
16205
16286
|
retryable: z.ZodOptional<z.ZodBoolean>;
|
|
16206
16287
|
}, z.core.$loose>>;
|
|
16207
16288
|
redacted: z.ZodOptional<z.ZodNumber>;
|
|
@@ -18934,6 +19015,7 @@ export declare const HistoryPage: z.ZodObject<{
|
|
|
18934
19015
|
code: z.ZodString;
|
|
18935
19016
|
message: z.ZodString;
|
|
18936
19017
|
server: z.ZodOptional<z.ZodString>;
|
|
19018
|
+
gateway: z.ZodOptional<z.ZodString>;
|
|
18937
19019
|
retryable: z.ZodOptional<z.ZodBoolean>;
|
|
18938
19020
|
}, z.core.$loose>>;
|
|
18939
19021
|
redacted: z.ZodOptional<z.ZodNumber>;
|
|
@@ -19499,6 +19581,15 @@ export declare const SessionUsageTotals: z.ZodObject<{
|
|
|
19499
19581
|
unpricedCalls: z.ZodNumber;
|
|
19500
19582
|
unreportedCalls: z.ZodNumber;
|
|
19501
19583
|
unknownQualityCalls: z.ZodNumber;
|
|
19584
|
+
costSplit: z.ZodObject<{
|
|
19585
|
+
input: z.ZodNumber;
|
|
19586
|
+
cacheRead: z.ZodNumber;
|
|
19587
|
+
cacheWrite: z.ZodNumber;
|
|
19588
|
+
output: z.ZodNumber;
|
|
19589
|
+
}, z.core.$strict>;
|
|
19590
|
+
splitCalls: z.ZodNumber;
|
|
19591
|
+
modelTimeMs: z.ZodNumber;
|
|
19592
|
+
timedCalls: z.ZodNumber;
|
|
19502
19593
|
}, z.core.$strict>;
|
|
19503
19594
|
export declare const ModelCallsPage: z.ZodObject<{
|
|
19504
19595
|
nextCursor: z.ZodNullable<z.ZodString>;
|
|
@@ -19512,6 +19603,8 @@ export declare const ModelCallsPage: z.ZodObject<{
|
|
|
19512
19603
|
provider: z.ZodNullable<z.ZodString>;
|
|
19513
19604
|
model: z.ZodNullable<z.ZodString>;
|
|
19514
19605
|
at: z.ZodString;
|
|
19606
|
+
startedAt: z.ZodNullable<z.ZodString>;
|
|
19607
|
+
endedAt: z.ZodNullable<z.ZodString>;
|
|
19515
19608
|
outcome: z.ZodEnum<{
|
|
19516
19609
|
completed: "completed";
|
|
19517
19610
|
failed: "failed";
|
|
@@ -19527,6 +19620,12 @@ export declare const ModelCallsPage: z.ZodObject<{
|
|
|
19527
19620
|
duplicate: z.ZodBoolean;
|
|
19528
19621
|
tokensReported: z.ZodNullable<z.ZodBoolean>;
|
|
19529
19622
|
costKnown: z.ZodNullable<z.ZodBoolean>;
|
|
19623
|
+
costSplit: z.ZodNullable<z.ZodObject<{
|
|
19624
|
+
input: z.ZodNumber;
|
|
19625
|
+
cacheRead: z.ZodNumber;
|
|
19626
|
+
cacheWrite: z.ZodNumber;
|
|
19627
|
+
output: z.ZodNumber;
|
|
19628
|
+
}, z.core.$strict>>;
|
|
19530
19629
|
}, z.core.$strict>>;
|
|
19531
19630
|
}, z.core.$strict>>;
|
|
19532
19631
|
}, z.core.$strict>;
|
|
@@ -19543,6 +19642,8 @@ export declare const ModelCallExportPage: z.ZodObject<{
|
|
|
19543
19642
|
provider: z.ZodNullable<z.ZodString>;
|
|
19544
19643
|
model: z.ZodNullable<z.ZodString>;
|
|
19545
19644
|
at: z.ZodString;
|
|
19645
|
+
startedAt: z.ZodNullable<z.ZodString>;
|
|
19646
|
+
endedAt: z.ZodNullable<z.ZodString>;
|
|
19546
19647
|
outcome: z.ZodEnum<{
|
|
19547
19648
|
completed: "completed";
|
|
19548
19649
|
failed: "failed";
|
|
@@ -19558,6 +19659,12 @@ export declare const ModelCallExportPage: z.ZodObject<{
|
|
|
19558
19659
|
duplicate: z.ZodBoolean;
|
|
19559
19660
|
tokensReported: z.ZodNullable<z.ZodBoolean>;
|
|
19560
19661
|
costKnown: z.ZodNullable<z.ZodBoolean>;
|
|
19662
|
+
costSplit: z.ZodNullable<z.ZodObject<{
|
|
19663
|
+
input: z.ZodNumber;
|
|
19664
|
+
cacheRead: z.ZodNumber;
|
|
19665
|
+
cacheWrite: z.ZodNumber;
|
|
19666
|
+
output: z.ZodNumber;
|
|
19667
|
+
}, z.core.$strict>>;
|
|
19561
19668
|
}, z.core.$strict>>;
|
|
19562
19669
|
}, z.core.$strict>>;
|
|
19563
19670
|
}, z.core.$strict>;
|
|
@@ -24,6 +24,10 @@ import type { TenantEnv } from "./app.js";
|
|
|
24
24
|
*/
|
|
25
25
|
export type Credential = "application" | "subject" | "management" | "token";
|
|
26
26
|
export interface RouteAccess {
|
|
27
|
+
/**
|
|
28
|
+
* The credentials the route takes. None (with `anonymous`): the route takes no credential and
|
|
29
|
+
* ignores one that is sent, as a webhook delivery, whose signature is its grant.
|
|
30
|
+
*/
|
|
27
31
|
readonly credentials: readonly Credential[];
|
|
28
32
|
/** The subject scopes that reach the route: any one of them, none (`never`), or all (`any`). */
|
|
29
33
|
readonly scopes: readonly SubjectScope[] | "never" | "any";
|
package/dist/api/http/define.js
CHANGED
|
@@ -63,6 +63,11 @@ export function declaredRoute(method, segments) {
|
|
|
63
63
|
(segment.startsWith("{") && segments[index] !== "")))?.access;
|
|
64
64
|
}
|
|
65
65
|
function authenticated(access) {
|
|
66
|
+
if (access.credentials.length === 0)
|
|
67
|
+
return async (c, next) => {
|
|
68
|
+
c.set("scope", { kind: "anonymous" });
|
|
69
|
+
await next();
|
|
70
|
+
};
|
|
66
71
|
return async (c, next) => {
|
|
67
72
|
const keys = keyAccess(access);
|
|
68
73
|
const scope = await authenticateCaller(c, access.anonymous === true, keys);
|
|
@@ -82,9 +87,12 @@ export const TraceHeaders = z.object({
|
|
|
82
87
|
export function tenantRoute(api, access, route, handler) {
|
|
83
88
|
const takes = (credential) => access.credentials.includes(credential);
|
|
84
89
|
const schemes = [...new Set(access.credentials.map((credential) => SCHEMES[credential]))];
|
|
90
|
+
// A route that takes no credential is called by others than Nylorun's clients: it documents
|
|
91
|
+
// neither a credential nor `Nylorun-*` headers.
|
|
92
|
+
const open = access.credentials.length === 0;
|
|
85
93
|
const protocol = z.string().meta({ description: `The protocol version, \`${PROTOCOL_VERSION}\`` });
|
|
86
94
|
const headers = z.object({
|
|
87
|
-
"Nylorun-Protocol": access.unversioned ? protocol.optional() : protocol,
|
|
95
|
+
...(open ? {} : { "Nylorun-Protocol": access.unversioned ? protocol.optional() : protocol }),
|
|
88
96
|
...(takes("subject")
|
|
89
97
|
? {
|
|
90
98
|
"Nylorun-Subject": z
|
|
@@ -100,11 +108,10 @@ export function tenantRoute(api, access, route, handler) {
|
|
|
100
108
|
});
|
|
101
109
|
api.openAPIRegistry.registerPath({
|
|
102
110
|
...route,
|
|
103
|
-
// `{}`: no credential needed (OpenAPI's optional security)
|
|
104
|
-
security:
|
|
105
|
-
|
|
106
|
-
...(access.anonymous ? [{}] : []),
|
|
107
|
-
],
|
|
111
|
+
// `{}`: no credential needed (OpenAPI's optional security); none at all: `[]`.
|
|
112
|
+
security: open
|
|
113
|
+
? []
|
|
114
|
+
: [...schemes.map((scheme) => ({ [scheme]: [] })), ...(access.anonymous ? [{}] : [])],
|
|
108
115
|
// A route's own headers (`traceparent`, R7.4) beside the common ones.
|
|
109
116
|
request: {
|
|
110
117
|
...route.request,
|
|
@@ -115,9 +122,13 @@ export function tenantRoute(api, access, route, handler) {
|
|
|
115
122
|
401: rejected(takes("token")
|
|
116
123
|
? "No credential (`credential_required`), one the Tenant does not accept (`credential_invalid`), a token that expired (`token_expired`), or a token whose issuer's keys cannot be fetched now (`issuer_unavailable`). `WWW-Authenticate: Bearer` names the protected resource metadata (`resource_metadata`)"
|
|
117
124
|
: "No credential (`credential_required`), or one the Tenant does not accept (`credential_invalid`), with a `WWW-Authenticate: Bearer` challenge"),
|
|
118
|
-
|
|
119
|
-
?
|
|
120
|
-
:
|
|
125
|
+
...(open
|
|
126
|
+
? {}
|
|
127
|
+
: {
|
|
128
|
+
403: rejected(takes("management")
|
|
129
|
+
? "Not allowed for this credential, a key of the other API (`key_role_mismatch`), a key from a browser (`origin_rejected`) or a management key acting for a subject"
|
|
130
|
+
: "Not allowed for this credential or subject scope (`scope_required`; a token also gets `WWW-Authenticate: Bearer error=\"insufficient_scope\"` and the scope), a key of the other API (`key_role_mismatch`), or an application key from a browser (`origin_rejected`)"),
|
|
131
|
+
}),
|
|
121
132
|
404: rejected("Not found (`not_found`)"),
|
|
122
133
|
426: { description: "`Nylorun-Protocol` missing or unsupported", content: { "application/json": { schema: ProtocolRejected } } },
|
|
123
134
|
503: rejected("The Tenant's storage or streams are unavailable"),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent manifests (`/v1/agent-manifests/**`, protocol 16): save, read, list and delete the named,
|
|
3
3
|
* versioned documents Agents are made from, each with a harness and a runtime section. A save
|
|
4
|
-
*
|
|
4
|
+
* moves every Agent that tracks the manifest to the new version; a pinned one stays. Reading needs `agents:read` (or a write scope), saving and deleting
|
|
5
5
|
* `agent-manifests:write`, from any client (Q12). A token caller reaches none: a manifest holds
|
|
6
6
|
* an agent's instructions, tools and servers.
|
|
7
7
|
*/
|
|
@@ -59,7 +59,7 @@ export function agentManifestRoutes(api) {
|
|
|
59
59
|
path: "/v1/agent-manifests/{name}",
|
|
60
60
|
tags: ["Agent manifests"],
|
|
61
61
|
summary: "Save an agent manifest",
|
|
62
|
-
description: "Saves the manifest as its next version, or answers the latest unchanged when nothing differs. Every Agent that tracks the manifest moves to the new version
|
|
62
|
+
description: "Saves the manifest as its next version, or answers the latest unchanged when nothing differs. Every Agent that tracks the manifest moves to the new version: at once, at its pod's next start for a runtime change a pod applies only when it starts, or once a required secret the version adds is set; a pinned one stays, and so does one whose kind, harness or storage the version changes (`agents_behind`). The Runtime checks the harness and runtime sections against each other: a custom harness needs a pod with an image, every credential the harness names is a declared slot of the right type, and the runtime's kind gives the loop the sandbox it needs; every gap is named in one `422 manifest_inconsistent` (`details.gaps`). `If-Match: <version>` refuses the save with `412 manifest_changed` when the latest version is no longer the one you read (`0` for a manifest that does not exist yet). With `?dryRun=true` the answer is the plan: the changes by section, every reason a save would be refused (`errors`, the gaps first), warnings, the Agents it would move (`moves`) and how many stay on older versions (`behind`); nothing is saved. Clients compose the authoring files and drop their `$schema` before they send one document.",
|
|
63
63
|
request: {
|
|
64
64
|
params: namePath,
|
|
65
65
|
query: z.object({
|
|
@@ -72,7 +72,7 @@ export function agentRoutes(api) {
|
|
|
72
72
|
path: "/v1/agents",
|
|
73
73
|
tags: ["Agents"],
|
|
74
74
|
summary: "List Agents",
|
|
75
|
-
description: "Every Agent with all the labels asked for, in `state`, made from `manifest` and `outdated` (moving to another version
|
|
75
|
+
description: "Every Agent with all the labels asked for, in `state`, made from `manifest` and `outdated` (moving to another version) when given, by id. A token caller sees only the Agents its grants reach, and a caller acting for a person only that person's sessions on each. `limit` opts into pages.",
|
|
76
76
|
request: {
|
|
77
77
|
query: pageQuery.extend({
|
|
78
78
|
label: z
|
|
@@ -122,7 +122,7 @@ export function agentRoutes(api) {
|
|
|
122
122
|
path: "/v1/agents/{agentId}",
|
|
123
123
|
tags: ["Agents"],
|
|
124
124
|
summary: "Create, find or move an Agent",
|
|
125
|
-
description: "Creates the Agent, its vault and its compute from a saved agent manifest, within the Tenant's limits, or answers the one with this id, so get-or-create is one call. `manifest: \"name\"` records that it tracks the manifest (its latest version, and each version saved later) and `\"name@n\"` that it is pinned; the version it runs is `resolvedVersion`. On an existing one, labels replace, `owner` sets or (with `null`) clears the owner guard, and `manifest` moves it
|
|
125
|
+
description: "Creates the Agent, its vault and its compute from a saved agent manifest, within the Tenant's limits, or answers the one with this id, so get-or-create is one call. `manifest: \"name\"` records that it tracks the manifest (its latest version, and each version saved later) and `\"name@n\"` that it is pinned; the version it runs is `resolvedVersion`. On an existing one, labels replace, `owner` sets or (with `null`) clears the owner guard, and `manifest` moves it with its id, disk, vault and sessions: a harness-only change applies at once (each session's next turn runs it), a runtime change of a pod at its next start (`targetVersion`, `waitingFor: start`), and a version that adds a required secret once a value is set (`waitingFor: secrets`). Its manifest's name, kind, harness and storage are fixed (`409 agent_fixed_field`): fork it to change them. `?dryRun=true` answers the move's plan and changes nothing. Creating an Agent opens no session. Kind `pod` needs sandbox pods (`nylorun local sandbox enable`) and is created at once.",
|
|
126
126
|
request: {
|
|
127
127
|
params: agentId,
|
|
128
128
|
query: z.object({
|
|
@@ -161,7 +161,7 @@ export function agentRoutes(api) {
|
|
|
161
161
|
path: "/v1/agents/{agentId}/events",
|
|
162
162
|
tags: ["Agents"],
|
|
163
163
|
summary: "Read an Agent's events",
|
|
164
|
-
description: "`agent.created`, `.attached`, `.detached`, `.deleted`, a pod's `.running`, `.suspended`, `.relaunched`, `.lost`, `.reset` and `.failed`, `.forked`, a move's `.outdated`, `.version_changed` and `.start_failed
|
|
164
|
+
description: "`agent.created`, `.attached`, `.detached`, `.deleted`, a pod's `.running`, `.suspended`, `.relaunched`, `.lost`, `.reset` and `.failed`, `.forked`, a move's `.outdated`, `.version_changed` and `.start_failed`, and `agent.egress` for every connection its sandbox opens through egress-gate, naming the turns that were running, in order, numbered from 0, at most the Tenant's Runtime limit `environmentEventItems` (default 1000) per call: `from` reads on.",
|
|
165
165
|
request: {
|
|
166
166
|
params: agentId,
|
|
167
167
|
query: z.object({
|
|
@@ -244,7 +244,7 @@ export function agentRoutes(api) {
|
|
|
244
244
|
path: "/v1/agents/{agentId}/restart",
|
|
245
245
|
tags: ["Agents"],
|
|
246
246
|
summary: "Restart an Agent on its pending version",
|
|
247
|
-
description: "Applies a version the Agent waits to apply
|
|
247
|
+
description: "Applies a version the Agent waits to apply: a running pod stops, so the next turn starts it on the version, on the same volume; a stopped or failed one is asked to run at once. `retry: true` first moves it to the version that failed to start (`failedVersion`) again. Kinds `virtual` and `none` apply a version at once, so there is nothing to wait for. Refused during a turn (`agent_busy`). The body is optional.",
|
|
248
248
|
request: {
|
|
249
249
|
params: agentId,
|
|
250
250
|
body: { required: false, content: { "application/json": { schema: RestartAgentRequest } } },
|
|
@@ -304,7 +304,7 @@ export function agentRoutes(api) {
|
|
|
304
304
|
path: "/v1/agents/{agentId}/fork",
|
|
305
305
|
tags: ["Agents"],
|
|
306
306
|
summary: "Fork an Agent",
|
|
307
|
-
description: "Copies the Agent into a new one
|
|
307
|
+
description: "Copies the Agent into a new one, which is how an Agent changes what is fixed for its life: a new Agent `id`, made from `manifest` (default the source's manifest name, tracking, at its latest version), its disk started from a version of this one's (`disk`: `latest`, the default, takes a snapshot first; a version number; or `empty`) and its secrets copied inside the Runtime (`secrets`: `copy`, the default, copies those the new manifest declares; `none`). On a fork onto other setup the new manifest's setup runs on the copied disk before its first turn. This Agent keeps what it runs, its disk and its sessions. `dryRun` answers the plan and makes nothing. To move an Agent to another version of the same manifest, with the same kind, harness and storage, `PUT` it instead.",
|
|
308
308
|
request: {
|
|
309
309
|
params: agentId,
|
|
310
310
|
body: { required: true, content: { "application/json": { schema: ForkAgentRequest } } },
|
|
@@ -378,7 +378,7 @@ export function agentRoutes(api) {
|
|
|
378
378
|
path: "/v1/agents/{agentId}/secrets/{name}",
|
|
379
379
|
tags: ["Agents"],
|
|
380
380
|
summary: "Write an Agent's secret",
|
|
381
|
-
description: "Creates or replaces one credential of the Agent's vault: an `environment_secret` (the variable `name` reads the sentinel `nylorun_managed` in the sandbox, and egress-gate sets the value as a header on requests to `allowedHosts`), an `environment_variable` (a plain variable), or a `bearer` token or `headers` map for the MCP servers and HTTP tools at `url`. The same name and type re-seals the value and binding; another type replaces it. A rotated value is used from the next request. A second credential for a host or a URL is `409 credential_conflict`. When the Agent's manifest declares secret slots (
|
|
381
|
+
description: "Creates or replaces one credential of the Agent's vault: an `environment_secret` (the variable `name` reads the sentinel `nylorun_managed` in the sandbox, and egress-gate sets the value as a header on requests to `allowedHosts`), an `environment_variable` (a plain variable), or a `bearer` token or `headers` map for the MCP servers and HTTP tools at `url`. The same name and type re-seals the value and binding; another type replaces it. A rotated value is used from the next request. A second credential for a host or a URL is `409 credential_conflict`. When the Agent's manifest declares secret slots (while it moves to another version, that version's), send only the value (`{ value }`, or `{ headers }` for a `headers` slot): the type and binding come from the slot, and a name it does not declare is `409 secret_not_in_manifest`.",
|
|
382
382
|
request: {
|
|
383
383
|
params: secretPath,
|
|
384
384
|
body: {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { SESSION_STATUSES } from "@nylorun/core/contracts";
|
|
3
|
+
import { PROTOCOL_HEADER } from "@nylorun/core/compatibility";
|
|
3
4
|
import { SessionManifestView, SessionUsageTotals, ModelCallsPage, ModelCallExportPage, ToolCallsPage, TurnTrace, } from "../../components.js";
|
|
4
5
|
import { turnTrace } from "../../../traces/read.js";
|
|
5
6
|
import { readAccess, readStoreOf } from "../../../reads/access.js";
|
|
@@ -8,6 +9,27 @@ import { fail } from "../../../tenant/http.js";
|
|
|
8
9
|
import { readRuntimeLimits } from "../../../tenant/runtime-limits.js";
|
|
9
10
|
import { tenantRoute } from "../define.js";
|
|
10
11
|
import { jsonResponse } from "../respond.js";
|
|
12
|
+
/**
|
|
13
|
+
* Whether a client speaks protocol 18, whose usage reads carry the calls' timing and the cost by
|
|
14
|
+
* token kind. An older client's SDK parses these reads strictly, so it gets them without.
|
|
15
|
+
*/
|
|
16
|
+
function usageByKind(header) {
|
|
17
|
+
const protocol = Number(header?.trim());
|
|
18
|
+
return Number.isInteger(protocol) && protocol >= 18;
|
|
19
|
+
}
|
|
20
|
+
/** A session's usage as a protocol 16 or 17 client reads it. */
|
|
21
|
+
function totalsBefore18(totals) {
|
|
22
|
+
const { costSplit: _split, splitCalls: _splitCalls, modelTimeMs: _time, timedCalls: _timed, ...rest } = totals;
|
|
23
|
+
return rest;
|
|
24
|
+
}
|
|
25
|
+
/** A model call as a protocol 16 or 17 client reads it. */
|
|
26
|
+
function callBefore18(call) {
|
|
27
|
+
const { startedAt: _started, endedAt: _ended, usage, ...rest } = call;
|
|
28
|
+
if (usage === null)
|
|
29
|
+
return { ...rest, usage };
|
|
30
|
+
const { costSplit: _split, ...counts } = usage;
|
|
31
|
+
return { ...rest, usage: counts };
|
|
32
|
+
}
|
|
11
33
|
/** A page's `limit`, held to the Tenant's Runtime limit `pageItems` (`pageSize`). */
|
|
12
34
|
const limitParam = (fallback) => z.coerce
|
|
13
35
|
.number()
|
|
@@ -105,14 +127,16 @@ export function readRoutes(api) {
|
|
|
105
127
|
},
|
|
106
128
|
}, async (c) => {
|
|
107
129
|
requirePrincipal(c.get("scope"));
|
|
108
|
-
const store = readStoreOf(c.env.tenant), access = readAccess(c.get("scope")), id = c.req.param("sessionId");
|
|
130
|
+
const store = readStoreOf(c.env.tenant), access = readAccess(c.get("scope")), id = c.req.param("sessionId"), current = usageByKind(c.req.header(PROTOCOL_HEADER));
|
|
109
131
|
if (kind === "usage") {
|
|
110
132
|
const q = parseQuery(turnQuery, c.req.query());
|
|
111
|
-
|
|
133
|
+
const totals = await store.usage(id, q.turnId, access);
|
|
134
|
+
return jsonResponse(200, current ? totals : totalsBefore18(totals));
|
|
112
135
|
}
|
|
113
136
|
const q = parseQuery(callsQuery, c.req.query());
|
|
114
137
|
const limit = await pageSize(c.env.tenant, q.limit, { fallback: CALLS_PAGE_DEFAULT });
|
|
115
|
-
|
|
138
|
+
const page = await store.modelCalls(id, q.turnId, { ...q, limit }, access);
|
|
139
|
+
return jsonResponse(200, current ? page : { ...page, calls: page.calls.map(callBefore18) });
|
|
116
140
|
});
|
|
117
141
|
}
|
|
118
142
|
const toolCallsQuery = turnQuery
|
|
@@ -193,6 +217,7 @@ export function readRoutes(api) {
|
|
|
193
217
|
}, async (c) => {
|
|
194
218
|
const q = parseQuery(exportQuery, c.req.query());
|
|
195
219
|
const limit = await pageSize(c.env.tenant, q.limit, { fallback: EXPORT_PAGE_DEFAULT, name: "exportPageItems" });
|
|
196
|
-
|
|
220
|
+
const page = await readStoreOf(c.env.tenant).exportModel(q.after, limit);
|
|
221
|
+
return jsonResponse(200, usageByKind(c.req.header(PROTOCOL_HEADER)) ? page : { ...page, calls: page.calls.map(callBefore18) });
|
|
197
222
|
});
|
|
198
223
|
}
|