@nylorun/runtime 0.51.2-beta → 0.52.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 +21 -0
- package/dist/api/components.d.ts +48 -0
- package/dist/api/components.js +3 -1
- package/dist/api/http/routes/triggers.js +38 -6
- package/dist/api/openapi.js +1 -0
- package/dist/management-openapi.json +2 -1
- package/dist/openapi.json +348 -44
- package/dist/store/postgres/drizzle/0049_agent_triggers_api.sql +3 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +7 -0
- package/dist/store/postgres/schema.d.ts +21 -4
- package/dist/store/postgres/schema.js +10 -7
- package/dist/tenant/agent-triggers.js +5 -2
- package/dist/tenant/api-triggers.d.ts +33 -0
- package/dist/tenant/api-triggers.js +140 -0
- package/dist/tenant/triggers.d.ts +6 -4
- package/dist/tenant/triggers.js +22 -11
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -249,11 +249,14 @@ export const agentTriggers = nylorun.table("agent_triggers", {
|
|
|
249
249
|
note: text(),
|
|
250
250
|
effectId: text(),
|
|
251
251
|
/**
|
|
252
|
-
* Where its definition comes from (D83): `manifest` (the version's `runtime.triggers`),
|
|
253
|
-
* `agent` (`definition`, made with the `triggers` tool)
|
|
252
|
+
* Where its definition comes from (D83, D88): `manifest` (the version's `runtime.triggers`),
|
|
253
|
+
* `agent` (`definition`, made with the `triggers` tool), `api` (`definition`, put by a client
|
|
254
|
+
* over the API) or `wake` (a booked wake).
|
|
254
255
|
*/
|
|
255
|
-
origin: text({ enum: ["manifest", "agent", "wake"] }).notNull().default("manifest"),
|
|
256
|
-
/**
|
|
256
|
+
origin: text({ enum: ["manifest", "agent", "api", "wake"] }).notNull().default("manifest"),
|
|
257
|
+
/** Who put an `api` trigger (D88): the caller's principal. */
|
|
258
|
+
principal: text(),
|
|
259
|
+
/** An agent-made or put trigger's title, its definition, and the session and turn that made it. */
|
|
257
260
|
title: text(),
|
|
258
261
|
definition: jsonText(),
|
|
259
262
|
createdSessionId: textC(),
|
|
@@ -261,7 +264,7 @@ export const agentTriggers = nylorun.table("agent_triggers", {
|
|
|
261
264
|
createdAt: textC().notNull(),
|
|
262
265
|
updatedAt: textC().notNull(),
|
|
263
266
|
}, (t) => [
|
|
264
|
-
check("agent_triggers_origin_check", sql `${t.origin} IN ('manifest', 'agent', 'wake')`),
|
|
267
|
+
check("agent_triggers_origin_check", sql `${t.origin} IN ('manifest', 'agent', 'api', 'wake')`),
|
|
265
268
|
primaryKey({ name: "agent_triggers_pkey", columns: [t.agentId, t.triggerId] }),
|
|
266
269
|
index("agent_triggers_created_session").on(t.agentId, t.createdSessionId).where(sql `created_session_id IS NOT NULL`),
|
|
267
270
|
index("agent_triggers_due").on(t.status, t.nextFireAt),
|
|
@@ -326,8 +329,8 @@ export const triggerRuns = nylorun.table("trigger_runs", {
|
|
|
326
329
|
sessionId: textC(),
|
|
327
330
|
turnId: textC(),
|
|
328
331
|
queuedMessageId: textC(),
|
|
329
|
-
/** Its trigger's origin and title when it ran (D83), for the runs stream after the trigger is gone. */
|
|
330
|
-
origin: text({ enum: ["manifest", "agent", "wake"] }).notNull().default("manifest"),
|
|
332
|
+
/** Its trigger's origin and title when it ran (D83, D88), for the runs stream after the trigger is gone. */
|
|
333
|
+
origin: text({ enum: ["manifest", "agent", "api", "wake"] }).notNull().default("manifest"),
|
|
331
334
|
title: text(),
|
|
332
335
|
/** When it was appended to the Tenant's `runs` stream (ISO), or null until then. */
|
|
333
336
|
streamedAt: textC(),
|
|
@@ -115,7 +115,7 @@ export async function serveTriggersTool(t, s, request) {
|
|
|
115
115
|
if (!row || !reaches(row, s.id))
|
|
116
116
|
return failed("tool.not-found", `This session has no trigger ${input.id}: list shows the ones it has.`);
|
|
117
117
|
await t.deleteAgentTrigger(s.agentId, input.id);
|
|
118
|
-
await t.agentEvent(s.agentId, "agent.trigger_deleted", { triggerId: input.id, sessionId: s.id });
|
|
118
|
+
await t.agentEvent(s.agentId, "agent.trigger_deleted", { triggerId: input.id, origin: "agent", sessionId: s.id });
|
|
119
119
|
return completed({ id: input.id, deleted: true });
|
|
120
120
|
}
|
|
121
121
|
// create: never from a turn a trigger or a booked wake started. Under the `nylorun-triggers`
|
|
@@ -153,7 +153,8 @@ export async function serveTriggersTool(t, s, request) {
|
|
|
153
153
|
const agent = await liveEnvironment(t, s.agentId);
|
|
154
154
|
const inForce = triggerLimitsInForce(runtime, agent?.applied?.limits);
|
|
155
155
|
if (!existing) {
|
|
156
|
-
|
|
156
|
+
// One count for every trigger not from the definition: the tool's and the API's (D88).
|
|
157
|
+
const made = (await t.agentTriggers(s.agentId)).filter((row) => originOf(row) === "agent" || originOf(row) === "api").length;
|
|
157
158
|
if (made >= inForce.count)
|
|
158
159
|
return failed("tool.limit", `This Agent has ${made} triggers, the most it can have. Delete one to add another.`);
|
|
159
160
|
}
|
|
@@ -176,6 +177,7 @@ export async function serveTriggersTool(t, s, request) {
|
|
|
176
177
|
note: null,
|
|
177
178
|
effectId: request.effectId,
|
|
178
179
|
origin: "agent",
|
|
180
|
+
principal: null,
|
|
179
181
|
title: input.title ?? null,
|
|
180
182
|
definition,
|
|
181
183
|
createdSessionId: s.id,
|
|
@@ -187,6 +189,7 @@ export async function serveTriggersTool(t, s, request) {
|
|
|
187
189
|
await t.agentEvent(s.agentId, existing ? "agent.trigger_updated" : "agent.trigger_created", {
|
|
188
190
|
triggerId: input.id,
|
|
189
191
|
kind: definition.schedule === undefined ? "at" : "schedule",
|
|
192
|
+
origin: "agent",
|
|
190
193
|
sessionId: s.id,
|
|
191
194
|
session,
|
|
192
195
|
...(row.title === null ? {} : { title: row.title }),
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Triggers a client puts on one Agent (D88): `PUT /v1/agents/{agentId}/triggers/{triggerId}` with
|
|
3
|
+
* a `Trigger`, exactly as a definition's `runtime.triggers` entry holds it, and an optional title.
|
|
4
|
+
*
|
|
5
|
+
* - **Origin `api`.** The row keeps its own definition, like an agent-made trigger (D83), and the
|
|
6
|
+
* principal that put it. Upgrades and moves never touch it (`mergeAgentTriggers` merges
|
|
7
|
+
* `manifest` rows only); `DELETE` removes it; pause, resume, run and a webhook's secret work as
|
|
8
|
+
* for any trigger; it fires through `fireTimer` and `deliverRun` like every other.
|
|
9
|
+
* - **Create or replace.** A new id makes it active with its next time. The same id replaces it:
|
|
10
|
+
* `generation` goes up and the next time is worked out again, so the timer armed for the old
|
|
11
|
+
* time does nothing. A paused one stays paused; an `at` that ran is active again at its new time.
|
|
12
|
+
* - **The same body again changes nothing** and records no event, so a client may put its desired
|
|
13
|
+
* state as often as it likes.
|
|
14
|
+
* - **Conflicts.** An id the definition declares, or a row of another origin holds, is
|
|
15
|
+
* `409 trigger_conflict`: the API never replaces a trigger it didn't put.
|
|
16
|
+
* - **Checks and limits.** Those a definition save runs (`triggerIssues`), against the limits in
|
|
17
|
+
* force; `count` covers the Agent's `agent` and `api` triggers together (`422 trigger_limit`).
|
|
18
|
+
* - **Events.** `agent.trigger_created` or `agent.trigger_updated` (with `changed`) on the Agent.
|
|
19
|
+
*
|
|
20
|
+
* One transaction with the Agent locked; the timer is armed after the commit.
|
|
21
|
+
*/
|
|
22
|
+
import { type Trigger, type TriggerPut, type TriggerView } from "@nylorun/core/contracts";
|
|
23
|
+
import type { TenantContext } from "./context.js";
|
|
24
|
+
/** The `Trigger` part of a put body, with only the fields it has. */
|
|
25
|
+
export declare function definitionOfPut(body: TriggerPut): Trigger;
|
|
26
|
+
/** The definition fields that differ between `before` and `after`, and `title` when it changed. */
|
|
27
|
+
export declare function changedFields(before: Trigger, after: Trigger, titleBefore: string | null, titleAfter: string | null): string[];
|
|
28
|
+
/**
|
|
29
|
+
* `PUT /v1/agents/{agentId}/triggers/{triggerId}` (D88): creates or replaces the Agent's `api`
|
|
30
|
+
* trigger `triggerId` and answers it as the list shows it. `principal` is who put it; `origin` is
|
|
31
|
+
* the URL origin the request reached, for a webhook's URL.
|
|
32
|
+
*/
|
|
33
|
+
export declare function putTrigger(ctx: TenantContext, agentId: string, triggerId: string, body: TriggerPut, principal: string | undefined, origin?: string): Promise<TriggerView>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Triggers a client puts on one Agent (D88): `PUT /v1/agents/{agentId}/triggers/{triggerId}` with
|
|
3
|
+
* a `Trigger`, exactly as a definition's `runtime.triggers` entry holds it, and an optional title.
|
|
4
|
+
*
|
|
5
|
+
* - **Origin `api`.** The row keeps its own definition, like an agent-made trigger (D83), and the
|
|
6
|
+
* principal that put it. Upgrades and moves never touch it (`mergeAgentTriggers` merges
|
|
7
|
+
* `manifest` rows only); `DELETE` removes it; pause, resume, run and a webhook's secret work as
|
|
8
|
+
* for any trigger; it fires through `fireTimer` and `deliverRun` like every other.
|
|
9
|
+
* - **Create or replace.** A new id makes it active with its next time. The same id replaces it:
|
|
10
|
+
* `generation` goes up and the next time is worked out again, so the timer armed for the old
|
|
11
|
+
* time does nothing. A paused one stays paused; an `at` that ran is active again at its new time.
|
|
12
|
+
* - **The same body again changes nothing** and records no event, so a client may put its desired
|
|
13
|
+
* state as often as it likes.
|
|
14
|
+
* - **Conflicts.** An id the definition declares, or a row of another origin holds, is
|
|
15
|
+
* `409 trigger_conflict`: the API never replaces a trigger it didn't put.
|
|
16
|
+
* - **Checks and limits.** Those a definition save runs (`triggerIssues`), against the limits in
|
|
17
|
+
* force; `count` covers the Agent's `agent` and `api` triggers together (`422 trigger_limit`).
|
|
18
|
+
* - **Events.** `agent.trigger_created` or `agent.trigger_updated` (with `changed`) on the Agent.
|
|
19
|
+
*
|
|
20
|
+
* One transaction with the Agent locked; the timer is armed after the commit.
|
|
21
|
+
*/
|
|
22
|
+
import { triggerKindOf } from "@nylorun/core/contracts";
|
|
23
|
+
import { liveEnvironment } from "./agents.js";
|
|
24
|
+
import { fail } from "./http.js";
|
|
25
|
+
import { triggerLimitsInForce } from "./limits.js";
|
|
26
|
+
import { readRuntimeLimits } from "./runtime-limits.js";
|
|
27
|
+
import { armTrigger, newEndpointId, nextFireAt, originOf, triggerIssues, triggersOf, triggerView } from "./triggers.js";
|
|
28
|
+
/** The definition fields a put compares, in a fixed order. */
|
|
29
|
+
const DEFINITION_FIELDS = ["schedule", "timezone", "at", "webhook", "session", "prompt"];
|
|
30
|
+
/** The `Trigger` part of a put body, with only the fields it has. */
|
|
31
|
+
export function definitionOfPut(body) {
|
|
32
|
+
const definition = {};
|
|
33
|
+
for (const field of DEFINITION_FIELDS)
|
|
34
|
+
if (body[field] !== undefined)
|
|
35
|
+
definition[field] = body[field];
|
|
36
|
+
return definition;
|
|
37
|
+
}
|
|
38
|
+
/** The definition fields that differ between `before` and `after`, and `title` when it changed. */
|
|
39
|
+
export function changedFields(before, after, titleBefore, titleAfter) {
|
|
40
|
+
const changed = DEFINITION_FIELDS.filter((field) => before[field] !== after[field]);
|
|
41
|
+
if (titleBefore !== titleAfter)
|
|
42
|
+
changed.push("title");
|
|
43
|
+
return changed;
|
|
44
|
+
}
|
|
45
|
+
/** The event payload's timing and session for `trigger`. */
|
|
46
|
+
function timingOf(trigger) {
|
|
47
|
+
return {
|
|
48
|
+
session: trigger.session,
|
|
49
|
+
...(trigger.schedule === undefined ? {} : { schedule: trigger.schedule, timezone: trigger.timezone ?? "UTC" }),
|
|
50
|
+
...(trigger.at === undefined ? {} : { at: trigger.at }),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* `PUT /v1/agents/{agentId}/triggers/{triggerId}` (D88): creates or replaces the Agent's `api`
|
|
55
|
+
* trigger `triggerId` and answers it as the list shows it. `principal` is who put it; `origin` is
|
|
56
|
+
* the URL origin the request reached, for a webhook's URL.
|
|
57
|
+
*/
|
|
58
|
+
export async function putTrigger(ctx, agentId, triggerId, body, principal, origin = "") {
|
|
59
|
+
const definition = definitionOfPut(body);
|
|
60
|
+
const title = body.title ?? null;
|
|
61
|
+
const { row, changed } = await ctx.store.tx(async (t) => {
|
|
62
|
+
const agent = (await liveEnvironment(t, agentId, { lock: true })) ?? fail(404, `Agent ${agentId} not found`, { code: "not_found" });
|
|
63
|
+
const existing = await t.agentTrigger(agentId, triggerId, { lock: true });
|
|
64
|
+
const declared = await triggersOf(t, agent);
|
|
65
|
+
const held = existing ? originOf(existing) : declared[triggerId] !== undefined ? "manifest" : undefined;
|
|
66
|
+
if (held !== undefined && held !== "api")
|
|
67
|
+
fail(409, held === "manifest"
|
|
68
|
+
? `Trigger ${triggerId} comes from the Agent's definition: put your trigger under another id.`
|
|
69
|
+
: held === "agent"
|
|
70
|
+
? `Trigger ${triggerId} was made by one of the Agent's agents: put your trigger under another id.`
|
|
71
|
+
: `${triggerId} is a session's booked wake: put your trigger under another id.`, { code: "trigger_conflict", details: { origin: held } });
|
|
72
|
+
const before = existing?.definition;
|
|
73
|
+
if (existing && before) {
|
|
74
|
+
const fields = changedFields(before, definition, existing.title, title);
|
|
75
|
+
// The same body again: nothing changes and nothing is recorded.
|
|
76
|
+
if (fields.length === 0)
|
|
77
|
+
return { row: existing, changed: undefined };
|
|
78
|
+
}
|
|
79
|
+
const now = new Date();
|
|
80
|
+
const stamp = now.toISOString();
|
|
81
|
+
const runtime = await readRuntimeLimits(t);
|
|
82
|
+
const inForce = triggerLimitsInForce(runtime, agent.applied?.limits);
|
|
83
|
+
if (!existing) {
|
|
84
|
+
// One count for every trigger not from the definition: the tool's and the API's.
|
|
85
|
+
const made = (await t.agentTriggers(agentId)).filter((other) => originOf(other) === "agent" || originOf(other) === "api").length;
|
|
86
|
+
if (made >= inForce.count)
|
|
87
|
+
fail(422, `Agent ${agentId} has ${made} triggers its agents or clients made, the most it can have (limits.triggers.count ${inForce.count}). Delete one to add another.`, {
|
|
88
|
+
code: "trigger_limit",
|
|
89
|
+
details: { limit: "triggers.count", max: inForce.count },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const issues = triggerIssues({ [triggerId]: definition }, { ...runtime, triggersPerAgent: inForce.count, triggerMinIntervalMs: inForce.minIntervalMs }, now, (id) => `trigger ${id}`);
|
|
93
|
+
if (issues.length > 0)
|
|
94
|
+
fail(400, issues.join(" "), { code: "invalid_request", details: { issues } });
|
|
95
|
+
const paused = existing?.status === "paused";
|
|
96
|
+
const next = paused ? null : nextFireAt(agentId, triggerId, definition, now, runtime);
|
|
97
|
+
const kind = triggerKindOf(definition);
|
|
98
|
+
const row = {
|
|
99
|
+
agentId,
|
|
100
|
+
triggerId,
|
|
101
|
+
kind,
|
|
102
|
+
// A webhook has no next time and stays active; an `at` with none has run.
|
|
103
|
+
status: paused ? "paused" : kind === "at" && next === null ? "completed" : "active",
|
|
104
|
+
pausedReason: paused ? existing.pausedReason : null,
|
|
105
|
+
generation: (existing?.generation ?? -1) + 1,
|
|
106
|
+
nextFireAt: next?.toISOString() ?? null,
|
|
107
|
+
lastFireAt: existing?.lastFireAt ?? null,
|
|
108
|
+
// A webhook keeps its endpoint and secret across replaces; another kind has none.
|
|
109
|
+
endpointId: kind === "webhook" ? (existing?.endpointId ?? newEndpointId()) : null,
|
|
110
|
+
sealedSecret: kind === "webhook" ? (existing?.sealedSecret ?? null) : null,
|
|
111
|
+
sessionId: null,
|
|
112
|
+
note: null,
|
|
113
|
+
effectId: null,
|
|
114
|
+
origin: "api",
|
|
115
|
+
principal: principal ?? existing?.principal ?? null,
|
|
116
|
+
title,
|
|
117
|
+
definition,
|
|
118
|
+
createdSessionId: null,
|
|
119
|
+
createdTurnId: null,
|
|
120
|
+
createdAt: existing?.createdAt ?? stamp,
|
|
121
|
+
updatedAt: stamp,
|
|
122
|
+
};
|
|
123
|
+
await t.putAgentTrigger(row);
|
|
124
|
+
const fields = existing && before ? changedFields(before, definition, existing.title, title) : undefined;
|
|
125
|
+
await t.agentEvent(agentId, existing ? "agent.trigger_updated" : "agent.trigger_created", {
|
|
126
|
+
triggerId,
|
|
127
|
+
kind,
|
|
128
|
+
origin: "api",
|
|
129
|
+
...(row.principal === null ? {} : { principal: row.principal }),
|
|
130
|
+
...timingOf(definition),
|
|
131
|
+
...(title === null ? {} : { title }),
|
|
132
|
+
...(fields === undefined ? {} : { changed: fields }),
|
|
133
|
+
nextRunAt: row.status === "active" ? row.nextFireAt : null,
|
|
134
|
+
});
|
|
135
|
+
return { row, changed: true };
|
|
136
|
+
});
|
|
137
|
+
if (changed)
|
|
138
|
+
await armTrigger(ctx, row);
|
|
139
|
+
return triggerView(row, definition, origin);
|
|
140
|
+
}
|
|
@@ -36,6 +36,8 @@ export declare function nextFireAt(agentId: string, triggerId: string, trigger:
|
|
|
36
36
|
export declare function triggerIssues(triggers: Readonly<Record<string, Trigger>> | undefined, limits: RuntimeLimits, now?: Date,
|
|
37
37
|
/** How an issue names trigger `id`: its place in the manifest by default. */
|
|
38
38
|
label?: (id: string) => string): string[];
|
|
39
|
+
/** The triggers of the manifest version an Agent runs. */
|
|
40
|
+
export declare function triggersOf(t: Tx, agent: Environment): Promise<Record<string, Trigger>>;
|
|
39
41
|
/**
|
|
40
42
|
* The line an agent-made trigger's run starts with under the `nylorun-triggers` plugin (ADR-106):
|
|
41
43
|
* which trigger woke the turn, and that nobody is watching.
|
|
@@ -45,7 +47,7 @@ export declare function triggerFrame(triggerId: string, title: string | null | u
|
|
|
45
47
|
export declare function originOf(row: Pick<AgentTriggerRow, "origin" | "kind">): AgentTriggerRow["origin"];
|
|
46
48
|
/**
|
|
47
49
|
* The definition trigger row `row` fires with (D83): a booked wake's, from its session and note;
|
|
48
|
-
* an agent-made trigger's own, from the row; a manifest trigger's, the entry of the version the
|
|
50
|
+
* an agent-made or put trigger's own, from the row (D88); a manifest trigger's, the entry of the version the
|
|
49
51
|
* Agent runs (`manifest`, read once by the caller). Undefined when it has none.
|
|
50
52
|
*/
|
|
51
53
|
export declare function definitionOf(row: AgentTriggerRow, manifest: Readonly<Record<string, Trigger>>): Trigger | undefined;
|
|
@@ -113,9 +115,9 @@ export declare function setTriggerStatus(ctx: TenantContext, agentId: string, tr
|
|
|
113
115
|
triggers: TriggerView[];
|
|
114
116
|
}>;
|
|
115
117
|
/**
|
|
116
|
-
* `DELETE /v1/agents/{id}/triggers/{triggerId}` (D83): deletes a trigger one of the Agent's
|
|
117
|
-
* made (origin `agent`), with `agent.trigger_deleted`. A
|
|
118
|
-
* (`409 trigger_from_manifest`); its runs stay.
|
|
118
|
+
* `DELETE /v1/agents/{id}/triggers/{triggerId}` (D83, D88): deletes a trigger one of the Agent's
|
|
119
|
+
* agents made (origin `agent`) or a client put (origin `api`), with `agent.trigger_deleted`. A
|
|
120
|
+
* manifest's is the manifest's to drop (`409 trigger_from_manifest`); its runs stay.
|
|
119
121
|
*/
|
|
120
122
|
export declare function deleteTrigger(ctx: TenantContext, agentId: string, triggerId: string, principal?: string): Promise<void>;
|
|
121
123
|
/**
|
package/dist/tenant/triggers.js
CHANGED
|
@@ -164,7 +164,7 @@ label = (id) => `runtime.triggers.${id}`) {
|
|
|
164
164
|
return issues;
|
|
165
165
|
}
|
|
166
166
|
/** The triggers of the manifest version an Agent runs. */
|
|
167
|
-
async function triggersOf(t, agent) {
|
|
167
|
+
export async function triggersOf(t, agent) {
|
|
168
168
|
return (await pinnedOf(t, agent)).triggers;
|
|
169
169
|
}
|
|
170
170
|
/** What the manifest version an Agent runs says of triggers: its own, and whether it declares the capability. */
|
|
@@ -192,7 +192,7 @@ export function originOf(row) {
|
|
|
192
192
|
}
|
|
193
193
|
/**
|
|
194
194
|
* The definition trigger row `row` fires with (D83): a booked wake's, from its session and note;
|
|
195
|
-
* an agent-made trigger's own, from the row; a manifest trigger's, the entry of the version the
|
|
195
|
+
* an agent-made or put trigger's own, from the row (D88); a manifest trigger's, the entry of the version the
|
|
196
196
|
* Agent runs (`manifest`, read once by the caller). Undefined when it has none.
|
|
197
197
|
*/
|
|
198
198
|
export function definitionOf(row, manifest) {
|
|
@@ -200,13 +200,14 @@ export function definitionOf(row, manifest) {
|
|
|
200
200
|
case "wake":
|
|
201
201
|
return wakeTriggerOf(row);
|
|
202
202
|
case "agent":
|
|
203
|
+
case "api":
|
|
203
204
|
return (row.definition ?? undefined);
|
|
204
205
|
default:
|
|
205
206
|
return manifest[row.triggerId];
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
209
|
/** The columns a row of origin `manifest` or `wake` leaves empty. */
|
|
209
|
-
const NO_AGENT_FIELDS = { title: null, definition: null, createdSessionId: null, createdTurnId: null };
|
|
210
|
+
const NO_AGENT_FIELDS = { title: null, definition: null, createdSessionId: null, createdTurnId: null, principal: null };
|
|
210
211
|
/**
|
|
211
212
|
* Writes the state of a new Agent's triggers (D74): every trigger of the version it is made from
|
|
212
213
|
* starts active, with its next time. Arm them after the commit (`armAgentTriggers`).
|
|
@@ -386,8 +387,8 @@ export async function fireTimer(ctx, key) {
|
|
|
386
387
|
const trigger = definitionOf(row, pinned.triggers);
|
|
387
388
|
if (!trigger) {
|
|
388
389
|
// A manifest's that the version no longer has, or a wake with nothing to say. An agent's
|
|
389
|
-
// row always holds its definition.
|
|
390
|
-
if (origin !== "agent")
|
|
390
|
+
// or a put row always holds its definition.
|
|
391
|
+
if (origin !== "agent" && origin !== "api")
|
|
391
392
|
await t.deleteAgentTrigger(agentId, triggerId);
|
|
392
393
|
return undefined;
|
|
393
394
|
}
|
|
@@ -593,6 +594,7 @@ export function triggerView(row, trigger, origin = "") {
|
|
|
593
594
|
origin: from,
|
|
594
595
|
title: row.title,
|
|
595
596
|
createdSessionId: row.createdSessionId,
|
|
597
|
+
principal: row.principal,
|
|
596
598
|
status: row.status,
|
|
597
599
|
pausedReason: row.pausedReason,
|
|
598
600
|
...(trigger.schedule === undefined ? {} : { schedule: trigger.schedule, timezone: trigger.timezone ?? "UTC" }),
|
|
@@ -652,7 +654,11 @@ export async function setTriggerStatus(ctx, agentId, triggerId, action, origin =
|
|
|
652
654
|
const next = nextFireAt(agentId, triggerId, trigger, now, await readRuntimeLimits(t));
|
|
653
655
|
// An `at` runs once: one that ran, or whose time passed, does not run again.
|
|
654
656
|
if (trigger.at !== undefined && (next === null || row.status === "completed"))
|
|
655
|
-
fail(409, `Trigger ${triggerId} was due at ${trigger.at} and does not run again: ${originOf(row) === "agent"
|
|
657
|
+
fail(409, `Trigger ${triggerId} was due at ${trigger.at} and does not run again: ${originOf(row) === "agent"
|
|
658
|
+
? "the agent creates it again with a new time"
|
|
659
|
+
: originOf(row) === "api"
|
|
660
|
+
? "put it again with a new time"
|
|
661
|
+
: "save a manifest version with a new time"}.`, { code: "trigger_expired" });
|
|
656
662
|
const updated = {
|
|
657
663
|
...row,
|
|
658
664
|
status: "active",
|
|
@@ -670,19 +676,24 @@ export async function setTriggerStatus(ctx, agentId, triggerId, action, origin =
|
|
|
670
676
|
return listTriggers(ctx, agentId, origin);
|
|
671
677
|
}
|
|
672
678
|
/**
|
|
673
|
-
* `DELETE /v1/agents/{id}/triggers/{triggerId}` (D83): deletes a trigger one of the Agent's
|
|
674
|
-
* made (origin `agent`), with `agent.trigger_deleted`. A
|
|
675
|
-
* (`409 trigger_from_manifest`); its runs stay.
|
|
679
|
+
* `DELETE /v1/agents/{id}/triggers/{triggerId}` (D83, D88): deletes a trigger one of the Agent's
|
|
680
|
+
* agents made (origin `agent`) or a client put (origin `api`), with `agent.trigger_deleted`. A
|
|
681
|
+
* manifest's is the manifest's to drop (`409 trigger_from_manifest`); its runs stay.
|
|
676
682
|
*/
|
|
677
683
|
export async function deleteTrigger(ctx, agentId, triggerId, principal) {
|
|
678
684
|
await ctx.store.tx(async (t) => {
|
|
679
685
|
const { row } = await lockedTrigger(t, agentId, triggerId);
|
|
680
|
-
|
|
686
|
+
const origin = originOf(row);
|
|
687
|
+
if (origin !== "agent" && origin !== "api")
|
|
681
688
|
fail(409, `Trigger ${triggerId} is declared by the Agent's manifest: save a version without it, or pause it.`, {
|
|
682
689
|
code: "trigger_from_manifest",
|
|
683
690
|
});
|
|
684
691
|
await t.deleteAgentTrigger(agentId, triggerId);
|
|
685
|
-
await t.agentEvent(agentId, "agent.trigger_deleted", {
|
|
692
|
+
await t.agentEvent(agentId, "agent.trigger_deleted", {
|
|
693
|
+
triggerId,
|
|
694
|
+
origin: origin,
|
|
695
|
+
...(principal === undefined ? {} : { principal }),
|
|
696
|
+
});
|
|
686
697
|
});
|
|
687
698
|
}
|
|
688
699
|
/**
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const RUNTIME_VERSION = "0.
|
|
1
|
+
export declare const RUNTIME_VERSION = "0.52.0-beta";
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// Kept in step with package.json by runtime/server/scripts/check-package.mjs, which runs in npm run check.
|
|
2
2
|
// release:prepare also rewrites this when it bumps @nylorun/runtime.
|
|
3
|
-
export const RUNTIME_VERSION = "0.
|
|
3
|
+
export const RUNTIME_VERSION = "0.52.0-beta";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.52.0-beta",
|
|
4
4
|
"description": "Nylorun Runtime: the agent execution Host on Postgres, Restate and S2, and model providers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"@hono/node-server": "^2.1.8",
|
|
66
66
|
"@hono/zod-openapi": "^1.6.3",
|
|
67
67
|
"@modelcontextprotocol/sdk": "^1.32.2",
|
|
68
|
-
"@nylorun/core": "0.
|
|
69
|
-
"@nylorun/harness": "0.36.
|
|
68
|
+
"@nylorun/core": "0.45.0-beta",
|
|
69
|
+
"@nylorun/harness": "0.36.5-beta",
|
|
70
70
|
"@restatedev/restate-sdk": "1.18.3",
|
|
71
71
|
"@restatedev/restate-sdk-clients": "1.18.3",
|
|
72
72
|
"@s2-dev/streamstore": "0.30.0",
|