@nylorun/runtime 0.17.0-beta → 0.19.1-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 +155 -0
- package/README.md +89 -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 +288 -63
- 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 +9372 -17030
- 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
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { type Action, type ActionOutcome, type DeliveryHeartbeatResponse, type EndpointPingResponse } from "@nylorun/core/contracts";
|
|
2
|
-
import type { DeliverResult } from "../execution/types.js";
|
|
3
|
-
import type { Tx } from "../store/types.js";
|
|
4
|
-
import { type Session, type TenantContext } from "./context.js";
|
|
5
|
-
import { type DeliveryScope } from "./delivery-token.js";
|
|
6
|
-
import type { OutboundResult } from "./outbound.js";
|
|
7
|
-
/**
|
|
8
|
-
* Offers an Action that just became `pending` to its agent's endpoint, after the transaction
|
|
9
|
-
* commits. Without an endpoint it waits for the agent's next registration (`PUT /v1/endpoints`).
|
|
10
|
-
*/
|
|
11
|
-
export declare function offerAction(t: Tx, ctx: Pick<TenantContext, "deliver">, action: Pick<Action, "actionId" | "agentId">): Promise<void>;
|
|
12
|
-
/** Delivers one Action (`WorkerHandlers.deliver`). Throws only on infrastructure errors. */
|
|
13
|
-
export declare function deliverAction(ctx: TenantContext, actionId: string, signal: AbortSignal): Promise<DeliverResult>;
|
|
14
|
-
type Settlement = {
|
|
15
|
-
kind: "outcome";
|
|
16
|
-
outcome: ActionOutcome;
|
|
17
|
-
} | {
|
|
18
|
-
kind: "accepted";
|
|
19
|
-
} | {
|
|
20
|
-
kind: "retry";
|
|
21
|
-
code: string;
|
|
22
|
-
message: string;
|
|
23
|
-
retryAfterMs?: number;
|
|
24
|
-
} | {
|
|
25
|
-
kind: "lost";
|
|
26
|
-
code: string;
|
|
27
|
-
message: string;
|
|
28
|
-
};
|
|
29
|
-
/** What an endpoint's answer means for the Action (design §5.2, §5.3). */
|
|
30
|
-
export declare function interpret(action: Action, result: OutboundResult): Settlement;
|
|
31
|
-
/**
|
|
32
|
-
* A delivery that may have reached the endpoint got no answer. A tool becomes `uncertain`, with
|
|
33
|
-
* its effect and its session. A hook,
|
|
34
|
-
* `fn` or `verify` is pure or repeat-safe and goes back to `pending`: delivered again right away
|
|
35
|
-
* (`after-commit`) or by the caller's retry (`retry`). Returns true when it will be delivered again.
|
|
36
|
-
*/
|
|
37
|
-
export declare function loseAction(t: Tx, ctx: Pick<TenantContext, "deliver">, s: Session, action: Action, options: {
|
|
38
|
-
redeliver: "after-commit" | "retry";
|
|
39
|
-
}): Promise<boolean>;
|
|
40
|
-
/**
|
|
41
|
-
* The sweep's part (design §7): deliveries whose deadline passed without an answer are lost,
|
|
42
|
-
* and pending Actions of agents with an endpoint are sent again, in case a send was lost
|
|
43
|
-
* between a commit and the execution. Returns how many deliveries it settled.
|
|
44
|
-
*/
|
|
45
|
-
export declare function sweepDeliveries(ctx: TenantContext, now?: Date): Promise<number>;
|
|
46
|
-
/**
|
|
47
|
-
* `POST /v1/endpoints/:agentId/ping`: a signed ping through the endpoint, so a wrong URL, a
|
|
48
|
-
* tunnel that is down or a handler serving other definitions shows up before the first turn.
|
|
49
|
-
*/
|
|
50
|
-
export declare function pingEndpoint(ctx: TenantContext, agentId: string): Promise<EndpointPingResponse>;
|
|
51
|
-
/**
|
|
52
|
-
* `POST /v1/actions/:id/heartbeat` with a delivery token: an endpoint that answered `202` keeps
|
|
53
|
-
* its delivery alive for another lease, and gets a fresh token for its next callbacks. `409`
|
|
54
|
-
* when the delivery was cancelled, lost or sent again, which tells the endpoint to stop.
|
|
55
|
-
*/
|
|
56
|
-
export declare function deliveryHeartbeat(ctx: TenantContext, scope: DeliveryScope, actionId: string): Promise<DeliveryHeartbeatResponse>;
|
|
57
|
-
/**
|
|
58
|
-
* `POST /v1/actions/:id/result` with a delivery token: the outcome of a delivery answered with
|
|
59
|
-
* `202`. The same result again returns the first receipt; a different one is `409`.
|
|
60
|
-
*/
|
|
61
|
-
export declare function deliveryResult(ctx: TenantContext, scope: DeliveryScope, actionId: string, outcome: ActionOutcome): Promise<Record<string, unknown>>;
|
|
62
|
-
export {};
|
package/dist/tenant/delivery.js
DELETED
|
@@ -1,481 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Action deliverer (design: Action endpoints §6, §7): sends a pending Action to its agent's
|
|
3
|
-
* Action endpoint and records what comes back, run by `DurableExecution.deliver` one delivery
|
|
4
|
-
* per Action at a time.
|
|
5
|
-
*
|
|
6
|
-
* 1. In one transaction, holding the session's lock: the Action must be `pending`, its turn
|
|
7
|
-
* active and its agent registered. Below the endpoint's `maxConcurrent`, it becomes
|
|
8
|
-
* `delivering`, its generation moves on, it gets a deadline, and `action.delivered` is
|
|
9
|
-
* written.
|
|
10
|
-
* 2. Outside any transaction: the body is signed with a delivery token and POSTed.
|
|
11
|
-
* 3. In a second transaction, only while the Action is still `delivering` at that generation:
|
|
12
|
-
* the answer becomes the outcome (`recordActionOutcome`, shared with background results), the
|
|
13
|
-
* Action goes back to `pending` to be tried again, or it is lost.
|
|
14
|
-
*
|
|
15
|
-
* Nothing sent (connection refused, unknown host, a refused address), `429`, `503` and a
|
|
16
|
-
* version mismatch (`409`) are retried with backoff, whatever the kind. A delivery that may have
|
|
17
|
-
* reached the endpoint but got no answer is lost: a tool becomes `uncertain`, a hook, `fn` or
|
|
18
|
-
* `verify` is delivered again. So is a delivery whose deadline passes with no answer, which is
|
|
19
|
-
* how a Worker that died mid-delivery is recovered (the sweep, `expireDeliveries`).
|
|
20
|
-
*/
|
|
21
|
-
import { OUTCOME_HEADER, PROTOCOL_HEADER, PROTOCOL_VERSION, SIGNATURE_HEADER, } from "@nylorun/core/compatibility";
|
|
22
|
-
import { ActionOutcomeSchema, EndpointPingResponseSchema, } from "@nylorun/core/contracts";
|
|
23
|
-
import { sessionHasSandbox } from "../sandbox/share.js";
|
|
24
|
-
import { canonical } from "../store/canonical.js";
|
|
25
|
-
import { scoped } from "./auth.js";
|
|
26
|
-
import { acceptedOutcome, recordActionOutcome } from "./commands.js";
|
|
27
|
-
import { sandboxLookup } from "./context.js";
|
|
28
|
-
import { mintDeliveryToken } from "./delivery-token.js";
|
|
29
|
-
import { fail } from "./http.js";
|
|
30
|
-
const DONE = { status: "done" };
|
|
31
|
-
/** Extra time past the endpoint's timeout before an unanswered delivery counts as lost. */
|
|
32
|
-
const DEADLINE_GRACE_MS = 5_000;
|
|
33
|
-
/** How long a delivery token outlives the request it signs. */
|
|
34
|
-
const TOKEN_SLACK_SECONDS = 60;
|
|
35
|
-
/** How soon a delivery refused by a full endpoint is tried again. */
|
|
36
|
-
const BUSY_RETRY_MS = 1_000;
|
|
37
|
-
const BACKOFF_FIRST_MS = 250;
|
|
38
|
-
const BACKOFF_MAX_MS = 30_000;
|
|
39
|
-
/** The longest `Retry-After` honoured. */
|
|
40
|
-
const RETRY_AFTER_MAX_MS = 5 * 60_000;
|
|
41
|
-
/** One `action.delivery_failed` per Action per this long. */
|
|
42
|
-
const NOTICE_INTERVAL_MS = 10_000;
|
|
43
|
-
/**
|
|
44
|
-
* Offers an Action that just became `pending` to its agent's endpoint, after the transaction
|
|
45
|
-
* commits. Without an endpoint it waits for the agent's next registration (`PUT /v1/endpoints`).
|
|
46
|
-
*/
|
|
47
|
-
export async function offerAction(t, ctx, action) {
|
|
48
|
-
if (await t.getEndpoint(action.agentId))
|
|
49
|
-
t.afterCommit(() => void ctx.deliver(action.actionId));
|
|
50
|
-
}
|
|
51
|
-
/** Delivers one Action (`WorkerHandlers.deliver`). Throws only on infrastructure errors. */
|
|
52
|
-
export async function deliverAction(ctx, actionId, signal) {
|
|
53
|
-
const started = await ctx.store.tx(async (t) => {
|
|
54
|
-
const found = await t.get("actions", actionId);
|
|
55
|
-
if (!found)
|
|
56
|
-
return { kind: "none" };
|
|
57
|
-
const s = await t.lockSession(found.sessionId);
|
|
58
|
-
// Read again under the session lock.
|
|
59
|
-
const action = await t.get("actions", actionId);
|
|
60
|
-
if (!action || !s)
|
|
61
|
-
return { kind: "none" };
|
|
62
|
-
if (action.status === "delivering") {
|
|
63
|
-
// In flight elsewhere, or answered with 202: its deadline settles it. Past the deadline
|
|
64
|
-
// (a Worker died mid-delivery), it is lost now.
|
|
65
|
-
if (Date.parse(action.deadlineAt ?? "") > Date.now())
|
|
66
|
-
return { kind: "none" };
|
|
67
|
-
await loseAction(t, ctx, s, action, { redeliver: "after-commit" });
|
|
68
|
-
return { kind: "none" };
|
|
69
|
-
}
|
|
70
|
-
if (action.status !== "pending" ||
|
|
71
|
-
s.status === "cancelled" ||
|
|
72
|
-
s.activeTurnId !== action.turnId)
|
|
73
|
-
return { kind: "none" };
|
|
74
|
-
const endpoint = await t.getEndpoint(action.agentId);
|
|
75
|
-
// No endpoint: it waits for the next registration.
|
|
76
|
-
if (!endpoint)
|
|
77
|
-
return { kind: "none" };
|
|
78
|
-
if ((await t.deliveringCount(action.agentId)) >= endpoint.maxConcurrent)
|
|
79
|
-
return { kind: "busy" };
|
|
80
|
-
action.status = "delivering";
|
|
81
|
-
action.generation += 1;
|
|
82
|
-
action.deadlineAt = new Date(Date.now() + endpoint.timeoutMs + DEADLINE_GRACE_MS).toISOString();
|
|
83
|
-
await t.put("actions", actionId, action);
|
|
84
|
-
await t.event(s.id, s.activeTurnId, "action.delivered", {
|
|
85
|
-
actionId,
|
|
86
|
-
generation: action.generation,
|
|
87
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
88
|
-
});
|
|
89
|
-
return {
|
|
90
|
-
kind: "deliver",
|
|
91
|
-
action: structuredClone(action),
|
|
92
|
-
endpoint,
|
|
93
|
-
sandbox: sessionHasSandbox(s, await sandboxLookup(t, s.sandboxOwnerId)),
|
|
94
|
-
};
|
|
95
|
-
});
|
|
96
|
-
if (started.kind === "none")
|
|
97
|
-
return DONE;
|
|
98
|
-
if (started.kind === "busy")
|
|
99
|
-
return { status: "retry", retryAfterMs: BUSY_RETRY_MS };
|
|
100
|
-
const { action, endpoint } = started;
|
|
101
|
-
const body = JSON.stringify({ type: "action", action, sandbox: started.sandbox });
|
|
102
|
-
const minted = await mintDeliveryToken(ctx, {
|
|
103
|
-
for: {
|
|
104
|
-
kind: "action",
|
|
105
|
-
actionId,
|
|
106
|
-
agentId: action.agentId,
|
|
107
|
-
generation: action.generation,
|
|
108
|
-
},
|
|
109
|
-
audience: endpoint.url,
|
|
110
|
-
body,
|
|
111
|
-
ttlSeconds: Math.ceil(endpoint.timeoutMs / 1000) + TOKEN_SLACK_SECONDS,
|
|
112
|
-
});
|
|
113
|
-
const cancel = new AbortController();
|
|
114
|
-
const inFlight = track(ctx, action.sessionId, cancel);
|
|
115
|
-
let result;
|
|
116
|
-
try {
|
|
117
|
-
// Through the Tool Gate (F4.1): the gates service POSTs it under its own address policy.
|
|
118
|
-
result = await ctx.toolGate.post({
|
|
119
|
-
url: endpoint.url,
|
|
120
|
-
body,
|
|
121
|
-
headers: {
|
|
122
|
-
[SIGNATURE_HEADER]: minted.token,
|
|
123
|
-
[PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
|
|
124
|
-
"idempotency-key": actionId,
|
|
125
|
-
},
|
|
126
|
-
timeoutMs: endpoint.timeoutMs,
|
|
127
|
-
}, AbortSignal.any([signal, cancel.signal, AbortSignal.timeout(endpoint.timeoutMs)]));
|
|
128
|
-
}
|
|
129
|
-
finally {
|
|
130
|
-
inFlight();
|
|
131
|
-
}
|
|
132
|
-
// A cancel already made the Action `uncertain`; a Worker that stops leaves it to its deadline.
|
|
133
|
-
if (cancel.signal.aborted || signal.aborted)
|
|
134
|
-
return DONE;
|
|
135
|
-
return settle(ctx, action, endpoint, result);
|
|
136
|
-
}
|
|
137
|
-
/** Registers a delivery under its session for `abortLocal`; the returned function removes it. */
|
|
138
|
-
function track(ctx, sessionId, controller) {
|
|
139
|
-
let set = ctx.work.deliveries.get(sessionId);
|
|
140
|
-
if (!set)
|
|
141
|
-
ctx.work.deliveries.set(sessionId, (set = new Set()));
|
|
142
|
-
set.add(controller);
|
|
143
|
-
return () => {
|
|
144
|
-
set.delete(controller);
|
|
145
|
-
if (set.size === 0 && ctx.work.deliveries.get(sessionId) === set)
|
|
146
|
-
ctx.work.deliveries.delete(sessionId);
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
/** What an endpoint's answer means for the Action (design §5.2, §5.3). */
|
|
150
|
-
export function interpret(action, result) {
|
|
151
|
-
if (result.kind === "not_sent")
|
|
152
|
-
return { kind: "retry", code: "endpoint.unreachable", message: result.message };
|
|
153
|
-
if (result.kind === "lost")
|
|
154
|
-
return { kind: "lost", code: "endpoint.no-answer", message: result.message };
|
|
155
|
-
if (result.kind === "too_large")
|
|
156
|
-
return rejected("endpoint.answer-too-large", "The endpoint's answer was too large");
|
|
157
|
-
const { status, headers, body } = result;
|
|
158
|
-
if (status === 202)
|
|
159
|
-
return { kind: "accepted" };
|
|
160
|
-
if (status === 429 || status === 503)
|
|
161
|
-
return {
|
|
162
|
-
kind: "retry",
|
|
163
|
-
code: status === 429 ? "endpoint.busy" : "endpoint.unavailable",
|
|
164
|
-
message: messageOf(body) ?? `The endpoint answered ${status}`,
|
|
165
|
-
...retryAfter(headers["retry-after"]),
|
|
166
|
-
};
|
|
167
|
-
if (status === 409)
|
|
168
|
-
return {
|
|
169
|
-
kind: "retry",
|
|
170
|
-
code: "endpoint.version-mismatch",
|
|
171
|
-
message: messageOf(body) ?? "The endpoint serves another version of the definition",
|
|
172
|
-
};
|
|
173
|
-
if (status >= 500)
|
|
174
|
-
return { kind: "lost", code: "endpoint.failed", message: messageOf(body) ?? `The endpoint answered ${status}` };
|
|
175
|
-
if (status !== 200)
|
|
176
|
-
return rejected("endpoint.rejected", messageOf(body) ?? `The endpoint answered ${status}`);
|
|
177
|
-
let value;
|
|
178
|
-
try {
|
|
179
|
-
value = JSON.parse(body.toString("utf8"));
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
return rejected("endpoint.invalid-answer", "The endpoint's answer is not JSON");
|
|
183
|
-
}
|
|
184
|
-
if (headers[OUTCOME_HEADER.toLowerCase()] === "1") {
|
|
185
|
-
const parsed = ActionOutcomeSchema.safeParse(value);
|
|
186
|
-
return parsed.success
|
|
187
|
-
? { kind: "outcome", outcome: parsed.data }
|
|
188
|
-
: rejected("endpoint.invalid-answer", "The endpoint's answer is not an Action outcome");
|
|
189
|
-
}
|
|
190
|
-
// A plain answer: a tool's output, or what an `fn` or `verify` returned.
|
|
191
|
-
if (action.kind === "tool")
|
|
192
|
-
return { kind: "outcome", outcome: { value: { kind: "completed", output: value } } };
|
|
193
|
-
if (action.kind === "fn" || action.kind === "verify")
|
|
194
|
-
return { kind: "outcome", outcome: { value } };
|
|
195
|
-
return rejected("endpoint.invalid-answer", `A ${action.kind} needs a tagged answer (${OUTCOME_HEADER}: 1)`);
|
|
196
|
-
}
|
|
197
|
-
function rejected(code, message) {
|
|
198
|
-
return { kind: "outcome", outcome: { value: { kind: "failed", code, message } } };
|
|
199
|
-
}
|
|
200
|
-
function messageOf(body) {
|
|
201
|
-
try {
|
|
202
|
-
const parsed = JSON.parse(body.toString("utf8"));
|
|
203
|
-
return typeof parsed.message === "string" ? parsed.message : undefined;
|
|
204
|
-
}
|
|
205
|
-
catch {
|
|
206
|
-
const text = body.toString("utf8").trim();
|
|
207
|
-
return text ? text.slice(0, 500) : undefined;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
function retryAfter(header) {
|
|
211
|
-
const value = Array.isArray(header) ? header[0] : header;
|
|
212
|
-
if (!value)
|
|
213
|
-
return {};
|
|
214
|
-
const seconds = Number(value);
|
|
215
|
-
const ms = Number.isFinite(seconds) ? seconds * 1000 : Date.parse(value) - Date.now();
|
|
216
|
-
return Number.isFinite(ms) && ms > 0 ? { retryAfterMs: Math.min(ms, RETRY_AFTER_MAX_MS) } : {};
|
|
217
|
-
}
|
|
218
|
-
/** Records the answer, in a transaction that still finds the Action at this delivery. */
|
|
219
|
-
async function settle(ctx, delivered, endpoint, result) {
|
|
220
|
-
const settlement = interpret(delivered, result);
|
|
221
|
-
const at = new Date().toISOString();
|
|
222
|
-
return ctx.store.tx(async (t) => {
|
|
223
|
-
const s = await t.lockSession(delivered.sessionId);
|
|
224
|
-
const action = await t.get("actions", delivered.actionId);
|
|
225
|
-
// A cancel, a deadline or another delivery settled it first.
|
|
226
|
-
if (!s ||
|
|
227
|
-
!action ||
|
|
228
|
-
action.status !== "delivering" ||
|
|
229
|
-
action.generation !== delivered.generation)
|
|
230
|
-
return DONE;
|
|
231
|
-
switch (settlement.kind) {
|
|
232
|
-
case "outcome": {
|
|
233
|
-
await t.recordEndpointHealth(endpoint.agentId, { kind: "success", at });
|
|
234
|
-
if (s.status === "cancelled" || s.activeTurnId !== action.turnId)
|
|
235
|
-
return DONE;
|
|
236
|
-
await recordActionOutcome(t, ctx, s, action, settlement.outcome);
|
|
237
|
-
await t.put("sessions", s.id, s);
|
|
238
|
-
return DONE;
|
|
239
|
-
}
|
|
240
|
-
case "accepted": {
|
|
241
|
-
// The endpoint answers later (`POST /v1/actions/:id/result`) and heartbeats meanwhile.
|
|
242
|
-
await t.recordEndpointHealth(endpoint.agentId, { kind: "success", at });
|
|
243
|
-
action.deadlineAt = new Date(Date.now() + (ctx.config.leaseMs ?? 30_000)).toISOString();
|
|
244
|
-
await t.put("actions", action.actionId, action);
|
|
245
|
-
return DONE;
|
|
246
|
-
}
|
|
247
|
-
case "retry": {
|
|
248
|
-
await t.recordEndpointHealth(endpoint.agentId, {
|
|
249
|
-
kind: "failure",
|
|
250
|
-
at,
|
|
251
|
-
code: settlement.code,
|
|
252
|
-
message: settlement.message,
|
|
253
|
-
});
|
|
254
|
-
action.status = "pending";
|
|
255
|
-
action.deadlineAt = null;
|
|
256
|
-
await t.put("actions", action.actionId, action);
|
|
257
|
-
const retryAfterMs = settlement.retryAfterMs ?? (await backoff(t, endpoint.agentId));
|
|
258
|
-
await notice(t, ctx, s, action, settlement, retryAfterMs);
|
|
259
|
-
return { status: "retry", retryAfterMs };
|
|
260
|
-
}
|
|
261
|
-
case "lost": {
|
|
262
|
-
await t.recordEndpointHealth(endpoint.agentId, {
|
|
263
|
-
kind: "failure",
|
|
264
|
-
at,
|
|
265
|
-
code: settlement.code,
|
|
266
|
-
message: settlement.message,
|
|
267
|
-
});
|
|
268
|
-
const again = await loseAction(t, ctx, s, action, { redeliver: "retry" });
|
|
269
|
-
if (!again)
|
|
270
|
-
return DONE;
|
|
271
|
-
const retryAfterMs = await backoff(t, endpoint.agentId);
|
|
272
|
-
await notice(t, ctx, s, action, settlement, retryAfterMs);
|
|
273
|
-
return { status: "retry", retryAfterMs };
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
/** Backoff from the endpoint's consecutive failures: 250 ms doubling to 30 s. */
|
|
279
|
-
async function backoff(t, agentId) {
|
|
280
|
-
const failures = (await t.getEndpoint(agentId))?.consecutiveFailures ?? 1;
|
|
281
|
-
return Math.min(BACKOFF_MAX_MS, BACKOFF_FIRST_MS * 2 ** Math.max(0, Math.min(failures - 1, 16)));
|
|
282
|
-
}
|
|
283
|
-
/** `action.delivery_failed`, at most once per Action per `NOTICE_INTERVAL_MS` on this process. */
|
|
284
|
-
async function notice(t, ctx, s, action, settlement, retryInMs) {
|
|
285
|
-
const last = ctx.work.deliveryNotices.get(action.actionId) ?? 0;
|
|
286
|
-
if (Date.now() - last < NOTICE_INTERVAL_MS)
|
|
287
|
-
return;
|
|
288
|
-
ctx.work.deliveryNotices.set(action.actionId, Date.now());
|
|
289
|
-
if (s.status === "cancelled" || s.activeTurnId !== action.turnId)
|
|
290
|
-
return;
|
|
291
|
-
await t.event(s.id, s.activeTurnId, "action.delivery_failed", {
|
|
292
|
-
actionId: action.actionId,
|
|
293
|
-
generation: action.generation,
|
|
294
|
-
reason: settlement.code,
|
|
295
|
-
message: settlement.message,
|
|
296
|
-
retryInMs,
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* A delivery that may have reached the endpoint got no answer. A tool becomes `uncertain`, with
|
|
301
|
-
* its effect and its session. A hook,
|
|
302
|
-
* `fn` or `verify` is pure or repeat-safe and goes back to `pending`: delivered again right away
|
|
303
|
-
* (`after-commit`) or by the caller's retry (`retry`). Returns true when it will be delivered again.
|
|
304
|
-
*/
|
|
305
|
-
export async function loseAction(t, ctx, s, action, options) {
|
|
306
|
-
if (action.kind === "hook" || action.kind === "fn" || action.kind === "verify") {
|
|
307
|
-
action.status = "pending";
|
|
308
|
-
action.deadlineAt = null;
|
|
309
|
-
await t.put("actions", action.actionId, action);
|
|
310
|
-
if (options.redeliver === "after-commit")
|
|
311
|
-
t.afterCommit(() => void ctx.deliver(action.actionId));
|
|
312
|
-
return options.redeliver === "retry";
|
|
313
|
-
}
|
|
314
|
-
action.status = "uncertain";
|
|
315
|
-
action.deadlineAt = null;
|
|
316
|
-
await t.put("actions", action.actionId, action);
|
|
317
|
-
const effect = await t.get("effects", action.actionId);
|
|
318
|
-
if (effect) {
|
|
319
|
-
effect.status = "uncertain";
|
|
320
|
-
await t.put("effects", action.actionId, effect);
|
|
321
|
-
}
|
|
322
|
-
if (s.status !== "cancelled" && s.activeTurnId === action.turnId) {
|
|
323
|
-
s.status = "uncertain";
|
|
324
|
-
await t.put("sessions", s.id, s);
|
|
325
|
-
await t.event(s.id, s.activeTurnId, "action.uncertain", {
|
|
326
|
-
actionId: action.actionId,
|
|
327
|
-
...(action.agent ? { agent: action.agent } : {}),
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* The sweep's part (design §7): deliveries whose deadline passed without an answer are lost,
|
|
334
|
-
* and pending Actions of agents with an endpoint are sent again, in case a send was lost
|
|
335
|
-
* between a commit and the execution. Returns how many deliveries it settled.
|
|
336
|
-
*/
|
|
337
|
-
export async function sweepDeliveries(ctx, now = new Date()) {
|
|
338
|
-
let settled = 0;
|
|
339
|
-
for (const expired of await ctx.store.tx((t) => t.expiredDeliveries(now, 100))) {
|
|
340
|
-
const changed = await ctx.store.tx(async (t) => {
|
|
341
|
-
const s = await t.lockSession(expired.sessionId);
|
|
342
|
-
const action = await t.get("actions", expired.actionId);
|
|
343
|
-
if (!s ||
|
|
344
|
-
!action ||
|
|
345
|
-
action.status !== "delivering" ||
|
|
346
|
-
Date.parse(action.deadlineAt ?? "") > now.getTime())
|
|
347
|
-
return false;
|
|
348
|
-
await loseAction(t, ctx, s, action, { redeliver: "after-commit" });
|
|
349
|
-
return true;
|
|
350
|
-
});
|
|
351
|
-
if (changed)
|
|
352
|
-
settled += 1;
|
|
353
|
-
}
|
|
354
|
-
for (const pending of await ctx.store.tx((t) => t.pendingActionsWithEndpoint(100)))
|
|
355
|
-
await ctx.deliver(pending.actionId);
|
|
356
|
-
return settled;
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* `POST /v1/endpoints/:agentId/ping`: a signed ping through the endpoint, so a wrong URL, a
|
|
360
|
-
* tunnel that is down or a handler serving other definitions shows up before the first turn.
|
|
361
|
-
*/
|
|
362
|
-
export async function pingEndpoint(ctx, agentId) {
|
|
363
|
-
const endpoint = (await ctx.store.tx((t) => t.getEndpoint(agentId))) ?? fail(404, "Endpoint not found");
|
|
364
|
-
const body = JSON.stringify({
|
|
365
|
-
type: "ping",
|
|
366
|
-
agentId,
|
|
367
|
-
...(endpoint.manifestHash === undefined ? {} : { manifestHash: endpoint.manifestHash }),
|
|
368
|
-
});
|
|
369
|
-
const minted = await mintDeliveryToken(ctx, {
|
|
370
|
-
for: { kind: "ping", agentId },
|
|
371
|
-
audience: endpoint.url,
|
|
372
|
-
body,
|
|
373
|
-
ttlSeconds: TOKEN_SLACK_SECONDS,
|
|
374
|
-
});
|
|
375
|
-
const timeoutMs = Math.min(endpoint.timeoutMs, 10_000);
|
|
376
|
-
const result = await ctx.toolGate.post({
|
|
377
|
-
url: endpoint.url,
|
|
378
|
-
body,
|
|
379
|
-
headers: { [SIGNATURE_HEADER]: minted.token, [PROTOCOL_HEADER]: String(PROTOCOL_VERSION) },
|
|
380
|
-
timeoutMs,
|
|
381
|
-
}, AbortSignal.timeout(timeoutMs));
|
|
382
|
-
const at = new Date().toISOString();
|
|
383
|
-
const refuse = async (code, message) => {
|
|
384
|
-
await ctx.store.tx((t) => t.recordEndpointHealth(agentId, { kind: "failure", at, code, message }));
|
|
385
|
-
return fail(502, `The endpoint did not answer the ping: ${message}`);
|
|
386
|
-
};
|
|
387
|
-
if (result.kind !== "response")
|
|
388
|
-
return refuse("endpoint.unreachable", result.kind === "too_large" ? "The answer was too large" : result.message);
|
|
389
|
-
if (result.status !== 200)
|
|
390
|
-
return refuse("endpoint.rejected", messageOf(result.body) ?? `The endpoint answered ${result.status}`);
|
|
391
|
-
let answer;
|
|
392
|
-
try {
|
|
393
|
-
answer = EndpointPingResponseSchema.parse(JSON.parse(result.body.toString("utf8")));
|
|
394
|
-
}
|
|
395
|
-
catch {
|
|
396
|
-
return refuse("endpoint.invalid-answer", "The endpoint's answer is not a ping answer");
|
|
397
|
-
}
|
|
398
|
-
if (answer.agentId !== agentId)
|
|
399
|
-
return refuse("endpoint.invalid-answer", `The endpoint answered for '${answer.agentId}'`);
|
|
400
|
-
await ctx.store.tx(async (t) => {
|
|
401
|
-
await t.recordEndpointHealth(agentId, { kind: "success", at });
|
|
402
|
-
await t.recordEndpointHealth(agentId, {
|
|
403
|
-
kind: "served",
|
|
404
|
-
implementationVersion: answer.implementationVersion,
|
|
405
|
-
...(answer.manifestHash === undefined ? {} : { manifestHash: answer.manifestHash }),
|
|
406
|
-
});
|
|
407
|
-
});
|
|
408
|
-
return answer;
|
|
409
|
-
}
|
|
410
|
-
const STALE_DELIVERY = "The delivery was cancelled, lost or delivered again";
|
|
411
|
-
/**
|
|
412
|
-
* The Action a delivery token's callback is about, read under its session's lock, and whether
|
|
413
|
-
* that delivery is still the live one: `delivering` at the token's generation, before its
|
|
414
|
-
* deadline, in the session's active turn.
|
|
415
|
-
*/
|
|
416
|
-
async function deliveredAction(t, scope, actionId) {
|
|
417
|
-
const found = (await t.get("actions", actionId)) ?? fail(404, "Action not found");
|
|
418
|
-
scoped(scope, found);
|
|
419
|
-
const s = (await t.lockSession(found.sessionId)) ?? fail(404, "Action not found");
|
|
420
|
-
const action = (await t.get("actions", actionId));
|
|
421
|
-
const live = action.status === "delivering" &&
|
|
422
|
-
action.generation === scope.generation &&
|
|
423
|
-
Date.parse(action.deadlineAt ?? "") > Date.now() &&
|
|
424
|
-
s.status !== "cancelled" &&
|
|
425
|
-
s.activeTurnId === action.turnId;
|
|
426
|
-
return { s, action, live };
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* `POST /v1/actions/:id/heartbeat` with a delivery token: an endpoint that answered `202` keeps
|
|
430
|
-
* its delivery alive for another lease, and gets a fresh token for its next callbacks. `409`
|
|
431
|
-
* when the delivery was cancelled, lost or sent again, which tells the endpoint to stop.
|
|
432
|
-
*/
|
|
433
|
-
export async function deliveryHeartbeat(ctx, scope, actionId) {
|
|
434
|
-
const leaseMs = ctx.config.leaseMs ?? 30_000;
|
|
435
|
-
const renewed = await ctx.store.tx(async (t) => {
|
|
436
|
-
const { action, live } = await deliveredAction(t, scope, actionId);
|
|
437
|
-
if (!live)
|
|
438
|
-
fail(409, STALE_DELIVERY);
|
|
439
|
-
action.deadlineAt = new Date(Date.now() + leaseMs).toISOString();
|
|
440
|
-
await t.put("actions", action.actionId, action);
|
|
441
|
-
return { action, endpoint: await t.getEndpoint(action.agentId) };
|
|
442
|
-
});
|
|
443
|
-
const minted = await mintDeliveryToken(ctx, {
|
|
444
|
-
for: {
|
|
445
|
-
kind: "action",
|
|
446
|
-
actionId,
|
|
447
|
-
agentId: renewed.action.agentId,
|
|
448
|
-
generation: renewed.action.generation,
|
|
449
|
-
},
|
|
450
|
-
audience: renewed.endpoint?.url ?? "",
|
|
451
|
-
body: "",
|
|
452
|
-
ttlSeconds: Math.ceil(leaseMs / 1000) + TOKEN_SLACK_SECONDS,
|
|
453
|
-
});
|
|
454
|
-
return { token: minted.token, deadlineAt: renewed.action.deadlineAt };
|
|
455
|
-
}
|
|
456
|
-
/**
|
|
457
|
-
* `POST /v1/actions/:id/result` with a delivery token: the outcome of a delivery answered with
|
|
458
|
-
* `202`. The same result again returns the first receipt; a different one is `409`.
|
|
459
|
-
*/
|
|
460
|
-
export async function deliveryResult(ctx, scope, actionId, outcome) {
|
|
461
|
-
return ctx.store.tx(async (t) => {
|
|
462
|
-
const { s, action, live } = await deliveredAction(t, scope, actionId);
|
|
463
|
-
if (action.status === "completed") {
|
|
464
|
-
const prior = await t.get("effects", actionId);
|
|
465
|
-
if (action.generation === scope.generation &&
|
|
466
|
-
prior?.receipt &&
|
|
467
|
-
canonical(prior.outcome) === canonical(acceptedOutcome(action, outcome)))
|
|
468
|
-
return prior.receipt;
|
|
469
|
-
return fail(409, "The Action already has another result");
|
|
470
|
-
}
|
|
471
|
-
if (!live)
|
|
472
|
-
return fail(409, STALE_DELIVERY);
|
|
473
|
-
const { receipt } = await recordActionOutcome(t, ctx, s, action, outcome);
|
|
474
|
-
await t.put("sessions", s.id, s);
|
|
475
|
-
await t.recordEndpointHealth(action.agentId, {
|
|
476
|
-
kind: "success",
|
|
477
|
-
at: new Date().toISOString(),
|
|
478
|
-
});
|
|
479
|
-
return receipt;
|
|
480
|
-
});
|
|
481
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Action endpoints (design: Action endpoints §4.2): where the Runtime delivers each agent's
|
|
3
|
-
* Actions, registered with the application key.
|
|
4
|
-
*/
|
|
5
|
-
import { type Endpoint, type PutEndpointsRequest } from "@nylorun/core/contracts";
|
|
6
|
-
import type { EndpointRow } from "../store/types.js";
|
|
7
|
-
import type { TenantContext } from "./context.js";
|
|
8
|
-
/** An endpoint as the Tenant API answers it. */
|
|
9
|
-
export declare function endpointView(row: EndpointRow): Endpoint;
|
|
10
|
-
/** `GET /v1/endpoints`. */
|
|
11
|
-
export declare function listEndpoints(ctx: TenantContext): Promise<{
|
|
12
|
-
endpoints: {
|
|
13
|
-
agentId: string;
|
|
14
|
-
url: string;
|
|
15
|
-
implementationVersion: string;
|
|
16
|
-
manifestHash?: string | undefined;
|
|
17
|
-
timeoutMs: number;
|
|
18
|
-
maxConcurrent: number;
|
|
19
|
-
health: {
|
|
20
|
-
lastDeliveryAt?: string | undefined;
|
|
21
|
-
lastSuccessAt?: string | undefined;
|
|
22
|
-
lastError?: {
|
|
23
|
-
code: string;
|
|
24
|
-
message: string;
|
|
25
|
-
} | undefined;
|
|
26
|
-
consecutiveFailures: number;
|
|
27
|
-
served?: {
|
|
28
|
-
implementationVersion: string;
|
|
29
|
-
manifestHash?: string | undefined;
|
|
30
|
-
} | undefined;
|
|
31
|
-
};
|
|
32
|
-
updatedAt: string;
|
|
33
|
-
}[];
|
|
34
|
-
}>;
|
|
35
|
-
/**
|
|
36
|
-
* `PUT /v1/endpoints`: upsert the batch in one transaction, then send the Actions already
|
|
37
|
-
* waiting for these agents. Answers every registered endpoint of the batch.
|
|
38
|
-
*/
|
|
39
|
-
export declare function putEndpoints(ctx: TenantContext, principalId: string, body: PutEndpointsRequest): Promise<{
|
|
40
|
-
endpoints: {
|
|
41
|
-
agentId: string;
|
|
42
|
-
url: string;
|
|
43
|
-
implementationVersion: string;
|
|
44
|
-
manifestHash?: string | undefined;
|
|
45
|
-
timeoutMs: number;
|
|
46
|
-
maxConcurrent: number;
|
|
47
|
-
health: {
|
|
48
|
-
lastDeliveryAt?: string | undefined;
|
|
49
|
-
lastSuccessAt?: string | undefined;
|
|
50
|
-
lastError?: {
|
|
51
|
-
code: string;
|
|
52
|
-
message: string;
|
|
53
|
-
} | undefined;
|
|
54
|
-
consecutiveFailures: number;
|
|
55
|
-
served?: {
|
|
56
|
-
implementationVersion: string;
|
|
57
|
-
manifestHash?: string | undefined;
|
|
58
|
-
} | undefined;
|
|
59
|
-
};
|
|
60
|
-
updatedAt: string;
|
|
61
|
-
}[];
|
|
62
|
-
}>;
|
|
63
|
-
/** `DELETE /v1/endpoints/:agentId`. The agent's pending Actions wait for a new endpoint. */
|
|
64
|
-
export declare function deleteEndpoint(ctx: TenantContext, agentId: string): Promise<{
|
|
65
|
-
agentId: string;
|
|
66
|
-
deleted: true;
|
|
67
|
-
}>;
|