@nylorun/runtime 0.17.0-beta → 0.19.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 +149 -0
- package/README.md +88 -58
- package/dist/adapters/execution/restate.d.ts +1 -3
- package/dist/adapters/execution/restate.js +4 -31
- package/dist/adapters/replication/pgoutput.js +1 -1
- package/dist/adapters/sandbox/local.js +1 -1
- package/dist/adapters/sandbox/virtual.js +1 -1
- package/dist/api/ag-ui/routes.js +1 -1
- package/dist/api/ag-ui/translate.d.ts +1 -3
- package/dist/api/ag-ui/translate.js +2 -17
- package/dist/api/components.d.ts +4871 -2614
- package/dist/api/components.js +12 -11
- package/dist/api/gate/routes.d.ts +7 -8
- package/dist/api/gate/routes.js +58 -52
- package/dist/api/http/app.d.ts +6 -0
- package/dist/api/http/app.js +18 -14
- package/dist/api/http/define.d.ts +14 -2
- package/dist/api/http/define.js +34 -15
- package/dist/api/http/routes/access.d.ts +3 -3
- package/dist/api/http/routes/access.js +18 -17
- package/dist/api/http/routes/artifacts.js +2 -4
- package/dist/api/http/routes/files.d.ts +8 -0
- package/dist/api/http/routes/files.js +77 -0
- package/dist/api/http/routes/keys.d.ts +10 -0
- package/dist/api/http/routes/keys.js +64 -0
- package/dist/api/http/routes/me.js +5 -2
- package/dist/api/http/routes/reads.d.ts +66 -0
- package/dist/api/http/routes/reads.js +127 -0
- package/dist/api/http/routes/sandboxes.js +7 -4
- package/dist/api/http/routes/sessions.js +25 -8
- package/dist/api/http/routes/tenant.js +15 -18
- package/dist/api/http/routes/vaults.d.ts +10 -9
- package/dist/api/http/routes/vaults.js +27 -23
- package/dist/api/openapi.d.ts +10 -11
- package/dist/api/openapi.js +291 -61
- package/dist/artifacts/links.js +1 -1
- package/dist/core/flow-host.d.ts +44 -23
- package/dist/core/flow-host.js +88 -106
- package/dist/core/provider.d.ts +4 -1
- package/dist/core/provider.js +6 -1
- package/dist/core/sandbox-routes.d.ts +0 -9
- package/dist/core/sandbox-routes.js +2 -21
- package/dist/execution/memory.d.ts +4 -5
- package/dist/execution/memory.js +11 -25
- package/dist/execution/types.d.ts +3 -33
- package/dist/execution/types.js +2 -12
- package/dist/gates/http-tool.d.ts +86 -0
- package/dist/gates/http-tool.js +197 -0
- package/dist/gates/mcp-handler.d.ts +3 -0
- package/dist/gates/mcp-handler.js +1 -3
- package/dist/gates/meter.d.ts +2 -2
- package/dist/gates/meter.js +6 -0
- package/dist/gates/tenant-vaults.d.ts +5 -9
- package/dist/gates/tool-calls.d.ts +7 -15
- package/dist/gates/tool-calls.js +4 -4
- package/dist/gates/tool-client.d.ts +1 -1
- package/dist/gates/tool-client.js +23 -47
- package/dist/gates/tool-contract.d.ts +27 -39
- package/dist/gates/tool-contract.js +30 -21
- package/dist/gates/tool-gate.d.ts +25 -24
- package/dist/gates/tool-gate.js +11 -7
- package/dist/harness/calls.d.ts +10 -4
- package/dist/harness/calls.js +15 -6
- package/dist/harness/executors.d.ts +1 -1
- package/dist/harness/executors.js +17 -12
- package/dist/harness/main.d.ts +2 -2
- package/dist/harness/main.js +5 -13
- package/dist/harness/service.d.ts +4 -5
- package/dist/harness/service.js +9 -2
- package/dist/harness-api/in-process.js +2 -2
- package/dist/harness-api/record.d.ts +6 -3
- package/dist/harness-api/record.js +65 -72
- package/dist/harness-api/server.d.ts +1 -9
- package/dist/harness-api/server.js +19 -17
- package/dist/harness-api/start.js +1 -5
- package/dist/harness-api/workspace.js +2 -3
- package/dist/harness-api/ws-server.js +1 -1
- package/dist/host/app.d.ts +2 -9
- package/dist/host/app.js +15 -25
- package/dist/host/config-for.d.ts +1 -5
- package/dist/host/config-for.js +0 -3
- package/dist/host/config.d.ts +0 -5
- package/dist/host/create-host.d.ts +3 -33
- package/dist/host/create-host.js +18 -94
- package/dist/host/environment.d.ts +0 -3
- package/dist/host/environment.js +0 -9
- package/dist/host/gates.d.ts +4 -1
- package/dist/host/gates.js +3 -2
- package/dist/host/http.d.ts +1 -2
- package/dist/host/http.js +1 -7
- package/dist/host/index.d.ts +2 -2
- package/dist/host/index.js +2 -2
- package/dist/host/main.js +27 -34
- package/dist/host/operate.d.ts +29 -0
- package/dist/host/operate.js +223 -0
- package/dist/host/stack-config.d.ts +12 -12
- package/dist/host/stack-config.js +5 -32
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/infra/workers.d.ts +1 -1
- package/dist/keys/keys.js +2 -2
- package/dist/management-openapi.json +6491 -0
- package/dist/mcp/connect.d.ts +8 -4
- package/dist/mcp/connect.js +6 -26
- package/dist/mcp/pool.d.ts +5 -9
- package/dist/mcp/pool.js +8 -19
- package/dist/mcp/snapshot.d.ts +8 -2
- package/dist/mcp/snapshot.js +29 -2
- package/dist/media.d.ts +1 -1
- package/dist/media.js +1 -1
- package/dist/model/pi-model.js +3 -0
- package/dist/openapi.json +4700 -12350
- package/dist/reads/access.d.ts +4 -0
- package/dist/reads/access.js +12 -0
- package/dist/reads/cursor.d.ts +11 -0
- package/dist/reads/cursor.js +80 -0
- package/dist/reads/types.d.ts +25 -0
- package/dist/reads/types.js +1 -0
- package/dist/sandbox/manager.d.ts +16 -0
- package/dist/sandbox/manager.js +40 -0
- package/dist/sandbox/session-sandbox.js +13 -3
- package/dist/sandbox/skills.d.ts +13 -0
- package/dist/sandbox/skills.js +46 -0
- package/dist/sandbox/types.d.ts +2 -2
- package/dist/store/ownership.d.ts +9 -0
- package/dist/store/ownership.js +13 -0
- package/dist/store/postgres/connect.d.ts +2 -0
- package/dist/store/postgres/connect.js +29 -0
- package/dist/store/postgres/drizzle/0011_key_roles.sql +3 -0
- package/dist/store/postgres/drizzle/0012_session_reads.sql +8 -0
- package/dist/store/postgres/drizzle/0013_definition_files.sql +16 -0
- package/dist/store/postgres/drizzle/0014_action_endpoints_removed.sql +2 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
- package/dist/store/postgres/reads.d.ts +3 -0
- package/dist/store/postgres/reads.js +272 -0
- package/dist/store/postgres/schema.d.ts +294 -489
- package/dist/store/postgres/schema.js +41 -76
- package/dist/store/postgres/store.js +51 -154
- package/dist/store/postgres/tenant.d.ts +34 -2
- package/dist/store/postgres/tenant.js +16 -32
- package/dist/store/types.d.ts +27 -96
- package/dist/store/types.js +0 -1
- package/dist/streams/control.d.ts +0 -2
- package/dist/streams/control.js +0 -5
- package/dist/streams/types.d.ts +1 -10
- package/dist/tenant/advance.d.ts +3 -3
- package/dist/tenant/advance.js +10 -7
- package/dist/tenant/auth.d.ts +14 -9
- package/dist/tenant/auth.js +24 -28
- package/dist/tenant/cause.d.ts +3 -3
- package/dist/tenant/cause.js +1 -1
- package/dist/tenant/commands.d.ts +2 -18
- package/dist/tenant/commands.js +35 -172
- package/dist/tenant/context.d.ts +14 -24
- package/dist/tenant/definition-files.d.ts +24 -0
- package/dist/tenant/definition-files.js +103 -0
- package/dist/tenant/effects.d.ts +18 -20
- package/dist/tenant/effects.js +56 -119
- package/dist/tenant/ephemeral.d.ts +7 -6
- package/dist/tenant/ephemeral.js +3 -11
- package/dist/tenant/host-token.js +1 -1
- package/dist/tenant/jwt.js +1 -1
- package/dist/tenant/module.d.ts +1 -4
- package/dist/tenant/module.js +3 -12
- package/dist/tenant/operator-keys.d.ts +34 -8
- package/dist/tenant/operator-keys.js +50 -18
- package/dist/tenant/outbound.d.ts +10 -1
- package/dist/tenant/outbound.js +44 -27
- package/dist/tenant/paths.d.ts +1 -1
- package/dist/tenant/paths.js +1 -3
- package/dist/tenant/principals.d.ts +11 -2
- package/dist/tenant/principals.js +27 -8
- package/dist/tenant/run-token.js +3 -3
- package/dist/tenant/runtime.d.ts +4 -6
- package/dist/tenant/runtime.js +19 -18
- package/dist/tenant/sandboxes.d.ts +4 -1
- package/dist/tenant/sandboxes.js +11 -0
- package/dist/tenant/scheduler.d.ts +1 -5
- package/dist/tenant/scheduler.js +2 -5
- package/dist/tenant/session-streams.d.ts +2 -1
- package/dist/tenant/session-streams.js +39 -5
- package/dist/tenant/session.d.ts +8 -41
- package/dist/tenant/session.js +0 -37
- package/dist/tenant/sessions.js +16 -8
- package/dist/tenant/signing-keys.d.ts +3 -3
- package/dist/tenant/signing-keys.js +5 -5
- package/dist/tenant/skill-tool.d.ts +20 -0
- package/dist/tenant/skill-tool.js +72 -0
- package/dist/tenant/slim.d.ts +1 -1
- package/dist/tenant/slim.js +1 -1
- package/dist/tenant/status.js +7 -12
- package/dist/tenant/store-pg.d.ts +15 -0
- package/dist/tenant/store-pg.js +7 -3
- package/dist/tenant/streams.d.ts +3 -10
- package/dist/tenant/streams.js +1 -24
- package/dist/tenant/sweep.js +0 -5
- package/dist/tenant/transcript.d.ts +2 -2
- package/dist/tenant/transcript.js +2 -2
- package/dist/tenant/types.d.ts +15 -22
- package/dist/tenant/worker.d.ts +1 -3
- package/dist/tenant/worker.js +3 -8
- package/dist/vault/sources.d.ts +7 -1
- package/dist/vault/sources.js +22 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/dist/admin-openapi.json +0 -904
- package/dist/api/http/routes/actions.d.ts +0 -8
- package/dist/api/http/routes/actions.js +0 -75
- package/dist/api/http/routes/endpoints.d.ts +0 -7
- package/dist/api/http/routes/endpoints.js +0 -100
- package/dist/host/admin-api.d.ts +0 -30
- package/dist/host/admin-api.js +0 -140
- package/dist/mcp/stdio.d.ts +0 -17
- package/dist/mcp/stdio.js +0 -82
- package/dist/tenant/actions.d.ts +0 -14
- package/dist/tenant/actions.js +0 -29
- package/dist/tenant/delivery-token.d.ts +0 -41
- package/dist/tenant/delivery-token.js +0 -104
- package/dist/tenant/delivery.d.ts +0 -62
- package/dist/tenant/delivery.js +0 -481
- package/dist/tenant/endpoints.d.ts +0 -67
- package/dist/tenant/endpoints.js +0 -90
package/dist/tenant/session.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers over the session document: turn-manifest pins and variants, and state rebasing.
|
|
3
|
+
* No store access and no I/O. (The tools of an MCP snapshot
|
|
4
|
+
* live in `mcp/snapshot.ts`.)
|
|
5
|
+
*
|
|
6
|
+
* Later waves: stable; the async store conversion (Wave 1 / A) does not change these.
|
|
7
|
+
*/
|
|
8
|
+
import type { AgentManifest } from "@nylorun/core/define";
|
|
3
9
|
import { type TurnManifestStore } from "../core/turn-manifest.js";
|
|
4
10
|
import type { Session } from "./context.js";
|
|
5
11
|
export { manifestFor, sessionToolsOf } from "../mcp/snapshot.js";
|
|
@@ -7,43 +13,4 @@ export { manifestFor, sessionToolsOf } from "../mcp/snapshot.js";
|
|
|
7
13
|
export declare function variantStore(session: Session): TurnManifestStore;
|
|
8
14
|
/** Manifest this turn's checkpoint is pinned to (session pin or a stored variant). */
|
|
9
15
|
export declare function turnManifestOf(session: Session): AgentManifest;
|
|
10
|
-
/** Wrap a linked agent turn so the Loop learns the turn's manifest (SD-I4 pin stays on session). */
|
|
11
|
-
export declare function linkedAgentOutput(session: Session, output: JsonValue | undefined): JsonValue;
|
|
12
16
|
export declare function rebaseSessionState(session: Session, turnHash: string): void;
|
|
13
|
-
export declare function pinnedTool(manifest: AgentManifest, capabilityId?: string, toolName?: string): import("@nylorun/core/define").ToolManifest | undefined;
|
|
14
|
-
/** What an action runs, for events: a tool name, or a hook point and its capabilities. */
|
|
15
|
-
export declare function actionTarget(action: Action): {
|
|
16
|
-
hook: {
|
|
17
|
-
at: "after" | "before";
|
|
18
|
-
scope: "step" | "turn";
|
|
19
|
-
capabilityIds: string[];
|
|
20
|
-
};
|
|
21
|
-
agent?: {
|
|
22
|
-
id: string;
|
|
23
|
-
path: string;
|
|
24
|
-
delegationId?: string | undefined;
|
|
25
|
-
} | undefined;
|
|
26
|
-
} | {
|
|
27
|
-
toolName: string;
|
|
28
|
-
agent?: {
|
|
29
|
-
id: string;
|
|
30
|
-
path: string;
|
|
31
|
-
delegationId?: string | undefined;
|
|
32
|
-
} | undefined;
|
|
33
|
-
} | {
|
|
34
|
-
path: string;
|
|
35
|
-
key: string;
|
|
36
|
-
agent?: {
|
|
37
|
-
id: string;
|
|
38
|
-
path: string;
|
|
39
|
-
delegationId?: string | undefined;
|
|
40
|
-
} | {
|
|
41
|
-
id: string;
|
|
42
|
-
path: string;
|
|
43
|
-
delegationId?: string | undefined;
|
|
44
|
-
} | {
|
|
45
|
-
id: string;
|
|
46
|
-
path: string;
|
|
47
|
-
delegationId?: string | undefined;
|
|
48
|
-
} | undefined;
|
|
49
|
-
};
|
package/dist/tenant/session.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure helpers over the session document: turn-manifest pins and variants, state rebasing,
|
|
3
|
-
* and the event target of an Action. No store access and no I/O. (The tools of an MCP snapshot
|
|
4
|
-
* live in `mcp/snapshot.ts`.)
|
|
5
|
-
*
|
|
6
|
-
* Later waves: stable; the async store conversion (Wave 1 / A) does not change these.
|
|
7
|
-
*/
|
|
8
|
-
import { agentTurnValue } from "@nylorun/harness/run";
|
|
9
|
-
import { isWorkflowManifest } from "../core/flow-host.js";
|
|
10
1
|
import { allowedManifestHashes, rebaseTurnState, } from "../core/turn-manifest.js";
|
|
11
2
|
export { manifestFor, sessionToolsOf } from "../mcp/snapshot.js";
|
|
12
3
|
/** Turn-manifest store backed by the session's `variants` map (no schema change). */
|
|
@@ -27,12 +18,6 @@ export function turnManifestOf(session) {
|
|
|
27
18
|
return session.manifest;
|
|
28
19
|
return session.variants?.[hash] ?? session.manifest;
|
|
29
20
|
}
|
|
30
|
-
/** Wrap a linked agent turn so the Loop learns the turn's manifest (SD-I4 pin stays on session). */
|
|
31
|
-
export function linkedAgentOutput(session, output) {
|
|
32
|
-
if (isWorkflowManifest(session.manifest))
|
|
33
|
-
return output ?? null;
|
|
34
|
-
return agentTurnValue(output ?? null, turnManifestOf(session));
|
|
35
|
-
}
|
|
36
21
|
export function rebaseSessionState(session, turnHash) {
|
|
37
22
|
const allowed = allowedManifestHashes({
|
|
38
23
|
pinnedHash: session.manifestHash,
|
|
@@ -46,25 +31,3 @@ export function rebaseSessionState(session, turnHash) {
|
|
|
46
31
|
if (next !== session.state)
|
|
47
32
|
session.state = next;
|
|
48
33
|
}
|
|
49
|
-
export function pinnedTool(manifest, capabilityId, toolName) {
|
|
50
|
-
const capability = manifest.capabilities.find((item) => item.id === capabilityId);
|
|
51
|
-
return capability?.tools?.find((tool) => tool.name === toolName);
|
|
52
|
-
}
|
|
53
|
-
/** What an action runs, for events: a tool name, or a hook point and its capabilities. */
|
|
54
|
-
export function actionTarget(action) {
|
|
55
|
-
if (action.kind === "hook")
|
|
56
|
-
return {
|
|
57
|
-
hook: action.hook,
|
|
58
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
59
|
-
};
|
|
60
|
-
if (action.kind === "tool" && "toolName" in action)
|
|
61
|
-
return {
|
|
62
|
-
toolName: action.toolName,
|
|
63
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
64
|
-
};
|
|
65
|
-
return {
|
|
66
|
-
path: action.path,
|
|
67
|
-
key: action.key,
|
|
68
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
69
|
-
};
|
|
70
|
-
}
|
package/dist/tenant/sessions.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* re-attach vaults), the session list and the session view. Reads use the store's typed
|
|
4
4
|
* queries; `PUT /v1/sessions/:id` runs in one transaction with the vault attachment checks.
|
|
5
5
|
*/
|
|
6
|
-
import { DefinitionDocumentSchema, } from "@nylorun/core/contracts";
|
|
6
|
+
import { DefinitionDocumentSchema, definitionFilesOf, } from "@nylorun/core/contracts";
|
|
7
7
|
import { hashManifest } from "@nylorun/core/compatibility";
|
|
8
|
+
import { codeToolRefusal } from "@nylorun/core/define";
|
|
8
9
|
import { aggregateWaits, isWorkflowManifest } from "../core/flow-host.js";
|
|
9
10
|
import { canonical } from "../store/canonical.js";
|
|
10
11
|
import { validateSandboxAttach } from "../core/sandbox-routes.js";
|
|
@@ -16,6 +17,7 @@ import { checkPlacement, requirePods } from "../sandbox/placement.js";
|
|
|
16
17
|
import { attachSandbox, recordAttachment } from "./sandboxes.js";
|
|
17
18
|
import { sandboxLookup, } from "./context.js";
|
|
18
19
|
import { fail } from "./http.js";
|
|
20
|
+
import { missingDefinitionFiles } from "./definition-files.js";
|
|
19
21
|
/** A session's creation identity: everything but the request id and vault attachments. */
|
|
20
22
|
const sessionIdentity = (value) => {
|
|
21
23
|
const { requestId: _requestId, vaultIds: _vaultIds, credentialSelections: _selections, ...body } = value ?? {};
|
|
@@ -54,6 +56,10 @@ export async function putDefinition(ctx, agentId, body) {
|
|
|
54
56
|
if (body.manifest.id !== agentId)
|
|
55
57
|
fail(400, "Agent id mismatch");
|
|
56
58
|
DefinitionDocumentSchema.parse(body.manifest);
|
|
59
|
+
// The Runtime runs no code of yours during a session (track R2): no tool may need it.
|
|
60
|
+
const code = codeToolRefusal(body.manifest);
|
|
61
|
+
if (code)
|
|
62
|
+
fail(400, code);
|
|
57
63
|
const declared = declaredSandboxes(body.manifest);
|
|
58
64
|
if (declared.length > 0)
|
|
59
65
|
fail(400, `${declared.join(", ")} declares a sandbox. Agents no longer declare one: remove .sandbox() and open the session with it, createSession({ sandbox: { image, network: { allow }, resources } }), or set the Tenant's default sandbox. See MIGRATION.md.`);
|
|
@@ -61,7 +67,14 @@ export async function putDefinition(ctx, agentId, body) {
|
|
|
61
67
|
...body,
|
|
62
68
|
manifestHash: hashManifest(body.manifest),
|
|
63
69
|
};
|
|
64
|
-
|
|
70
|
+
const files = [...definitionFilesOf(body.manifest)];
|
|
71
|
+
await ctx.store.tx(async (t) => {
|
|
72
|
+
const missing = await missingDefinitionFiles(t, body.manifest);
|
|
73
|
+
if (missing.length > 0)
|
|
74
|
+
fail(400, `The definition names ${missing.length} file(s) the Runtime does not hold; upload each with PUT /v1/files/<sha256> first: ${missing.join(", ")}`, { code: "definition_files_missing", details: { missing } });
|
|
75
|
+
await t.put("definitions", agentId, definition);
|
|
76
|
+
await t.insertDefinitionFileUses(agentId, definition.manifestHash, files);
|
|
77
|
+
});
|
|
65
78
|
return {
|
|
66
79
|
agentId,
|
|
67
80
|
manifestHash: definition.manifestHash,
|
|
@@ -156,7 +169,6 @@ export async function putSession(ctx, id, body, access, options = {}) {
|
|
|
156
169
|
creation: body,
|
|
157
170
|
vaultIds,
|
|
158
171
|
credentialSelections,
|
|
159
|
-
pluginRoots: definition.pluginRoots ?? {},
|
|
160
172
|
...(sandbox.sandboxOwnerId !== undefined
|
|
161
173
|
? { sandboxOwnerId: sandbox.sandboxOwnerId }
|
|
162
174
|
: {}),
|
|
@@ -221,7 +233,7 @@ async function sessionSandbox(t, body, definition, options) {
|
|
|
221
233
|
return pin(definition, resolved.spec, resolved.source);
|
|
222
234
|
}
|
|
223
235
|
async function pin(definition, spec, source) {
|
|
224
|
-
// A workflow's manifest stays as registered:
|
|
236
|
+
// A workflow's manifest stays as registered: its agents inherit the sandbox when they start.
|
|
225
237
|
if (isWorkflowManifest(definition.manifest))
|
|
226
238
|
return { spec, source };
|
|
227
239
|
const sandboxed = withSandboxCapability(definition.manifest, spec);
|
|
@@ -249,9 +261,6 @@ export async function sessionView(t, s) {
|
|
|
249
261
|
if (aggregated.length > 0)
|
|
250
262
|
waits = aggregated;
|
|
251
263
|
}
|
|
252
|
-
const actions = await t.actionsForSession(s.id, {
|
|
253
|
-
statuses: ["pending", "delivering", "uncertain"],
|
|
254
|
-
});
|
|
255
264
|
const uncertain = await t.effectsForSession(s.id, {
|
|
256
265
|
statuses: ["uncertain"],
|
|
257
266
|
});
|
|
@@ -273,7 +282,6 @@ export async function sessionView(t, s) {
|
|
|
273
282
|
mcpDiagnostics: s.mcpDiagnostics ?? [],
|
|
274
283
|
waits,
|
|
275
284
|
error: s.error,
|
|
276
|
-
actions,
|
|
277
285
|
uncertainEffects: uncertain.map((e) => ({
|
|
278
286
|
effectId: e.request.effectId,
|
|
279
287
|
turnId: e.request.turnId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tenant signing keys for the tokens the Runtime signs itself (
|
|
3
|
-
*
|
|
2
|
+
* Tenant signing keys for the tokens the Runtime signs itself (capability links, run and host
|
|
3
|
+
* tokens). Each key is an ES256 pair: the public JWK is stored
|
|
4
4
|
* as is, the PKCS#8 private key is sealed with the vault KEK (AAD bound to the Tenant and key
|
|
5
5
|
* id), like a credential.
|
|
6
6
|
*
|
|
@@ -44,7 +44,7 @@ export declare class SigningKeys {
|
|
|
44
44
|
/**
|
|
45
45
|
* Rotates: previous → revoked, current → previous, standby → current, new standby. Refused
|
|
46
46
|
* with 409 while the previous key may still verify live tokens (retired less than the
|
|
47
|
-
* longest token lifetime, `maxTtlSeconds` or
|
|
47
|
+
* longest token lifetime, `maxTtlSeconds` or `TOKEN_TTL_MAX_SECONDS`, plus a minute ago), unless
|
|
48
48
|
* `force`.
|
|
49
49
|
*/
|
|
50
50
|
rotate(t: Tx, kek: Buffer, maxTtlSeconds: number, force: boolean): Promise<SigningKeyRow[]>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tenant signing keys for the tokens the Runtime signs itself (
|
|
3
|
-
*
|
|
2
|
+
* Tenant signing keys for the tokens the Runtime signs itself (capability links, run and host
|
|
3
|
+
* tokens). Each key is an ES256 pair: the public JWK is stored
|
|
4
4
|
* as is, the PKCS#8 private key is sealed with the vault KEK (AAD bound to the Tenant and key
|
|
5
5
|
* id), like a credential.
|
|
6
6
|
*
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { exportJWK, exportPKCS8, generateKeyPair, importJWK, importPKCS8, } from "jose";
|
|
17
17
|
import { newSigningKeyId, SIGNING_KEY_ID_PATTERN, } from "@nylorun/core/compatibility";
|
|
18
|
-
import {
|
|
18
|
+
import { TOKEN_TTL_MAX_SECONDS } from "@nylorun/core/contracts";
|
|
19
19
|
import { decryptSecret, encryptSecret } from "../vault/crypto.js";
|
|
20
20
|
import { fail } from "./http.js";
|
|
21
21
|
const ALG = "ES256";
|
|
@@ -107,7 +107,7 @@ export class SigningKeys {
|
|
|
107
107
|
/**
|
|
108
108
|
* Rotates: previous → revoked, current → previous, standby → current, new standby. Refused
|
|
109
109
|
* with 409 while the previous key may still verify live tokens (retired less than the
|
|
110
|
-
* longest token lifetime, `maxTtlSeconds` or
|
|
110
|
+
* longest token lifetime, `maxTtlSeconds` or `TOKEN_TTL_MAX_SECONDS`, plus a minute ago), unless
|
|
111
111
|
* `force`.
|
|
112
112
|
*/
|
|
113
113
|
async rotate(t, kek, maxTtlSeconds, force) {
|
|
@@ -118,7 +118,7 @@ export class SigningKeys {
|
|
|
118
118
|
const [previous] = await t.signingKeys(["previous"]);
|
|
119
119
|
if (previous && !force) {
|
|
120
120
|
const retired = Date.parse(previous.retiredAt ?? previous.createdAt);
|
|
121
|
-
const longest = Math.max(maxTtlSeconds,
|
|
121
|
+
const longest = Math.max(maxTtlSeconds, TOKEN_TTL_MAX_SECONDS);
|
|
122
122
|
const until = retired + longest * 1000 + ROTATION_GRACE_MS;
|
|
123
123
|
if (until > now.getTime())
|
|
124
124
|
fail(409, "The previous key may still verify live tokens", {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The skill tools (track R2 M4): `load_skill` and `read_skill_resource`, which the build gives
|
|
3
|
+
* the first capability with skills. The Runtime runs them itself, like `save_artifact`, from the
|
|
4
|
+
* definition files uploaded with the agent: no developer process is involved.
|
|
5
|
+
*
|
|
6
|
+
* - `load_skill`: the skill's instructions (its `SKILL.md` after the frontmatter), the paths of
|
|
7
|
+
* its other files, and, when the session has a sandbox, where they are in it
|
|
8
|
+
* (`/skills/<name>/`, read-only).
|
|
9
|
+
* - `read_skill_resource`: one text file of the skill. A binary file is refused: the model reads
|
|
10
|
+
* it in the sandbox, when there is one.
|
|
11
|
+
*
|
|
12
|
+
* Expected problems are failed outcomes the model sees; only infrastructure errors throw.
|
|
13
|
+
*/
|
|
14
|
+
import type { SandboxToolOutcome } from "@nylorun/core/contracts";
|
|
15
|
+
import { type AgentManifest } from "@nylorun/core/define";
|
|
16
|
+
import type { HostEffect } from "@nylorun/harness/run";
|
|
17
|
+
import type { TenantContext } from "./context.js";
|
|
18
|
+
/** True when `request` calls a skill tool the Runtime serves for `manifest`'s agent. */
|
|
19
|
+
export declare function isSkillToolCall(manifest: AgentManifest | undefined, request: HostEffect): boolean;
|
|
20
|
+
export declare function callSkillTool(ctx: TenantContext, manifest: AgentManifest, request: HostEffect, signal: AbortSignal): Promise<SandboxToolOutcome>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { LOAD_SKILL_TOOL, SANDBOX_CAPABILITY_ID, SKILL_ENTRY, SKILLS_MOUNT, isSkillTool, skillInstructions, } from "@nylorun/core/define";
|
|
2
|
+
import { sandboxCapabilityOf } from "../sandbox/capability.js";
|
|
3
|
+
import { readDefinitionFile } from "./definition-files.js";
|
|
4
|
+
const failed = (code, message) => ({ kind: "failed", code, message });
|
|
5
|
+
/** True when `request` calls a skill tool the Runtime serves for `manifest`'s agent. */
|
|
6
|
+
export function isSkillToolCall(manifest, request) {
|
|
7
|
+
return (request.kind === "tool" &&
|
|
8
|
+
isSkillTool(manifest?.capabilities.find((capability) => capability.id === request.capabilityId), request.toolName));
|
|
9
|
+
}
|
|
10
|
+
/** Every skill of the agent, by name. */
|
|
11
|
+
function skillsOf(manifest) {
|
|
12
|
+
const skills = new Map();
|
|
13
|
+
for (const capability of manifest.capabilities)
|
|
14
|
+
for (const skill of Object.values(capability.skills ?? {}))
|
|
15
|
+
skills.set(skill.name, skill);
|
|
16
|
+
return skills;
|
|
17
|
+
}
|
|
18
|
+
/** UTF-8 text, or undefined for bytes that are not (a NUL byte, or invalid UTF-8). */
|
|
19
|
+
function textOf(bytes) {
|
|
20
|
+
if (bytes.includes(0))
|
|
21
|
+
return undefined;
|
|
22
|
+
try {
|
|
23
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export async function callSkillTool(ctx, manifest, request, signal) {
|
|
30
|
+
const input = (request.input ?? {});
|
|
31
|
+
const skills = skillsOf(manifest);
|
|
32
|
+
const name = typeof input.name === "string" ? input.name : "";
|
|
33
|
+
const skill = skills.get(name);
|
|
34
|
+
if (!skill)
|
|
35
|
+
return request.toolName === LOAD_SKILL_TOOL
|
|
36
|
+
? { kind: "completed", output: { unknown: name, available: [...skills.keys()].sort() } }
|
|
37
|
+
: failed("skill.unknown", `There is no skill '${name}'.`);
|
|
38
|
+
const sandboxed = sandboxCapabilityOf(manifest, SANDBOX_CAPABILITY_ID, "bash") !== undefined;
|
|
39
|
+
const directory = `${SKILLS_MOUNT}/${skill.name}/`;
|
|
40
|
+
const read = async (path) => {
|
|
41
|
+
const bytes = await readDefinitionFile(ctx.blobs, skill.files[path], signal);
|
|
42
|
+
if (!bytes)
|
|
43
|
+
throw new Error(`The bytes of ${skill.files[path]} (${skill.name}/${path}) are missing from the Object store`);
|
|
44
|
+
return bytes;
|
|
45
|
+
};
|
|
46
|
+
if (request.toolName === LOAD_SKILL_TOOL) {
|
|
47
|
+
const text = textOf(await read(SKILL_ENTRY));
|
|
48
|
+
if (text === undefined)
|
|
49
|
+
return failed("skill.binary_resource", `${SKILL_ENTRY} of '${skill.name}' is not text.`);
|
|
50
|
+
const resources = Object.keys(skill.files)
|
|
51
|
+
.filter((path) => path !== SKILL_ENTRY)
|
|
52
|
+
.sort();
|
|
53
|
+
return {
|
|
54
|
+
kind: "completed",
|
|
55
|
+
output: {
|
|
56
|
+
name: skill.name,
|
|
57
|
+
content: skillInstructions(text),
|
|
58
|
+
...(resources.length === 0 ? {} : { resources }),
|
|
59
|
+
...(sandboxed ? { sandboxPath: directory } : {}),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const path = typeof input.path === "string" ? input.path : "";
|
|
64
|
+
if (skill.files[path] === undefined)
|
|
65
|
+
return failed("skill.unknown_resource", `Skill '${skill.name}' has no resource '${path}'.`);
|
|
66
|
+
const content = textOf(await read(path));
|
|
67
|
+
if (content === undefined)
|
|
68
|
+
return failed("skill.binary_resource", sandboxed
|
|
69
|
+
? `${path} is not a text file. It is in the sandbox at ${directory}${path}; use it there.`
|
|
70
|
+
: `${path} is not a text file; only text files can be read without a sandbox.`);
|
|
71
|
+
return { kind: "completed", output: { name: skill.name, path, content } };
|
|
72
|
+
}
|
package/dist/tenant/slim.d.ts
CHANGED
|
@@ -3,6 +3,6 @@ import type { Tx } from "../store/types.js";
|
|
|
3
3
|
* Slim the completed model effects of a turn that ended (Model Calls §9): drop the prompt
|
|
4
4
|
* and the answer, which the transcript already holds, and keep the identity and status.
|
|
5
5
|
* Replay only ever reads the effects of a running segment. Tool, flow and uncertain rows
|
|
6
|
-
* are never touched:
|
|
6
|
+
* are never touched: status lists uncertain work.
|
|
7
7
|
*/
|
|
8
8
|
export declare function slimModelEffects(t: Tx, sessionId: string, turnId: string | null): Promise<void>;
|
package/dist/tenant/slim.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Slim the completed model effects of a turn that ended (Model Calls §9): drop the prompt
|
|
3
3
|
* and the answer, which the transcript already holds, and keep the identity and status.
|
|
4
4
|
* Replay only ever reads the effects of a running segment. Tool, flow and uncertain rows
|
|
5
|
-
* are never touched:
|
|
5
|
+
* are never touched: status lists uncertain work.
|
|
6
6
|
*/
|
|
7
7
|
export async function slimModelEffects(t, sessionId, turnId) {
|
|
8
8
|
if (!turnId)
|
package/dist/tenant/status.js
CHANGED
|
@@ -56,16 +56,13 @@ export async function buildTenantStatus(ctx) {
|
|
|
56
56
|
ctx.stuckInvocations ? executionStatus(ctx.stuckInvocations) : undefined,
|
|
57
57
|
ctx.streamsStatus?.(),
|
|
58
58
|
]);
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
agentId
|
|
66
|
-
registered: definitionIds.has(agentId),
|
|
67
|
-
endpoint: endpointIds.has(agentId),
|
|
68
|
-
}));
|
|
59
|
+
const agents = [
|
|
60
|
+
...new Set(definitions
|
|
61
|
+
.map((d) => d.manifest?.id)
|
|
62
|
+
.filter((id) => typeof id === "string")),
|
|
63
|
+
]
|
|
64
|
+
.sort()
|
|
65
|
+
.map((agentId) => ({ agentId }));
|
|
69
66
|
return {
|
|
70
67
|
tenant: ctx.envelope,
|
|
71
68
|
path: ctx.config.paths.root,
|
|
@@ -73,7 +70,6 @@ export async function buildTenantStatus(ctx) {
|
|
|
73
70
|
store: health.schemaVersion > 0,
|
|
74
71
|
scheduler: !ctx.closing,
|
|
75
72
|
model: ctx.modelConfigured || modelView.configured,
|
|
76
|
-
endpoints: true,
|
|
77
73
|
schema: health.ok,
|
|
78
74
|
},
|
|
79
75
|
model: modelView,
|
|
@@ -81,7 +77,6 @@ export async function buildTenantStatus(ctx) {
|
|
|
81
77
|
counts: {
|
|
82
78
|
sessions: counts.sessions,
|
|
83
79
|
runningSessions: counts.runningSessions,
|
|
84
|
-
pendingActions: counts.pendingActions,
|
|
85
80
|
uncertainEffects: counts.uncertainEffects,
|
|
86
81
|
},
|
|
87
82
|
sandbox: {
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opens the Host's Tenant on its Postgres database (tenancy.md §4–§5, plan P9).
|
|
3
|
+
*
|
|
4
|
+
* The database holds one Tenant (`store/postgres/tenant.ts`): opening migrates it, creates
|
|
5
|
+
* the Tenant on first start (from the Host's configuration: id, name, Studio and derived
|
|
6
|
+
* principals), and opens the Tenant Runtime on its Session Store. What stays on the Host root
|
|
7
|
+
* is the Tenant directory `tenant/`: the vault key (`vault-kek`), `logs/`, and the private
|
|
8
|
+
* `home/` and `sandboxes/`.
|
|
9
|
+
*
|
|
10
|
+
* - A failure in the Tenant (an old layout, a database newer than this Runtime, a failed
|
|
11
|
+
* migration, an unreadable Tenant row, vault ciphertext without its key) rejects with that
|
|
12
|
+
* `TenantOpenError`; the Host reports it and fails readiness.
|
|
13
|
+
* - A failure outside the Tenant (Postgres unreachable, its sweep not armed in Restate) is
|
|
14
|
+
* `TenantUnavailableError`; the Tenant module retries.
|
|
15
|
+
*/
|
|
1
16
|
import type { PostgresClient } from "../store/postgres/connect.js";
|
|
2
17
|
import type { Migration } from "../store/postgres/migrate.js";
|
|
3
18
|
import { type TenantCreation } from "../store/postgres/tenant.js";
|
package/dist/tenant/store-pg.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* The database holds one Tenant (`store/postgres/tenant.ts`): opening migrates it, creates
|
|
5
5
|
* the Tenant on first start (from the Host's configuration: id, name, Studio and derived
|
|
6
6
|
* principals), and opens the Tenant Runtime on its Session Store. What stays on the Host root
|
|
7
|
-
* is the Tenant directory `tenant/`: the vault key (`vault-kek`), `
|
|
8
|
-
*
|
|
7
|
+
* is the Tenant directory `tenant/`: the vault key (`vault-kek`), `logs/`, and the private
|
|
8
|
+
* `home/` and `sandboxes/`.
|
|
9
9
|
*
|
|
10
10
|
* - A failure in the Tenant (an old layout, a database newer than this Runtime, a failed
|
|
11
11
|
* migration, an unreadable Tenant row, vault ciphertext without its key) rejects with that
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - A failure outside the Tenant (Postgres unreachable, its sweep not armed in Restate) is
|
|
14
14
|
* `TenantUnavailableError`; the Tenant module retries.
|
|
15
15
|
*/
|
|
16
|
+
import { createPostgresReadStore } from "../store/postgres/reads.js";
|
|
16
17
|
import { mkdirSync } from "node:fs";
|
|
17
18
|
import { openTenantDatabase, } from "../store/postgres/tenant.js";
|
|
18
19
|
import { TenantOpenError } from "./cause.js";
|
|
@@ -54,13 +55,16 @@ export function createPostgresTenantOpener(options) {
|
|
|
54
55
|
from: opened.migrated.from,
|
|
55
56
|
to: opened.migrated.to,
|
|
56
57
|
});
|
|
58
|
+
let reads;
|
|
57
59
|
try {
|
|
60
|
+
reads = createPostgresReadStore(options.sql, tenantId);
|
|
58
61
|
const config = options.configFor(tenantId);
|
|
59
62
|
const paths = tenantPaths(options.hostRoot);
|
|
60
63
|
mkdirSync(paths.root, { recursive: true, mode: 0o700 });
|
|
61
|
-
return await options.openRuntime({ ...config, tenantId }, { store, envelope });
|
|
64
|
+
return await options.openRuntime({ ...config, tenantId }, { store, envelope, reads });
|
|
62
65
|
}
|
|
63
66
|
catch (error) {
|
|
67
|
+
await reads?.close().catch(() => undefined);
|
|
64
68
|
await store.close().catch(() => undefined);
|
|
65
69
|
if (error instanceof TenantOpenError) {
|
|
66
70
|
// The Tenant's own failure (`kek-missing`): report which Tenant it is.
|
package/dist/tenant/streams.d.ts
CHANGED
|
@@ -16,9 +16,8 @@
|
|
|
16
16
|
* and `streamsStatus` reports the basin's state.
|
|
17
17
|
* - **Readers.** History and session SSE read the session's stream
|
|
18
18
|
* (`tenant/session-streams.ts`). This module runs one `tenant/control` reader per Tenant per
|
|
19
|
-
* process, on the current basin, which calls `ctx.abortLocal` for each `session.cancel
|
|
20
|
-
*
|
|
21
|
-
* checks the session streams for each `sessions.reset`.
|
|
19
|
+
* process, on the current basin, which calls `ctx.abortLocal` for each `session.cancel`
|
|
20
|
+
* and checks the session streams for each `sessions.reset`.
|
|
22
21
|
*
|
|
23
22
|
* The caller passes the streams: the Host's S2 streams, or `MemoryStreams` for tests and a
|
|
24
23
|
* local development Host (not durable).
|
|
@@ -78,12 +77,6 @@ export declare function wireStreams(ctx: TenantContext, options: WireStreamsOpti
|
|
|
78
77
|
* effect), so failures are logged, never thrown.
|
|
79
78
|
*/
|
|
80
79
|
export declare function signalSessionCancel(ctx: TenantContext, sessionId: string, turnId: string | null): void;
|
|
81
|
-
/**
|
|
82
|
-
* Appends `action.resolved` for an Action whose outcome just committed, so a run held for it
|
|
83
|
-
* by a harness of another process goes on (F6.2). Call it from `t.afterCommit`. A lost signal
|
|
84
|
-
* costs the hold's time only: the segment then ends as waiting and resumes by replay.
|
|
85
|
-
*/
|
|
86
|
-
export declare function signalActionOutcome(ctx: TenantContext, sessionId: string, actionId: string): void;
|
|
87
80
|
/**
|
|
88
81
|
* After a reset deleted the Tenant's sessions and moved it to a new basin generation: tells
|
|
89
82
|
* every process with the Tenant open (`sessions.reset` on the old basin's control stream),
|
|
@@ -91,7 +84,7 @@ export declare function signalActionOutcome(ctx: TenantContext, sessionId: strin
|
|
|
91
84
|
* are logged; the periodic check and the next open finish the job.
|
|
92
85
|
*/
|
|
93
86
|
export declare function tenantReset(ctx: TenantContext): Promise<void>;
|
|
94
|
-
/** Tenant status of the streams seam (for `GET /v1/tenant`
|
|
87
|
+
/** Tenant status of the streams seam (for `GET /v1/tenant`). */
|
|
95
88
|
export interface StreamsStatus {
|
|
96
89
|
/** The streams' service answered a probe (`probeStreams`) within the timeout. */
|
|
97
90
|
reachable: boolean;
|
package/dist/tenant/streams.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basinOf } from "../streams/basin.js";
|
|
2
|
-
import {
|
|
2
|
+
import { signalCancel, signalSessionsReset } from "../streams/control.js";
|
|
3
3
|
import { createStreamRelay, } from "../streams/relay/core.js";
|
|
4
4
|
import { CONTROL_STREAM, } from "../streams/types.js";
|
|
5
5
|
import { checkSessionStreams, currentBasin, sleep, } from "./session-streams.js";
|
|
@@ -59,10 +59,6 @@ export async function wireStreams(ctx, options) {
|
|
|
59
59
|
const signal = body;
|
|
60
60
|
if (signal?.type === "session.cancel" && typeof signal.sessionId === "string")
|
|
61
61
|
ctx.abortLocal(signal.sessionId, typeof signal.turnId === "string" ? signal.turnId : undefined);
|
|
62
|
-
else if (signal?.type === "action.resolved" &&
|
|
63
|
-
typeof signal.sessionId === "string" &&
|
|
64
|
-
typeof signal.actionId === "string")
|
|
65
|
-
void resolveHeld(ctx, signal.sessionId, signal.actionId).catch(report("held run resolution failed"));
|
|
66
62
|
else if (signal?.type === "sessions.reset")
|
|
67
63
|
void checkSessionStreams(ctx).catch(report("session stream check failed"));
|
|
68
64
|
}, report("control stream read failed; retrying"));
|
|
@@ -171,25 +167,6 @@ export function signalSessionCancel(ctx, sessionId, turnId) {
|
|
|
171
167
|
message: messageOf(error),
|
|
172
168
|
}));
|
|
173
169
|
}
|
|
174
|
-
/**
|
|
175
|
-
* Appends `action.resolved` for an Action whose outcome just committed, so a run held for it
|
|
176
|
-
* by a harness of another process goes on (F6.2). Call it from `t.afterCommit`. A lost signal
|
|
177
|
-
* costs the hold's time only: the segment then ends as waiting and resumes by replay.
|
|
178
|
-
*/
|
|
179
|
-
export function signalActionOutcome(ctx, sessionId, actionId) {
|
|
180
|
-
const streams = ctx.sessionStreams.wiring?.streams;
|
|
181
|
-
if (!streams)
|
|
182
|
-
return;
|
|
183
|
-
void signalActionResolved(streams, currentBasin(ctx), sessionId, actionId).catch((error) => ctx.config.logger.warn("action resolved signal failed", { sessionId, message: messageOf(error) }));
|
|
184
|
-
}
|
|
185
|
-
/** Passes an Action's recorded outcome to the run of `sessionId` held here, if any. */
|
|
186
|
-
async function resolveHeld(ctx, sessionId, actionId) {
|
|
187
|
-
if (!ctx.harness.holds(sessionId))
|
|
188
|
-
return;
|
|
189
|
-
const effect = await ctx.store.tx((t) => t.get("effects", actionId));
|
|
190
|
-
if (effect?.status === "completed" && effect.outcome)
|
|
191
|
-
ctx.harness.resolved(sessionId, actionId, effect.outcome);
|
|
192
|
-
}
|
|
193
170
|
/**
|
|
194
171
|
* After a reset deleted the Tenant's sessions and moved it to a new basin generation: tells
|
|
195
172
|
* every process with the Tenant open (`sessions.reset` on the old basin's control stream),
|
package/dist/tenant/sweep.js
CHANGED
|
@@ -14,9 +14,6 @@
|
|
|
14
14
|
* workspace capability (`harness-api/workspace.ts`: here, or in the harness that serves
|
|
15
15
|
* workspaces). Idle MCP connections of the in-process harness are closed.
|
|
16
16
|
* 4. **Hooks.** Callbacks registered with `ctx.onSweep`.
|
|
17
|
-
* 5. **Deliveries.** Deliveries to Action endpoints whose deadline passed without an answer are
|
|
18
|
-
* lost (`delivery.ts` `loseAction`), and pending Actions of agents with an endpoint are sent
|
|
19
|
-
* again, in case a send was lost between a commit and the execution.
|
|
20
17
|
*
|
|
21
18
|
* Every step runs one transaction per session it changes (a linked agent and its workflow
|
|
22
19
|
* share one, child first), so the sweep follows the lock order in `store/types.ts`. A failing
|
|
@@ -24,14 +21,12 @@
|
|
|
24
21
|
* reports it.
|
|
25
22
|
*/
|
|
26
23
|
import { pendingAgentEffects, reconcilePendingAgentEffect, } from "../core/flow-host.js";
|
|
27
|
-
import { sweepDeliveries } from "./delivery.js";
|
|
28
24
|
const BATCH = 100;
|
|
29
25
|
export async function sweep(ctx) {
|
|
30
26
|
if (ctx.closing || ctx.closed)
|
|
31
27
|
return;
|
|
32
28
|
const now = new Date();
|
|
33
29
|
const steps = [
|
|
34
|
-
["deliveries", () => sweepDeliveries(ctx, now)],
|
|
35
30
|
["linked", () => reconcileLinkedAgents(ctx)],
|
|
36
31
|
["orphans", () => wakeOrphanedSessions(ctx, now)],
|
|
37
32
|
[
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Payload schemas: `@nylorun/core/contracts` (`parseTranscriptEvent`).
|
|
5
5
|
*/
|
|
6
6
|
import type { HostEffect } from "@nylorun/harness/run";
|
|
7
|
-
/** The model's tool call id and the harness invocation, for tool effects
|
|
7
|
+
/** The model's tool call id and the harness invocation, for tool effects. */
|
|
8
8
|
export declare function toolIds(context: unknown): {
|
|
9
9
|
callId: string;
|
|
10
10
|
invocationId: string;
|
|
@@ -75,7 +75,7 @@ export declare function modelFailed(request: HostEffect, value: unknown): {
|
|
|
75
75
|
message: string;
|
|
76
76
|
retryable: boolean;
|
|
77
77
|
} | undefined;
|
|
78
|
-
/** `tool.completed` for
|
|
78
|
+
/** `tool.completed` for a tool the Runtime ran: its output, or the tool error it reported. */
|
|
79
79
|
export declare function toolCompleted(request: HostEffect, value: unknown): {
|
|
80
80
|
agent: import("@nylorun/core/define").AgentRef;
|
|
81
81
|
error: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isModelFailureOutcome } from "@nylorun/core/define";
|
|
2
|
-
/** The model's tool call id and the harness invocation, for tool effects
|
|
2
|
+
/** The model's tool call id and the harness invocation, for tool effects. */
|
|
3
3
|
export function toolIds(context) {
|
|
4
4
|
const c = context;
|
|
5
5
|
return typeof c?.callId === "string" && typeof c.invocationId === "string"
|
|
@@ -91,7 +91,7 @@ export function modelFailed(request, value) {
|
|
|
91
91
|
...agentOf(request),
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
|
-
/** `tool.completed` for
|
|
94
|
+
/** `tool.completed` for a tool the Runtime ran: its output, or the tool error it reported. */
|
|
95
95
|
export function toolCompleted(request, value) {
|
|
96
96
|
const ids = toolIds(request.context);
|
|
97
97
|
if (!("callId" in ids))
|