@nylorun/runtime 0.26.0-beta → 0.28.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 +171 -0
- package/README.md +18 -14
- package/dist/adapters/execution/restate.d.ts +15 -18
- package/dist/adapters/execution/restate.js +31 -27
- package/dist/adapters/replication/pgoutput.d.ts +1 -1
- package/dist/adapters/replication/pgoutput.js +3 -2
- package/dist/adapters/sandbox/local.js +8 -5
- package/dist/adapters/sandbox/virtual.js +2 -2
- package/dist/adapters/streams/s2.d.ts +1 -1
- package/dist/adapters/streams/s2.js +18 -14
- package/dist/api/a2a/card.d.ts +4 -3
- package/dist/api/a2a/card.js +4 -4
- package/dist/api/a2a/endpoint.js +3 -4
- package/dist/api/a2a/protocol.js +4 -0
- package/dist/api/a2a/routes.d.ts +2 -6
- package/dist/api/a2a/routes.js +30 -25
- package/dist/api/ag-ui/endpoint.js +2 -3
- package/dist/api/ag-ui/routes.js +8 -11
- package/dist/api/components.d.ts +6789 -3405
- package/dist/api/components.js +43 -30
- package/dist/api/gate/keys.js +7 -4
- package/dist/api/gate/routes.d.ts +6 -2
- package/dist/api/gate/routes.js +15 -11
- package/dist/api/http/app.js +9 -4
- package/dist/api/http/body.d.ts +17 -3
- package/dist/api/http/body.js +35 -7
- package/dist/api/http/respond.js +6 -2
- package/dist/api/http/routes/access.js +5 -4
- package/dist/api/http/routes/agent-manifests.d.ts +10 -0
- package/dist/api/http/routes/agent-manifests.js +135 -0
- package/dist/api/http/routes/agents.d.ts +11 -0
- package/dist/api/http/routes/agents.js +418 -0
- package/dist/api/http/routes/artifacts.js +21 -9
- package/dist/api/http/routes/coverage.d.ts +4 -4
- package/dist/api/http/routes/coverage.js +13 -7
- package/dist/api/http/routes/files.d.ts +2 -1
- package/dist/api/http/routes/files.js +31 -5
- package/dist/api/http/routes/mcp.js +3 -3
- package/dist/api/http/routes/me.d.ts +1 -1
- package/dist/api/http/routes/me.js +1 -2
- package/dist/api/http/routes/memories.d.ts +9 -0
- package/dist/api/http/routes/memories.js +152 -0
- package/dist/api/http/routes/reads.d.ts +10 -111
- package/dist/api/http/routes/reads.js +51 -29
- package/dist/api/http/routes/sessions.js +26 -54
- package/dist/api/http/routes/tenant.d.ts +2 -2
- package/dist/api/http/routes/tenant.js +77 -24
- package/dist/api/http/routes/triggers.d.ts +10 -0
- package/dist/api/http/routes/triggers.js +180 -0
- package/dist/api/inbound-files.d.ts +3 -9
- package/dist/api/inbound-files.js +18 -24
- package/dist/api/openapi.js +73 -47
- package/dist/artifacts/disk.d.ts +10 -14
- package/dist/artifacts/disk.js +99 -95
- package/dist/artifacts/files.d.ts +13 -4
- package/dist/artifacts/files.js +27 -9
- package/dist/artifacts/folder-upload.d.ts +75 -0
- package/dist/artifacts/folder-upload.js +263 -0
- package/dist/artifacts/folders.d.ts +14 -8
- package/dist/artifacts/folders.js +19 -11
- package/dist/artifacts/links.js +7 -6
- package/dist/artifacts/parts.d.ts +9 -14
- package/dist/artifacts/parts.js +11 -9
- package/dist/artifacts/pipe.d.ts +15 -0
- package/dist/artifacts/pipe.js +71 -0
- package/dist/artifacts/quota.d.ts +36 -0
- package/dist/artifacts/quota.js +44 -0
- package/dist/artifacts/service.d.ts +25 -1
- package/dist/artifacts/service.js +72 -27
- package/dist/blob/fs.js +2 -1
- package/dist/blob/s3.d.ts +6 -2
- package/dist/blob/s3.js +9 -7
- package/dist/blob/types.d.ts +1 -1
- package/dist/blob/types.js +1 -1
- package/dist/core/flow-host.d.ts +0 -1
- package/dist/core/limits.d.ts +11 -35
- package/dist/core/limits.js +5 -73
- package/dist/core/sandbox-routes.js +0 -1
- package/dist/core/turn-manifest.d.ts +1 -2
- package/dist/core/turn-manifest.js +4 -28
- package/dist/execution/memory.d.ts +8 -5
- package/dist/execution/memory.js +8 -6
- package/dist/execution/types.d.ts +1 -6
- package/dist/execution/types.js +0 -5
- package/dist/gates/contract.d.ts +3 -2
- package/dist/gates/contract.js +1 -1
- package/dist/gates/egress-credentials.js +5 -4
- package/dist/gates/egress.d.ts +13 -13
- package/dist/gates/egress.js +19 -21
- package/dist/gates/fixture-model.js +13 -2
- package/dist/gates/handler.d.ts +1 -3
- package/dist/gates/handler.js +4 -3
- package/dist/gates/http-client.d.ts +4 -3
- package/dist/gates/http-client.js +5 -7
- package/dist/gates/http-tool.d.ts +24 -4
- package/dist/gates/http-tool.js +41 -13
- package/dist/gates/in-process.d.ts +2 -1
- package/dist/gates/in-process.js +17 -9
- package/dist/gates/inflight.d.ts +2 -2
- package/dist/gates/inflight.js +3 -2
- package/dist/gates/journal.js +5 -7
- package/dist/gates/mcp-handler.d.ts +4 -3
- package/dist/gates/mcp-handler.js +15 -5
- package/dist/gates/meter.js +6 -5
- package/dist/gates/model-gate.d.ts +11 -2
- package/dist/gates/policy.d.ts +34 -6
- package/dist/gates/policy.js +66 -18
- package/dist/gates/provider-gate.d.ts +22 -0
- package/dist/gates/provider-gate.js +30 -0
- package/dist/gates/tool-calls.d.ts +1 -3
- package/dist/gates/tool-calls.js +2 -3
- package/dist/gates/tool-client.d.ts +1 -1
- package/dist/gates/tool-client.js +5 -6
- package/dist/gates/tool-contract.d.ts +8 -5
- package/dist/gates/tool-contract.js +1 -1
- package/dist/gates/tool-gate.d.ts +18 -7
- package/dist/gates/tool-gate.js +49 -7
- package/dist/harness/calls.d.ts +27 -25
- package/dist/harness/calls.js +40 -46
- package/dist/harness/executors.d.ts +10 -3
- package/dist/harness/executors.js +53 -23
- package/dist/harness/main.js +2 -2
- package/dist/harness/pod.d.ts +2 -2
- package/dist/harness/pod.js +7 -6
- package/dist/harness/run-tokens.d.ts +4 -1
- package/dist/harness/run-tokens.js +6 -2
- package/dist/harness/service.d.ts +17 -14
- package/dist/harness/service.js +21 -35
- package/dist/harness/setup.d.ts +0 -2
- package/dist/harness/setup.js +21 -15
- package/dist/harness/ws-client.d.ts +2 -2
- package/dist/harness/ws-client.js +7 -5
- package/dist/harness/ws-port.d.ts +3 -4
- package/dist/harness/ws-port.js +3 -4
- package/dist/harness-api/artifacts.d.ts +20 -0
- package/dist/harness-api/artifacts.js +478 -0
- package/dist/harness-api/in-process.d.ts +2 -2
- package/dist/harness-api/in-process.js +18 -16
- package/dist/harness-api/record.d.ts +10 -9
- package/dist/harness-api/record.js +113 -157
- package/dist/harness-api/renew.d.ts +1 -1
- package/dist/harness-api/renew.js +2 -2
- package/dist/harness-api/server.d.ts +1 -16
- package/dist/harness-api/server.js +86 -73
- package/dist/harness-api/start.d.ts +27 -5
- package/dist/harness-api/start.js +102 -19
- package/dist/harness-api/tool-journal.d.ts +15 -10
- package/dist/harness-api/tool-journal.js +26 -24
- package/dist/harness-api/workspace.d.ts +0 -4
- package/dist/harness-api/workspace.js +4 -47
- package/dist/harness-api/ws-server.js +10 -10
- package/dist/host/create-host.js +2 -3
- package/dist/host/execution.js +2 -3
- package/dist/host/gates.d.ts +2 -9
- package/dist/host/gates.js +15 -12
- package/dist/host/http.d.ts +2 -4
- package/dist/host/http.js +5 -29
- package/dist/host/main.js +10 -3
- package/dist/host/operate.js +12 -3
- package/dist/host/stack-config.d.ts +11 -0
- package/dist/host/stack-config.js +21 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/infra/index.js +2 -1
- package/dist/infra/readiness.d.ts +0 -2
- package/dist/infra/readiness.js +4 -3
- package/dist/keys/client.d.ts +1 -0
- package/dist/keys/client.js +2 -3
- package/dist/keys/contract.d.ts +0 -2
- package/dist/keys/contract.js +0 -2
- package/dist/keys/egress-ca.d.ts +0 -2
- package/dist/keys/egress-ca.js +2 -3
- package/dist/keys/keys.d.ts +15 -4
- package/dist/keys/keys.js +22 -1
- package/dist/keys/webhooks.d.ts +25 -0
- package/dist/keys/webhooks.js +62 -0
- package/dist/keys/x509.d.ts +8 -4
- package/dist/keys/x509.js +14 -5
- package/dist/management-openapi.json +3043 -1954
- package/dist/mcp/connect.d.ts +35 -26
- package/dist/mcp/connect.js +112 -141
- package/dist/mcp/pool.d.ts +27 -22
- package/dist/mcp/pool.js +34 -48
- package/dist/mcp/preview.d.ts +12 -5
- package/dist/mcp/preview.js +43 -26
- package/dist/mcp/snapshot.d.ts +35 -86
- package/dist/mcp/snapshot.js +93 -135
- package/dist/memory/service.d.ts +97 -0
- package/dist/memory/service.js +335 -0
- package/dist/memory/tool.d.ts +36 -0
- package/dist/memory/tool.js +84 -0
- package/dist/model/auth-store.js +5 -3
- package/dist/model/capabilities.d.ts +1 -1
- package/dist/model/catalog.d.ts +9 -36
- package/dist/model/catalog.js +6 -33
- package/dist/model/descriptor.d.ts +51 -0
- package/dist/model/descriptor.js +83 -0
- package/dist/model/models.d.ts +0 -3
- package/dist/model/models.js +3 -5
- package/dist/model/native-blocks.js +1 -1
- package/dist/model/pi-model.d.ts +16 -5
- package/dist/model/pi-model.js +86 -105
- package/dist/openapi.json +13653 -9986
- package/dist/reads/cursor.js +3 -1
- package/dist/reads/types.d.ts +3 -3
- package/dist/record/agent.d.ts +27 -0
- package/dist/record/agent.js +46 -0
- package/dist/record/append.d.ts +34 -2
- package/dist/record/append.js +50 -1
- package/dist/record/index.d.ts +2 -2
- package/dist/record/index.js +2 -2
- package/dist/redact.d.ts +1 -1
- package/dist/redact.js +3 -2
- package/dist/sandbox/egress-token.d.ts +3 -3
- package/dist/sandbox/egress-token.js +3 -3
- package/dist/sandbox/join.js +8 -7
- package/dist/sandbox/manager.d.ts +41 -41
- package/dist/sandbox/manager.js +112 -44
- package/dist/sandbox/placement.d.ts +2 -2
- package/dist/sandbox/placement.js +7 -10
- package/dist/sandbox/pods/client.d.ts +1 -10
- package/dist/sandbox/pods/client.js +8 -4
- package/dist/sandbox/pods/lifecycle.d.ts +25 -17
- package/dist/sandbox/pods/lifecycle.js +51 -29
- package/dist/sandbox/pods/network-gate.d.ts +4 -5
- package/dist/sandbox/pods/network-gate.js +7 -7
- package/dist/sandbox/pods/reconcile.js +14 -3
- package/dist/sandbox/pods/spec.js +8 -5
- package/dist/sandbox/policy.d.ts +7 -1
- package/dist/sandbox/policy.js +10 -3
- package/dist/sandbox/resolve.d.ts +11 -6
- package/dist/sandbox/resolve.js +19 -9
- package/dist/sandbox/setup.d.ts +6 -2
- package/dist/sandbox/setup.js +47 -14
- package/dist/sandbox/share.d.ts +5 -14
- package/dist/sandbox/share.js +5 -34
- package/dist/sandbox/skills.d.ts +7 -13
- package/dist/sandbox/skills.js +16 -31
- package/dist/sandbox/tenant-config.d.ts +2 -2
- package/dist/sandbox/tenant-config.js +4 -3
- package/dist/sandbox/tools.d.ts +7 -1
- package/dist/sandbox/tools.js +26 -26
- package/dist/sandbox/types.d.ts +10 -3
- package/dist/sandbox/types.js +9 -0
- package/dist/store/postgres/connect.d.ts +6 -5
- package/dist/store/postgres/connect.js +14 -11
- package/dist/store/postgres/control.js +13 -13
- package/dist/store/postgres/drizzle/0028_artifact_write_keys.sql +2 -0
- package/dist/store/postgres/drizzle/0029_protocol_15.sql +11 -0
- package/dist/store/postgres/drizzle/0030_protocol_15_runtime_block.sql +11 -0
- package/dist/store/postgres/drizzle/0031_protocol_15_mcp_snapshot.sql +8 -0
- package/dist/store/postgres/drizzle/0032_agents.sql +54 -0
- package/dist/store/postgres/drizzle/0033_agent_versions.sql +7 -0
- package/dist/store/postgres/drizzle/0034_protocol_17_session_queue.sql +13 -0
- package/dist/store/postgres/drizzle/0035_t4_triggers.sql +41 -0
- package/dist/store/postgres/drizzle/0036_t5_memories.sql +30 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +63 -0
- package/dist/store/postgres/reads.js +17 -82
- package/dist/store/postgres/record-writer.d.ts +4 -4
- package/dist/store/postgres/record-writer.js +9 -9
- package/dist/store/postgres/schema.d.ts +1382 -151
- package/dist/store/postgres/schema.js +191 -37
- package/dist/store/postgres/store.js +384 -105
- package/dist/store/postgres/tenant.js +1 -2
- package/dist/store/types.d.ts +172 -57
- package/dist/store/types.js +0 -1
- package/dist/streams/relay/core.d.ts +3 -3
- package/dist/streams/relay/core.js +9 -10
- package/dist/tenant/advance.js +41 -39
- package/dist/tenant/agent-manifests.d.ts +72 -0
- package/dist/tenant/agent-manifests.js +359 -0
- package/dist/tenant/agent-versions.d.ts +126 -0
- package/dist/tenant/agent-versions.js +389 -0
- package/dist/tenant/agents.d.ts +230 -0
- package/dist/tenant/{environments.js → agents.js} +493 -328
- package/dist/tenant/auth.d.ts +1 -1
- package/dist/tenant/auth.js +3 -3
- package/dist/tenant/commands.d.ts +63 -2
- package/dist/tenant/commands.js +240 -90
- package/dist/tenant/context.d.ts +57 -33
- package/dist/tenant/context.js +6 -2
- package/dist/tenant/definition-files.d.ts +25 -4
- package/dist/tenant/definition-files.js +85 -47
- package/dist/tenant/effects.js +15 -51
- package/dist/tenant/ephemeral.js +2 -1
- package/dist/tenant/history.d.ts +1 -1
- package/dist/tenant/history.js +1 -1
- package/dist/tenant/host-token.d.ts +3 -3
- package/dist/tenant/host-token.js +11 -10
- package/dist/tenant/http.d.ts +5 -8
- package/dist/tenant/http.js +9 -0
- package/dist/tenant/identity-file.d.ts +29 -6
- package/dist/tenant/identity-file.js +45 -15
- package/dist/tenant/issuers.d.ts +5 -5
- package/dist/tenant/issuers.js +34 -26
- package/dist/tenant/jwt.d.ts +8 -2
- package/dist/tenant/jwt.js +10 -2
- package/dist/tenant/limits.d.ts +87 -0
- package/dist/tenant/limits.js +172 -0
- package/dist/tenant/memories.d.ts +38 -0
- package/dist/tenant/memories.js +119 -0
- package/dist/tenant/module.d.ts +4 -1
- package/dist/tenant/module.js +9 -8
- package/dist/tenant/outbound.d.ts +11 -14
- package/dist/tenant/outbound.js +10 -15
- package/dist/tenant/reset.js +2 -2
- package/dist/tenant/run-grants.d.ts +6 -0
- package/dist/tenant/run-grants.js +7 -2
- package/dist/tenant/run-token.d.ts +0 -4
- package/dist/tenant/run-token.js +6 -11
- package/dist/tenant/runtime-limits.d.ts +24 -0
- package/dist/tenant/runtime-limits.js +27 -0
- package/dist/tenant/runtime.d.ts +1 -1
- package/dist/tenant/runtime.js +38 -43
- package/dist/tenant/session-streams.js +7 -6
- package/dist/tenant/session.d.ts +1 -1
- package/dist/tenant/session.js +1 -1
- package/dist/tenant/sessions.d.ts +28 -45
- package/dist/tenant/sessions.js +89 -209
- package/dist/tenant/signing-keys.d.ts +1 -1
- package/dist/tenant/signing-keys.js +5 -6
- package/dist/tenant/status.js +10 -10
- package/dist/tenant/streams.js +18 -20
- package/dist/tenant/sweep.d.ts +1 -21
- package/dist/tenant/sweep.js +51 -51
- package/dist/tenant/transcript.d.ts +70 -23
- package/dist/tenant/transcript.js +28 -22
- package/dist/tenant/triggers.d.ts +143 -0
- package/dist/tenant/triggers.js +715 -0
- package/dist/tenant/turn-timing.d.ts +11 -1
- package/dist/tenant/turn-timing.js +3 -1
- package/dist/tenant/types.d.ts +9 -14
- package/dist/tenant/worker.d.ts +4 -10
- package/dist/tenant/worker.js +10 -14
- package/dist/traces/ids.js +5 -1
- package/dist/traces/map.d.ts +10 -7
- package/dist/traces/map.js +16 -12
- package/dist/traces/otlp.d.ts +3 -3
- package/dist/traces/otlp.js +5 -3
- package/dist/traces/projector.d.ts +9 -4
- package/dist/traces/projector.js +13 -7
- package/dist/traces/read.js +6 -1
- package/dist/tuning.d.ts +390 -0
- package/dist/tuning.js +677 -0
- package/dist/vault/headers.js +4 -2
- package/dist/vault/service.d.ts +13 -8
- package/dist/vault/service.js +61 -17
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +13 -12
- package/dist/api/http/routes/environment-manifests.d.ts +0 -9
- package/dist/api/http/routes/environment-manifests.js +0 -118
- package/dist/api/http/routes/environments.d.ts +0 -11
- package/dist/api/http/routes/environments.js +0 -332
- package/dist/artifacts/export.d.ts +0 -8
- package/dist/artifacts/export.js +0 -204
- package/dist/artifacts/media-types.d.ts +0 -30
- package/dist/artifacts/media-types.js +0 -137
- package/dist/artifacts/workspace.d.ts +0 -60
- package/dist/artifacts/workspace.js +0 -45
- package/dist/media.d.ts +0 -10
- package/dist/media.js +0 -58
- package/dist/record/environment.d.ts +0 -25
- package/dist/record/environment.js +0 -44
- package/dist/sandbox/runtime-tools.d.ts +0 -9
- package/dist/sandbox/runtime-tools.js +0 -16
- package/dist/sandbox/session-sandbox.d.ts +0 -16
- package/dist/sandbox/session-sandbox.js +0 -77
- package/dist/tenant/artifact-tool.d.ts +0 -13
- package/dist/tenant/artifact-tool.js +0 -243
- package/dist/tenant/environment-manifests.d.ts +0 -57
- package/dist/tenant/environment-manifests.js +0 -200
- package/dist/tenant/environments.d.ts +0 -174
- package/dist/tenant/skill-tool.d.ts +0 -20
- package/dist/tenant/skill-tool.js +0 -67
- package/dist/tenant/tool-results.d.ts +0 -57
- package/dist/tenant/tool-results.js +0 -298
- package/dist/tenant/tool-search.d.ts +0 -39
- package/dist/tenant/tool-search.js +0 -103
|
@@ -16,17 +16,17 @@ export function mcpRoutes(api) {
|
|
|
16
16
|
path: "/v1/tenant/mcp/preview",
|
|
17
17
|
tags: ["MCP servers"],
|
|
18
18
|
summary: "Preview an MCP server's tools",
|
|
19
|
-
description: "Connects to the remote MCP server at `url` with the credential for that URL in the vault of `
|
|
19
|
+
description: "Connects to the remote MCP server at `url` with the credential for that URL in the vault of the Agent `agentId`, if given (its headers and `via`; never an identity header), under the Host's address policy, lists its tools within 15 s and closes the connection. It never calls a tool. Each tool comes with the name the model would call it (`modelName`, made with `name`), its annotations and its input schema's size. A server that answers `401` is `authRequired`, with its RFC 9728 protected-resource metadata when it publishes any: it needs a person's sign-in, so reach it through a gateway (`via`), or with a key. No credential value is in the answer.",
|
|
20
20
|
request: {
|
|
21
21
|
body: { required: true, content: { "application/json": { schema: McpPreviewRequest } } },
|
|
22
22
|
},
|
|
23
23
|
responses: {
|
|
24
24
|
200: json(McpPreview, "The server's tools, or that it needs a credential (`authRequired`)"),
|
|
25
|
-
409: json(Rejected, "The
|
|
25
|
+
409: json(Rejected, "The Agent's credential for the URL cannot be used"),
|
|
26
26
|
502: json(Rejected, "The server could not be listed (`mcp_preview_failed`): `details.failure` is the code a tool call would have failed with, such as `mcp.unreachable` for an address the Host refuses"),
|
|
27
27
|
},
|
|
28
28
|
}, async (c) => {
|
|
29
|
-
const request = McpPreviewRequestSchema.parse(await readJson(c
|
|
29
|
+
const request = McpPreviewRequestSchema.parse(await readJson(c));
|
|
30
30
|
return jsonResponse(200, await c.env.tenant.keys.previewMcp(request));
|
|
31
31
|
});
|
|
32
32
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `GET /v1/me` (Host feature `trusted-issuers`): who the Runtime takes the caller to be, for any
|
|
3
3
|
* credential that acts on the Tenant. It shows what a trusted issuer's token renders to (its
|
|
4
|
-
* subject, scopes
|
|
4
|
+
* subject, scopes and Agent grants), so an operator can check an identity file, and
|
|
5
5
|
* Studio can check a forwarded token for the `studio` scope.
|
|
6
6
|
*/
|
|
7
7
|
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
@@ -19,7 +19,6 @@ export function describeCaller(scope) {
|
|
|
19
19
|
subject: scope.subject,
|
|
20
20
|
scopes: ordered(scope.scopes),
|
|
21
21
|
agents: scope.agents === "*" ? "*" : [...scope.agents].sort(),
|
|
22
|
-
environments: [...(scope.environments ?? [])],
|
|
23
22
|
via: `issuer:${scope.issuer}`,
|
|
24
23
|
};
|
|
25
24
|
case "management":
|
|
@@ -34,7 +33,7 @@ export function meRoutes(api) {
|
|
|
34
33
|
path: "/v1/me",
|
|
35
34
|
tags: ["Access"],
|
|
36
35
|
summary: "Get who the caller is",
|
|
37
|
-
description: "The subject, scopes
|
|
36
|
+
description: "The subject, scopes and Agent grants of the credential that sends it: an " +
|
|
38
37
|
"application key (alone or acting for a subject), a management key " +
|
|
39
38
|
"(`via: management:<principalId>`, no scopes, no agents), or a trusted issuer's token " +
|
|
40
39
|
"(`via: issuer:<name>`).",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An Agent's memories (track T5, D72), shaped like Anthropic's memory stores: list, read, write
|
|
3
|
+
* whole, delete, and the versions every change leaves. A memory's path is relative to
|
|
4
|
+
* `/memories`, with `/` percent-encoded (`conventions%2Frelease.md`), as an Agent id is. The
|
|
5
|
+
* caller reaches an Agent's memories as it reaches the Agent; writes are `agents:write`.
|
|
6
|
+
*/
|
|
7
|
+
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
8
|
+
import type { TenantEnv } from "../app.js";
|
|
9
|
+
export declare function memoryRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { isAgentId, PutMemoryRequestSchema } from "@nylorun/core/contracts";
|
|
3
|
+
import { MemoryList, MemoryVersionDetail, MemoryVersionPage, MemoryView, PutMemoryRequest } from "../../components.js";
|
|
4
|
+
import { assertReaches } from "../../../tenant/agents.js";
|
|
5
|
+
import { fail } from "../../../tenant/http.js";
|
|
6
|
+
import { deleteMemoryPath, listMemories, listMemoryVersions, putMemoryContent, readMemory, readMemoryVersion, } from "../../../tenant/memories.js";
|
|
7
|
+
import { readJson } from "../body.js";
|
|
8
|
+
import { tenantRoute } from "../define.js";
|
|
9
|
+
import { pageQuery, pageSize, parseQuery } from "./reads.js";
|
|
10
|
+
import { jsonResponse } from "../respond.js";
|
|
11
|
+
const READ = {
|
|
12
|
+
credentials: ["application", "subject", "token"],
|
|
13
|
+
scopes: ["sessions:own", "agents:read", "agents:write"],
|
|
14
|
+
};
|
|
15
|
+
const WRITE = {
|
|
16
|
+
credentials: ["application", "subject", "token"],
|
|
17
|
+
scopes: ["agents:write"],
|
|
18
|
+
};
|
|
19
|
+
const json = (schema, description) => ({
|
|
20
|
+
description,
|
|
21
|
+
content: { "application/json": { schema } },
|
|
22
|
+
});
|
|
23
|
+
const agentId = z.object({
|
|
24
|
+
agentId: z.string().meta({ description: "The Agent id, percent-encoded" }),
|
|
25
|
+
});
|
|
26
|
+
const memoryPath = agentId.extend({
|
|
27
|
+
path: z.string().meta({
|
|
28
|
+
description: "The memory's path under `/memories`, percent-encoded: `conventions%2Frelease.md` is `/memories/conventions/release.md`",
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
function idOf(value) {
|
|
32
|
+
if (!isAgentId(value))
|
|
33
|
+
return fail(400, "An Agent id is up to 200 characters: /-separated segments of letters, digits, '.', '_' and '-'");
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
export function memoryRoutes(api) {
|
|
37
|
+
tenantRoute(api, READ, {
|
|
38
|
+
method: "get",
|
|
39
|
+
path: "/v1/agents/{agentId}/memories",
|
|
40
|
+
tags: ["Memory"],
|
|
41
|
+
summary: "List an Agent's memories",
|
|
42
|
+
description: "Its memories by path, each with its size, `content_sha256`, frontmatter `description` and version. `pathPrefix` keeps one folder's (`conventions` for `/memories/conventions/…`).",
|
|
43
|
+
request: {
|
|
44
|
+
params: agentId,
|
|
45
|
+
query: pageQuery.extend({
|
|
46
|
+
pathPrefix: z.string().optional().meta({ description: "Only the memories in this folder, relative to `/memories`" }),
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
responses: { 200: json(MemoryList, "A page of memories") },
|
|
50
|
+
}, async (c) => {
|
|
51
|
+
const id = idOf(c.req.param("agentId"));
|
|
52
|
+
assertReaches(c.get("scope"), id);
|
|
53
|
+
const pathPrefix = c.req.query("pathPrefix");
|
|
54
|
+
const { limit, cursor } = parseQuery(pageQuery, { limit: c.req.query("limit"), cursor: c.req.query("cursor") });
|
|
55
|
+
return jsonResponse(200, await listMemories(c.env.tenant, id, {
|
|
56
|
+
...(pathPrefix ? { pathPrefix } : {}),
|
|
57
|
+
...(cursor ? { cursor } : {}),
|
|
58
|
+
limit: await pageSize(c.env.tenant, limit, { fallback: 100 }),
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
tenantRoute(api, READ, {
|
|
62
|
+
method: "get",
|
|
63
|
+
path: "/v1/agents/{agentId}/memories/{path}",
|
|
64
|
+
tags: ["Memory"],
|
|
65
|
+
summary: "Read a memory",
|
|
66
|
+
description: "The memory's content, with its size, `content_sha256`, description and version.",
|
|
67
|
+
request: { params: memoryPath },
|
|
68
|
+
responses: { 200: json(MemoryView, "The memory"), 404: { description: "No memory has this path" } },
|
|
69
|
+
}, async (c) => {
|
|
70
|
+
const id = idOf(c.req.param("agentId"));
|
|
71
|
+
assertReaches(c.get("scope"), id);
|
|
72
|
+
return jsonResponse(200, await readMemory(c.env.tenant, id, c.req.param("path") ?? ""));
|
|
73
|
+
});
|
|
74
|
+
tenantRoute(api, WRITE, {
|
|
75
|
+
method: "put",
|
|
76
|
+
path: "/v1/agents/{agentId}/memories/{path}",
|
|
77
|
+
tags: ["Memory"],
|
|
78
|
+
summary: "Write a memory",
|
|
79
|
+
description: "Creates the memory or replaces its content, as the `memory` tool's `create` does, and records a version with the caller as its actor. This is how an app seeds an Agent's memory. With `contentSha256` the write applies only while the memory still has that content (`\"\"`: only while no memory has the path); otherwise `409 memory_conflict` with the current memory. The path ends in `.md`; the Runtime limits `memoryBytes` (`413`) and `memoriesPerAgent` (`409 limit_exceeded`) hold.",
|
|
80
|
+
request: {
|
|
81
|
+
params: memoryPath,
|
|
82
|
+
body: { required: true, content: { "application/json": { schema: PutMemoryRequest } } },
|
|
83
|
+
},
|
|
84
|
+
responses: {
|
|
85
|
+
200: json(MemoryView, "The memory as written"),
|
|
86
|
+
409: { description: "The `contentSha256` precondition no longer holds, or a folder has this path (`memory_conflict`)" },
|
|
87
|
+
413: { description: "Larger than the Runtime limit `memoryBytes`" },
|
|
88
|
+
},
|
|
89
|
+
}, async (c) => {
|
|
90
|
+
const id = idOf(c.req.param("agentId"));
|
|
91
|
+
const scope = c.get("scope");
|
|
92
|
+
assertReaches(scope, id);
|
|
93
|
+
const body = PutMemoryRequestSchema.safeParse(await readJson(c));
|
|
94
|
+
if (!body.success)
|
|
95
|
+
fail(400, "The body is { content, contentSha256? }", { code: "invalid_request" });
|
|
96
|
+
return jsonResponse(200, await putMemoryContent(c.env.tenant, id, c.req.param("path") ?? "", body.data, scope));
|
|
97
|
+
});
|
|
98
|
+
tenantRoute(api, WRITE, {
|
|
99
|
+
method: "delete",
|
|
100
|
+
path: "/v1/agents/{agentId}/memories/{path}",
|
|
101
|
+
tags: ["Memory"],
|
|
102
|
+
summary: "Delete a memory or a folder",
|
|
103
|
+
description: "Deletes the memory, or every memory in the folder the path names, each with a version that records the delete. Versions stay with the Agent.",
|
|
104
|
+
request: { params: memoryPath },
|
|
105
|
+
responses: {
|
|
106
|
+
200: json(z.object({ path: z.string(), deleted: z.number().int().nonnegative() }).strict(), "What was deleted"),
|
|
107
|
+
404: { description: "No memory or folder has this path" },
|
|
108
|
+
},
|
|
109
|
+
}, async (c) => {
|
|
110
|
+
const id = idOf(c.req.param("agentId"));
|
|
111
|
+
const scope = c.get("scope");
|
|
112
|
+
assertReaches(scope, id);
|
|
113
|
+
return jsonResponse(200, await deleteMemoryPath(c.env.tenant, id, c.req.param("path") ?? "", scope));
|
|
114
|
+
});
|
|
115
|
+
tenantRoute(api, READ, {
|
|
116
|
+
method: "get",
|
|
117
|
+
path: "/v1/agents/{agentId}/memory_versions",
|
|
118
|
+
tags: ["Memory"],
|
|
119
|
+
summary: "List an Agent's memory versions",
|
|
120
|
+
description: "Every change to its memories, newest first: the operation, the path (a rename's names its old one), and who made it: `agent:<manifest>@<version>` with the session, turn and trigger run of a turn's write, or the API caller. `path` keeps one memory's.",
|
|
121
|
+
request: {
|
|
122
|
+
params: agentId,
|
|
123
|
+
query: pageQuery.extend({
|
|
124
|
+
path: z.string().optional().meta({ description: "Only this memory's versions, relative to `/memories`" }),
|
|
125
|
+
}),
|
|
126
|
+
},
|
|
127
|
+
responses: { 200: json(MemoryVersionPage, "A page of versions") },
|
|
128
|
+
}, async (c) => {
|
|
129
|
+
const id = idOf(c.req.param("agentId"));
|
|
130
|
+
assertReaches(c.get("scope"), id);
|
|
131
|
+
const path = c.req.query("path");
|
|
132
|
+
const { limit, cursor } = parseQuery(pageQuery, { limit: c.req.query("limit"), cursor: c.req.query("cursor") });
|
|
133
|
+
return jsonResponse(200, await listMemoryVersions(c.env.tenant, id, {
|
|
134
|
+
...(path ? { path } : {}),
|
|
135
|
+
...(cursor ? { cursor } : {}),
|
|
136
|
+
limit: await pageSize(c.env.tenant, limit, { fallback: 50 }),
|
|
137
|
+
}));
|
|
138
|
+
});
|
|
139
|
+
tenantRoute(api, READ, {
|
|
140
|
+
method: "get",
|
|
141
|
+
path: "/v1/agents/{agentId}/memory_versions/{versionId}",
|
|
142
|
+
tags: ["Memory"],
|
|
143
|
+
summary: "Read a memory version",
|
|
144
|
+
description: "One version with the content it left (`null` for a delete). To roll a memory back, write this content again.",
|
|
145
|
+
request: { params: agentId.extend({ versionId: z.string().meta({ description: "The version's id (`mv_…`)" }) }) },
|
|
146
|
+
responses: { 200: json(MemoryVersionDetail, "The version"), 404: { description: "No such version" } },
|
|
147
|
+
}, async (c) => {
|
|
148
|
+
const id = idOf(c.req.param("agentId"));
|
|
149
|
+
assertReaches(c.get("scope"), id);
|
|
150
|
+
return jsonResponse(200, await readMemoryVersion(c.env.tenant, id, c.req.param("versionId") ?? ""));
|
|
151
|
+
});
|
|
152
|
+
}
|
|
@@ -6,6 +6,15 @@ export declare const pageQuery: z.ZodObject<{
|
|
|
6
6
|
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
7
7
|
cursor: z.ZodOptional<z.ZodString>;
|
|
8
8
|
}, z.core.$strip>;
|
|
9
|
+
/**
|
|
10
|
+
* The size of a page: `asked`, or, when the query names none, `fallback`, each within the Tenant's
|
|
11
|
+
* Runtime limit `name` (read for each request): a page asked larger holds that many, and its
|
|
12
|
+
* cursor reads on.
|
|
13
|
+
*/
|
|
14
|
+
export declare function pageSize(ctx: TenantEnv["Bindings"]["tenant"], asked: number | undefined, options?: {
|
|
15
|
+
fallback?: number;
|
|
16
|
+
name?: "pageItems" | "exportPageItems";
|
|
17
|
+
}): Promise<number>;
|
|
9
18
|
export declare const sessionPageQuery: z.ZodObject<{
|
|
10
19
|
limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
11
20
|
cursor: z.ZodOptional<z.ZodString>;
|
|
@@ -21,7 +30,7 @@ export declare const sessionPageQuery: z.ZodObject<{
|
|
|
21
30
|
uncertain: "uncertain";
|
|
22
31
|
waiting: "waiting";
|
|
23
32
|
}>>;
|
|
24
|
-
|
|
33
|
+
manifest: z.ZodOptional<z.ZodString>;
|
|
25
34
|
ownerUserId: z.ZodOptional<z.ZodString>;
|
|
26
35
|
}, z.core.$strict>;
|
|
27
36
|
export declare function parseQuery<T>(schema: z.ZodType<T>, query: unknown): T;
|
|
@@ -33,119 +42,9 @@ export declare function sessionPage(ctx: TenantEnv["Bindings"]["tenant"], scope:
|
|
|
33
42
|
status: "cancelled" | "completed" | "failed" | "idle" | "paused" | "runnable" | "running" | "uncertain" | "waiting";
|
|
34
43
|
activeTurnId: string | null;
|
|
35
44
|
lastTurnId: string | null;
|
|
36
|
-
environmentId: string | null;
|
|
37
45
|
createdAt: string | null;
|
|
38
46
|
lastEventAt: string | null;
|
|
39
47
|
}[];
|
|
40
48
|
nextCursor: string | null;
|
|
41
49
|
}>;
|
|
42
|
-
export declare function environmentPage(ctx: TenantEnv["Bindings"]["tenant"], scope: TenantEnv["Variables"]["scope"], query: Record<string, string>, labels: Record<string, string>): Promise<{
|
|
43
|
-
environments: {
|
|
44
|
-
id: string;
|
|
45
|
-
kind: "none" | "pod" | "virtual";
|
|
46
|
-
labels: Record<string, string>;
|
|
47
|
-
manifest: {
|
|
48
|
-
image?: string | undefined;
|
|
49
|
-
resources?: {
|
|
50
|
-
cpus: number;
|
|
51
|
-
memory: string;
|
|
52
|
-
} | undefined;
|
|
53
|
-
storage?: string | undefined;
|
|
54
|
-
network?: {
|
|
55
|
-
allowedHosts: string[];
|
|
56
|
-
} | undefined;
|
|
57
|
-
harness: string;
|
|
58
|
-
lifecycle: {
|
|
59
|
-
idle?: string | undefined;
|
|
60
|
-
deleteAfter?: string | undefined;
|
|
61
|
-
};
|
|
62
|
-
setup?: {
|
|
63
|
-
command: string;
|
|
64
|
-
cwd?: string | undefined;
|
|
65
|
-
timeout?: string | undefined;
|
|
66
|
-
}[] | undefined;
|
|
67
|
-
files?: ({
|
|
68
|
-
artifactId: string;
|
|
69
|
-
version: number;
|
|
70
|
-
path: string;
|
|
71
|
-
} | {
|
|
72
|
-
path: string;
|
|
73
|
-
files: Record<string, string>;
|
|
74
|
-
})[] | undefined;
|
|
75
|
-
secrets?: Record<string, {
|
|
76
|
-
required?: boolean | undefined;
|
|
77
|
-
description?: string | undefined;
|
|
78
|
-
type: "environment_secret";
|
|
79
|
-
allowedHosts: string[];
|
|
80
|
-
inject?: {
|
|
81
|
-
header: string;
|
|
82
|
-
format: string;
|
|
83
|
-
} | undefined;
|
|
84
|
-
} | {
|
|
85
|
-
required?: boolean | undefined;
|
|
86
|
-
description?: string | undefined;
|
|
87
|
-
type: "environment_variable";
|
|
88
|
-
} | {
|
|
89
|
-
via?: string | undefined;
|
|
90
|
-
identity?: {
|
|
91
|
-
header: string;
|
|
92
|
-
} | undefined;
|
|
93
|
-
required?: boolean | undefined;
|
|
94
|
-
description?: string | undefined;
|
|
95
|
-
type: "bearer";
|
|
96
|
-
url: string;
|
|
97
|
-
} | {
|
|
98
|
-
via?: string | undefined;
|
|
99
|
-
identity?: {
|
|
100
|
-
header: string;
|
|
101
|
-
} | undefined;
|
|
102
|
-
required?: boolean | undefined;
|
|
103
|
-
description?: string | undefined;
|
|
104
|
-
type: "headers";
|
|
105
|
-
url: string;
|
|
106
|
-
}> | undefined;
|
|
107
|
-
};
|
|
108
|
-
manifestName?: string | undefined;
|
|
109
|
-
manifestVersion?: number | undefined;
|
|
110
|
-
manifestHash?: string | undefined;
|
|
111
|
-
forkedFrom?: {
|
|
112
|
-
environment: string;
|
|
113
|
-
disk: number | null;
|
|
114
|
-
} | undefined;
|
|
115
|
-
slots?: {
|
|
116
|
-
name: string;
|
|
117
|
-
type: string;
|
|
118
|
-
required: boolean;
|
|
119
|
-
set: boolean;
|
|
120
|
-
}[] | undefined;
|
|
121
|
-
version: number;
|
|
122
|
-
appliedVersion: number;
|
|
123
|
-
ownerUserId: string | null;
|
|
124
|
-
state: string;
|
|
125
|
-
pod?: {
|
|
126
|
-
desired: "deleted" | "running" | "suspended";
|
|
127
|
-
observed: "creating" | "deleting" | "failed" | "lost" | "running" | "suspended";
|
|
128
|
-
volumeGeneration: number;
|
|
129
|
-
hostEpoch: number;
|
|
130
|
-
reason?: string | undefined;
|
|
131
|
-
imageDigest?: string | undefined;
|
|
132
|
-
} | undefined;
|
|
133
|
-
lastUsedAt: string;
|
|
134
|
-
disk?: {
|
|
135
|
-
latestVersion: number | null;
|
|
136
|
-
operation?: {
|
|
137
|
-
kind: "restore" | "seed" | "snapshot";
|
|
138
|
-
version?: number | undefined;
|
|
139
|
-
startedAt: string;
|
|
140
|
-
} | undefined;
|
|
141
|
-
} | undefined;
|
|
142
|
-
sessions: {
|
|
143
|
-
id: string;
|
|
144
|
-
activeTurnId: string | null;
|
|
145
|
-
}[];
|
|
146
|
-
createdAt: string;
|
|
147
|
-
updatedAt: string;
|
|
148
|
-
}[];
|
|
149
|
-
nextCursor: string | null;
|
|
150
|
-
}>;
|
|
151
50
|
export declare function readRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
@@ -5,18 +5,42 @@ import { turnTrace } from "../../../traces/read.js";
|
|
|
5
5
|
import { readAccess, readStoreOf } from "../../../reads/access.js";
|
|
6
6
|
import { requireApplication, requirePrincipal } from "../../../tenant/auth.js";
|
|
7
7
|
import { fail } from "../../../tenant/http.js";
|
|
8
|
-
import {
|
|
8
|
+
import { readRuntimeLimits } from "../../../tenant/runtime-limits.js";
|
|
9
9
|
import { tenantRoute } from "../define.js";
|
|
10
10
|
import { jsonResponse } from "../respond.js";
|
|
11
|
+
/** A page's `limit`, held to the Tenant's Runtime limit `pageItems` (`pageSize`). */
|
|
12
|
+
const limitParam = (fallback) => z.coerce
|
|
13
|
+
.number()
|
|
14
|
+
.int()
|
|
15
|
+
.min(1)
|
|
16
|
+
.optional()
|
|
17
|
+
.meta({
|
|
18
|
+
description: `A page holds at most the Tenant's Runtime limit \`pageItems\` (default 200); a larger limit gets that many${fallback === undefined ? "" : `. Default ${fallback}, or that limit when it is lower`}`,
|
|
19
|
+
});
|
|
11
20
|
export const pageQuery = z.object({
|
|
12
|
-
limit:
|
|
21
|
+
limit: limitParam(),
|
|
13
22
|
cursor: z.string().optional(),
|
|
14
23
|
});
|
|
24
|
+
/** The size of a page of a session's calls when the query names none (within `pageItems`). */
|
|
25
|
+
const CALLS_PAGE_DEFAULT = 50;
|
|
26
|
+
/** The size of a page of the model call export when the query names none (within `exportPageItems`). */
|
|
27
|
+
const EXPORT_PAGE_DEFAULT = 200;
|
|
28
|
+
/**
|
|
29
|
+
* The size of a page: `asked`, or, when the query names none, `fallback`, each within the Tenant's
|
|
30
|
+
* Runtime limit `name` (read for each request): a page asked larger holds that many, and its
|
|
31
|
+
* cursor reads on.
|
|
32
|
+
*/
|
|
33
|
+
export async function pageSize(ctx, asked, options = {}) {
|
|
34
|
+
const name = options.name ?? "pageItems";
|
|
35
|
+
const limit = (await ctx.store.tx((t) => readRuntimeLimits(t)))[name];
|
|
36
|
+
return Math.min(asked ?? options.fallback ?? limit, limit);
|
|
37
|
+
}
|
|
15
38
|
export const sessionPageQuery = pageQuery
|
|
16
39
|
.extend({
|
|
17
40
|
agentId: z.string().optional(),
|
|
18
41
|
status: z.enum(SESSION_STATUSES).optional(),
|
|
19
|
-
|
|
42
|
+
/** Sessions that pinned a version of this agent manifest. */
|
|
43
|
+
manifest: z.string().optional(),
|
|
20
44
|
ownerUserId: z.string().optional(),
|
|
21
45
|
})
|
|
22
46
|
.strict();
|
|
@@ -30,13 +54,7 @@ export async function sessionPage(ctx, scope, query) {
|
|
|
30
54
|
return fail(400, "Pagination requires limit");
|
|
31
55
|
if (filters.ownerUserId !== undefined)
|
|
32
56
|
requireApplication(scope);
|
|
33
|
-
return readStoreOf(ctx).sessions(filters, { limit, cursor }, readAccess(scope));
|
|
34
|
-
}
|
|
35
|
-
export async function environmentPage(ctx, scope, query, labels) {
|
|
36
|
-
const { limit, cursor } = parseQuery(pageQuery.extend({ label: z.string().optional() }).strict(), query);
|
|
37
|
-
if (limit === undefined)
|
|
38
|
-
return fail(400, "Pagination requires limit");
|
|
39
|
-
return readStoreOf(ctx).environments(labels, { limit, cursor }, readAccess(scope), environmentGrantsOf(scope));
|
|
57
|
+
return readStoreOf(ctx).sessions(filters, { limit: await pageSize(ctx, limit), cursor }, readAccess(scope));
|
|
40
58
|
}
|
|
41
59
|
export function readRoutes(api) {
|
|
42
60
|
const sessionId = z.object({ sessionId: z.string() });
|
|
@@ -57,15 +75,14 @@ export function readRoutes(api) {
|
|
|
57
75
|
requirePrincipal(c.get("scope"));
|
|
58
76
|
return jsonResponse(200, await readStoreOf(c.env.tenant).manifest(c.req.param("sessionId"), readAccess(c.get("scope"))));
|
|
59
77
|
});
|
|
78
|
+
const callsQuery = turnQuery
|
|
79
|
+
.extend({
|
|
80
|
+
limit: limitParam(CALLS_PAGE_DEFAULT),
|
|
81
|
+
cursor: z.string().optional(),
|
|
82
|
+
})
|
|
83
|
+
.strict();
|
|
60
84
|
for (const kind of ["usage", "calls/model"]) {
|
|
61
|
-
const query = kind === "usage"
|
|
62
|
-
? turnQuery
|
|
63
|
-
: turnQuery
|
|
64
|
-
.extend({
|
|
65
|
-
limit: z.coerce.number().int().min(1).max(200).default(50),
|
|
66
|
-
cursor: z.string().optional(),
|
|
67
|
-
})
|
|
68
|
-
.strict();
|
|
85
|
+
const query = kind === "usage" ? turnQuery : callsQuery;
|
|
69
86
|
// Spend is the application's to show: no subject scope reaches it (`tenant:settings`,
|
|
70
87
|
// which used to, is retired in protocol 8).
|
|
71
88
|
tenantRoute(api, { credentials: ["application"], scopes: "never" }, {
|
|
@@ -93,18 +110,14 @@ export function readRoutes(api) {
|
|
|
93
110
|
const q = parseQuery(turnQuery, c.req.query());
|
|
94
111
|
return jsonResponse(200, await store.usage(id, q.turnId, access));
|
|
95
112
|
}
|
|
96
|
-
const q = parseQuery(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
cursor: z.string().optional(),
|
|
100
|
-
})
|
|
101
|
-
.strict(), c.req.query());
|
|
102
|
-
return jsonResponse(200, await store.modelCalls(id, q.turnId, q, access));
|
|
113
|
+
const q = parseQuery(callsQuery, c.req.query());
|
|
114
|
+
const limit = await pageSize(c.env.tenant, q.limit, { fallback: CALLS_PAGE_DEFAULT });
|
|
115
|
+
return jsonResponse(200, await store.modelCalls(id, q.turnId, { ...q, limit }, access));
|
|
103
116
|
});
|
|
104
117
|
}
|
|
105
118
|
const toolCallsQuery = turnQuery
|
|
106
119
|
.extend({
|
|
107
|
-
limit:
|
|
120
|
+
limit: limitParam(CALLS_PAGE_DEFAULT),
|
|
108
121
|
cursor: z.string().optional(),
|
|
109
122
|
})
|
|
110
123
|
.strict();
|
|
@@ -125,7 +138,8 @@ export function readRoutes(api) {
|
|
|
125
138
|
}, async (c) => {
|
|
126
139
|
requirePrincipal(c.get("scope"));
|
|
127
140
|
const q = parseQuery(toolCallsQuery, c.req.query());
|
|
128
|
-
|
|
141
|
+
const limit = await pageSize(c.env.tenant, q.limit, { fallback: CALLS_PAGE_DEFAULT });
|
|
142
|
+
return jsonResponse(200, await readStoreOf(c.env.tenant).toolCalls(c.req.param("sessionId"), q.turnId, { ...q, limit }, readAccess(c.get("scope"))));
|
|
129
143
|
});
|
|
130
144
|
// A turn's spans (R7.5): the same mapping the trace projector posts, from the turn's log rows,
|
|
131
145
|
// with the installation's content opt-ins. Spans carry cost: the application's, as /calls are.
|
|
@@ -153,7 +167,14 @@ export function readRoutes(api) {
|
|
|
153
167
|
const exportQuery = z
|
|
154
168
|
.object({
|
|
155
169
|
after: z.string().optional(),
|
|
156
|
-
limit: z.coerce
|
|
170
|
+
limit: z.coerce
|
|
171
|
+
.number()
|
|
172
|
+
.int()
|
|
173
|
+
.min(1)
|
|
174
|
+
.optional()
|
|
175
|
+
.meta({
|
|
176
|
+
description: `A page holds at most the Tenant's Runtime limit \`exportPageItems\` (default 1000); a larger limit gets that many. Default ${EXPORT_PAGE_DEFAULT}, or that limit when it is lower`,
|
|
177
|
+
}),
|
|
157
178
|
})
|
|
158
179
|
.strict();
|
|
159
180
|
// The whole Tenant's ledger is the Management API's (protocol 8): a management key, as itself.
|
|
@@ -171,6 +192,7 @@ export function readRoutes(api) {
|
|
|
171
192
|
},
|
|
172
193
|
}, async (c) => {
|
|
173
194
|
const q = parseQuery(exportQuery, c.req.query());
|
|
174
|
-
|
|
195
|
+
const limit = await pageSize(c.env.tenant, q.limit, { fallback: EXPORT_PAGE_DEFAULT, name: "exportPageItems" });
|
|
196
|
+
return jsonResponse(200, await readStoreOf(c.env.tenant).exportModel(q.after, limit));
|
|
175
197
|
});
|
|
176
198
|
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { RESPONSE_ALREADY_SENT } from "@hono/node-server/utils/response";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { PROTOCOL_HEADER } from "@nylorun/core/compatibility";
|
|
4
|
+
import { PutSessionRequestSchema, SessionCommandSchema, } from "@nylorun/core/contracts";
|
|
4
5
|
import { handleSessionSandboxTool, SandboxRouteError } from "../../../core/sandbox-routes.js";
|
|
5
6
|
import { traceContextOf } from "../../../traces/ids.js";
|
|
6
|
-
import { AcceptedResponse,
|
|
7
|
+
import { AcceptedResponse, QueuedResponse, ListSessionsResponse, SessionPage, HistoryPage, SessionEvent, PutSessionRequest, SandboxToolOutcome, SessionCommand, SessionItemsResponse, SessionView, StreamClosedFrame, } from "../../components.js";
|
|
7
8
|
import { accessOf, requireApplication } from "../../../tenant/auth.js";
|
|
8
9
|
import { command } from "../../../tenant/commands.js";
|
|
9
10
|
import { loadSession, sessionOf } from "../../../tenant/context.js";
|
|
10
11
|
import { fail } from "../../../tenant/http.js";
|
|
11
|
-
import {
|
|
12
|
+
import { agentGrantsOf, sandboxRouteDeps } from "../../../tenant/agents.js";
|
|
12
13
|
import { readHistory, requestCursor, streamHolderOf, streamSessionEvents } from "../../../tenant/session-streams.js";
|
|
13
|
-
import {
|
|
14
|
+
import { listSessions, putSession, sessionView } from "../../../tenant/sessions.js";
|
|
14
15
|
import { readJson } from "../body.js";
|
|
15
16
|
import { TraceHeaders, tenantRoute } from "../define.js";
|
|
16
|
-
import { pageQuery, sessionPage, sessionPageQuery, parseQuery } from "./reads.js";
|
|
17
|
+
import { pageQuery, pageSize, sessionPage, sessionPageQuery, parseQuery } from "./reads.js";
|
|
17
18
|
import { jsonResponse } from "../respond.js";
|
|
18
19
|
const OWN_SESSIONS = {
|
|
19
20
|
credentials: ["application", "subject", "token"],
|
|
@@ -46,61 +47,31 @@ async function sessionBelow(ctx, incoming, id, access) {
|
|
|
46
47
|
await loadSession(ctx, id, access);
|
|
47
48
|
return requestCursor(incoming, urlOf(incoming));
|
|
48
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* What a message to a busy session does when it says nothing (D76): a protocol 17 client's waits
|
|
52
|
+
* in the queue; a protocol 16 client's is refused, as before.
|
|
53
|
+
*/
|
|
54
|
+
function deliveryFor(headers) {
|
|
55
|
+
const protocol = Number(headers.get(PROTOCOL_HEADER)?.trim());
|
|
56
|
+
return Number.isInteger(protocol) && protocol >= 17 ? "queue" : "reject";
|
|
57
|
+
}
|
|
49
58
|
export function sessionRoutes(api) {
|
|
50
59
|
tenantRoute(api, OWN_SESSIONS, {
|
|
51
60
|
method: "post",
|
|
52
61
|
path: "/v1/sessions/{sessionId}/commands",
|
|
53
62
|
tags: ["Sessions"],
|
|
54
63
|
summary: "Send a command to a session",
|
|
55
|
-
description: "A message starts a turn; the others answer what the session waits on, or cancel. Idempotent on the command's `idempotencyKey`.",
|
|
64
|
+
description: "A message starts a turn, or waits in the session's queue while a turn runs or waits (protocol 17; `delivery: \"reject\"` is refused with `409 session_busy` instead); the others answer what the session waits on, or cancel. Idempotent on the command's `idempotencyKey`.",
|
|
56
65
|
request: { params: sessionId, body: body(SessionCommand), headers: TraceHeaders },
|
|
57
66
|
responses: {
|
|
58
|
-
200: json(AcceptedResponse, "The command, accepted"),
|
|
59
|
-
409: { description: "A turn is running, or the session does not wait on this" },
|
|
60
|
-
|
|
61
|
-
description: "A message names a file the Tenant's model does not read (`attachment_unsupported`; `details.parts` lists each with its reason). No turn starts.",
|
|
62
|
-
},
|
|
67
|
+
200: json(z.union([AcceptedResponse, QueuedResponse]), "The command, accepted; a message may be queued"),
|
|
68
|
+
409: { description: "A turn is running (`session_busy`), or the session does not wait on this" },
|
|
69
|
+
429: { description: "The session's queue is full (`queue_full`)" },
|
|
63
70
|
},
|
|
64
71
|
}, async (c) => {
|
|
65
72
|
// A `traceparent` joins the turn to the caller's trace (R7.4); a malformed one is ignored.
|
|
66
73
|
const trace = traceContextOf(c.req.raw.headers);
|
|
67
|
-
return jsonResponse(200, await command(c.env.tenant, c.req.param("sessionId"), SessionCommandSchema.parse(await readJson(c
|
|
68
|
-
});
|
|
69
|
-
tenantRoute(api, {
|
|
70
|
-
credentials: ["application", "subject", "token"],
|
|
71
|
-
scopes: ["agents:read", "agents:write"],
|
|
72
|
-
}, {
|
|
73
|
-
method: "get",
|
|
74
|
-
path: "/v1/agents",
|
|
75
|
-
tags: ["Agents"],
|
|
76
|
-
summary: "List agents",
|
|
77
|
-
description: "With an application key, every definition, manifest included. With a trusted issuer's token, only the agents it may use, by name.",
|
|
78
|
-
responses: {
|
|
79
|
-
200: json(z.union([ListAgentsResponse, ListPublicAgentsResponse]), "The agents"),
|
|
80
|
-
},
|
|
81
|
-
}, async (c) => {
|
|
82
|
-
const scope = c.get("scope");
|
|
83
|
-
const ctx = c.env.tenant;
|
|
84
|
-
return jsonResponse(200, scope.kind === "token"
|
|
85
|
-
? await listAgentsPublic(ctx, scope.agents)
|
|
86
|
-
: await listDefinitions(ctx));
|
|
87
|
-
});
|
|
88
|
-
tenantRoute(api, { credentials: ["application", "subject"], scopes: ["agents:write"] }, {
|
|
89
|
-
method: "put",
|
|
90
|
-
path: "/v1/agents/{agentId}",
|
|
91
|
-
tags: ["Agents"],
|
|
92
|
-
summary: "Put an agent's definition",
|
|
93
|
-
description: "Saves the agent's definition. With `?dryRun=true` (protocol 14) every check runs and nothing is saved: the answer says what a save would record.",
|
|
94
|
-
request: {
|
|
95
|
-
params: z.object({ agentId: z.string() }),
|
|
96
|
-
query: z.object({
|
|
97
|
-
dryRun: z.enum(["true", "false"]).optional().meta({ description: "`true`: check and save nothing" }),
|
|
98
|
-
}),
|
|
99
|
-
body: body(PutAgentRequest),
|
|
100
|
-
},
|
|
101
|
-
responses: { 200: json(PutAgentResponse, "The definition, stored (or checked, with dryRun)") },
|
|
102
|
-
}, async (c) => {
|
|
103
|
-
return jsonResponse(200, await putDefinition(c.env.tenant, c.req.param("agentId"), PutAgentRequestSchema.parse(await readJson(c.req.raw)), { dryRun: c.req.query("dryRun") === "true" }));
|
|
74
|
+
return jsonResponse(200, await command(c.env.tenant, c.req.param("sessionId"), SessionCommandSchema.parse(await readJson(c)), c.get("scope"), { ...(trace ? { trace } : {}), delivery: deliveryFor(c.req.raw.headers) }));
|
|
104
75
|
});
|
|
105
76
|
tenantRoute(api, OWN_SESSIONS, {
|
|
106
77
|
method: "get",
|
|
@@ -121,7 +92,7 @@ export function sessionRoutes(api) {
|
|
|
121
92
|
path: "/v1/sessions/{sessionId}",
|
|
122
93
|
tags: ["Sessions"],
|
|
123
94
|
summary: "Open a session",
|
|
124
|
-
description: "Creates the session, or answers the one already opened with the same
|
|
95
|
+
description: "Creates the session on an Agent, or answers the one already opened with the same Agent, owner and info. Its Agent (its sandbox and vault) is fixed for its life, and it pins the manifest version the Agent runs. No session is special: an app that keeps one conversation going reuses its id.",
|
|
125
96
|
request: { params: sessionId, body: body(PutSessionRequest) },
|
|
126
97
|
responses: {
|
|
127
98
|
200: json(SessionView, "The session"),
|
|
@@ -130,12 +101,12 @@ export function sessionRoutes(api) {
|
|
|
130
101
|
}, async (c) => {
|
|
131
102
|
const scope = c.get("scope");
|
|
132
103
|
const ctx = c.env.tenant;
|
|
133
|
-
const request = PutSessionRequestSchema.parse(await readJson(c
|
|
104
|
+
const request = PutSessionRequestSchema.parse(await readJson(c));
|
|
134
105
|
// Agent code may trust `info`: only an app server sets it.
|
|
135
106
|
if (scope.kind === "token" && request.info !== undefined)
|
|
136
107
|
fail(403, "A token caller cannot set session info", { code: "scope_required" });
|
|
137
|
-
const grants =
|
|
138
|
-
const session = await putSession(ctx, c.req.param("sessionId"), request, accessOf(scope), grants === undefined ? {} : {
|
|
108
|
+
const grants = agentGrantsOf(scope);
|
|
109
|
+
const session = await putSession(ctx, c.req.param("sessionId"), request, accessOf(scope), grants === undefined ? {} : { agentGrants: grants });
|
|
139
110
|
return jsonResponse(200, await ctx.store.tx((t) => sessionView(t, session)));
|
|
140
111
|
});
|
|
141
112
|
tenantRoute(api, OWN_SESSIONS, {
|
|
@@ -172,7 +143,8 @@ export function sessionRoutes(api) {
|
|
|
172
143
|
const ctx = c.env.tenant;
|
|
173
144
|
const id = c.req.param("sessionId");
|
|
174
145
|
const cursor = await sessionBelow(ctx, c.env.incoming, id, accessOf(scope));
|
|
175
|
-
const { limit } = parseQuery(pageQuery.pick({ limit: true }), { limit: c.req.query("limit") });
|
|
146
|
+
const { limit: asked } = parseQuery(pageQuery.pick({ limit: true }), { limit: c.req.query("limit") });
|
|
147
|
+
const limit = asked === undefined ? undefined : await pageSize(ctx, asked);
|
|
176
148
|
return jsonResponse(200, await readHistory(ctx, id, cursor, c.req.query("agent"), limit));
|
|
177
149
|
});
|
|
178
150
|
tenantRoute(api, OWN_SESSIONS, {
|
|
@@ -222,7 +194,7 @@ export function sessionRoutes(api) {
|
|
|
222
194
|
await sessionBelow(ctx, c.env.incoming, id, accessOf(scope));
|
|
223
195
|
requireApplication(scope);
|
|
224
196
|
try {
|
|
225
|
-
return jsonResponse(200, await handleSessionSandboxTool(sandboxRouteDeps(ctx), id, c.req.param("tool"), await readJson(c
|
|
197
|
+
return jsonResponse(200, await handleSessionSandboxTool(sandboxRouteDeps(ctx), id, c.req.param("tool"), await readJson(c), c.req.raw.signal));
|
|
226
198
|
}
|
|
227
199
|
catch (error) {
|
|
228
200
|
if (error instanceof SandboxRouteError)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The Tenant's own settings (`/v1/tenant/**`): its status, reset, a first configuration, the
|
|
3
|
-
* model it calls, what its model calls cost and may cost (budgets),
|
|
4
|
-
* sessions get.
|
|
3
|
+
* model it calls, what its model calls cost and may cost (budgets), the sandboxes its
|
|
4
|
+
* sessions get, and its Runtime limits.
|
|
5
5
|
*
|
|
6
6
|
* A reset that deletes sessions moves the Tenant to a new basin generation, so a session
|
|
7
7
|
* created again starts in an empty basin; the old basin is deleted after a grace period.
|