@junejs/server 1.0.0-dev.29 → 1.0.0-dev.42

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.
Files changed (77) hide show
  1. package/dist/agent-compile.d.ts +8 -9
  2. package/dist/agent-discover.d.ts +3 -4
  3. package/dist/agent-durable.d.ts +38 -20
  4. package/dist/agent-durable.js +159 -13
  5. package/dist/agent-native.d.ts +15 -12
  6. package/dist/agent-native.js +72 -8
  7. package/dist/app.d.ts +4 -5
  8. package/dist/app.js +2 -1
  9. package/dist/blob.d.ts +4 -5
  10. package/dist/build.d.ts +6 -6
  11. package/dist/build.js +38 -7
  12. package/dist/client-bundle.d.ts +8 -9
  13. package/dist/{config-freeze-DwI-Rmvq.d.ts → config-freeze-ZWC_Qd4h.d.ts} +1 -1
  14. package/dist/config-freeze.d.ts +1 -1
  15. package/dist/config-loader.d.ts +3 -4
  16. package/dist/connection-auth.d.ts +8 -9
  17. package/dist/content.d.ts +9 -10
  18. package/dist/core-version.d.ts +3 -4
  19. package/dist/core-version.js +1 -1
  20. package/dist/css-modules-ambient.d.ts +2 -1
  21. package/dist/css-modules.d.ts +10 -11
  22. package/dist/css.d.ts +9 -10
  23. package/dist/d1-migrate.d.ts +6 -7
  24. package/dist/d1-migrate.js +3 -2
  25. package/dist/db.d.ts +2 -2
  26. package/dist/deploy.d.ts +3 -4
  27. package/dist/deploy.js +3 -2
  28. package/dist/dev-reload.d.ts +3 -4
  29. package/dist/dev.d.ts +4 -5
  30. package/dist/favicon.d.ts +16 -17
  31. package/dist/host.d.ts +5 -5
  32. package/dist/icon-letter.d.ts +2 -3
  33. package/dist/index.d.ts +4 -4
  34. package/dist/instrumentation.d.ts +2 -3
  35. package/dist/instrumentation.js +2 -1
  36. package/dist/island-registry.d.ts +6 -7
  37. package/dist/isolate-local.d.ts +4 -5
  38. package/dist/kv.d.ts +3 -4
  39. package/dist/llms-links.d.ts +8 -5
  40. package/dist/llms-links.js +31 -1
  41. package/dist/{manifest-gcNWqWoI.d.ts → manifest-DSNX4I-G.d.ts} +2 -2
  42. package/dist/manifest.d.ts +1 -1
  43. package/dist/negotiate.d.ts +4 -3
  44. package/dist/negotiate.js +24 -14
  45. package/dist/{pipeline-cCR6MGNK.d.ts → pipeline-BHUjBO0G.d.ts} +5 -1
  46. package/dist/pipeline.d.ts +2 -2
  47. package/dist/pipeline.js +260 -41
  48. package/dist/resources.d.ts +5 -6
  49. package/dist/router.d.ts +12 -13
  50. package/dist/rsc-build.d.ts +6 -7
  51. package/dist/rsc-bundle.d.ts +6 -7
  52. package/dist/rsc-manifest.d.ts +5 -6
  53. package/dist/rsc-runtime/flight-render-routes.d.ts +3 -4
  54. package/dist/rsc-runtime/flight-render.d.ts +2 -3
  55. package/dist/rsc-runtime/flight-to-html.d.ts +2 -3
  56. package/dist/rsc-runtime/flight-to-html.js +3 -2
  57. package/dist/rsc-runtime/rsdw-shims.d.ts +2 -1
  58. package/dist/segment.d.ts +4 -5
  59. package/dist/sqlite-driver.d.ts +10 -11
  60. package/dist/static-files.d.ts +4 -5
  61. package/dist/tsconfig-jsx.d.ts +4 -5
  62. package/dist/turn-events.d.ts +2 -3
  63. package/dist/web-manifest.d.ts +3 -4
  64. package/dist/web-manifest.js +2 -6
  65. package/dist/{worker-BkFHGtxp.d.ts → worker-Dv4l6Ybs.d.ts} +4 -2
  66. package/dist/worker.d.ts +1 -1
  67. package/dist/worker.js +35 -18
  68. package/package.json +5 -5
  69. package/src/agent-durable.ts +203 -21
  70. package/src/agent-native.ts +94 -7
  71. package/src/build.ts +67 -5
  72. package/src/core-version.ts +1 -1
  73. package/src/llms-links.ts +46 -1
  74. package/src/negotiate.ts +39 -15
  75. package/src/pipeline.ts +433 -45
  76. package/src/web-manifest.ts +2 -6
  77. package/src/worker.ts +55 -17
@@ -1,6 +1,6 @@
1
1
  //#region src/agent-compile.d.ts
2
- declare const AGENT_MODULE_FILE = "_agent.gen.ts";
3
- type AgentDirScan = {
2
+ export declare const AGENT_MODULE_FILE = "_agent.gen.ts";
3
+ export type AgentDirScan = {
4
4
  dir: string;
5
5
  name: string;
6
6
  hasConfig: boolean;
@@ -21,13 +21,13 @@ type AgentDirScan = {
21
21
  }[];
22
22
  connections: string[];
23
23
  };
24
- declare function scanAgentDir(dir: string): AgentDirScan | null;
25
- type EmitOptions = {
24
+ export declare function scanAgentDir(dir: string): AgentDirScan | null;
25
+ export type EmitOptions = {
26
26
  tsExtensions?: boolean;
27
27
  };
28
- declare function emitAgentModule(scan: AgentDirScan, opts?: EmitOptions): string;
29
- declare function findAgentDir(root: string, dirName?: string): string | null;
30
- declare function generateAgentModule(dir: string, opts?: {
28
+ export declare function emitAgentModule(scan: AgentDirScan, opts?: EmitOptions): string;
29
+ export declare function findAgentDir(root: string, dirName?: string): string | null;
30
+ export declare function generateAgentModule(dir: string, opts?: {
31
31
  check?: boolean;
32
32
  } & EmitOptions): {
33
33
  file: string;
@@ -35,5 +35,4 @@ declare function generateAgentModule(dir: string, opts?: {
35
35
  stale: boolean;
36
36
  written: boolean;
37
37
  } | null;
38
- //#endregion
39
- export { AGENT_MODULE_FILE, AgentDirScan, EmitOptions, emitAgentModule, findAgentDir, generateAgentModule, scanAgentDir };
38
+ //#endregion
@@ -1,6 +1,5 @@
1
1
  import { AgentDefinition, AgentModule } from "@junejs/core/agent-config";
2
2
  //#region src/agent-discover.d.ts
3
- declare function discoverAgentModule(dir: string): Promise<AgentModule>;
4
- declare function discoverAgent(dir: string): Promise<AgentDefinition>;
5
- //#endregion
6
- export { discoverAgent, discoverAgentModule };
3
+ export declare function discoverAgentModule(dir: string): Promise<AgentModule>;
4
+ export declare function discoverAgent(dir: string): Promise<AgentDefinition>;
5
+ //#endregion
@@ -1,31 +1,32 @@
1
1
  import { Channel, ChannelFactory } from "@junejs/core/agent-config";
2
- import { ChannelPolicy, InboundEvent, Model, Msg, ProactiveTrigger, SessionStore, Tool, TurnError, TurnEvent, TurnFailurePhase } from "@junejs/core/agent-runtime";
2
+ import { AuthorizeAnswer, ChannelPolicy, InboundEvent, InputAnnouncement, Model, Msg, NoteKind, ProactiveTrigger, SessionStore, Tool, TurnError, TurnEvent, TurnFailurePhase } from "@junejs/core/agent-runtime";
3
3
  import { Connection } from "@junejs/core/connections";
4
4
  import { Resources } from "@junejs/core/resources";
5
5
  //#region src/agent-durable.d.ts
6
- type SqlStorageValue = ArrayBuffer | string | number | null;
7
- interface SqlStorageCursor<T extends Record<string, SqlStorageValue> = Record<string, SqlStorageValue>> {
6
+ export type SqlStorageValue = ArrayBuffer | string | number | null;
7
+ export interface SqlStorageCursor<T extends Record<string, SqlStorageValue> = Record<string, SqlStorageValue>> {
8
8
  toArray(): T[];
9
9
  one(): T;
10
10
  }
11
- interface SqlStorage {
11
+ export interface SqlStorage {
12
12
  exec<T extends Record<string, SqlStorageValue> = Record<string, SqlStorageValue>>(query: string, ...bindings: unknown[]): SqlStorageCursor<T>;
13
13
  }
14
- interface DurableStorage {
14
+ export interface DurableStorage {
15
15
  sql: SqlStorage;
16
16
  transactionSync<T>(fn: () => T): T;
17
+ setAlarm?(scheduledTime: number): unknown;
17
18
  }
18
- interface DurableObjectState {
19
+ export interface DurableObjectState {
19
20
  storage: DurableStorage;
20
21
  }
21
- interface DurableObjectStub {
22
+ export interface DurableObjectStub {
22
23
  fetch(request: Request): Promise<Response>;
23
24
  }
24
- interface DurableObjectNamespace {
25
+ export interface DurableObjectNamespace {
25
26
  idFromName(name: string): unknown;
26
27
  get(id: unknown): DurableObjectStub;
27
28
  }
28
- declare class DoSessionStore implements SessionStore {
29
+ export declare class DoSessionStore implements SessionStore {
29
30
  private readonly storage;
30
31
  constructor(storage: DurableStorage);
31
32
  private get sql();
@@ -40,10 +41,10 @@ declare class DoSessionStore implements SessionStore {
40
41
  getSessionKey(): string | undefined;
41
42
  setSessionKey(key: string): void;
42
43
  tx<T>(fn: () => T): T;
43
- reset(): number;
44
+ reset(inTx?: () => void): number;
44
45
  unwrap<H = unknown>(): H;
45
46
  }
46
- type DoAgentDef = {
47
+ export type DoAgentDef = {
47
48
  name?: string;
48
49
  model: Model;
49
50
  tools: Tool[];
@@ -60,8 +61,10 @@ type DoAgentDef = {
60
61
  phase?: TurnFailurePhase;
61
62
  step?: string;
62
63
  }) => void | Promise<void>;
64
+ authorizeAnswer?: AuthorizeAnswer;
65
+ onInputAnnouncement?: (a: InputAnnouncement) => void | Promise<void>;
63
66
  };
64
- declare class AgentDurableObject {
67
+ export declare class AgentDurableObject {
65
68
  private session;
66
69
  private sessionKey;
67
70
  private readonly name;
@@ -77,11 +80,19 @@ declare class AgentDurableObject {
77
80
  private connectionsOpened;
78
81
  private readonly doEnv;
79
82
  private readonly services;
83
+ private readonly authorizeAnswer?;
84
+ private readonly onInputAnnouncement?;
85
+ private readonly storage;
86
+ private announceFailures;
80
87
  private resolveResources;
81
88
  private resolveConnections;
82
89
  private ready;
83
90
  constructor(state: DurableObjectState, def: DoAgentDef);
84
91
  private resolveSession;
92
+ alarm(): Promise<void>;
93
+ private armWatchdog;
94
+ private scheduleAlarm;
95
+ private deliverHeld;
85
96
  turn(input: {
86
97
  turnId?: string;
87
98
  userText: string;
@@ -98,6 +109,14 @@ declare class AgentDurableObject {
98
109
  }): Promise<{
99
110
  turnId: string;
100
111
  }>;
112
+ note(input: {
113
+ by: string;
114
+ kind: NoteKind;
115
+ text: string;
116
+ session?: string;
117
+ }): Promise<{
118
+ noteId: string;
119
+ }>;
101
120
  reset(opts?: {
102
121
  session?: string;
103
122
  }): Promise<{
@@ -107,20 +126,19 @@ declare class AgentDurableObject {
107
126
  transcript(): import("@junejs/core/agent-runtime").Turn[];
108
127
  fetch(req: Request): Promise<Response>;
109
128
  }
110
- declare function sseTurnFinalText(res: Response): Promise<string>;
111
- declare function sseTurnEvents(res: Response): AsyncIterable<TurnEvent>;
112
- declare const SESSION_HEADER = "x-june-session";
113
- declare function durableFetch(namespace: DurableObjectNamespace, agent: string, session: string, req: Request): Promise<Response>;
114
- declare function durableAgentSurface(getNamespace: () => DurableObjectNamespace | undefined, opts: {
129
+ export declare function sseTurnFinalText(res: Response): Promise<string>;
130
+ export declare function sseTurnEvents(res: Response): AsyncIterable<TurnEvent>;
131
+ export declare const SESSION_HEADER = "x-june-session";
132
+ export declare function durableFetch(namespace: DurableObjectNamespace, agent: string, session: string, req: Request): Promise<Response>;
133
+ export declare function durableAgentSurface(getNamespace: () => DurableObjectNamespace | undefined, opts: {
115
134
  agentName: string;
116
135
  chatPath?: string;
117
136
  }): (req: Request) => Promise<Response | null>;
118
- declare function durableChannelSurface(getNamespace: () => DurableObjectNamespace | undefined, opts: {
137
+ export declare function durableChannelSurface(getNamespace: () => DurableObjectNamespace | undefined, opts: {
119
138
  agentName: string;
120
139
  channels: (Channel | ChannelFactory)[];
121
140
  env: unknown;
122
141
  services?: (env: unknown) => unknown;
123
142
  waitUntil?: (p: Promise<unknown>) => void;
124
143
  }): (req: Request) => Promise<Response | null>;
125
- //#endregion
126
- export { AgentDurableObject, DoAgentDef, DoSessionStore, DurableObjectNamespace, DurableObjectState, DurableObjectStub, DurableStorage, SESSION_HEADER, SqlStorage, SqlStorageCursor, SqlStorageValue, durableAgentSurface, durableChannelSurface, durableFetch, sseTurnEvents, sseTurnFinalText };
144
+ //#endregion
@@ -2,7 +2,7 @@ import { observeTurnEvents } from "./turn-events.js";
2
2
  import { isolateLocal } from "./isolate-local.js";
3
3
  import { assertCoreRuntimeVersion } from "./core-version.js";
4
4
  import { DeliverUnsupportedError, actionToTool, channelDispatch, resolveChannel } from "@junejs/core/agent-config";
5
- import { AgentSession, ResumeAuthorizationError, withSystem } from "@junejs/core/agent-runtime";
5
+ import { AgentSession, ResumeAuthorizationError, grantAnswer, withSystem } from "@junejs/core/agent-runtime";
6
6
  import { connectAll } from "@junejs/core/connections";
7
7
  import { ensureScope, runInScope } from "@junejs/db";
8
8
  //#region src/agent-durable.ts
@@ -54,7 +54,7 @@ var DoSessionStore = class {
54
54
  tx(fn) {
55
55
  return this.storage.transactionSync(fn);
56
56
  }
57
- reset() {
57
+ reset(inTx) {
58
58
  return this.storage.transactionSync(() => {
59
59
  const sql = this.sql;
60
60
  sql.exec(`CREATE TABLE IF NOT EXISTS agent_messages_archive (generation INTEGER, seq INTEGER, body TEXT)`);
@@ -67,6 +67,7 @@ var DoSessionStore = class {
67
67
  sql.exec("DELETE FROM agent_steps");
68
68
  this.setStatus("new");
69
69
  sql.exec("INSERT INTO agent_meta (k, v) VALUES ('generation', ?) ON CONFLICT(k) DO UPDATE SET v = ?", String(generation + 1), String(generation + 1));
70
+ inTx?.();
70
71
  return generation;
71
72
  });
72
73
  }
@@ -107,6 +108,10 @@ var AgentDurableObject = class {
107
108
  connectionsOpened;
108
109
  doEnv;
109
110
  services;
111
+ authorizeAnswer;
112
+ onInputAnnouncement;
113
+ storage;
114
+ announceFailures = 0;
110
115
  resolveResources() {
111
116
  return this.resourcesOpened ??= Promise.resolve(typeof this.resourcesInput === "function" ? this.resourcesInput(this.doEnv) : this.resourcesInput ?? {});
112
117
  }
@@ -136,8 +141,14 @@ var AgentDurableObject = class {
136
141
  this.connectionsInput = def.connections;
137
142
  this.doEnv = def.env;
138
143
  this.services = def.services;
144
+ this.authorizeAnswer = def.authorizeAnswer;
145
+ this.onInputAnnouncement = def.onInputAnnouncement;
146
+ this.storage = state.storage;
139
147
  const name = def.name ?? "agent";
140
148
  const sink = new InProcEventSink();
149
+ sink.subscribe((e) => {
150
+ if (e.type === "turn.started") this.armWatchdog();
151
+ });
141
152
  sink.subscribe((e) => {
142
153
  if (e.type !== "turn.failed") return;
143
154
  const defaultLog = () => console.error(`[june] agent "${name}" turn ${e.turnId} failed${e.step ? ` at ${e.step}` : ""}: ${e.error.stack ?? e.error.message}${e.error.causeChain?.length ? `\ncaused by: ${e.error.causeChain.join(" ← ")}` : ""}`);
@@ -191,8 +202,71 @@ var AgentDurableObject = class {
191
202
  if (key !== void 0 && key !== "self" && stored === void 0) this.store.setSessionKey(key);
192
203
  this.sessionKey = resolved;
193
204
  this.session = new AgentSession(this.name, resolved, this.store, this.sink, this.model, this.tools, crossDoUnsupported, this.channelInstructions);
205
+ this.session.onDequeue = (heldTurnId, held) => {
206
+ if (held.hostContext?.deliver && held.event) this.deliverHeld(this.session, heldTurnId, held.event);
207
+ };
208
+ const announce = this.onInputAnnouncement;
209
+ if (announce) {
210
+ this.session.onAnnounce = async (a) => {
211
+ await ensureScope();
212
+ const resources = await this.ready();
213
+ try {
214
+ await runInScope({
215
+ resources,
216
+ services: this.services
217
+ }, () => announce(a));
218
+ } catch (err) {
219
+ this.scheduleAlarm(Math.min(5e3 * 2 ** this.announceFailures, 3e5));
220
+ this.announceFailures++;
221
+ throw err;
222
+ }
223
+ this.announceFailures = 0;
224
+ };
225
+ this.session.flushAnnouncements();
226
+ }
194
227
  return this.session;
195
228
  }
229
+ async alarm() {
230
+ if (!this.onInputAnnouncement) return;
231
+ await this.resolveSession().flushAnnouncements();
232
+ }
233
+ armWatchdog() {
234
+ if (this.onInputAnnouncement) this.scheduleAlarm(6e4);
235
+ }
236
+ scheduleAlarm(inMs) {
237
+ const failed = (err) => console.error(`[june] agent "${this.name}": could not schedule the announcement alarm — delivery waits for the next announcement, turn or rebuild:`, err);
238
+ try {
239
+ Promise.resolve(this.storage.setAlarm?.(Date.now() + inMs)).catch(failed);
240
+ } catch (err) {
241
+ failed(err);
242
+ }
243
+ }
244
+ deliverHeld(session, turnId, event) {
245
+ const logRenderFailure = (err) => console.error(`[june] agent "${this.name}": delivered render for held turn ${turnId} failed:`, err);
246
+ try {
247
+ const channel = this.channels.find((c) => c.name === event.source);
248
+ if (!channel?.deliver) {
249
+ logRenderFailure(/* @__PURE__ */ new Error(`no deliver()-capable channel named "${event.source}" is wired into this DO — the held turn runs, but its reply is not rendered`));
250
+ return;
251
+ }
252
+ const it = observeTurnEvents(session, turnId)[Symbol.asyncIterator]();
253
+ const events = { [Symbol.asyncIterator]: () => it };
254
+ const target = {
255
+ channelId: event.channelId,
256
+ threadId: event.threadId,
257
+ recipientUserId: event.user?.id,
258
+ recipientTeamId: event.teamId
259
+ };
260
+ this.ready().then((resources) => runInScope({
261
+ resources,
262
+ services: this.services
263
+ }, () => channel.deliver(target, events, { session: this.sessionKey }))).catch(logRenderFailure).finally(() => {
264
+ it.return?.();
265
+ });
266
+ } catch (err) {
267
+ logRenderFailure(err);
268
+ }
269
+ }
196
270
  async turn(input) {
197
271
  await ensureScope();
198
272
  const resources = await this.ready();
@@ -211,8 +285,14 @@ var AgentDurableObject = class {
211
285
  services: this.services
212
286
  }, () => session.start(input));
213
287
  }
288
+ note(input) {
289
+ const { session, ...note } = input;
290
+ return this.resolveSession(session).note(note);
291
+ }
214
292
  reset(opts) {
215
- return this.resolveSession(opts?.session).reset();
293
+ const session = this.resolveSession(opts?.session);
294
+ this.armWatchdog();
295
+ return session.reset();
216
296
  }
217
297
  transcript() {
218
298
  if (this.session) return this.session.transcript();
@@ -223,10 +303,13 @@ var AgentDurableObject = class {
223
303
  const url = new URL(req.url);
224
304
  const key = req.headers.get("x-june-session") ?? void 0;
225
305
  if (req.method === "POST" && url.pathname.endsWith("/turn")) {
226
- const { userText, turnId, event, trigger } = await req.json();
306
+ const { userText, turnId, event, trigger, ifSuspended } = await req.json();
227
307
  await ensureScope();
228
308
  const replace = url.searchParams.get("replace") === "1";
229
309
  const wantsDeliver = url.searchParams.get("deliver") === "1";
310
+ const detached = url.searchParams.get("detach") === "1";
311
+ if (ifSuspended === "queue" && !wantsDeliver && !detached) return Response.json({ error: `ifSuspended "queue" needs deliver=1 or detach=1: a held turn runs later, when no one is streaming it` }, { status: 400 });
312
+ if (ifSuspended === "queue" && replace) return Response.json({ error: `ifSuspended "queue" and replace=1 cannot be combined — replacing would drop held turns that were accepted` }, { status: 400 });
230
313
  let deliverChannel;
231
314
  if (wantsDeliver) {
232
315
  if (!event?.channelId) return Response.json({ error: "deliver=1 needs an inbound event (event.channelId names the reply target)" }, { status: 400 });
@@ -238,6 +321,7 @@ var AgentDurableObject = class {
238
321
  let started;
239
322
  try {
240
323
  session = this.resolveSession(key);
324
+ this.armWatchdog();
241
325
  started = runInScope({
242
326
  resources,
243
327
  services: this.services
@@ -246,11 +330,17 @@ var AgentDurableObject = class {
246
330
  turnId,
247
331
  event,
248
332
  trigger,
249
- replace
333
+ replace,
334
+ ifSuspended,
335
+ hostContext: wantsDeliver ? { deliver: true } : void 0
250
336
  }));
251
337
  } catch (err) {
252
338
  return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
253
339
  }
340
+ if (started.queued) return Response.json({
341
+ turnId: started.turnId,
342
+ queued: true
343
+ }, { status: 202 });
254
344
  if (wantsDeliver) {
255
345
  const logRenderFailure = (err) => console.error(`[june] agent "${this.name}": delivered render for turn ${started.turnId} failed:`, err);
256
346
  try {
@@ -273,11 +363,11 @@ var AgentDurableObject = class {
273
363
  }
274
364
  return Response.json({ turnId: started.turnId }, { status: 202 });
275
365
  }
276
- if (url.searchParams.get("detach") === "1") return Response.json({ turnId: started.turnId }, { status: 202 });
366
+ if (detached) return Response.json({ turnId: started.turnId }, { status: 202 });
277
367
  return new Response(sseTurnStream(session, started.turnId), { headers: SSE_HEADERS });
278
368
  }
279
369
  if (req.method === "POST" && url.pathname.endsWith("/resume")) {
280
- const { turnId, inputId, input, by, source, target } = await req.json();
370
+ const { turnId, inputId, input, by, principal, source, target } = await req.json();
281
371
  await ensureScope();
282
372
  const wantsDeliver = url.searchParams.get("deliver") === "1";
283
373
  let resumeChannel;
@@ -290,10 +380,33 @@ var AgentDurableObject = class {
290
380
  let session;
291
381
  try {
292
382
  session = this.resolveSession(key);
383
+ } catch (err) {
384
+ return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
385
+ }
386
+ let granted;
387
+ try {
388
+ granted = await runInScope({
389
+ resources,
390
+ services: this.services
391
+ }, () => grantAnswer(session, {
392
+ turnId,
393
+ inputId,
394
+ by,
395
+ principal
396
+ }, this.authorizeAnswer));
397
+ } catch (err) {
398
+ console.error(`[june] agent "${this.name}": authorizeAnswer failed for input "${inputId}" of turn ${turnId}:`, err);
399
+ return Response.json({ error: `authorizeAnswer failed: ${err instanceof Error ? err.message : String(err)} — the answer was NOT applied` }, { status: 500 });
400
+ }
401
+ this.armWatchdog();
402
+ try {
293
403
  runInScope({
294
404
  resources,
295
405
  services: this.services
296
- }, () => session.resume(turnId, inputId, input, { by }));
406
+ }, () => session.resume(turnId, inputId, input, {
407
+ by,
408
+ granted
409
+ }));
297
410
  } catch (err) {
298
411
  const message = err instanceof Error ? err.message : String(err);
299
412
  return Response.json({ error: message }, { status: err instanceof ResumeAuthorizationError ? 403 : 409 });
@@ -323,12 +436,33 @@ var AgentDurableObject = class {
323
436
  } catch (err) {
324
437
  return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
325
438
  }
439
+ this.armWatchdog();
326
440
  try {
327
441
  return Response.json(await session.reset());
328
442
  } catch (err) {
329
443
  return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
330
444
  }
331
445
  }
446
+ if (req.method === "POST" && url.pathname.endsWith("/note")) {
447
+ let input;
448
+ try {
449
+ input = await req.json();
450
+ } catch {
451
+ return Response.json({ error: "note: the body must be JSON { by, kind, text }" }, { status: 400 });
452
+ }
453
+ let session;
454
+ try {
455
+ session = this.resolveSession(key);
456
+ } catch (err) {
457
+ return Response.json({ error: err instanceof Error ? err.message : String(err) }, { status: 409 });
458
+ }
459
+ try {
460
+ return Response.json(await session.note(input));
461
+ } catch (err) {
462
+ if (err instanceof TypeError) return Response.json({ error: err.message }, { status: 400 });
463
+ throw err;
464
+ }
465
+ }
332
466
  if (url.pathname.endsWith("/transcript")) {
333
467
  if (key !== void 0) try {
334
468
  return Response.json({ transcript: this.resolveSession(key).transcript() });
@@ -337,7 +471,7 @@ var AgentDurableObject = class {
337
471
  }
338
472
  return Response.json({ transcript: this.transcript() });
339
473
  }
340
- return new Response("agent DO — POST /turn, POST /resume, POST /reset, or GET /transcript", { status: 404 });
474
+ return new Response("agent DO — POST /turn, POST /resume, POST /reset, POST /note, or GET /transcript", { status: 404 });
341
475
  }
342
476
  };
343
477
  const SSE_HEADERS = {
@@ -466,7 +600,8 @@ function resolveServices(factory, env, agentName) {
466
600
  return perAgent.get(agentName);
467
601
  }
468
602
  function durableChannelSurface(getNamespace, opts) {
469
- return channelDispatch(opts.channels.map((c) => resolveChannel(c, opts.env)), {
603
+ const resolved = opts.channels.map((c) => resolveChannel(c, opts.env));
604
+ const ctx = {
470
605
  agent: {
471
606
  name: opts.agentName,
472
607
  instructions: "",
@@ -552,7 +687,8 @@ function durableChannelSurface(getNamespace, opts) {
552
687
  }
553
688
  return await res.json();
554
689
  }
555
- });
690
+ };
691
+ return channelDispatch(resolved, ctx);
556
692
  }
557
693
  function serializeResume(o) {
558
694
  try {
@@ -561,11 +697,20 @@ function serializeResume(o) {
561
697
  inputId: o.inputId,
562
698
  input: o.input,
563
699
  by: o.by,
700
+ principal: o.principal,
564
701
  source: o.source,
565
702
  target: o.target
566
703
  });
567
704
  } catch (err) {
568
- throw new Error(`resume: input is not JSON-serializable (${err.message}) — a resume answer must round-trip to the DO`);
705
+ const culprit = ["input", "principal"].find((field) => {
706
+ try {
707
+ JSON.stringify(o[field]);
708
+ return false;
709
+ } catch {
710
+ return true;
711
+ }
712
+ }) ?? "payload";
713
+ throw new Error(`resume: ${culprit} is not JSON-serializable (${err.message}) — a resume must round-trip to the DO`);
569
714
  }
570
715
  }
571
716
  function serializeTurn(userText, o) {
@@ -573,7 +718,8 @@ function serializeTurn(userText, o) {
573
718
  userText,
574
719
  turnId: o?.turnId,
575
720
  event: o?.event,
576
- trigger: o?.trigger
721
+ trigger: o?.trigger,
722
+ ifSuspended: o?.ifSuspended
577
723
  };
578
724
  try {
579
725
  return JSON.stringify(payload);
@@ -1,44 +1,48 @@
1
1
  import { SyncSqlite } from "./sqlite-driver.js";
2
2
  import { AgentDefinition, ChannelContext } from "@junejs/core/agent-config";
3
- import { AgentSession, ChannelPolicy, Model, Runtime, Tool } from "@junejs/core/agent-runtime";
3
+ import { AgentSession, ChannelPolicy, InputAnnouncement, Model, Runtime, Tool } from "@junejs/core/agent-runtime";
4
4
  //#region src/agent-native.d.ts
5
- type AgentDef = {
5
+ export type AgentDef = {
6
6
  model: Model;
7
7
  tools: Tool[];
8
8
  instructions?: string;
9
9
  channelInstructions?: Record<string, string | ChannelPolicy>;
10
+ onInputAnnouncement?: (a: InputAnnouncement) => void | Promise<void>;
10
11
  };
11
- declare function toAgentDef(agent: AgentDefinition, model: Model): AgentDef;
12
- type NativeRuntimeOptions = {
12
+ export declare function toAgentDef(agent: AgentDefinition, model: Model): AgentDef;
13
+ export type NativeRuntimeOptions = {
13
14
  maxSessions?: number;
14
15
  };
15
- declare class NativeRuntime implements Runtime {
16
+ export declare class NativeRuntime implements Runtime {
16
17
  private actors;
17
18
  private readonly agents;
18
19
  private readonly db;
20
+ private readonly announceRetry;
19
21
  private readonly maxSessions;
20
22
  constructor(agents: Record<string, AgentDef>, db: SyncSqlite, opts?: NativeRuntimeOptions);
21
23
  agentDef(name: string): AgentDef | undefined;
22
24
  session(agent: string, id: string): AgentSession;
23
25
  get sessionCount(): number;
26
+ recoverAnnouncements(): void;
24
27
  private evictIdle;
25
28
  }
26
- declare function createNativeRuntime(agents: Record<string, AgentDef>, path?: string, opts?: NativeRuntimeOptions): Promise<NativeRuntime>;
27
- declare class MemoryRuntime implements Runtime {
29
+ export declare function createNativeRuntime(agents: Record<string, AgentDef>, path?: string, opts?: NativeRuntimeOptions): Promise<NativeRuntime>;
30
+ export declare class MemoryRuntime implements Runtime {
28
31
  private actors;
29
32
  private stores;
30
33
  private readonly agents;
34
+ private readonly announceRetry;
31
35
  constructor(agents: Record<string, AgentDef>);
32
36
  agentDef(name: string): AgentDef | undefined;
33
37
  session(agent: string, id: string): AgentSession;
34
38
  }
35
- type AgentBackend = "native" | "memory" | "durable";
36
- declare function createAgentRuntime(agents: Record<string, AgentDef>, opts?: {
39
+ export type AgentBackend = "native" | "memory" | "durable";
40
+ export declare function createAgentRuntime(agents: Record<string, AgentDef>, opts?: {
37
41
  backend?: AgentBackend;
38
42
  path?: string;
39
43
  maxSessions?: number;
40
44
  }): Promise<Runtime>;
41
- declare function mountAgent(agent: AgentDefinition, runtime: Runtime, opts?: {
45
+ export declare function mountAgent(agent: AgentDefinition, runtime: Runtime, opts?: {
42
46
  chatPath?: string;
43
47
  channels?: boolean;
44
48
  services?: unknown;
@@ -48,5 +52,4 @@ declare function mountAgent(agent: AgentDefinition, runtime: Runtime, opts?: {
48
52
  startAll: () => Promise<void>;
49
53
  ctx: ChannelContext;
50
54
  };
51
- //#endregion
52
- export { AgentBackend, AgentDef, MemoryRuntime, NativeRuntime, NativeRuntimeOptions, createAgentRuntime, createNativeRuntime, mountAgent, toAgentDef };
55
+ //#endregion