@nylorun/runtime 0.27.0-beta → 0.29.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 +67 -0
- package/README.md +1 -1
- 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 +5854 -2718
- 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/define.d.ts +4 -0
- package/dist/api/http/define.js +20 -9
- 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 +31 -12
- package/dist/api/http/routes/sessions.js +21 -50
- package/dist/api/http/routes/tenant.js +13 -10
- package/dist/api/http/routes/triggers.d.ts +10 -0
- package/dist/api/http/routes/triggers.js +183 -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 +2 -2
- package/dist/gates/meter.js +22 -5
- package/dist/gates/policy.d.ts +8 -3
- package/dist/gates/policy.js +7 -2
- package/dist/gates/tenant-vaults.d.ts +1 -1
- 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/config-for.d.ts +2 -0
- package/dist/host/config-for.js +1 -0
- package/dist/host/http.d.ts +2 -2
- package/dist/host/http.js +5 -2
- package/dist/host/main.js +1 -0
- 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 +313 -133
- package/dist/mcp/connect.d.ts +2 -2
- package/dist/mcp/connect.js +3 -3
- 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/model/pi-model.js +7 -0
- package/dist/openapi.json +13120 -9034
- 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/0037_model_usage_cost_split.sql +4 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +42 -0
- package/dist/store/postgres/reads.js +44 -87
- 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 +1408 -123
- package/dist/store/postgres/schema.js +194 -38
- 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/types.d.ts +5 -0
- 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
package/dist/reads/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ArtifactKind, ArtifactPage, ModelCallExportPage, ModelCallsPage,
|
|
1
|
+
import type { ArtifactKind, ArtifactPage, ModelCallExportPage, ModelCallsPage, ToolCallsPage, SessionManifestView, SessionPage, SessionListItem, SessionUsageTotals, LiveEvent } from "@nylorun/core/contracts";
|
|
2
2
|
export type ReadAccess = {
|
|
3
3
|
owner?: string;
|
|
4
4
|
agents?: readonly string[];
|
|
@@ -6,7 +6,8 @@ export type ReadAccess = {
|
|
|
6
6
|
export type SessionFilters = {
|
|
7
7
|
agentId?: string;
|
|
8
8
|
status?: SessionListItem["status"];
|
|
9
|
-
|
|
9
|
+
/** Sessions that pinned a version of this agent manifest. */
|
|
10
|
+
manifest?: string;
|
|
10
11
|
ownerUserId?: string;
|
|
11
12
|
};
|
|
12
13
|
export type PageOptions = {
|
|
@@ -33,6 +34,5 @@ export interface ReadStore {
|
|
|
33
34
|
* for a turn the session never had.
|
|
34
35
|
*/
|
|
35
36
|
turnEvents(id: string, turnId: string, access: ReadAccess): Promise<LiveEvent[]>;
|
|
36
|
-
environments(labels: Record<string, string>, page: PageOptions, access: ReadAccess, grants?: readonly string[]): Promise<EnvironmentPage>;
|
|
37
37
|
close(): Promise<void>;
|
|
38
38
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type AgentEvent, type AgentEventPayload, type AgentEventType } from "@nylorun/core/contracts";
|
|
2
|
+
/** The Agent stream's two statements, in the caller's transaction. */
|
|
3
|
+
export interface AgentRecordWriter {
|
|
4
|
+
/** The seq the Agent's next event takes: one past its last, or 0. */
|
|
5
|
+
nextSeq(agentId: string): Promise<number>;
|
|
6
|
+
insert(row: {
|
|
7
|
+
agentId: string;
|
|
8
|
+
seq: number;
|
|
9
|
+
type: string;
|
|
10
|
+
body: AgentEvent;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export interface AgentAppendInput<T extends AgentEventType> {
|
|
14
|
+
tenantId: string;
|
|
15
|
+
agentId: string;
|
|
16
|
+
time: Date;
|
|
17
|
+
type: T;
|
|
18
|
+
payload: AgentEventPayload<T>;
|
|
19
|
+
/** The Tenant's Runtime limit `recordEntryBytes`, as for a session's events. */
|
|
20
|
+
maxEntryBytes: number;
|
|
21
|
+
}
|
|
22
|
+
/** Builds the event and checks it against the Agent event catalog. */
|
|
23
|
+
export declare function buildAgentEvent<T extends AgentEventType>(input: AgentAppendInput<T> & {
|
|
24
|
+
seq: number;
|
|
25
|
+
}): AgentEvent;
|
|
26
|
+
/** Appends one event to the Agent's stream through `writer`. */
|
|
27
|
+
export declare function appendAgentEvent<T extends AgentEventType>(writer: AgentRecordWriter, input: AgentAppendInput<T>): Promise<AgentEvent>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An Agent's lifecycle stream (blueprint D39, F7.1; an Environment's before protocol 16):
|
|
3
|
+
* `agent.created`, `agent.attached`, `agent.detached` and `agent.deleted` (and the rest of
|
|
4
|
+
* `AGENT_EVENT_TYPES`, egress-gate's `agent.egress` for every connection among them, D67), on
|
|
5
|
+
* the `nylorun.agent-event/1` envelope, numbered from 0 per Agent id in
|
|
6
|
+
* `nylorun_streams.agent_events`. The record module is its only writer, as for session events;
|
|
7
|
+
* the store runs the two statements through `AgentRecordWriter` in the caller's transaction, under
|
|
8
|
+
* the Agent row's lock (or, for an Agent being created, its new row).
|
|
9
|
+
*
|
|
10
|
+
* The stream lives in the record only: it is not published to the stream relay, so no S2 stream
|
|
11
|
+
* follows it yet. Clients read it with `GET /v1/agents/{id}/events`.
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { AGENT_EVENT_PAYLOADS, AGENT_EVENT_SCHEMA, AgentEventSchema, } from "@nylorun/core/contracts";
|
|
16
|
+
import { InvalidEventError } from "./envelope.js";
|
|
17
|
+
import { checkEntry } from "./append.js";
|
|
18
|
+
/** Builds the event and checks it against the Agent event catalog. */
|
|
19
|
+
export function buildAgentEvent(input) {
|
|
20
|
+
const payload = AGENT_EVENT_PAYLOADS[input.type];
|
|
21
|
+
const checkedPayload = payload.safeParse(input.payload);
|
|
22
|
+
if (!checkedPayload.success)
|
|
23
|
+
throw new InvalidEventError(input.type, z.prettifyError(checkedPayload.error));
|
|
24
|
+
const event = JSON.parse(JSON.stringify({
|
|
25
|
+
schema: AGENT_EVENT_SCHEMA,
|
|
26
|
+
eventId: randomUUID(),
|
|
27
|
+
tenantId: input.tenantId,
|
|
28
|
+
agentId: input.agentId,
|
|
29
|
+
seq: input.seq,
|
|
30
|
+
time: input.time.toISOString(),
|
|
31
|
+
type: input.type,
|
|
32
|
+
payload: input.payload,
|
|
33
|
+
}));
|
|
34
|
+
const checked = AgentEventSchema.safeParse(event);
|
|
35
|
+
if (!checked.success)
|
|
36
|
+
throw new InvalidEventError(input.type, z.prettifyError(checked.error));
|
|
37
|
+
return event;
|
|
38
|
+
}
|
|
39
|
+
/** Appends one event to the Agent's stream through `writer`. */
|
|
40
|
+
export async function appendAgentEvent(writer, input) {
|
|
41
|
+
checkEntry(`The ${input.type} event's payload`, input.payload, input.maxEntryBytes);
|
|
42
|
+
const seq = await writer.nextSeq(input.agentId);
|
|
43
|
+
const event = buildAgentEvent({ ...input, seq });
|
|
44
|
+
await writer.insert({ agentId: input.agentId, seq, type: input.type, body: event });
|
|
45
|
+
return event;
|
|
46
|
+
}
|
package/dist/record/index.d.ts
CHANGED
|
@@ -9,4 +9,4 @@
|
|
|
9
9
|
export { buildEvent, InvalidEventError, type EventInput } from "./envelope.js";
|
|
10
10
|
export { decodeCursor, encodeCursor } from "./cursor.js";
|
|
11
11
|
export { RecordEntryTooLargeError, appendEvent, checkEntry, entryBytes, type AppendInput, type RecordWriter, } from "./append.js";
|
|
12
|
-
export {
|
|
12
|
+
export { appendAgentEvent, buildAgentEvent, type AgentAppendInput, type AgentRecordWriter, } from "./agent.js";
|
package/dist/record/index.js
CHANGED
|
@@ -9,4 +9,4 @@
|
|
|
9
9
|
export { buildEvent, InvalidEventError } from "./envelope.js";
|
|
10
10
|
export { decodeCursor, encodeCursor } from "./cursor.js";
|
|
11
11
|
export { RecordEntryTooLargeError, appendEvent, checkEntry, entryBytes, } from "./append.js";
|
|
12
|
-
export {
|
|
12
|
+
export { appendAgentEvent, buildAgentEvent, } from "./agent.js";
|
package/dist/sandbox/join.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* which check failed.
|
|
33
33
|
*/
|
|
34
34
|
import { createHash, timingSafeEqual } from "node:crypto";
|
|
35
|
-
import {
|
|
35
|
+
import { isAgentId } from "@nylorun/core/contracts";
|
|
36
36
|
import { recoverLostVolume, runPendingSeed } from "../artifacts/disk.js";
|
|
37
37
|
import { recordSetup, setupFile, setupPlanOf, setupState, } from "./setup.js";
|
|
38
38
|
import { mintHostTokens, staleHost, verifyHostToken, } from "../tenant/host-token.js";
|
|
@@ -87,7 +87,7 @@ export function hostAuthority(ctx) {
|
|
|
87
87
|
return {
|
|
88
88
|
async join(request) {
|
|
89
89
|
const { sandboxId, podUid, joinToken, volumeId } = request;
|
|
90
|
-
if (!
|
|
90
|
+
if (!isAgentId(sandboxId) ||
|
|
91
91
|
typeof podUid !== "string" ||
|
|
92
92
|
!POD_UID.test(podUid) ||
|
|
93
93
|
typeof joinToken !== "string" ||
|
|
@@ -136,7 +136,7 @@ export function hostAuthority(ctx) {
|
|
|
136
136
|
// A new, empty volume under the same Sandbox: the sandbox's files are gone.
|
|
137
137
|
const reason = "The sandbox's volume was replaced: its files are gone";
|
|
138
138
|
await t.updateEnvironmentPod(sandboxId, { observed: "lost", reason, hostEpoch: epoch }, now);
|
|
139
|
-
await t.
|
|
139
|
+
await t.agentEvent(sandboxId, "agent.lost", { reason });
|
|
140
140
|
// Its Sandbox is deleted; only a reset brings the sandbox back.
|
|
141
141
|
await t.signal({ type: "host.revoked", sandboxId, epoch });
|
|
142
142
|
await t.signalSandbox(sandboxId, { kind: "reconcile" });
|
|
@@ -150,9 +150,9 @@ export function hostAuthority(ctx) {
|
|
|
150
150
|
}, now);
|
|
151
151
|
if (pod.podUid !== podUid) {
|
|
152
152
|
if (pod.podUid !== undefined)
|
|
153
|
-
await t.
|
|
153
|
+
await t.agentEvent(sandboxId, "agent.relaunched", { hostEpoch: epoch });
|
|
154
154
|
else
|
|
155
|
-
await t.
|
|
155
|
+
await t.agentEvent(sandboxId, "agent.running", { hostEpoch: epoch });
|
|
156
156
|
}
|
|
157
157
|
// The previous host's connection (an older epoch) serves nothing more, on any process.
|
|
158
158
|
await t.signal({ type: "host.revoked", sandboxId, epoch });
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* A session on a pod Environment runs on `sandbox`; every other session (a virtual or `none`
|
|
9
9
|
* Environment, or none) on `harness-container` (D52). A host the Tenant does not allow is
|
|
10
10
|
* `409 placement_refused`. A pod Environment needs sandbox pods: without a cluster (`nylorun
|
|
11
|
-
* sandbox enable`), or with the sandboxes service not ready, it is `409
|
|
11
|
+
* sandbox enable`), or with the sandboxes service not ready, it is `409 agent_unavailable`.
|
|
12
12
|
*/
|
|
13
13
|
import { type EnvironmentKind, type PlacementHost as SandboxPlacementHost } from "@nylorun/core/contracts";
|
|
14
14
|
import type { TenantSandboxConfig } from "./tenant-config.js";
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* A session on a pod Environment runs on `sandbox`; every other session (a virtual or `none`
|
|
9
9
|
* Environment, or none) on `harness-container` (D52). A host the Tenant does not allow is
|
|
10
10
|
* `409 placement_refused`. A pod Environment needs sandbox pods: without a cluster (`nylorun
|
|
11
|
-
* sandbox enable`), or with the sandboxes service not ready, it is `409
|
|
11
|
+
* sandbox enable`), or with the sandboxes service not ready, it is `409 agent_unavailable`.
|
|
12
12
|
*/
|
|
13
13
|
import { DEFAULT_HARNESS, } from "@nylorun/core/contracts";
|
|
14
14
|
import { fail, failRetryLater } from "../tenant/http.js";
|
|
@@ -50,9 +50,9 @@ export async function podsReady(pods) {
|
|
|
50
50
|
export async function requirePods(pods, what) {
|
|
51
51
|
if (!pods)
|
|
52
52
|
return fail(409, `${what} needs sandbox pods, and this Runtime has no cluster: ${ENABLE_PODS}.`, {
|
|
53
|
-
code: "
|
|
53
|
+
code: "agent_unavailable",
|
|
54
54
|
});
|
|
55
55
|
if (!(await podsReady(pods)))
|
|
56
|
-
failRetryLater(`${what} needs sandbox pods, and the sandboxes service is not ready. Check \`nylorun local sandbox status\`.`, "
|
|
56
|
+
failRetryLater(`${what} needs sandbox pods, and the sandboxes service is not ready. Check \`nylorun local sandbox status\`.`, "agent_unavailable");
|
|
57
57
|
return pods;
|
|
58
58
|
}
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
* <name>.r<rev>`, so a repeated apply is a no-op at the service, and a Sandbox whose `opId`
|
|
14
14
|
* is not the row's is applied again.
|
|
15
15
|
* - **Idle** (`trigger: idle`): no turn on a session that names it, and none ended within its
|
|
16
|
-
* `lifecycle.idle` (at most the Tenant's `limits.idle`) → `Suspended` (`
|
|
16
|
+
* `lifecycle.idle` (at most the Tenant's `limits.idle`) → `Suspended` (`agent.suspended`,
|
|
17
17
|
* reason `idle`). The volume is kept; the next turn start asks for `Running` again.
|
|
18
18
|
* - **Lost**: an incarnation that has run (a pod joined) whose Sandbox is gone or whose volume
|
|
19
|
-
* is missing is `lost` (`
|
|
19
|
+
* is missing is `lost` (`agent.lost`): its host epoch moves, its Sandbox is deleted, and
|
|
20
20
|
* only a reset brings the Environment back. agent-sandbox recreates a deleted claim empty, so
|
|
21
21
|
* the engine's join also checks the id it keeps on the volume (`join.ts`): a new volume is
|
|
22
22
|
* lost too. A pod replaced on the same volume is not lost: the new pod's join bumps the epoch
|
|
23
|
-
* (`
|
|
23
|
+
* (`agent.relaunched`).
|
|
24
24
|
* - **Delete** (`desired: deleted`): the Sandbox is deleted, and the row once it is gone.
|
|
25
25
|
* - **Reset** (`tenant/environments.ts`) bumps the volume generation: a new name, so a new
|
|
26
26
|
* Sandbox and volume; the old name is `retiring` and deleted here.
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
*
|
|
36
36
|
* An unused Environment is deleted by the Tenant sweep (`lifecycle.deleteAfter`), not here.
|
|
37
37
|
*/
|
|
38
|
-
import type {
|
|
38
|
+
import type { AgentEventPayload, AgentEventType } from "@nylorun/core/contracts";
|
|
39
39
|
import type { Environment, SandboxPodPatch, SandboxPodState } from "../../store/types.js";
|
|
40
40
|
import type { PodStatus } from "./client.js";
|
|
41
41
|
/**
|
|
@@ -79,9 +79,9 @@ export interface PodFacts {
|
|
|
79
79
|
readonly now: number;
|
|
80
80
|
readonly trigger: PodTrigger;
|
|
81
81
|
}
|
|
82
|
-
export interface PodEvent<T extends
|
|
82
|
+
export interface PodEvent<T extends AgentEventType = AgentEventType> {
|
|
83
83
|
readonly type: T;
|
|
84
|
-
readonly payload:
|
|
84
|
+
readonly payload: AgentEventPayload<T>;
|
|
85
85
|
}
|
|
86
86
|
export interface PodDecision {
|
|
87
87
|
/** Apply the row's spec (after `patch`) in this mode; `rotateJoin` mints a new join token. */
|
|
@@ -113,7 +113,7 @@ export function decide(facts) {
|
|
|
113
113
|
patch.desired = desired;
|
|
114
114
|
patch.rev = rev;
|
|
115
115
|
patch.hostEpoch = pod.hostEpoch + 1;
|
|
116
|
-
events.push(event("
|
|
116
|
+
events.push(event("agent.suspended", { reason: "idle" }));
|
|
117
117
|
}
|
|
118
118
|
else
|
|
119
119
|
arm.push({ timer: "idle", at: due });
|
|
@@ -121,14 +121,14 @@ export function decide(facts) {
|
|
|
121
121
|
// An incarnation a pod has joined, whose Sandbox or volume is gone: lost.
|
|
122
122
|
if (pod.podUid !== undefined && (!status.exists || status.deleting || status.volume === "missing")) {
|
|
123
123
|
const reason = !status.exists
|
|
124
|
-
? "The
|
|
124
|
+
? "The Agent's pod and volume were deleted outside the Runtime"
|
|
125
125
|
: status.deleting
|
|
126
|
-
? "The
|
|
127
|
-
: "The
|
|
126
|
+
? "The Agent's pod is being deleted outside the Runtime"
|
|
127
|
+
: "The Agent's volume is gone";
|
|
128
128
|
patch.observed = "lost";
|
|
129
129
|
patch.reason = reason;
|
|
130
130
|
patch.hostEpoch = (patch.hostEpoch ?? pod.hostEpoch) + 1;
|
|
131
|
-
events.push(event("
|
|
131
|
+
events.push(event("agent.lost", { reason }));
|
|
132
132
|
if (status.exists && !status.deleting)
|
|
133
133
|
deletes.push(pod.k8sName);
|
|
134
134
|
if (status.exists)
|
|
@@ -184,7 +184,7 @@ export function decide(facts) {
|
|
|
184
184
|
`The pod was not ready within ${Math.round(readyDeadlineMs / 1000)} s`;
|
|
185
185
|
patch.observed = "failed";
|
|
186
186
|
patch.reason = reason;
|
|
187
|
-
events.push(event("
|
|
187
|
+
events.push(event("agent.failed", { reason }));
|
|
188
188
|
return done();
|
|
189
189
|
}
|
|
190
190
|
if (pod.observed !== "creating")
|
|
@@ -23,6 +23,7 @@ import { recoverLostVolume } from "../../artifacts/disk.js";
|
|
|
23
23
|
import { decide } from "./lifecycle.js";
|
|
24
24
|
import { podLifecycleConfig, podSpecOf } from "./spec.js";
|
|
25
25
|
import { hostTuning } from "../../tuning.js";
|
|
26
|
+
import { idleMsOf, revertStart } from "../../tenant/agent-versions.js";
|
|
26
27
|
export async function reconcileSandbox(ctx, sandboxId, trigger) {
|
|
27
28
|
const pods = ctx.pods;
|
|
28
29
|
if (!pods || ctx.closed)
|
|
@@ -51,7 +52,8 @@ export async function reconcileSandbox(ctx, sandboxId, trigger) {
|
|
|
51
52
|
return undefined;
|
|
52
53
|
}
|
|
53
54
|
};
|
|
54
|
-
|
|
55
|
+
// While a start would apply a new version (track T3), it idles at most `tenant.upgradeIdleMs`.
|
|
56
|
+
const lifecycle = { ...podLifecycleConfig(config, row.recipe), idleMs: idleMsOf(config, row) };
|
|
55
57
|
const decision = decide({
|
|
56
58
|
row,
|
|
57
59
|
image: row.applied.image ?? DEFAULT_SANDBOX_IMAGE,
|
|
@@ -140,9 +142,15 @@ export async function reconcileSandbox(ctx, sandboxId, trigger) {
|
|
|
140
142
|
if (Object.keys(finalPatch).length > 0)
|
|
141
143
|
await t.updateEnvironmentPod(sandboxId, finalPatch, new Date().toISOString());
|
|
142
144
|
for (const item of decision.events)
|
|
143
|
-
await t.
|
|
145
|
+
await t.agentEvent(sandboxId, item.type, item.payload);
|
|
144
146
|
if (epochMoved)
|
|
145
147
|
await t.signal({ type: "host.revoked", sandboxId, epoch: finalPatch.hostEpoch });
|
|
148
|
+
// A pod that failed to start on a new version goes back to the version it ran (track T3).
|
|
149
|
+
if (finalPatch.observed === "failed" && current.startCheck) {
|
|
150
|
+
const failed = (await t.environment(sandboxId, { lock: true }));
|
|
151
|
+
await revertStart(t, failed, finalPatch.reason ?? "The pod failed", new Date().toISOString());
|
|
152
|
+
return { kind: "changed" };
|
|
153
|
+
}
|
|
146
154
|
return { kind: "written" };
|
|
147
155
|
});
|
|
148
156
|
if (written.kind === "changed")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Resolves an
|
|
2
|
+
* Resolves an Agent's recipe (`PUT /v1/agents/{id}`) against its Tenant's limits,
|
|
3
3
|
* and the sandbox spec a recipe gives a session (`Session.sandbox`) and the pod. Pure: the
|
|
4
4
|
* caller supplies the configuration. Every problem is reported, not only the first, so one
|
|
5
5
|
* response lists all of them.
|
|
@@ -38,11 +38,11 @@ export type RecipeResolution = {
|
|
|
38
38
|
readonly kind: "error";
|
|
39
39
|
readonly errors: readonly string[];
|
|
40
40
|
};
|
|
41
|
-
/** The recipe `request` asks for an
|
|
41
|
+
/** The recipe `request` asks for an Agent of `kind`, or every reason it cannot have it. */
|
|
42
42
|
export declare function resolveRecipe(kind: EnvironmentKind, request: RecipeRequest, config: EffectiveSandboxConfig): RecipeResolution;
|
|
43
43
|
/**
|
|
44
44
|
* The sandbox spec of a recipe: what a session pins when it opens and the virtual
|
|
45
|
-
* workspace runs. Idle is the
|
|
45
|
+
* workspace runs. Idle is the Agent's `lifecycle.idle`, else the Tenant's.
|
|
46
46
|
*/
|
|
47
47
|
export declare function sandboxSpecOf(recipe: EnvironmentRecipe, tenantIdle: string): SandboxManifest;
|
|
48
48
|
/** The pod's spec of a recipe: its sandbox spec and its volume's size. */
|
package/dist/sandbox/resolve.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_HARNESS } from "@nylorun/core/contracts";
|
|
2
2
|
import { parseSandboxDuration } from "@nylorun/core/define";
|
|
3
3
|
import { memoryMiB } from "./tenant-config.js";
|
|
4
|
-
/** The recipe `request` asks for an
|
|
4
|
+
/** The recipe `request` asks for an Agent of `kind`, or every reason it cannot have it. */
|
|
5
5
|
export function resolveRecipe(kind, request, config) {
|
|
6
6
|
const { limits } = config;
|
|
7
7
|
const errors = [];
|
|
@@ -9,7 +9,7 @@ export function resolveRecipe(kind, request, config) {
|
|
|
9
9
|
// Any harness id (R4.1): placement decides where it may run, when a session opens.
|
|
10
10
|
const harness = request.harness ?? DEFAULT_HARNESS;
|
|
11
11
|
if (pod && harness !== DEFAULT_HARNESS && request.image === undefined)
|
|
12
|
-
errors.push(`harness ${harness} needs image: a pod
|
|
12
|
+
errors.push(`harness ${harness} needs image: a pod Agent runs its image as the harness.`);
|
|
13
13
|
const lifecycle = request.lifecycle ?? {};
|
|
14
14
|
const idle = lifecycle.idle === undefined ? undefined : parseSandboxDuration(lifecycle.idle);
|
|
15
15
|
if (idle !== undefined && idle > (parseSandboxDuration(limits.idle) ?? Infinity))
|
|
@@ -17,7 +17,7 @@ export function resolveRecipe(kind, request, config) {
|
|
|
17
17
|
if (kind === "none") {
|
|
18
18
|
for (const field of ["image", "resources", "storage", "network", "setup", "files"])
|
|
19
19
|
if (request[field] !== undefined)
|
|
20
|
-
errors.push(`${field} is for an
|
|
20
|
+
errors.push(`${field} is for an Agent with a sandbox: kind none has none.`);
|
|
21
21
|
if (errors.length > 0)
|
|
22
22
|
return { kind: "error", errors };
|
|
23
23
|
return {
|
|
@@ -26,9 +26,9 @@ export function resolveRecipe(kind, request, config) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
if (request.image !== undefined && !pod)
|
|
29
|
-
errors.push("image is for kind pod: a virtual
|
|
29
|
+
errors.push("image is for kind pod: a virtual Agent runs no images.");
|
|
30
30
|
if (request.storage !== undefined && !pod)
|
|
31
|
-
errors.push("storage is for kind pod: a virtual
|
|
31
|
+
errors.push("storage is for kind pod: a virtual Agent has no volume.");
|
|
32
32
|
for (const field of ["setup", "files"])
|
|
33
33
|
if (request[field] !== undefined && request[field].length > 0 && !pod)
|
|
34
34
|
errors.push(`${field} is for kind pod: it runs when a pod's disk is made or reset.`);
|
|
@@ -37,7 +37,7 @@ export function resolveRecipe(kind, request, config) {
|
|
|
37
37
|
if (!withinCeiling(host, limits.network))
|
|
38
38
|
errors.push(`network.allowedHosts includes ${host}, which this Tenant does not allow.`);
|
|
39
39
|
else if (host.startsWith("*.") && !pod)
|
|
40
|
-
errors.push(`network.allowedHosts includes ${host}; a virtual
|
|
40
|
+
errors.push(`network.allowedHosts includes ${host}; a virtual Agent allows exact host names only, such as ${host.slice(2)}.`);
|
|
41
41
|
}
|
|
42
42
|
const cpus = request.resources?.cpus ?? limits.defaultResources.cpus;
|
|
43
43
|
const memory = request.resources?.memory === undefined
|
|
@@ -79,7 +79,7 @@ function slotsOf(request) {
|
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* The sandbox spec of a recipe: what a session pins when it opens and the virtual
|
|
82
|
-
* workspace runs. Idle is the
|
|
82
|
+
* workspace runs. Idle is the Agent's `lifecycle.idle`, else the Tenant's.
|
|
83
83
|
*/
|
|
84
84
|
export function sandboxSpecOf(recipe, tenantIdle) {
|
|
85
85
|
const allow = recipe.network?.allowedHosts ?? [];
|
package/dist/sandbox/setup.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export { SETUP_FAILED };
|
|
|
6
6
|
export interface SetupPlan {
|
|
7
7
|
/** The applied recipe's version: written into the volume's marker. */
|
|
8
8
|
readonly recipeVersion: number;
|
|
9
|
+
/** The sha256 of the commands and files: a marker with another runs the setup again (T3). */
|
|
10
|
+
readonly setupHash: string;
|
|
9
11
|
readonly commands: readonly {
|
|
10
12
|
readonly command: string;
|
|
11
13
|
readonly cwd: string;
|
|
@@ -33,7 +35,7 @@ export interface SetupReport {
|
|
|
33
35
|
export declare function parseSetupReport(value: unknown): SetupReport | undefined;
|
|
34
36
|
/**
|
|
35
37
|
* Records a failed setup on Environment `id` held at host epoch `epoch` (the reporting engine's):
|
|
36
|
-
* the pod is `failed` with a reason that starts `setup:`, and `
|
|
38
|
+
* the pod is `failed` with a reason that starts `setup:`, and `agent.failed` says which
|
|
37
39
|
* command failed and how, with the end of its output (the Tenant's `setupOutputChars`; the reason
|
|
38
40
|
* quotes `setupReasonChars` of it and `setupCommandExcerptChars` of the command). A report
|
|
39
41
|
* from an older host, or a success, changes nothing.
|
package/dist/sandbox/setup.js
CHANGED
|
@@ -10,19 +10,26 @@
|
|
|
10
10
|
* a pod reads the artifact versions and the definition files by hash (Q6) its own recipe names,
|
|
11
11
|
* and nothing else of the Object store.
|
|
12
12
|
*
|
|
13
|
+
* The plan's `setupHash` names its commands and files: the engine runs the setup again on a volume
|
|
14
|
+
* whose marker names another (a new version's setup, track T3).
|
|
15
|
+
*
|
|
13
16
|
* A failed command fails the pod (`observed: failed`, a reason that starts `setup:`, and
|
|
14
|
-
* `
|
|
17
|
+
* `agent.failed` with the command, its exit code and the end of its output), or, on a start on
|
|
18
|
+
* a new version, takes the Agent back to the version it ran (`revertStart`, T3): the turn that
|
|
15
19
|
* waits for it fails with that reason (`podUnusable`, `tenant/advance.ts`), the failure stays
|
|
16
20
|
* until a turn start asks the pod to run again (`wantRunning`), and the engine, polling, runs the
|
|
17
21
|
* setup again then.
|
|
18
22
|
*/
|
|
19
23
|
import { ENVIRONMENT_SETUP_TIMEOUT_DEFAULT, } from "@nylorun/core/contracts";
|
|
24
|
+
import { createHash } from "node:crypto";
|
|
20
25
|
import { parseSandboxDuration } from "@nylorun/core/define";
|
|
26
|
+
import { canonical } from "../store/canonical.js";
|
|
21
27
|
import { contentKey, readManifest } from "../artifacts/folders.js";
|
|
22
28
|
import { contentTypeFor } from "@nylorun/core/contracts";
|
|
23
29
|
import { definitionFileKey } from "../tenant/definition-files.js";
|
|
24
30
|
import { SETUP_FAILED } from "./pods/lifecycle.js";
|
|
25
31
|
import { readRuntimeLimits } from "../tenant/runtime-limits.js";
|
|
32
|
+
import { revertStart } from "../tenant/agent-versions.js";
|
|
26
33
|
export { SETUP_FAILED };
|
|
27
34
|
/** The setup of `recipe`, or undefined when it has neither commands nor files. */
|
|
28
35
|
export async function setupPlanOf(ctx, t, environment) {
|
|
@@ -34,6 +41,7 @@ export async function setupPlanOf(ctx, t, environment) {
|
|
|
34
41
|
const timeoutOf = (timeout) => Math.min(parseSandboxDuration(timeout ?? ENVIRONMENT_SETUP_TIMEOUT_DEFAULT), setupCommandMs);
|
|
35
42
|
return {
|
|
36
43
|
recipeVersion: environment.appliedVersion,
|
|
44
|
+
setupHash: createHash("sha256").update(canonical({ setup: recipe.setup ?? [], files: recipe.files ?? [] })).digest("hex"),
|
|
37
45
|
commands: (recipe.setup ?? []).map((command) => ({
|
|
38
46
|
command: command.command,
|
|
39
47
|
cwd: command.cwd ?? "/workspace",
|
|
@@ -61,7 +69,7 @@ export function parseSetupReport(value) {
|
|
|
61
69
|
}
|
|
62
70
|
/**
|
|
63
71
|
* Records a failed setup on Environment `id` held at host epoch `epoch` (the reporting engine's):
|
|
64
|
-
* the pod is `failed` with a reason that starts `setup:`, and `
|
|
72
|
+
* the pod is `failed` with a reason that starts `setup:`, and `agent.failed` says which
|
|
65
73
|
* command failed and how, with the end of its output (the Tenant's `setupOutputChars`; the reason
|
|
66
74
|
* quotes `setupReasonChars` of it and `setupCommandExcerptChars` of the command). A report
|
|
67
75
|
* from an older host, or a success, changes nothing.
|
|
@@ -84,8 +92,7 @@ export async function recordSetup(ctx, id, epoch, report) {
|
|
|
84
92
|
const what = command === undefined ? "copying the input files failed" : `command ${report.index + 1} (${command.command.slice(0, setupCommandExcerptChars)}) exited ${report.exitCode ?? "abnormally"}`;
|
|
85
93
|
const tail = output.trim().slice(-setupReasonChars);
|
|
86
94
|
const reason = `${SETUP_FAILED} ${what}${tail ? `: ${tail}` : ""}`;
|
|
87
|
-
await t.
|
|
88
|
-
await t.environmentEvent(id, "environment.failed", {
|
|
95
|
+
await t.agentEvent(id, "agent.failed", {
|
|
89
96
|
reason,
|
|
90
97
|
setup: {
|
|
91
98
|
...(report.index === undefined ? {} : { index: report.index }),
|
|
@@ -93,6 +100,9 @@ export async function recordSetup(ctx, id, epoch, report) {
|
|
|
93
100
|
output,
|
|
94
101
|
},
|
|
95
102
|
});
|
|
103
|
+
// On a start on a new version (track T3), back to the version it ran; else failed.
|
|
104
|
+
if (!(await revertStart(t, environment, reason, new Date().toISOString())))
|
|
105
|
+
await t.updateEnvironmentPod(id, { observed: "failed", reason }, new Date().toISOString());
|
|
96
106
|
});
|
|
97
107
|
if (report.status === "failed")
|
|
98
108
|
ctx.config.logger.warn("environment setup failed", { environmentId: id, index: report.index, exitCode: report.exitCode });
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
-- Protocol 16: Agents from one manifest (track T2), a fresh start. Agent definitions and
|
|
2
|
+
-- environment manifests cannot become agent manifests (v8) on their own: a definition has no
|
|
3
|
+
-- runtime section, and an Environment held sessions of many agents. So both go, and so do the
|
|
4
|
+
-- Environments with their pods, disks and vaults, as protocol 11 dropped sandboxes and vaults.
|
|
5
|
+
-- Every open session is closed (`protocol_16`): its history stays readable. `environments` is
|
|
6
|
+
-- renamed `agents` (made from a saved agent manifest only) and its lifecycle stream
|
|
7
|
+
-- `agent_events`; model budget scope `agent` is `manifest`, keyed by the manifest's name, so a
|
|
8
|
+
-- budget keeps its meaning, and the usage ledger names the manifest.
|
|
9
|
+
UPDATE "nylorun"."sessions" SET "body" = ("body"::jsonb || '{"closedReason":"protocol_16"}'::jsonb)::json
|
|
10
|
+
WHERE nylorun.doc("body") ->> 'closedReason' IS NULL;--> statement-breakpoint
|
|
11
|
+
DELETE FROM "nylorun"."vaults" WHERE "id" <> 'host';--> statement-breakpoint
|
|
12
|
+
DELETE FROM "nylorun"."vault_idempotency" WHERE "id" NOT LIKE 'host-model%';--> statement-breakpoint
|
|
13
|
+
DELETE FROM "nylorun"."sandboxes";--> statement-breakpoint
|
|
14
|
+
DELETE FROM "nylorun"."sandbox_signals";--> statement-breakpoint
|
|
15
|
+
DELETE FROM "nylorun"."artifacts" WHERE "environment_id" IS NOT NULL;--> statement-breakpoint
|
|
16
|
+
DELETE FROM "nylorun"."environments";--> statement-breakpoint
|
|
17
|
+
DELETE FROM "nylorun"."definition_file_uses";--> statement-breakpoint
|
|
18
|
+
DROP TABLE "nylorun"."definitions";--> statement-breakpoint
|
|
19
|
+
DROP TABLE "nylorun"."environment_manifests";--> statement-breakpoint
|
|
20
|
+
DROP TABLE "nylorun_streams"."environment_events";--> statement-breakpoint
|
|
21
|
+
CREATE TABLE "nylorun_streams"."agent_events" (
|
|
22
|
+
"agent_id" text COLLATE "C" NOT NULL,
|
|
23
|
+
"seq" bigint NOT NULL,
|
|
24
|
+
"type" text NOT NULL,
|
|
25
|
+
"body" json NOT NULL,
|
|
26
|
+
"committed_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
27
|
+
CONSTRAINT "agent_events_pkey" PRIMARY KEY("agent_id","seq")
|
|
28
|
+
);
|
|
29
|
+
--> statement-breakpoint
|
|
30
|
+
CREATE TABLE "nylorun"."agent_manifests" (
|
|
31
|
+
"name" text COLLATE "C" NOT NULL,
|
|
32
|
+
"version" integer NOT NULL,
|
|
33
|
+
"body" json NOT NULL,
|
|
34
|
+
"hash" text COLLATE "C" NOT NULL,
|
|
35
|
+
"saved_by" json NOT NULL,
|
|
36
|
+
"created_at" text COLLATE "C" NOT NULL,
|
|
37
|
+
CONSTRAINT "agent_manifests_pkey" PRIMARY KEY("name","version")
|
|
38
|
+
);
|
|
39
|
+
--> statement-breakpoint
|
|
40
|
+
ALTER TABLE "nylorun"."environments" RENAME TO "agents";--> statement-breakpoint
|
|
41
|
+
ALTER TABLE "nylorun"."agents" RENAME CONSTRAINT "environments_pkey" TO "agents_pkey";--> statement-breakpoint
|
|
42
|
+
ALTER TABLE "nylorun"."agents" DROP CONSTRAINT "environments_kind_check";--> statement-breakpoint
|
|
43
|
+
ALTER TABLE "nylorun"."agents" ADD CONSTRAINT "agents_kind_check" CHECK ("nylorun"."agents"."kind" IN ('virtual', 'pod', 'none'));--> statement-breakpoint
|
|
44
|
+
ALTER INDEX "nylorun"."environments_manifest" RENAME TO "agents_manifest";--> statement-breakpoint
|
|
45
|
+
ALTER TABLE "nylorun"."agents" ALTER COLUMN "manifest_name" SET NOT NULL;--> statement-breakpoint
|
|
46
|
+
ALTER TABLE "nylorun"."agents" ALTER COLUMN "manifest_version" SET NOT NULL;--> statement-breakpoint
|
|
47
|
+
ALTER TABLE "nylorun"."agents" ALTER COLUMN "manifest_hash" SET NOT NULL;--> statement-breakpoint
|
|
48
|
+
ALTER TABLE "nylorun"."agents" ADD COLUMN "manifest_ref" text NOT NULL;--> statement-breakpoint
|
|
49
|
+
ALTER TABLE "nylorun"."agents" ADD COLUMN "desired_state" text DEFAULT 'on' NOT NULL;--> statement-breakpoint
|
|
50
|
+
ALTER TABLE "nylorun"."model_usage" RENAME COLUMN "agent_id" TO "manifest_name";--> statement-breakpoint
|
|
51
|
+
ALTER INDEX "nylorun"."model_usage_agent" RENAME TO "model_usage_manifest";--> statement-breakpoint
|
|
52
|
+
UPDATE "nylorun"."model_budgets" SET "scope" = 'manifest' WHERE "scope" = 'agent';--> statement-breakpoint
|
|
53
|
+
ALTER TABLE "nylorun"."sessions" ADD COLUMN "manifest_name" text GENERATED ALWAYS AS (nylorun.doc(body)->'definition'->>'name') STORED;--> statement-breakpoint
|
|
54
|
+
CREATE INDEX "sessions_manifest" ON "nylorun"."sessions" USING btree ("manifest_name");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
-- Track T3, Agents that evolve (D73): an Agent moves between versions of its manifest. While it
|
|
2
|
+
-- is outdated it names the version it moves to (`target_version`); a version that failed to start
|
|
3
|
+
-- is kept so a tracking Agent does not move to it again (`failed_version`); and while a pod starts
|
|
4
|
+
-- on a new version, what it ran before (`start_check`), which a failed start reverts to.
|
|
5
|
+
ALTER TABLE "nylorun"."agents" ADD COLUMN "target_version" integer;--> statement-breakpoint
|
|
6
|
+
ALTER TABLE "nylorun"."agents" ADD COLUMN "failed_version" integer;--> statement-breakpoint
|
|
7
|
+
ALTER TABLE "nylorun"."agents" ADD COLUMN "start_check" json;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
CREATE TABLE "nylorun"."session_queue" (
|
|
2
|
+
"id" text COLLATE "C" PRIMARY KEY NOT NULL,
|
|
3
|
+
"session_id" text COLLATE "C" NOT NULL,
|
|
4
|
+
"seq" bigint NOT NULL,
|
|
5
|
+
"command" json NOT NULL,
|
|
6
|
+
"input" json NOT NULL,
|
|
7
|
+
"file_artifacts" json NOT NULL,
|
|
8
|
+
"writer" json NOT NULL,
|
|
9
|
+
"trace" json,
|
|
10
|
+
"created_at" text COLLATE "C" NOT NULL
|
|
11
|
+
);
|
|
12
|
+
--> statement-breakpoint
|
|
13
|
+
CREATE UNIQUE INDEX "session_queue_order" ON "nylorun"."session_queue" USING btree ("session_id","seq");
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
CREATE TABLE "nylorun"."agent_triggers" (
|
|
2
|
+
"agent_id" text COLLATE "C" NOT NULL,
|
|
3
|
+
"trigger_id" text COLLATE "C" NOT NULL,
|
|
4
|
+
"kind" text NOT NULL,
|
|
5
|
+
"status" text NOT NULL,
|
|
6
|
+
"paused_reason" text,
|
|
7
|
+
"generation" integer DEFAULT 0 NOT NULL,
|
|
8
|
+
"next_fire_at" text COLLATE "C",
|
|
9
|
+
"last_fire_at" text COLLATE "C",
|
|
10
|
+
"endpoint_id" text COLLATE "C",
|
|
11
|
+
"sealed_secret" json,
|
|
12
|
+
"session_id" text COLLATE "C",
|
|
13
|
+
"note" text,
|
|
14
|
+
"effect_id" text,
|
|
15
|
+
"created_at" text COLLATE "C" NOT NULL,
|
|
16
|
+
"updated_at" text COLLATE "C" NOT NULL,
|
|
17
|
+
CONSTRAINT "agent_triggers_pkey" PRIMARY KEY("agent_id","trigger_id")
|
|
18
|
+
);
|
|
19
|
+
--> statement-breakpoint
|
|
20
|
+
CREATE TABLE "nylorun"."trigger_runs" (
|
|
21
|
+
"id" text COLLATE "C" PRIMARY KEY NOT NULL,
|
|
22
|
+
"agent_id" text COLLATE "C" NOT NULL,
|
|
23
|
+
"trigger_id" text COLLATE "C" NOT NULL,
|
|
24
|
+
"kind" text NOT NULL,
|
|
25
|
+
"run_key" text COLLATE "C" NOT NULL,
|
|
26
|
+
"due_at" text COLLATE "C" NOT NULL,
|
|
27
|
+
"fired_at" text COLLATE "C" NOT NULL,
|
|
28
|
+
"late" boolean DEFAULT false NOT NULL,
|
|
29
|
+
"status" text NOT NULL,
|
|
30
|
+
"reason" text,
|
|
31
|
+
"session_id" text COLLATE "C",
|
|
32
|
+
"turn_id" text COLLATE "C",
|
|
33
|
+
"queued_message_id" text COLLATE "C"
|
|
34
|
+
);
|
|
35
|
+
--> statement-breakpoint
|
|
36
|
+
ALTER TABLE "nylorun"."session_queue" ADD COLUMN "cause" json;--> statement-breakpoint
|
|
37
|
+
CREATE INDEX "agent_triggers_due" ON "nylorun"."agent_triggers" USING btree ("status","next_fire_at");--> statement-breakpoint
|
|
38
|
+
CREATE UNIQUE INDEX "agent_triggers_endpoint" ON "nylorun"."agent_triggers" USING btree ("endpoint_id") WHERE endpoint_id IS NOT NULL;--> statement-breakpoint
|
|
39
|
+
CREATE UNIQUE INDEX "trigger_runs_key" ON "nylorun"."trigger_runs" USING btree ("agent_id","run_key");--> statement-breakpoint
|
|
40
|
+
CREATE INDEX "trigger_runs_agent" ON "nylorun"."trigger_runs" USING btree ("agent_id","id");--> statement-breakpoint
|
|
41
|
+
CREATE INDEX "trigger_runs_fired" ON "nylorun"."trigger_runs" USING btree ("fired_at");
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
CREATE TABLE "nylorun"."memories" (
|
|
2
|
+
"agent_id" text COLLATE "C" NOT NULL,
|
|
3
|
+
"path" text COLLATE "C" NOT NULL,
|
|
4
|
+
"content" text NOT NULL,
|
|
5
|
+
"content_sha256" text NOT NULL,
|
|
6
|
+
"bytes" integer NOT NULL,
|
|
7
|
+
"description" text,
|
|
8
|
+
"version" integer NOT NULL,
|
|
9
|
+
"updated_at" text COLLATE "C" NOT NULL,
|
|
10
|
+
CONSTRAINT "memories_pkey" PRIMARY KEY("agent_id","path")
|
|
11
|
+
);
|
|
12
|
+
--> statement-breakpoint
|
|
13
|
+
CREATE TABLE "nylorun"."memory_versions" (
|
|
14
|
+
"id" text COLLATE "C" PRIMARY KEY NOT NULL,
|
|
15
|
+
"agent_id" text COLLATE "C" NOT NULL,
|
|
16
|
+
"path" text COLLATE "C" NOT NULL,
|
|
17
|
+
"from_path" text COLLATE "C",
|
|
18
|
+
"operation" text NOT NULL,
|
|
19
|
+
"content" text,
|
|
20
|
+
"content_sha256" text,
|
|
21
|
+
"bytes" integer,
|
|
22
|
+
"actor" text NOT NULL,
|
|
23
|
+
"session_id" text COLLATE "C",
|
|
24
|
+
"turn_id" text COLLATE "C",
|
|
25
|
+
"trigger_run_id" text COLLATE "C",
|
|
26
|
+
"created_at" text COLLATE "C" NOT NULL
|
|
27
|
+
);
|
|
28
|
+
--> statement-breakpoint
|
|
29
|
+
CREATE INDEX "memory_versions_agent" ON "nylorun"."memory_versions" USING btree ("agent_id","id");--> statement-breakpoint
|
|
30
|
+
CREATE INDEX "memory_versions_path" ON "nylorun"."memory_versions" USING btree ("agent_id","path","id");
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
ALTER TABLE "nylorun"."model_usage" ADD COLUMN "cost_input_usd" double precision;--> statement-breakpoint
|
|
2
|
+
ALTER TABLE "nylorun"."model_usage" ADD COLUMN "cost_cache_read_usd" double precision;--> statement-breakpoint
|
|
3
|
+
ALTER TABLE "nylorun"."model_usage" ADD COLUMN "cost_cache_write_usd" double precision;--> statement-breakpoint
|
|
4
|
+
ALTER TABLE "nylorun"."model_usage" ADD COLUMN "cost_output_usd" double precision;
|