@nylorun/runtime 0.27.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 +41 -0
- package/dist/api/a2a/card.d.ts +4 -3
- package/dist/api/a2a/card.js +3 -3
- package/dist/api/a2a/routes.js +18 -7
- package/dist/api/ag-ui/routes.js +4 -7
- package/dist/api/components.d.ts +5823 -2720
- package/dist/api/components.js +39 -30
- package/dist/api/http/app.js +9 -4
- package/dist/api/http/body.d.ts +2 -0
- package/dist/api/http/body.js +20 -0
- 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 +2 -2
- package/dist/api/http/routes/coverage.d.ts +4 -4
- package/dist/api/http/routes/coverage.js +12 -6
- package/dist/api/http/routes/files.js +1 -1
- package/dist/api/http/routes/mcp.js +2 -2
- 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 +1 -137
- package/dist/api/http/routes/reads.js +2 -8
- package/dist/api/http/routes/sessions.js +21 -50
- package/dist/api/http/routes/tenant.js +8 -8
- package/dist/api/http/routes/triggers.d.ts +10 -0
- package/dist/api/http/routes/triggers.js +180 -0
- package/dist/api/openapi.js +69 -47
- package/dist/artifacts/disk.d.ts +10 -10
- package/dist/artifacts/disk.js +27 -27
- package/dist/artifacts/quota.d.ts +1 -1
- package/dist/artifacts/quota.js +2 -2
- package/dist/artifacts/service.js +2 -2
- package/dist/core/flow-host.d.ts +0 -1
- package/dist/gates/egress-credentials.js +1 -1
- package/dist/gates/egress.d.ts +5 -5
- package/dist/gates/egress.js +6 -6
- package/dist/gates/http-tool.js +1 -1
- package/dist/gates/meter.js +6 -5
- package/dist/gates/policy.d.ts +8 -3
- package/dist/gates/policy.js +7 -2
- package/dist/harness/pod.d.ts +2 -0
- package/dist/harness/setup.js +17 -6
- package/dist/harness-api/record.js +11 -0
- package/dist/harness-api/server.js +4 -0
- package/dist/harness-api/start.d.ts +11 -7
- package/dist/harness-api/start.js +49 -5
- package/dist/harness-api/workspace.js +2 -2
- package/dist/host/http.d.ts +2 -2
- package/dist/host/http.js +5 -2
- package/dist/keys/keys.d.ts +15 -4
- package/dist/keys/keys.js +16 -0
- package/dist/keys/webhooks.d.ts +25 -0
- package/dist/keys/webhooks.js +62 -0
- package/dist/management-openapi.json +245 -123
- package/dist/mcp/preview.js +7 -7
- 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/openapi.json +12837 -8790
- 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/index.d.ts +1 -1
- package/dist/record/index.js +1 -1
- package/dist/sandbox/join.js +5 -5
- package/dist/sandbox/placement.d.ts +1 -1
- package/dist/sandbox/placement.js +3 -3
- package/dist/sandbox/pods/lifecycle.d.ts +6 -6
- package/dist/sandbox/pods/lifecycle.js +6 -6
- package/dist/sandbox/pods/reconcile.js +10 -2
- package/dist/sandbox/resolve.d.ts +3 -3
- package/dist/sandbox/resolve.js +7 -7
- package/dist/sandbox/setup.d.ts +3 -1
- package/dist/sandbox/setup.js +14 -4
- 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 +35 -0
- package/dist/store/postgres/reads.js +13 -86
- 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 +1373 -161
- package/dist/store/postgres/schema.js +184 -37
- package/dist/store/postgres/store.js +329 -79
- package/dist/store/postgres/tenant.js +1 -2
- package/dist/store/types.d.ts +155 -50
- package/dist/store/types.js +0 -1
- package/dist/tenant/advance.js +20 -8
- 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} +464 -320
- 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 -83
- package/dist/tenant/context.d.ts +46 -19
- package/dist/tenant/context.js +6 -2
- package/dist/tenant/effects.js +7 -16
- package/dist/tenant/identity-file.d.ts +6 -6
- package/dist/tenant/identity-file.js +12 -10
- package/dist/tenant/issuers.js +3 -3
- package/dist/tenant/limits.d.ts +0 -3
- package/dist/tenant/limits.js +0 -3
- package/dist/tenant/memories.d.ts +38 -0
- package/dist/tenant/memories.js +119 -0
- package/dist/tenant/reset.js +2 -2
- package/dist/tenant/run-grants.d.ts +6 -0
- package/dist/tenant/run-grants.js +4 -0
- package/dist/tenant/runtime.d.ts +1 -1
- package/dist/tenant/runtime.js +8 -0
- package/dist/tenant/sessions.d.ts +28 -45
- package/dist/tenant/sessions.js +85 -208
- package/dist/tenant/status.js +6 -7
- package/dist/tenant/sweep.js +12 -3
- package/dist/tenant/transcript.d.ts +16 -16
- 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/worker.d.ts +2 -0
- package/dist/tenant/worker.js +5 -0
- package/dist/traces/map.d.ts +1 -1
- package/dist/traces/map.js +7 -1
- package/dist/tuning.d.ts +7 -0
- package/dist/tuning.js +19 -0
- 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/record/environment.d.ts +0 -27
- package/dist/record/environment.js +0 -46
- package/dist/tenant/environment-manifests.d.ts +0 -57
- package/dist/tenant/environment-manifests.js +0 -208
- package/dist/tenant/environments.d.ts +0 -172
|
@@ -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
|
+
}
|
|
@@ -30,7 +30,7 @@ export declare const sessionPageQuery: z.ZodObject<{
|
|
|
30
30
|
uncertain: "uncertain";
|
|
31
31
|
waiting: "waiting";
|
|
32
32
|
}>>;
|
|
33
|
-
|
|
33
|
+
manifest: z.ZodOptional<z.ZodString>;
|
|
34
34
|
ownerUserId: z.ZodOptional<z.ZodString>;
|
|
35
35
|
}, z.core.$strict>;
|
|
36
36
|
export declare function parseQuery<T>(schema: z.ZodType<T>, query: unknown): T;
|
|
@@ -42,145 +42,9 @@ export declare function sessionPage(ctx: TenantEnv["Bindings"]["tenant"], scope:
|
|
|
42
42
|
status: "cancelled" | "completed" | "failed" | "idle" | "paused" | "runnable" | "running" | "uncertain" | "waiting";
|
|
43
43
|
activeTurnId: string | null;
|
|
44
44
|
lastTurnId: string | null;
|
|
45
|
-
environmentId: string | null;
|
|
46
45
|
createdAt: string | null;
|
|
47
46
|
lastEventAt: string | null;
|
|
48
47
|
}[];
|
|
49
48
|
nextCursor: string | null;
|
|
50
49
|
}>;
|
|
51
|
-
export declare function environmentPage(ctx: TenantEnv["Bindings"]["tenant"], scope: TenantEnv["Variables"]["scope"], query: Record<string, string>, labels: Record<string, string>): Promise<{
|
|
52
|
-
environments: {
|
|
53
|
-
id: string;
|
|
54
|
-
kind: "none" | "pod" | "virtual";
|
|
55
|
-
labels: Record<string, string>;
|
|
56
|
-
manifest: {
|
|
57
|
-
image?: string | undefined;
|
|
58
|
-
resources?: {
|
|
59
|
-
cpus: number;
|
|
60
|
-
memory: string;
|
|
61
|
-
} | undefined;
|
|
62
|
-
storage?: string | undefined;
|
|
63
|
-
network?: {
|
|
64
|
-
allowedHosts: string[];
|
|
65
|
-
} | undefined;
|
|
66
|
-
harness: string;
|
|
67
|
-
lifecycle: {
|
|
68
|
-
idle?: string | undefined;
|
|
69
|
-
deleteAfter?: string | undefined;
|
|
70
|
-
};
|
|
71
|
-
setup?: {
|
|
72
|
-
command: string;
|
|
73
|
-
cwd?: string | undefined;
|
|
74
|
-
timeout?: string | undefined;
|
|
75
|
-
}[] | undefined;
|
|
76
|
-
files?: ({
|
|
77
|
-
artifactId: string;
|
|
78
|
-
version: number;
|
|
79
|
-
path: string;
|
|
80
|
-
} | {
|
|
81
|
-
path: string;
|
|
82
|
-
files: Record<string, string>;
|
|
83
|
-
})[] | undefined;
|
|
84
|
-
limits?: {
|
|
85
|
-
artifacts?: {
|
|
86
|
-
fileBytes?: number | undefined;
|
|
87
|
-
totalBytes?: number | undefined;
|
|
88
|
-
} | undefined;
|
|
89
|
-
skills?: {
|
|
90
|
-
totalBytes?: number | undefined;
|
|
91
|
-
} | undefined;
|
|
92
|
-
disk?: {
|
|
93
|
-
versionBytes?: number | undefined;
|
|
94
|
-
versionEntries?: number | undefined;
|
|
95
|
-
} | undefined;
|
|
96
|
-
} | undefined;
|
|
97
|
-
secrets?: Record<string, {
|
|
98
|
-
required?: boolean | undefined;
|
|
99
|
-
description?: string | undefined;
|
|
100
|
-
type: "environment_secret";
|
|
101
|
-
allowedHosts: string[];
|
|
102
|
-
inject?: {
|
|
103
|
-
header: string;
|
|
104
|
-
format: string;
|
|
105
|
-
} | undefined;
|
|
106
|
-
} | {
|
|
107
|
-
required?: boolean | undefined;
|
|
108
|
-
description?: string | undefined;
|
|
109
|
-
type: "environment_variable";
|
|
110
|
-
} | {
|
|
111
|
-
via?: string | undefined;
|
|
112
|
-
identity?: {
|
|
113
|
-
header: string;
|
|
114
|
-
} | undefined;
|
|
115
|
-
required?: boolean | undefined;
|
|
116
|
-
description?: string | undefined;
|
|
117
|
-
type: "bearer";
|
|
118
|
-
url: string;
|
|
119
|
-
} | {
|
|
120
|
-
via?: string | undefined;
|
|
121
|
-
identity?: {
|
|
122
|
-
header: string;
|
|
123
|
-
} | undefined;
|
|
124
|
-
required?: boolean | undefined;
|
|
125
|
-
description?: string | undefined;
|
|
126
|
-
type: "headers";
|
|
127
|
-
url: string;
|
|
128
|
-
}> | undefined;
|
|
129
|
-
};
|
|
130
|
-
manifestName?: string | undefined;
|
|
131
|
-
manifestVersion?: number | undefined;
|
|
132
|
-
manifestHash?: string | undefined;
|
|
133
|
-
limits: {
|
|
134
|
-
artifacts: {
|
|
135
|
-
fileBytes: number;
|
|
136
|
-
totalBytes: number;
|
|
137
|
-
};
|
|
138
|
-
skills: {
|
|
139
|
-
totalBytes: number;
|
|
140
|
-
};
|
|
141
|
-
disk: {
|
|
142
|
-
versionBytes: number;
|
|
143
|
-
versionEntries: number;
|
|
144
|
-
};
|
|
145
|
-
};
|
|
146
|
-
forkedFrom?: {
|
|
147
|
-
environment: string;
|
|
148
|
-
disk: number | null;
|
|
149
|
-
} | undefined;
|
|
150
|
-
slots?: {
|
|
151
|
-
name: string;
|
|
152
|
-
type: string;
|
|
153
|
-
required: boolean;
|
|
154
|
-
set: boolean;
|
|
155
|
-
}[] | undefined;
|
|
156
|
-
version: number;
|
|
157
|
-
appliedVersion: number;
|
|
158
|
-
ownerUserId: string | null;
|
|
159
|
-
state: string;
|
|
160
|
-
pod?: {
|
|
161
|
-
desired: "deleted" | "running" | "suspended";
|
|
162
|
-
observed: "creating" | "deleting" | "failed" | "lost" | "running" | "suspended";
|
|
163
|
-
volumeGeneration: number;
|
|
164
|
-
hostEpoch: number;
|
|
165
|
-
reason?: string | undefined;
|
|
166
|
-
imageDigest?: string | undefined;
|
|
167
|
-
} | undefined;
|
|
168
|
-
lastUsedAt: string;
|
|
169
|
-
disk?: {
|
|
170
|
-
latestVersion: number | null;
|
|
171
|
-
operation?: {
|
|
172
|
-
kind: "restore" | "seed" | "snapshot";
|
|
173
|
-
version?: number | undefined;
|
|
174
|
-
startedAt: string;
|
|
175
|
-
} | undefined;
|
|
176
|
-
} | undefined;
|
|
177
|
-
sessions: {
|
|
178
|
-
id: string;
|
|
179
|
-
activeTurnId: string | null;
|
|
180
|
-
}[];
|
|
181
|
-
createdAt: string;
|
|
182
|
-
updatedAt: string;
|
|
183
|
-
}[];
|
|
184
|
-
nextCursor: string | null;
|
|
185
|
-
}>;
|
|
186
50
|
export declare function readRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
@@ -6,7 +6,6 @@ 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
8
|
import { readRuntimeLimits } from "../../../tenant/runtime-limits.js";
|
|
9
|
-
import { environmentGrantsOf } from "../../../tenant/environments.js";
|
|
10
9
|
import { tenantRoute } from "../define.js";
|
|
11
10
|
import { jsonResponse } from "../respond.js";
|
|
12
11
|
/** A page's `limit`, held to the Tenant's Runtime limit `pageItems` (`pageSize`). */
|
|
@@ -40,7 +39,8 @@ export const sessionPageQuery = pageQuery
|
|
|
40
39
|
.extend({
|
|
41
40
|
agentId: z.string().optional(),
|
|
42
41
|
status: z.enum(SESSION_STATUSES).optional(),
|
|
43
|
-
|
|
42
|
+
/** Sessions that pinned a version of this agent manifest. */
|
|
43
|
+
manifest: z.string().optional(),
|
|
44
44
|
ownerUserId: z.string().optional(),
|
|
45
45
|
})
|
|
46
46
|
.strict();
|
|
@@ -56,12 +56,6 @@ export async function sessionPage(ctx, scope, query) {
|
|
|
56
56
|
requireApplication(scope);
|
|
57
57
|
return readStoreOf(ctx).sessions(filters, { limit: await pageSize(ctx, limit), cursor }, readAccess(scope));
|
|
58
58
|
}
|
|
59
|
-
export async function environmentPage(ctx, scope, query, labels) {
|
|
60
|
-
const { limit, cursor } = parseQuery(pageQuery.extend({ label: z.string().optional() }).strict(), query);
|
|
61
|
-
if (limit === undefined)
|
|
62
|
-
return fail(400, "Pagination requires limit");
|
|
63
|
-
return readStoreOf(ctx).environments(labels, { limit: await pageSize(ctx, limit), cursor }, readAccess(scope), environmentGrantsOf(scope));
|
|
64
|
-
}
|
|
65
59
|
export function readRoutes(api) {
|
|
66
60
|
const sessionId = z.object({ sessionId: z.string() });
|
|
67
61
|
const turnQuery = z.object({ turnId: z.string().optional() }).strict();
|
|
@@ -1,16 +1,17 @@
|
|
|
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
17
|
import { pageQuery, pageSize, sessionPage, sessionPageQuery, parseQuery } from "./reads.js";
|
|
@@ -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" },
|
|
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`)" },
|
|
60
70
|
},
|
|
61
71
|
}, async (c) => {
|
|
62
72
|
// A `traceparent` joins the turn to the caller's trace (R7.4); a malformed one is ignored.
|
|
63
73
|
const trace = traceContextOf(c.req.raw.headers);
|
|
64
|
-
return jsonResponse(200, await command(c.env.tenant, c.req.param("sessionId"), SessionCommandSchema.parse(await readJson(c)), c.get("scope"), trace ? { trace } : {}));
|
|
65
|
-
});
|
|
66
|
-
tenantRoute(api, {
|
|
67
|
-
credentials: ["application", "subject", "token"],
|
|
68
|
-
scopes: ["agents:read", "agents:write"],
|
|
69
|
-
}, {
|
|
70
|
-
method: "get",
|
|
71
|
-
path: "/v1/agents",
|
|
72
|
-
tags: ["Agents"],
|
|
73
|
-
summary: "List agents",
|
|
74
|
-
description: "With an application key, every definition, manifest included. With a trusted issuer's token, only the agents it may use, by name.",
|
|
75
|
-
responses: {
|
|
76
|
-
200: json(z.union([ListAgentsResponse, ListPublicAgentsResponse]), "The agents"),
|
|
77
|
-
},
|
|
78
|
-
}, async (c) => {
|
|
79
|
-
const scope = c.get("scope");
|
|
80
|
-
const ctx = c.env.tenant;
|
|
81
|
-
return jsonResponse(200, scope.kind === "token"
|
|
82
|
-
? await listAgentsPublic(ctx, scope.agents)
|
|
83
|
-
: await listDefinitions(ctx));
|
|
84
|
-
});
|
|
85
|
-
tenantRoute(api, { credentials: ["application", "subject"], scopes: ["agents:write"] }, {
|
|
86
|
-
method: "put",
|
|
87
|
-
path: "/v1/agents/{agentId}",
|
|
88
|
-
tags: ["Agents"],
|
|
89
|
-
summary: "Put an agent's definition",
|
|
90
|
-
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.",
|
|
91
|
-
request: {
|
|
92
|
-
params: z.object({ agentId: z.string() }),
|
|
93
|
-
query: z.object({
|
|
94
|
-
dryRun: z.enum(["true", "false"]).optional().meta({ description: "`true`: check and save nothing" }),
|
|
95
|
-
}),
|
|
96
|
-
body: body(PutAgentRequest),
|
|
97
|
-
},
|
|
98
|
-
responses: {
|
|
99
|
-
200: json(PutAgentResponse, "The definition, stored (or checked, with dryRun)"),
|
|
100
|
-
413: { description: "A skill's files hold more than the Tenant's skill limit together (`limit_exceeded`)" },
|
|
101
|
-
},
|
|
102
|
-
}, async (c) => {
|
|
103
|
-
return jsonResponse(200, await putDefinition(c.env.tenant, c.req.param("agentId"), PutAgentRequestSchema.parse(await readJson(c)), { 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"),
|
|
@@ -134,8 +105,8 @@ export function sessionRoutes(api) {
|
|
|
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, {
|
|
@@ -18,7 +18,7 @@ import { tenantReset, streamsStatus, } from "../../../tenant/streams.js";
|
|
|
18
18
|
import { readJson } from "../body.js";
|
|
19
19
|
import { pathSegments, tenantRoute } from "../define.js";
|
|
20
20
|
import { jsonResponse } from "../respond.js";
|
|
21
|
-
import { rearmPodTimers } from "../../../tenant/
|
|
21
|
+
import { rearmPodTimers } from "../../../tenant/agents.js";
|
|
22
22
|
import { hostTuning } from "../../../tuning.js";
|
|
23
23
|
import { budgetIssues, toolPolicyIssues } from "../../../tenant/limits.js";
|
|
24
24
|
/** Every Management API route (`/v1/tenant/*`): a management key, acting as itself (protocol 8). */
|
|
@@ -37,7 +37,7 @@ const body = (schema) => ({
|
|
|
37
37
|
});
|
|
38
38
|
const budgetRow = (budget, updatedAt) => ({
|
|
39
39
|
scope: budget.scope,
|
|
40
|
-
scopeId: budget.scope === "
|
|
40
|
+
scopeId: budget.scope === "manifest" ? budget.id : "*",
|
|
41
41
|
period: budget.period ?? null,
|
|
42
42
|
limitUsd: budget.limitUsd ?? null,
|
|
43
43
|
limitTokens: budget.limitTokens ?? null,
|
|
@@ -45,7 +45,7 @@ const budgetRow = (budget, updatedAt) => ({
|
|
|
45
45
|
});
|
|
46
46
|
const budgetView = (row) => ({
|
|
47
47
|
scope: row.scope,
|
|
48
|
-
...(row.scope === "
|
|
48
|
+
...(row.scope === "manifest" ? { id: row.scopeId } : {}),
|
|
49
49
|
...(row.period ? { period: row.period } : {}),
|
|
50
50
|
...(row.limitUsd !== null ? { limitUsd: row.limitUsd } : {}),
|
|
51
51
|
...(row.limitTokens !== null ? { limitTokens: row.limitTokens } : {}),
|
|
@@ -114,7 +114,7 @@ export function tenantRoutes(api) {
|
|
|
114
114
|
path: "/v1/tenant/reset",
|
|
115
115
|
tags: ["Tenant"],
|
|
116
116
|
summary: "Reset the Tenant",
|
|
117
|
-
description: "Deletes its sessions, its
|
|
117
|
+
description: "Deletes its sessions, its Agents (with their vaults), or both, after draining or cancelling the turns in progress. The Tenant stays open.",
|
|
118
118
|
request: { body: body(ResetTenantRequest) },
|
|
119
119
|
responses: { 200: json(ResetTenantResponse, "Reset") },
|
|
120
120
|
}, async (c) => {
|
|
@@ -123,7 +123,7 @@ export function tenantRoutes(api) {
|
|
|
123
123
|
await drain(ctx, request.activeWork, hostTuning().tenant.drainTimeoutMs);
|
|
124
124
|
// A sessions reset moves the Tenant to a new basin generation, so a session created
|
|
125
125
|
// again with the same id, during or after the reset, starts in an empty basin at 0.
|
|
126
|
-
const sessionsReset = request.scope !== "
|
|
126
|
+
const sessionsReset = request.scope !== "agents";
|
|
127
127
|
await resetTenant({
|
|
128
128
|
store: ctx.store,
|
|
129
129
|
sandbox: ctx.sandbox,
|
|
@@ -221,15 +221,15 @@ export function tenantRoutes(api) {
|
|
|
221
221
|
method: "get",
|
|
222
222
|
path: "/v1/tenant/sandbox",
|
|
223
223
|
tags: ["Tenant"],
|
|
224
|
-
summary: "Get the Tenant's sandbox backend and
|
|
224
|
+
summary: "Get the Tenant's sandbox backend and Agent compute settings",
|
|
225
225
|
responses: { 200: json(TenantSandboxView, "The backend in use and the configuration in force") },
|
|
226
226
|
}, async (c) => jsonResponse(200, await sandboxView(c.env.tenant)));
|
|
227
227
|
tenantRoute(api, MANAGEMENT, {
|
|
228
228
|
method: "put",
|
|
229
229
|
path: "/v1/tenant/sandbox",
|
|
230
230
|
tags: ["Tenant"],
|
|
231
|
-
summary: "Set the Tenant's
|
|
232
|
-
description: "The limits every
|
|
231
|
+
summary: "Set the Tenant's Agent compute settings",
|
|
232
|
+
description: "The limits every Agent's runtime must fit, the pods' stop grace and where harnesses may run (Tenant setting `environments.config`).",
|
|
233
233
|
request: { body: body(PutTenantEnvironmentsRequest) },
|
|
234
234
|
responses: { 200: json(TenantSandboxView, "The configuration now in force") },
|
|
235
235
|
}, async (c) => {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An Agent's triggers and their runs (track T4, D74): read them, pause and resume one, run one now
|
|
3
|
+
* (keyed by `Idempotency-Key`), and page the runs; make a webhook trigger's signing secret, and
|
|
4
|
+
* take a sender's delivery at its endpoint (D75), an anonymous, unversioned route. What a trigger is lives in the Agent's manifest
|
|
5
|
+
* (`runtime.triggers`); these routes change only what the Agent owns, its status.
|
|
6
|
+
*/
|
|
7
|
+
import type { OpenAPIHono } from "@hono/zod-openapi";
|
|
8
|
+
import type { TenantEnv } from "../app.js";
|
|
9
|
+
export declare function triggerRoutes(api: OpenAPIHono<TenantEnv>): void;
|
|
10
|
+
export declare function webhookRoutes(api: OpenAPIHono<TenantEnv>): void;
|