@crazx/dsh-api-session-controller 0.1.2-alpha.3.zw.1

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 (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +74 -0
  4. package/README.zh.md +74 -0
  5. package/lib/client.js +2724 -0
  6. package/lib/index.js +2826 -0
  7. package/lib/invariant.js +13 -0
  8. package/lib/typert.host.d.ts +3 -0
  9. package/lib/typert.host.js +2574 -0
  10. package/lib/typert.remote-client.d.ts +67 -0
  11. package/lib/typert.remote-client.js +1119 -0
  12. package/lib/types/agent.d.ts +156 -0
  13. package/lib/types/agent.js +537 -0
  14. package/lib/types/catalog.d.ts +11 -0
  15. package/lib/types/catalog.js +58 -0
  16. package/lib/types/client/contract/events.d.ts +71 -0
  17. package/lib/types/client/contract/events.js +91 -0
  18. package/lib/types/client/contract/session.d.ts +150 -0
  19. package/lib/types/client/contract/session.js +2 -0
  20. package/lib/types/client/contract/sessions.d.ts +125 -0
  21. package/lib/types/client/contract/sessions.js +2 -0
  22. package/lib/types/client/contract/snapshot.d.ts +82 -0
  23. package/lib/types/client/contract/snapshot.js +2 -0
  24. package/lib/types/client/index.d.ts +30 -0
  25. package/lib/types/client/index.js +48 -0
  26. package/lib/types/client/ordered-baseline.d.ts +12 -0
  27. package/lib/types/client/ordered-baseline.js +41 -0
  28. package/lib/types/client/scope.d.ts +36 -0
  29. package/lib/types/client/scope.js +54 -0
  30. package/lib/types/client/sessions/history-records.d.ts +22 -0
  31. package/lib/types/client/sessions/history-records.js +31 -0
  32. package/lib/types/client/sessions/lineage.d.ts +38 -0
  33. package/lib/types/client/sessions/lineage.js +56 -0
  34. package/lib/types/client/sessions/manager.d.ts +280 -0
  35. package/lib/types/client/sessions/manager.js +894 -0
  36. package/lib/types/client/sessions/notifier.d.ts +39 -0
  37. package/lib/types/client/sessions/notifier.js +98 -0
  38. package/lib/types/client/sessions/projection-store.d.ts +108 -0
  39. package/lib/types/client/sessions/projection-store.js +129 -0
  40. package/lib/types/client/sessions/queue-mirror.d.ts +26 -0
  41. package/lib/types/client/sessions/queue-mirror.js +61 -0
  42. package/lib/types/client/sessions/remotes.d.ts +30 -0
  43. package/lib/types/client/sessions/remotes.js +8 -0
  44. package/lib/types/client/sessions/service.d.ts +349 -0
  45. package/lib/types/client/sessions/service.js +574 -0
  46. package/lib/types/client/sessions/session.d.ts +294 -0
  47. package/lib/types/client/sessions/session.js +711 -0
  48. package/lib/types/client/time-zone.d.ts +8 -0
  49. package/lib/types/client/time-zone.js +14 -0
  50. package/lib/types/client/transport.d.ts +73 -0
  51. package/lib/types/client/transport.js +106 -0
  52. package/lib/types/commands.d.ts +69 -0
  53. package/lib/types/commands.js +544 -0
  54. package/lib/types/control.d.ts +23 -0
  55. package/lib/types/control.js +192 -0
  56. package/lib/types/file-references.d.ts +27 -0
  57. package/lib/types/file-references.js +69 -0
  58. package/lib/types/history.d.ts +31 -0
  59. package/lib/types/history.js +376 -0
  60. package/lib/types/index.d.ts +171 -0
  61. package/lib/types/index.js +424 -0
  62. package/lib/types/invariant.d.ts +9 -0
  63. package/lib/types/invariant.js +12 -0
  64. package/lib/types/list.d.ts +53 -0
  65. package/lib/types/list.js +405 -0
  66. package/lib/types/model-selection-projection.d.ts +8 -0
  67. package/lib/types/model-selection-projection.js +66 -0
  68. package/lib/types/remote-events.d.ts +8 -0
  69. package/lib/types/remote-events.js +2 -0
  70. package/lib/types/skill-catalog.d.ts +28 -0
  71. package/lib/types/skill-catalog.js +192 -0
  72. package/lib/types/types.d.ts +505 -0
  73. package/lib/types/types.js +6 -0
  74. package/package.json +154 -0
package/lib/index.js ADDED
@@ -0,0 +1,2826 @@
1
+ import z from "@deepseek-ai/schemastery";
2
+ import { ReasoningEffortId, createUserMessage, errorChain, freezeMessage } from "@deepseek-ai/dsh-llm";
3
+ import { canOpenNativePath, openNativePath } from "@deepseek-ai/dsh-native-command";
4
+ import { Remote, RemoteError, TypertRemoteService, remoteErrorOf } from "@deepseek-ai/dsh-typert-protocol";
5
+ import { mkdir, stat } from "node:fs/promises";
6
+ import { installModelSelection } from "@deepseek-ai/dsh-agent";
7
+ import { SessionQueryError } from "@deepseek-ai/dsh-session-query";
8
+ import { randomUUID } from "node:crypto";
9
+ import { brandString } from "@deepseek-ai/dsh-brand";
10
+ import { AttachmentError, admitPromptContent } from "@deepseek-ai/dsh-attachment";
11
+ import { SessionTitleInvalidError } from "@deepseek-ai/dsh-session-title";
12
+ import { canonicalClientTimeZone } from "@deepseek-ai/dsh-util-time";
13
+ import { Deque } from "@deepseek-ai/dsh-deque";
14
+ import { isAppendSurfaceEvent } from "@deepseek-ai/dsh-session";
15
+ import { isChunkRow, packChunkRuns } from "@deepseek-ai/dsh-session/chunk-rows";
16
+ import { z as z$1 } from "zod";
17
+ import { isUserInvocable } from "@deepseek-ai/dsh-skill";
18
+ //#region lib/types/agent.js
19
+ /** Agent activation, composition, and model-selection policy owned by API Session. */
20
+ var __addDisposableResource$5 = function(env, value, async) {
21
+ if (value !== null && value !== void 0) {
22
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
23
+ var dispose, inner;
24
+ if (async) {
25
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
26
+ dispose = value[Symbol.asyncDispose];
27
+ }
28
+ if (dispose === void 0) {
29
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
30
+ dispose = value[Symbol.dispose];
31
+ if (async) inner = dispose;
32
+ }
33
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
34
+ if (inner) dispose = function() {
35
+ try {
36
+ inner.call(this);
37
+ } catch (e) {
38
+ return Promise.reject(e);
39
+ }
40
+ };
41
+ env.stack.push({
42
+ value,
43
+ dispose,
44
+ async
45
+ });
46
+ } else if (async) env.stack.push({ async: true });
47
+ return value;
48
+ };
49
+ var __disposeResources$5 = (function(SuppressedError) {
50
+ return function(env) {
51
+ function fail(e) {
52
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
53
+ env.hasError = true;
54
+ }
55
+ var r, s = 0;
56
+ function next() {
57
+ while (r = env.stack.pop()) try {
58
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
59
+ if (r.dispose) {
60
+ var result = r.dispose.call(r.value);
61
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
62
+ fail(e);
63
+ return next();
64
+ });
65
+ } else s |= 1;
66
+ } catch (e) {
67
+ fail(e);
68
+ }
69
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
70
+ if (env.hasError) throw env.error;
71
+ }
72
+ return next();
73
+ };
74
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
75
+ var e = new Error(message);
76
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
77
+ });
78
+ /** Cold Session identity absent from persistence. */
79
+ var ApiSessionNotFound = class extends Error {};
80
+ /** Session identity whose lifecycle belongs to subagent routing. */
81
+ var ApiSessionSubagentOwnership = class extends Error {
82
+ sessionId;
83
+ /** @param sessionId - identity reserved to subagent routing. */
84
+ constructor(sessionId) {
85
+ super(`session "${sessionId}" is a subagent session; use subagent delivery`);
86
+ this.sessionId = sessionId;
87
+ }
88
+ };
89
+ /** Explicit-id creation attempted to adopt a Session under another cwd. */
90
+ var ApiSessionCwdConflict = class extends Error {
91
+ sessionId;
92
+ requestedCwd;
93
+ existingCwd;
94
+ constructor(sessionId, requestedCwd, existingCwd) {
95
+ super(existingCwd === void 0 ? `session "${sessionId}" records no cwd and cannot be adopted for "${requestedCwd}"` : `session "${sessionId}" belongs to "${existingCwd}", not "${requestedCwd}"`);
96
+ this.sessionId = sessionId;
97
+ this.requestedCwd = requestedCwd;
98
+ this.existingCwd = existingCwd;
99
+ }
100
+ };
101
+ /** Explicit-id creation attempted to adopt a Session under another preset. */
102
+ var ApiSessionPresetConflict = class extends Error {
103
+ sessionId;
104
+ requestedPreset;
105
+ existingPreset;
106
+ constructor(sessionId, requestedPreset, existingPreset) {
107
+ super(existingPreset === void 0 ? `session "${sessionId}" records no agent preset and cannot be adopted under "${requestedPreset}"` : `session "${sessionId}" runs agent preset "${existingPreset}", not "${requestedPreset}"`);
108
+ this.sessionId = sessionId;
109
+ this.requestedPreset = requestedPreset;
110
+ this.existingPreset = existingPreset;
111
+ }
112
+ };
113
+ /**
114
+ * Test whether generic Session routing must leave an identity to subagent routing.
115
+ * @param ctx - Host context carrying the Agent ownership registry.
116
+ * @param session - attached or live Session whose ownership is tested.
117
+ * @param agent - live Agent when one exists for the Session.
118
+ * @returns whether subagent routing owns the Session identity.
119
+ */
120
+ function hasApiSessionSubagentOwner(ctx, session, agent) {
121
+ if (session.header.origin === "subagent") return true;
122
+ const parentId = session.header.parentSession;
123
+ if (parentId === void 0 || agent === void 0) return false;
124
+ const parent = ctx.agents.get(parentId);
125
+ return parent !== void 0 && ctx.agents.isOwnedBy(agent.id, parent);
126
+ }
127
+ /**
128
+ * Build the stable caller-facing subagent ownership rejection.
129
+ * @param sessionId - Session identity owned by subagent routing.
130
+ * @returns a stable Session-domain failure.
131
+ */
132
+ function apiSessionSubagentOwnershipError(sessionId) {
133
+ return new RemoteError("session/agent-busy", `session "${sessionId}" is owned by subagent routing`, { reason: "use subagent delivery for this child session" });
134
+ }
135
+ /**
136
+ * Inspect one cold Session without repairing, resuming, or publishing it.
137
+ * @param ctx - Host context carrying Session persistence.
138
+ * @param sessionId - durable Session identity.
139
+ * @param signal - optional cancellation for persistence reads.
140
+ * @returns the persisted header and complete event prefix.
141
+ */
142
+ async function inspectApiSession(ctx, sessionId, signal) {
143
+ try {
144
+ const env_1 = {
145
+ stack: [],
146
+ error: void 0,
147
+ hasError: false
148
+ };
149
+ try {
150
+ const observation = __addDisposableResource$5(env_1, await ctx.sessionQuery.observeSession(sessionId, {
151
+ ...signal === void 0 ? {} : { signal },
152
+ projectionMode: "none"
153
+ }), false);
154
+ if (observation.header.cwd === void 0) throw new ApiSessionNotFound(`session "${sessionId}" not found`);
155
+ return {
156
+ meta: observation.header,
157
+ events: [...observation.events]
158
+ };
159
+ } catch (e_1) {
160
+ env_1.error = e_1;
161
+ env_1.hasError = true;
162
+ } finally {
163
+ __disposeResources$5(env_1);
164
+ }
165
+ } catch (error) {
166
+ if (error instanceof SessionQueryError && error.code === "SESSION_QUERY_SESSION_NOT_FOUND") throw new ApiSessionNotFound(`session "${sessionId}" not found`);
167
+ throw error;
168
+ }
169
+ }
170
+ /** Owns every operation that may create, resume, or configure a Web Agent. */
171
+ var ApiSessionAgentController = class {
172
+ ctx;
173
+ resumes = /* @__PURE__ */ new Map();
174
+ creations = /* @__PURE__ */ new Map();
175
+ selections = /* @__PURE__ */ new WeakMap();
176
+ imageAdmissionChains = /* @__PURE__ */ new WeakMap();
177
+ /** @param ctx - Host context carrying Agent, model, persistence, and Typert services. */
178
+ constructor(ctx) {
179
+ this.ctx = ctx;
180
+ ctx.typert.lookups.configure("agent", async (sessionId) => {
181
+ const found = await this.resolveAgent(sessionId);
182
+ if ("error" in found) throw found.error;
183
+ return found.agent;
184
+ });
185
+ ctx.typert.lookups.configure("session", async (sessionId) => {
186
+ const found = await this.resolveAgent(sessionId);
187
+ if ("error" in found) throw found.error;
188
+ return found.agent.session;
189
+ });
190
+ ctx.typert.contexts.configureHost("agent", async (sessionId) => {
191
+ const found = await this.resolveAgent(sessionId);
192
+ if ("error" in found) throw found.error;
193
+ return found.agent.ctx;
194
+ });
195
+ }
196
+ /**
197
+ * Resolve or resume one ordinary Session, deduplicating concurrent resumes.
198
+ * @param sessionId - ordinary Session identity.
199
+ * @returns the live Agent or a stable Session-domain failure.
200
+ */
201
+ async resolveAgent(sessionId) {
202
+ return this.resolve(sessionId);
203
+ }
204
+ /**
205
+ * Resolve one ordinary Session from an already-retained exact observation.
206
+ * @param observation - Host-owned observation whose preparation stays pinned through setup.
207
+ * @returns the live Agent or a stable Session-domain failure.
208
+ */
209
+ async resolveObservedAgent(observation) {
210
+ return this.resolve(observation.header.id, observation);
211
+ }
212
+ async resolve(sessionId, observation) {
213
+ const live = this.liveAgent(sessionId);
214
+ if (live !== void 0) return live;
215
+ const attached = this.ctx.sessions.get(sessionId);
216
+ if (attached !== void 0 && hasApiSessionSubagentOwner(this.ctx, attached, void 0)) return { error: apiSessionSubagentOwnershipError(sessionId) };
217
+ let resume = this.resumes.get(sessionId);
218
+ if (resume === void 0) {
219
+ resume = this.resume(sessionId, observation).finally(() => {
220
+ this.resumes.delete(sessionId);
221
+ });
222
+ this.resumes.set(sessionId, resume);
223
+ }
224
+ try {
225
+ return { agent: await resume };
226
+ } catch (error) {
227
+ if (error instanceof ApiSessionNotFound) return { error: new RemoteError("session/not-found", error.message, { sessionId }) };
228
+ if (error instanceof ApiSessionSubagentOwnership) return { error: apiSessionSubagentOwnershipError(error.sessionId) };
229
+ const raced = this.liveAgent(sessionId);
230
+ if (raced !== void 0) return raced;
231
+ const racedSession = this.ctx.sessions.get(sessionId);
232
+ if (racedSession !== void 0 && hasApiSessionSubagentOwner(this.ctx, racedSession, void 0)) return { error: apiSessionSubagentOwnershipError(sessionId) };
233
+ return { error: new RemoteError("gateway/internal", `resume failed for session "${sessionId}": ${String(error)}`, {}) };
234
+ }
235
+ }
236
+ /**
237
+ * Resolve one requested identity, creating or resuming it once.
238
+ * @param sessionId - requested Session identity.
239
+ * @param cwd - directory the Session must own.
240
+ * @param checkPersistedIdentity - whether to inspect a cold identity before creation.
241
+ * @param presetId - optional Agent preset the Session must own.
242
+ * @returns the matching live ordinary Agent.
243
+ */
244
+ async ensureSession(sessionId, cwd, checkPersistedIdentity, presetId) {
245
+ let creation = this.creations.get(sessionId);
246
+ if (creation === void 0) {
247
+ creation = this.createOrAdopt(sessionId, cwd, checkPersistedIdentity, presetId).catch((error) => {
248
+ const live = this.ctx.agents.get(sessionId);
249
+ if (live !== void 0) {
250
+ if (hasApiSessionSubagentOwner(this.ctx, live.session, live)) throw new ApiSessionSubagentOwnership(sessionId);
251
+ return live;
252
+ }
253
+ const attached = this.ctx.sessions.get(sessionId);
254
+ if (attached !== void 0 && hasApiSessionSubagentOwner(this.ctx, attached, void 0)) throw new ApiSessionSubagentOwnership(sessionId);
255
+ throw error;
256
+ }).finally(() => {
257
+ this.creations.delete(sessionId);
258
+ });
259
+ this.creations.set(sessionId, creation);
260
+ }
261
+ const agent = await creation;
262
+ if (hasApiSessionSubagentOwner(this.ctx, agent.session, agent)) throw new ApiSessionSubagentOwnership(sessionId);
263
+ if (presetId !== void 0) this.assertPresetUnchanged(sessionId, presetId, this.presetForSession(agent.session));
264
+ if (agent.session.header.cwd !== cwd) throw new ApiSessionCwdConflict(sessionId, cwd, agent.session.header.cwd);
265
+ return agent;
266
+ }
267
+ /**
268
+ * Install or return the Session-local model selection used by prompt assembly.
269
+ * @param agent - live Agent that owns the selection.
270
+ * @returns the installed mutable selection reference.
271
+ */
272
+ selectionFor(agent) {
273
+ const installed = this.selections.get(agent);
274
+ if (installed !== void 0) return installed;
275
+ const projectionState = this.ctx.sessionProjections.stateOf(agent.session, "modelSelection");
276
+ if (projectionState === void 0) throw new Error("api-session: required modelSelection projection is not registered");
277
+ let picked = projectionState.pending === null ? void 0 : agentModelSelection(projectionState.pending);
278
+ const defaultModel = this.ctx.agentDefaultModel;
279
+ const selection = {
280
+ get current() {
281
+ if (picked !== void 0) return picked;
282
+ const loggedHeader = agent.session.requestHeader();
283
+ if (loggedHeader === void 0) return defaultModel.currentSelection();
284
+ const logged = loggedHeader.config;
285
+ return {
286
+ provider: logged.provider,
287
+ model: logged.model,
288
+ ...logged.reasoningEffort === void 0 || loggedHeader.adapterDefaults?.reasoningEffort === true ? {} : { reasoningEffort: logged.reasoningEffort }
289
+ };
290
+ },
291
+ set current(next) {
292
+ picked = next;
293
+ },
294
+ consume(provider, model, reasoningEffort) {
295
+ if (picked?.provider !== provider || picked.model !== model || picked.reasoningEffort !== reasoningEffort) return false;
296
+ picked = void 0;
297
+ return true;
298
+ },
299
+ assembled: void 0
300
+ };
301
+ installModelSelection(agent.ctx, selection);
302
+ this.selections.set(agent, selection);
303
+ return selection;
304
+ }
305
+ /**
306
+ * Commit and cache one validated selection for the next prompt assembly.
307
+ * @param agent - live Agent that owns the selection.
308
+ * @param selection - validated selection to record and apply.
309
+ */
310
+ selectForNextRequest(agent, selection) {
311
+ agent.session.append("model/selection", selection);
312
+ this.selectionFor(agent).current = selection;
313
+ }
314
+ /**
315
+ * Let a matching durable request header retire the execution cache.
316
+ * @param agent - live Agent whose request was recorded.
317
+ * @param provider - provider route used by the request.
318
+ * @param model - provider-owned model used by the request.
319
+ * @param reasoningEffort - adapter-owned effort used by the request.
320
+ * @returns whether the pending selection was consumed.
321
+ */
322
+ consumeSelection(agent, provider, model, reasoningEffort) {
323
+ return this.selections.get(agent)?.consume(provider, model, reasoningEffort) ?? false;
324
+ }
325
+ /**
326
+ * Read the current Agent preset from the Session projection.
327
+ * @param session - live Session whose projection state is available.
328
+ * @returns the current preset, or undefined when the capability is absent.
329
+ */
330
+ presetForSession(session) {
331
+ return this.ctx.sessionProjections.stateOf(session, "agentPreset") ?? void 0;
332
+ }
333
+ /**
334
+ * Serialize image admission and model selection for one Agent.
335
+ * @param agent - live Agent that owns the serialization chain.
336
+ * @param operation - asynchronous operation admitted after prior work settles.
337
+ * @returns the operation result or rejection.
338
+ */
339
+ serializeImageAdmission(agent, operation) {
340
+ const result = (this.imageAdmissionChains.get(agent) ?? Promise.resolve()).then(operation);
341
+ this.imageAdmissionChains.set(agent, result.then(() => void 0, () => void 0));
342
+ return result;
343
+ }
344
+ /**
345
+ * Resolve the preset id and pre-publication Agent setup for a create or resume.
346
+ * @param presetId - requested preset or the configured default when omitted.
347
+ * @returns the resolved preset identity and Agent setup callback.
348
+ */
349
+ async composeAgent(presetId) {
350
+ const presets = this.ctx.get("agentPresets");
351
+ if (presets === void 0) return { setup: (agentCtx) => {
352
+ this.installSelection(agentCtx);
353
+ } };
354
+ const resolvedId = (await presets.resolve(presetId)).id;
355
+ return {
356
+ agentPreset: resolvedId,
357
+ setup: async (agentCtx) => {
358
+ this.installSelection(agentCtx);
359
+ await presets.mount(agentCtx, resolvedId);
360
+ }
361
+ };
362
+ }
363
+ liveAgent(sessionId) {
364
+ const agent = this.ctx.agents.get(sessionId);
365
+ if (agent === void 0) return void 0;
366
+ return hasApiSessionSubagentOwner(this.ctx, agent.session, agent) ? { error: apiSessionSubagentOwnershipError(sessionId) } : { agent };
367
+ }
368
+ async resume(sessionId, supplied) {
369
+ if (supplied !== void 0) return this.resumeObserved(sessionId, supplied);
370
+ try {
371
+ const env_2 = {
372
+ stack: [],
373
+ error: void 0,
374
+ hasError: false
375
+ };
376
+ try {
377
+ const observation = __addDisposableResource$5(env_2, await this.ctx.sessionQuery.observeSession(sessionId), false);
378
+ return await this.resumeObserved(sessionId, observation);
379
+ } catch (e_2) {
380
+ env_2.error = e_2;
381
+ env_2.hasError = true;
382
+ } finally {
383
+ __disposeResources$5(env_2);
384
+ }
385
+ } catch (error) {
386
+ if (error instanceof SessionQueryError && error.code === "SESSION_QUERY_SESSION_NOT_FOUND") throw new ApiSessionNotFound(`session "${sessionId}" not found`);
387
+ throw error;
388
+ }
389
+ }
390
+ async resumeObserved(sessionId, observation) {
391
+ if (observation.header.id !== sessionId || observation.header.cwd === void 0) throw new ApiSessionNotFound(`session "${sessionId}" not found`);
392
+ if (hasApiSessionSubagentOwner(this.ctx, { header: observation.header }, void 0)) throw new ApiSessionSubagentOwnership(sessionId);
393
+ const composition = await this.composeAgent(this.presetForObservation(observation));
394
+ const published = this.ctx.sessions.get(sessionId);
395
+ const live = this.ctx.agents.get(sessionId);
396
+ if (published !== void 0 && hasApiSessionSubagentOwner(this.ctx, published, live)) throw new ApiSessionSubagentOwnership(sessionId);
397
+ return (await this.ctx.agents.resume({
398
+ resumeSessionId: sessionId,
399
+ agentOptions: this.agentOptions(),
400
+ setup: composition.setup
401
+ })).agent;
402
+ }
403
+ async createOrAdopt(sessionId, cwd, checkPersistedIdentity, presetId) {
404
+ const attached = this.ctx.sessions.get(sessionId);
405
+ const live = this.ctx.agents.get(sessionId);
406
+ if (attached !== void 0 && hasApiSessionSubagentOwner(this.ctx, attached, live)) throw new ApiSessionSubagentOwnership(sessionId);
407
+ if (live !== void 0) return live;
408
+ if (checkPersistedIdentity) try {
409
+ const env_3 = {
410
+ stack: [],
411
+ error: void 0,
412
+ hasError: false
413
+ };
414
+ try {
415
+ const observation = __addDisposableResource$5(env_3, await this.ctx.sessionQuery.observeSession(sessionId), false);
416
+ if (hasApiSessionSubagentOwner(this.ctx, { header: observation.header }, void 0)) throw new ApiSessionSubagentOwnership(sessionId);
417
+ if (observation.header.cwd !== cwd) throw new ApiSessionCwdConflict(sessionId, cwd, observation.header.cwd);
418
+ const storedPreset = this.presetForObservation(observation);
419
+ this.assertPresetUnchanged(sessionId, presetId, storedPreset);
420
+ const composition = await this.composeAgent(storedPreset);
421
+ return (await this.ctx.agents.resume({
422
+ resumeSessionId: sessionId,
423
+ agentOptions: this.agentOptions(),
424
+ setup: composition.setup
425
+ })).agent;
426
+ } catch (e_3) {
427
+ env_3.error = e_3;
428
+ env_3.hasError = true;
429
+ } finally {
430
+ __disposeResources$5(env_3);
431
+ }
432
+ } catch (error) {
433
+ if (!(error instanceof SessionQueryError) || error.code !== "SESSION_QUERY_SESSION_NOT_FOUND") throw error;
434
+ }
435
+ try {
436
+ await mkdir(cwd, { recursive: true });
437
+ } catch (error) {
438
+ throw new Error(`failed to ensure project directory "${cwd}": ${String(error)}`, { cause: error });
439
+ }
440
+ const composition = await this.composeAgent(presetId);
441
+ return (await this.ctx.agents.create({
442
+ sessionId,
443
+ agentOptions: this.agentOptions(),
444
+ meta: {
445
+ cwd,
446
+ ...composition.agentPreset === void 0 ? {} : { agentPreset: composition.agentPreset }
447
+ },
448
+ setup: composition.setup
449
+ })).agent;
450
+ }
451
+ agentOptions() {
452
+ const { provider, model } = this.ctx.agentDefaultModel.currentSelection();
453
+ return {
454
+ provider,
455
+ model
456
+ };
457
+ }
458
+ installSelection(agentCtx) {
459
+ const agent = agentCtx.agent;
460
+ if (agent === void 0) throw new Error("api-session: Agent setup has no scoped Agent");
461
+ this.selectionFor(agent);
462
+ }
463
+ /**
464
+ * Read the current Agent preset from an all-projections observation.
465
+ * @param observation - exact Session observation carrying its projection snapshot.
466
+ * @returns the current preset, or undefined when the capability is absent.
467
+ */
468
+ presetForObservation(observation) {
469
+ if (observation.projections === void 0) throw new Error("api-session: Agent activation requires a projected Session observation");
470
+ return observation.projections.values.agentPreset ?? void 0;
471
+ }
472
+ assertPresetUnchanged(sessionId, requested, existing) {
473
+ if (requested === void 0 || requested === existing) return;
474
+ throw new ApiSessionPresetConflict(sessionId, requested, existing);
475
+ }
476
+ };
477
+ function agentModelSelection(selection) {
478
+ return {
479
+ provider: selection.provider,
480
+ model: selection.model,
481
+ ...selection.reasoningEffort === void 0 ? {} : { reasoningEffort: ReasoningEffortId(selection.reasoningEffort) }
482
+ };
483
+ }
484
+ //#endregion
485
+ //#region lib/types/commands.js
486
+ /** Session commands whose activation policy is explicit at each Remote method. */
487
+ var __addDisposableResource$4 = function(env, value, async) {
488
+ if (value !== null && value !== void 0) {
489
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
490
+ var dispose, inner;
491
+ if (async) {
492
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
493
+ dispose = value[Symbol.asyncDispose];
494
+ }
495
+ if (dispose === void 0) {
496
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
497
+ dispose = value[Symbol.dispose];
498
+ if (async) inner = dispose;
499
+ }
500
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
501
+ if (inner) dispose = function() {
502
+ try {
503
+ inner.call(this);
504
+ } catch (e) {
505
+ return Promise.reject(e);
506
+ }
507
+ };
508
+ env.stack.push({
509
+ value,
510
+ dispose,
511
+ async
512
+ });
513
+ } else if (async) env.stack.push({ async: true });
514
+ return value;
515
+ };
516
+ var __disposeResources$4 = (function(SuppressedError) {
517
+ return function(env) {
518
+ function fail(e) {
519
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
520
+ env.hasError = true;
521
+ }
522
+ var r, s = 0;
523
+ function next() {
524
+ while (r = env.stack.pop()) try {
525
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
526
+ if (r.dispose) {
527
+ var result = r.dispose.call(r.value);
528
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
529
+ fail(e);
530
+ return next();
531
+ });
532
+ } else s |= 1;
533
+ } catch (e) {
534
+ fail(e);
535
+ }
536
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
537
+ if (env.hasError) throw env.error;
538
+ }
539
+ return next();
540
+ };
541
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
542
+ var e = new Error(message);
543
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
544
+ });
545
+ /** Implements Session business commands delegated by the Session Controller Remote service. */
546
+ var SessionCommandController = class {
547
+ ctx;
548
+ agents;
549
+ defaultCwd;
550
+ /**
551
+ * @param ctx - Host context carrying Agent, model, attachment, title, and Workspace services.
552
+ * @param agents - sole owner of create, resume, and Session-local model selection.
553
+ * @param defaultCwd - project directory used when create names neither a Workspace nor a cwd.
554
+ */
555
+ constructor(ctx, agents, defaultCwd) {
556
+ this.ctx = ctx;
557
+ this.agents = agents;
558
+ this.defaultCwd = defaultCwd;
559
+ }
560
+ /**
561
+ * Create or idempotently adopt one ordinary Session.
562
+ * @param request - requested identity, location, and Agent preset.
563
+ * @returns the Session identity and resolved preset when configured.
564
+ */
565
+ async create(request) {
566
+ if (request.workspaceId !== void 0 && request.cwd !== void 0) throw new RemoteError("gateway/bad-request", "session.create accepts workspaceId or cwd, not both", {});
567
+ const sessionId = request.sessionId ?? brandString(`session-${randomUUID()}`);
568
+ let workspace;
569
+ if (request.workspaceId !== void 0) {
570
+ workspace = this.ctx.workspaceRegistry.get(request.workspaceId);
571
+ if (workspace === void 0) throw new RemoteError("workspace/not-found", `workspace "${request.workspaceId}" not found`, { workspaceId: request.workspaceId });
572
+ }
573
+ const cwd = workspace?.path ?? request.cwd ?? this.defaultCwd;
574
+ let adopted;
575
+ try {
576
+ adopted = await this.agents.ensureSession(sessionId, cwd, request.sessionId !== void 0, request.agentPreset);
577
+ } catch (error) {
578
+ this.rejectCreation(sessionId, error);
579
+ }
580
+ if (workspace !== void 0) try {
581
+ await workspace.attachSession(sessionId);
582
+ } catch (error) {
583
+ throw new RemoteError("session/workspace-attach-failed", `session "${sessionId}" was created but could not attach to workspace "${workspace.id}": ${String(error)}`, {
584
+ sessionId,
585
+ workspaceId: workspace.id
586
+ });
587
+ }
588
+ const agentPreset = this.agents.presetForSession(adopted.session);
589
+ return {
590
+ sessionId,
591
+ ...agentPreset === void 0 ? {} : { agentPreset }
592
+ };
593
+ }
594
+ /**
595
+ * Validate and install one Session-local model selection.
596
+ * @param request - Session identity and requested model selection.
597
+ * @returns the normalized selection installed for the Session.
598
+ */
599
+ async selectModel(request) {
600
+ const agent = await this.resolveAgent(request.sessionId);
601
+ return this.agents.serializeImageAdmission(agent, async () => {
602
+ const persistEffortMemory = async (effort) => {
603
+ try {
604
+ await this.ctx.agentDefaultModel.rememberEffort(request.provider, request.model, effort === void 0 ? void 0 : ReasoningEffortId(effort));
605
+ } catch (error) {
606
+ this.ctx.logger.warn(`session-controller: the model switch applies to this Session but its effort memory was not updated: ${String(error)}`);
607
+ }
608
+ };
609
+ try {
610
+ const current = this.agents.selectionFor(agent).current;
611
+ const sameRoute = current.provider === request.provider && current.model === request.model;
612
+ let requested = request.reasoningEffort;
613
+ if (requested === void 0 && !sameRoute) {
614
+ const remembered = this.ctx.agentDefaultModel.recallEffort(request.provider, request.model);
615
+ if (remembered !== void 0) if ((await this.ctx.llm.resolveModelInfo(request.provider, request.model)).reasoning?.efforts.some((effort) => effort.id === remembered)) requested = remembered;
616
+ else await persistEffortMemory(void 0);
617
+ }
618
+ const resolved = await this.ctx.llm.resolveCallConfig({
619
+ provider: request.provider,
620
+ model: request.model,
621
+ ...requested === void 0 ? {} : { reasoningEffort: ReasoningEffortId(requested) }
622
+ });
623
+ const selected = {
624
+ provider: resolved.provider,
625
+ model: resolved.model,
626
+ ...resolved.reasoningEffort === void 0 ? {} : { reasoningEffort: resolved.reasoningEffort }
627
+ };
628
+ this.agents.selectForNextRequest(agent, selected);
629
+ try {
630
+ await this.ctx.agentDefaultModel.saveSelection(selected);
631
+ } catch (error) {
632
+ this.ctx.logger.warn(`session-controller: model selection changed for the Session but the default was not saved: ${String(error)}`);
633
+ }
634
+ if (request.reasoningEffort !== void 0) await persistEffortMemory(resolved.reasoningEffort);
635
+ else if (sameRoute) await persistEffortMemory(void 0);
636
+ return { selected: { ...selected } };
637
+ } catch (error) {
638
+ if (remoteErrorOf(error) !== void 0) throw error;
639
+ throw new RemoteError("session/model-unavailable", error instanceof Error ? error.message : String(error), {
640
+ provider: request.provider,
641
+ model: request.model
642
+ });
643
+ }
644
+ });
645
+ }
646
+ /**
647
+ * Normalize and append a user-owned Session title.
648
+ * @param request - Session identity and proposed title.
649
+ * @returns the accepted title and durable event sequence.
650
+ */
651
+ async rename(request) {
652
+ const agent = await this.resolveAgent(request.sessionId);
653
+ const titles = this.ctx.get("sessionTitle");
654
+ if (titles === void 0) throw new RemoteError("gateway/internal", "renaming is unavailable: this deployment mounts no session-title service", {});
655
+ try {
656
+ const accepted = titles.rename(agent.session, request.title);
657
+ return {
658
+ title: accepted.title,
659
+ seq: accepted.eventSeq
660
+ };
661
+ } catch (error) {
662
+ if (error instanceof SessionTitleInvalidError) throw new RemoteError("session/title-invalid", error.message, { sessionId: request.sessionId });
663
+ throw new RemoteError("gateway/internal", `failed to rename session "${request.sessionId}": ${String(error)}`, {});
664
+ }
665
+ }
666
+ /**
667
+ * Create a new ordinary Session from one completed-turn prefix.
668
+ * @param request - source Session and optional event anchor.
669
+ * @returns the new Session identity.
670
+ */
671
+ async fork(request) {
672
+ const env_1 = {
673
+ stack: [],
674
+ error: void 0,
675
+ hasError: false
676
+ };
677
+ try {
678
+ if (request.atSeq !== void 0 && (!Number.isInteger(request.atSeq) || request.atSeq < 0)) throw new RemoteError("gateway/bad-request", "atSeq must be a non-negative integer", {});
679
+ let observed;
680
+ try {
681
+ observed = await this.ctx.sessionQuery.observeSession(request.sessionId);
682
+ } catch (error) {
683
+ if (error instanceof SessionQueryError && error.code === "SESSION_QUERY_SESSION_NOT_FOUND") throw new RemoteError("session/not-found", `session "${request.sessionId}" not found`, { sessionId: request.sessionId });
684
+ throw new RemoteError("gateway/internal", `fork source unavailable for session "${request.sessionId}": ${String(error)}`, {});
685
+ }
686
+ const source = __addDisposableResource$4(env_1, observed, false);
687
+ const lastSeq = source.events.at(-1)?.seq ?? -1;
688
+ const atSeq = request.atSeq;
689
+ const boundary = (atSeq === void 0 ? void 0 : source.events.find((event) => event.type === "turn/end" && event.seq >= atSeq)) ?? (atSeq === void 0 || atSeq > lastSeq ? source.events.findLast((event) => event.type === "turn/end") : void 0);
690
+ if (boundary === void 0) throw new RemoteError("session/fork-unavailable", atSeq !== void 0 && atSeq <= lastSeq ? `session "${request.sessionId}" has not completed the turn containing event ${String(atSeq)}` : `session "${request.sessionId}" has no completed turn to fork from`, { sessionId: request.sessionId });
691
+ let cut = boundary.seq + 1;
692
+ while (cut < source.events.length && source.events[cut]?.type !== "turn/start") cut++;
693
+ let workspace;
694
+ try {
695
+ workspace = await this.forkWorkspace(source.header);
696
+ } catch (error) {
697
+ throw new RemoteError("gateway/internal", `failed to resolve fork workspace for session "${request.sessionId}": ${String(error)}`, {});
698
+ }
699
+ const childId = brandString(`session-${randomUUID()}`);
700
+ const composition = await this.agents.composeAgent(this.agents.presetForObservation(source));
701
+ try {
702
+ const { provider, model } = this.ctx.agentDefaultModel.currentSelection();
703
+ await this.ctx.agents.create({
704
+ sessionId: childId,
705
+ seed: source.events.slice(0, cut),
706
+ meta: {
707
+ ...source.header.cwd === void 0 ? {} : { cwd: source.header.cwd },
708
+ parentSession: source.header.id,
709
+ seedLength: cut,
710
+ ...composition.agentPreset === void 0 ? {} : { agentPreset: composition.agentPreset }
711
+ },
712
+ agentOptions: {
713
+ provider,
714
+ model
715
+ },
716
+ setup: composition.setup
717
+ });
718
+ } catch (error) {
719
+ throw new RemoteError("gateway/internal", `failed to fork session "${request.sessionId}": ${String(error)}`, {});
720
+ }
721
+ if (workspace !== void 0) try {
722
+ await workspace.attachSession(childId);
723
+ } catch (error) {
724
+ throw new RemoteError("session/workspace-attach-failed", `session "${childId}" was forked but could not attach to workspace "${workspace.id}": ${String(error)}`, {
725
+ sessionId: childId,
726
+ workspaceId: workspace.id
727
+ });
728
+ }
729
+ return { sessionId: childId };
730
+ } catch (e_1) {
731
+ env_1.error = e_1;
732
+ env_1.hasError = true;
733
+ } finally {
734
+ __disposeResources$4(env_1);
735
+ }
736
+ }
737
+ /**
738
+ * Admit one browser prompt after explicit Agent resume and image validation.
739
+ * @param request - Session identity, prompt content, source metadata, and delivery mode.
740
+ * @returns acknowledgement that the Agent accepted the prompt.
741
+ */
742
+ async prompt(request) {
743
+ const clientTimeZone = request.clientTimeZone === void 0 ? void 0 : canonicalClientTimeZone(request.clientTimeZone);
744
+ if (request.clientTimeZone !== void 0 && clientTimeZone === void 0) throw new RemoteError("session/invalid-time-zone", "clientTimeZone must be UTC or a valid IANA Area/Location name", { value: request.clientTimeZone });
745
+ const agent = await this.resolveAgent(request.sessionId);
746
+ const selection = this.agents.selectionFor(agent).current;
747
+ if (!routeServed(this.ctx, selection.provider)) throw new RemoteError("session/model-unavailable", `no adapter serves provider "${selection.provider}"; select a model for this session`, {
748
+ provider: selection.provider,
749
+ model: selection.model
750
+ });
751
+ const source = {
752
+ kind: "user",
753
+ rpcId: request.requestId,
754
+ ...clientTimeZone === void 0 ? {} : { clientTimeZone }
755
+ };
756
+ const hasImage = request.content.some((part) => part.type === "image");
757
+ const admit = async () => {
758
+ try {
759
+ if (hasImage) {
760
+ const current = this.agents.selectionFor(agent).current;
761
+ const model = await this.ctx.llm.resolveModelInfo(current.provider, current.model);
762
+ if (model.inputModalities !== void 0 && !model.inputModalities.includes("image")) throw new RemoteError("session/attachment-invalid", `Model "${current.model}" does not support image input.`, { reason: "MODEL_DOES_NOT_SUPPORT_IMAGES" });
763
+ }
764
+ const message = createUserMessage({
765
+ content: await admitPromptContent(this.ctx.attachments, request.content),
766
+ source
767
+ });
768
+ if (request.mode === "steer") agent.steer(message);
769
+ else agent.followup(message);
770
+ } catch (error) {
771
+ if (remoteErrorOf(error) !== void 0) throw error;
772
+ if (error instanceof AttachmentError) throw new RemoteError("session/attachment-invalid", error.message, { reason: error.code });
773
+ throw new RemoteError("session/agent-busy", "prompt rejected", { reason: String(error) });
774
+ }
775
+ return { accepted: true };
776
+ };
777
+ return hasImage ? this.agents.serializeImageAdmission(agent, admit) : admit();
778
+ }
779
+ /**
780
+ * Read one durable image after proving the Session log references it.
781
+ * @param request - Session and attachment identities used for authorization.
782
+ * @returns the durable attachment reference and base64-encoded bytes.
783
+ */
784
+ async attachment(request) {
785
+ let source;
786
+ try {
787
+ source = await this.readSessionState(request.sessionId);
788
+ } catch (error) {
789
+ if (error instanceof ApiSessionNotFound) throw new RemoteError("session/not-found", error.message, { sessionId: request.sessionId });
790
+ throw new RemoteError("gateway/internal", `attachment authorization unavailable for session "${request.sessionId}": ${String(error)}`, {});
791
+ }
792
+ const ref = referencedImage(source.events, String(request.attachmentId));
793
+ if (ref === void 0) throw new RemoteError("session/attachment-invalid", "Image is not referenced by this session.", { reason: "ATTACHMENT_NOT_REFERENCED" });
794
+ try {
795
+ const stored = await this.ctx.attachments.readImage(ref);
796
+ return {
797
+ attachment: stored.ref,
798
+ data: Buffer.from(stored.data).toString("base64")
799
+ };
800
+ } catch (error) {
801
+ if (error instanceof AttachmentError) throw new RemoteError("session/attachment-invalid", error.message, { reason: error.code });
802
+ throw new RemoteError("gateway/internal", "Unable to read image attachment.", {});
803
+ }
804
+ }
805
+ /**
806
+ * Mutate one still-pending queue occurrence without resuming a cold Agent.
807
+ * @param request - Session, queue item, and requested mutation.
808
+ * @returns acknowledgement that the queue mutation was applied.
809
+ */
810
+ updateQueue(request) {
811
+ if (request.action.kind === "edit" && request.action.content.some((block) => block.type !== "text")) throw new RemoteError("session/attachment-invalid", "queue edits accept text content only", { reason: "QUEUE_EDIT_NON_TEXT" });
812
+ const agent = this.ctx.agents.get(request.sessionId);
813
+ if (agent !== void 0 && hasApiSessionSubagentOwner(this.ctx, agent.session, agent)) throw apiSessionSubagentOwnershipError(request.sessionId);
814
+ if (agent === void 0) throw new RemoteError("session/queue-item-not-found", "queued item is no longer pending", { itemId: request.itemId });
815
+ const nextTurn = agent.inbox.nextTurn.find((message) => message.id === request.itemId);
816
+ const nextStep = agent.inbox.nextStep.find((message) => message.id === request.itemId);
817
+ const located = nextTurn === void 0 ? nextStep === void 0 ? void 0 : {
818
+ target: "next-step",
819
+ message: nextStep
820
+ } : {
821
+ target: "next-turn",
822
+ message: nextTurn
823
+ };
824
+ if (located === void 0) throw new RemoteError("session/queue-item-not-found", "queued item is no longer pending", { itemId: request.itemId });
825
+ const { target, message } = located;
826
+ if (request.action.kind === "steer" && (target !== "next-turn" || agent.status !== "running")) throw new RemoteError("session/steer-unavailable", "current turn no longer accepts steering", { itemId: request.itemId });
827
+ if (request.action.kind === "edit") agent.inbox.replace(request.itemId, freezeMessage({
828
+ ...message,
829
+ content: [...request.action.content]
830
+ }));
831
+ else {
832
+ agent.inbox.remove(request.itemId);
833
+ if (request.action.kind === "steer") agent.steer(message);
834
+ }
835
+ return { accepted: true };
836
+ }
837
+ /**
838
+ * Cancel one live ordinary Agent while retaining pending inbox work.
839
+ * @param request - Session whose active Agent turn is cancelled.
840
+ * @returns acknowledgement that cancellation was requested.
841
+ */
842
+ cancel(request) {
843
+ const agent = this.ctx.agents.get(request.sessionId);
844
+ if (agent === void 0) throw new RemoteError("session/not-found", `session "${request.sessionId}" not found (not attached)`, { sessionId: request.sessionId });
845
+ if (hasApiSessionSubagentOwner(this.ctx, agent.session, agent)) throw apiSessionSubagentOwnershipError(request.sessionId);
846
+ agent.cancel({ kind: "user" }, { keepInbox: true });
847
+ return { accepted: true };
848
+ }
849
+ async resolveAgent(sessionId) {
850
+ const found = await this.agents.resolveAgent(sessionId);
851
+ if ("error" in found) throw found.error;
852
+ return found.agent;
853
+ }
854
+ rejectCreation(sessionId, error) {
855
+ if (remoteErrorOf(error) !== void 0) throw error;
856
+ if (error instanceof ApiSessionPresetConflict) throw new RemoteError("agent-preset/conflict", error.message, {
857
+ sessionId: error.sessionId,
858
+ requestedPreset: error.requestedPreset,
859
+ ...error.existingPreset === void 0 ? {} : { existingPreset: error.existingPreset }
860
+ });
861
+ if (error instanceof ApiSessionCwdConflict) throw new RemoteError("session/conflict", error.message, {
862
+ sessionId: error.sessionId,
863
+ requestedCwd: error.requestedCwd,
864
+ ...error.existingCwd === void 0 ? {} : { existingCwd: error.existingCwd }
865
+ });
866
+ if (error instanceof ApiSessionSubagentOwnership) throw apiSessionSubagentOwnershipError(error.sessionId);
867
+ throw new RemoteError("gateway/internal", `failed to create session "${sessionId}": ${String(error)}`, {});
868
+ }
869
+ async readSessionState(sessionId) {
870
+ const attached = this.ctx.sessions.get(sessionId);
871
+ if (attached !== void 0) return {
872
+ id: attached.id,
873
+ header: attached.header,
874
+ events: [...attached.events]
875
+ };
876
+ const inspected = await inspectApiSession(this.ctx, sessionId);
877
+ return {
878
+ id: inspected.meta.id,
879
+ header: inspected.meta,
880
+ events: inspected.events
881
+ };
882
+ }
883
+ async forkWorkspace(source) {
884
+ const workspaces = this.ctx.workspaceRegistry.list();
885
+ const direct = workspaces.find((workspace) => workspace.sessionIds.includes(source.id));
886
+ if (direct !== void 0 || source.origin !== "subagent") return direct;
887
+ const lineage = await this.ctx.sessionQuery.traceSession(source.id);
888
+ for (const ancestor of lineage.ancestors) {
889
+ const workspace = workspaces.find((candidate) => candidate.sessionIds.includes(ancestor.header.id));
890
+ if (workspace !== void 0) return workspace;
891
+ }
892
+ }
893
+ };
894
+ function imageBlockIn(content, match) {
895
+ if (!Array.isArray(content)) return void 0;
896
+ for (const value of content) {
897
+ if (typeof value !== "object" || value === null || Array.isArray(value)) continue;
898
+ const block = value;
899
+ if (block.type === "image" && typeof block.attachment === "object" && block.attachment !== null) {
900
+ const ref = block.attachment;
901
+ if (match(ref)) return ref;
902
+ }
903
+ if (block.type === "tool-result") {
904
+ const nested = imageBlockIn(block.content, match);
905
+ if (nested !== void 0) return nested;
906
+ }
907
+ }
908
+ }
909
+ function imageInEvent(event, match) {
910
+ const data = event.data;
911
+ const direct = imageBlockIn(data.content, match);
912
+ if (direct !== void 0) return direct;
913
+ const message = imageBlockIn(data.message?.content, match);
914
+ if (message !== void 0) return message;
915
+ for (const inserted of data.inserted ?? []) {
916
+ const found = imageBlockIn(inserted.content, match);
917
+ if (found !== void 0) return found;
918
+ }
919
+ return event.type === "assistant/chunk" && data.chunk?.type === "block-end" ? imageBlockIn([data.chunk.block], match) : void 0;
920
+ }
921
+ function referencedImage(events, attachmentId) {
922
+ for (const event of events) {
923
+ const found = imageInEvent(event, (ref) => String(ref.attachmentId) === attachmentId);
924
+ if (found !== void 0) return found;
925
+ }
926
+ }
927
+ function routeServed(ctx, provider) {
928
+ return ctx.llm.listProviders().some((entry) => entry.id === provider);
929
+ }
930
+ //#endregion
931
+ //#region lib/types/control.js
932
+ /** Live Session queue, jobs, and projection state with reconnect baselines. */
933
+ /** Owns the Host-wide Session control stream. */
934
+ var SessionControlController = class {
935
+ ctx;
936
+ streams = /* @__PURE__ */ new Set();
937
+ /** @param ctx - Host context carrying live Agent, projection, and jobs services. */
938
+ constructor(ctx) {
939
+ this.ctx = ctx;
940
+ ctx.on("session/event", (session, event) => {
941
+ this.onSessionEvent(session, event);
942
+ });
943
+ ctx.sessionProjections.onChanged((session, key, value, seq) => {
944
+ this.broadcast({
945
+ type: "projection",
946
+ sessionId: session.id,
947
+ key,
948
+ value,
949
+ seq
950
+ });
951
+ });
952
+ ctx.inject(["jobs"], (jobsCtx) => {
953
+ jobsCtx.jobs.onJobsChanged((owner) => {
954
+ this.onJobsChanged(owner);
955
+ });
956
+ });
957
+ ctx.on("session/created", (session) => {
958
+ const jobs = this.jobsFor(this.ctx.agents.get(session.id));
959
+ if (jobs.length > 0) this.broadcast({
960
+ type: "jobs",
961
+ sessionId: session.id,
962
+ jobs
963
+ });
964
+ });
965
+ ctx.effect(() => () => {
966
+ for (const stream of this.streams) stream.end();
967
+ this.streams.clear();
968
+ }, "session-controller.control");
969
+ }
970
+ /**
971
+ * Open one generation of Host-wide live control state.
972
+ * @param signal - Remote stream cancellation.
973
+ * @returns one complete baseline followed by live replacement frames.
974
+ */
975
+ async *control(signal) {
976
+ signal.throwIfAborted();
977
+ const queue = new ControlQueue();
978
+ this.streams.add(queue);
979
+ try {
980
+ yield {
981
+ type: "baseline",
982
+ value: this.baseline()
983
+ };
984
+ yield* queue.iterate(signal);
985
+ } finally {
986
+ this.streams.delete(queue);
987
+ queue.end();
988
+ }
989
+ }
990
+ baseline() {
991
+ const sessions = this.ctx.sessions.list();
992
+ const queues = Object.create(null);
993
+ const jobs = Object.create(null);
994
+ for (const session of sessions) {
995
+ const agent = this.ctx.agents.get(session.id);
996
+ queues[session.id] = agent?.session === session ? queueItems(agent) : [];
997
+ jobs[session.id] = this.jobsFor(agent);
998
+ }
999
+ return {
1000
+ queues,
1001
+ jobs,
1002
+ projections: this.projectionBaseline(sessions)
1003
+ };
1004
+ }
1005
+ projectionBaseline(sessions) {
1006
+ const blocks = Object.create(null);
1007
+ for (const session of sessions) {
1008
+ const snapshot = this.ctx.sessionProjections.snapshot(session);
1009
+ blocks[session.id] = {
1010
+ asOfSeq: snapshot.asOfSeq,
1011
+ values: snapshot.values
1012
+ };
1013
+ }
1014
+ return blocks;
1015
+ }
1016
+ onSessionEvent(session, event) {
1017
+ if (event.type !== "agent/inbox/spliced") return;
1018
+ const agent = this.ctx.agents.get(session.id);
1019
+ if (agent?.session !== session) return;
1020
+ this.broadcast({
1021
+ type: "queue",
1022
+ sessionId: session.id,
1023
+ items: queueItems(agent, event.data)
1024
+ });
1025
+ }
1026
+ onJobsChanged(owner) {
1027
+ if (owner !== void 0) {
1028
+ this.broadcast({
1029
+ type: "jobs",
1030
+ sessionId: owner.id,
1031
+ jobs: this.jobsFor(owner)
1032
+ });
1033
+ return;
1034
+ }
1035
+ for (const session of this.ctx.sessions.list()) this.broadcast({
1036
+ type: "jobs",
1037
+ sessionId: session.id,
1038
+ jobs: this.jobsFor(this.ctx.agents.get(session.id))
1039
+ });
1040
+ }
1041
+ jobsFor(agent) {
1042
+ const jobs = this.ctx.get("jobs");
1043
+ return jobs === void 0 ? [] : jobs.list(agent).map(jobView);
1044
+ }
1045
+ broadcast(frame) {
1046
+ for (const stream of this.streams) stream.push(frame);
1047
+ }
1048
+ };
1049
+ var ControlQueue = class {
1050
+ buffer = new Deque();
1051
+ wake;
1052
+ done = false;
1053
+ push(frame) {
1054
+ if (this.done) return;
1055
+ this.buffer.pushBack(frame);
1056
+ const wake = this.wake;
1057
+ this.wake = void 0;
1058
+ wake?.();
1059
+ }
1060
+ end() {
1061
+ if (this.done) return;
1062
+ this.done = true;
1063
+ const wake = this.wake;
1064
+ this.wake = void 0;
1065
+ wake?.();
1066
+ }
1067
+ async *iterate(signal) {
1068
+ const onAbort = () => {
1069
+ this.end();
1070
+ };
1071
+ signal.addEventListener("abort", onAbort, { once: true });
1072
+ try {
1073
+ while (!this.done && !signal.aborted) {
1074
+ const frame = this.buffer.popFront();
1075
+ if (frame !== void 0) {
1076
+ yield frame;
1077
+ continue;
1078
+ }
1079
+ await new Promise((resolve) => {
1080
+ this.wake = resolve;
1081
+ });
1082
+ }
1083
+ while (this.buffer.size > 0 && !signal.aborted) yield this.buffer.popFront();
1084
+ } finally {
1085
+ signal.removeEventListener("abort", onAbort);
1086
+ this.end();
1087
+ }
1088
+ }
1089
+ };
1090
+ function queueItems(agent, splice) {
1091
+ const project = (target) => {
1092
+ const messages = target === "next-turn" ? agent.inbox.nextTurn : agent.inbox.nextStep;
1093
+ return splice?.target === target ? messages.toSpliced(splice.start, splice.removedCount ?? 0, ...splice.inserted) : messages;
1094
+ };
1095
+ return [...project("next-turn").map((message) => ({
1096
+ id: message.id,
1097
+ placement: "queued",
1098
+ ...promptRpcId(message),
1099
+ message: {
1100
+ id: message.id,
1101
+ content: message.content
1102
+ }
1103
+ })), ...project("next-step").map((message) => ({
1104
+ id: message.id,
1105
+ placement: message.source.kind === "user" ? "steering" : "context",
1106
+ ...promptRpcId(message),
1107
+ message: {
1108
+ id: message.id,
1109
+ content: message.content
1110
+ }
1111
+ }))];
1112
+ }
1113
+ /** Prompt-RPC identity carried by a browser-submitted message's user source. */
1114
+ function promptRpcId(message) {
1115
+ const source = message.source;
1116
+ return source.kind === "user" && "rpcId" in source ? { rpcId: source.rpcId } : {};
1117
+ }
1118
+ function jobView(job) {
1119
+ return {
1120
+ id: job.id,
1121
+ kind: job.kind,
1122
+ label: job.label,
1123
+ status: job.status,
1124
+ ...job.detail === void 0 ? {} : { detail: job.detail },
1125
+ startedAt: job.startedAt,
1126
+ ...job.finishedAt === void 0 ? {} : { finishedAt: job.finishedAt }
1127
+ };
1128
+ }
1129
+ //#endregion
1130
+ //#region lib/types/history.js
1131
+ /** Cold Session history pagination and live-event source. */
1132
+ var __addDisposableResource$3 = function(env, value, async) {
1133
+ if (value !== null && value !== void 0) {
1134
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1135
+ var dispose, inner;
1136
+ if (async) {
1137
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
1138
+ dispose = value[Symbol.asyncDispose];
1139
+ }
1140
+ if (dispose === void 0) {
1141
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
1142
+ dispose = value[Symbol.dispose];
1143
+ if (async) inner = dispose;
1144
+ }
1145
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
1146
+ if (inner) dispose = function() {
1147
+ try {
1148
+ inner.call(this);
1149
+ } catch (e) {
1150
+ return Promise.reject(e);
1151
+ }
1152
+ };
1153
+ env.stack.push({
1154
+ value,
1155
+ dispose,
1156
+ async
1157
+ });
1158
+ } else if (async) env.stack.push({ async: true });
1159
+ return value;
1160
+ };
1161
+ var __disposeResources$3 = (function(SuppressedError) {
1162
+ return function(env) {
1163
+ function fail(e) {
1164
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
1165
+ env.hasError = true;
1166
+ }
1167
+ var r, s = 0;
1168
+ function next() {
1169
+ while (r = env.stack.pop()) try {
1170
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
1171
+ if (r.dispose) {
1172
+ var result = r.dispose.call(r.value);
1173
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
1174
+ fail(e);
1175
+ return next();
1176
+ });
1177
+ } else s |= 1;
1178
+ } catch (e) {
1179
+ fail(e);
1180
+ }
1181
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
1182
+ if (env.hasError) throw env.error;
1183
+ }
1184
+ return next();
1185
+ };
1186
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
1187
+ var e = new Error(message);
1188
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1189
+ });
1190
+ const DEFAULT_MAX_MESSAGES = 50;
1191
+ const MESSAGE_TYPES$1 = new Set(["user/message", "assistant/message"]);
1192
+ /** Implements cold-safe history operations delegated by the Session Controller. */
1193
+ var SessionHistoryController = class {
1194
+ ctx;
1195
+ promote;
1196
+ closeFollowers = /* @__PURE__ */ new Set();
1197
+ /**
1198
+ * @param ctx - Host context carrying Session query and projection services.
1199
+ * @param promote - starts ordinary Session activation after snapshot delivery.
1200
+ */
1201
+ constructor(ctx, promote) {
1202
+ this.ctx = ctx;
1203
+ this.promote = promote;
1204
+ ctx.effect(() => () => {
1205
+ for (const close of this.closeFollowers) close();
1206
+ this.closeFollowers.clear();
1207
+ }, "session-controller.history");
1208
+ }
1209
+ /**
1210
+ * Read one message-aligned history page without activating an Agent.
1211
+ * @param request - durable address and backwards-page cursor.
1212
+ * @param signal - caller cancellation for persistence reads.
1213
+ * @returns a contiguous event page.
1214
+ */
1215
+ async page(request, signal) {
1216
+ const env_1 = {
1217
+ stack: [],
1218
+ error: void 0,
1219
+ hasError: false
1220
+ };
1221
+ try {
1222
+ validatePageRequest(request);
1223
+ const source = __addDisposableResource$3(env_1, await this.sourceFor(request.address, signal, false), false);
1224
+ signal.throwIfAborted();
1225
+ const sourceLog = source.events;
1226
+ const sourceCursor = sourceLog.at(-1)?.seq ?? -1;
1227
+ if (request.throughSeq > sourceCursor) throw new RemoteError("gateway/bad-request", `session page through seq ${String(request.throughSeq)} is past cursor ${String(sourceCursor)}`, {});
1228
+ /* v8 ignore next -- Session and persistence validation guarantee a dense zero-based event prefix. */
1229
+ if (request.throughSeq >= 0 && sourceLog[request.throughSeq]?.seq !== request.throughSeq) throw new RemoteError("gateway/internal", `session log does not contain through seq ${String(request.throughSeq)}`, {});
1230
+ const page = paginate(sourceLog, request.beforeSeq, request.maxMessages ?? DEFAULT_MAX_MESSAGES, request.throughSeq);
1231
+ return {
1232
+ records: pageRecords(page.events),
1233
+ hasMore: page.hasMore
1234
+ };
1235
+ } catch (e_1) {
1236
+ env_1.error = e_1;
1237
+ env_1.hasError = true;
1238
+ } finally {
1239
+ __disposeResources$3(env_1);
1240
+ }
1241
+ }
1242
+ /**
1243
+ * Follow events appended after an initial cursor on one durable address.
1244
+ * @param request - durable address and last committed sequence already held by the caller.
1245
+ * @param signal - stream cancellation owned by the Remote carrier.
1246
+ * @returns a complete opening snapshot followed by gap-free event frames.
1247
+ */
1248
+ async *follow(request, signal) {
1249
+ validateFollowRequest(request);
1250
+ const { address } = request;
1251
+ const target = addressId(address);
1252
+ const buffered = new Deque();
1253
+ let snapshotCursor;
1254
+ let wake;
1255
+ const notify = () => {
1256
+ const resume = wake;
1257
+ wake = void 0;
1258
+ resume?.();
1259
+ };
1260
+ const follower = { closed: false };
1261
+ const close = () => {
1262
+ follower.closed = true;
1263
+ notify();
1264
+ };
1265
+ this.closeFollowers.add(close);
1266
+ const disposeEvent = this.ctx.on("session/event", (session, event) => {
1267
+ if (session.id !== target) return;
1268
+ buffered.pushBack(event);
1269
+ notify();
1270
+ }, { global: true });
1271
+ const disposeCreated = this.ctx.on("session/created", (session) => {
1272
+ if (session.id !== target) return;
1273
+ const suffix = session.events.slice(snapshotCursor === void 0 ? session.firstLiveSeq : snapshotCursor + 1);
1274
+ for (let index = suffix.length - 1; index >= 0; index -= 1) buffered.pushFront(suffix[index]);
1275
+ notify();
1276
+ }, { global: true });
1277
+ const onAbort = () => {
1278
+ notify();
1279
+ };
1280
+ signal.addEventListener("abort", onAbort, { once: true });
1281
+ try {
1282
+ const env_2 = {
1283
+ stack: [],
1284
+ error: void 0,
1285
+ hasError: false
1286
+ };
1287
+ try {
1288
+ const source = __addDisposableResource$3(env_2, await this.sourceFor(address, signal, true), false);
1289
+ const events = source.events;
1290
+ signal.throwIfAborted();
1291
+ const cursor = source.cursor;
1292
+ snapshotCursor = cursor;
1293
+ const page = paginate(events, void 0, request.maxMessages ?? DEFAULT_MAX_MESSAGES);
1294
+ yield {
1295
+ type: "snapshot",
1296
+ header: source.header,
1297
+ cursor,
1298
+ records: pageRecords(page.events),
1299
+ hasMore: page.hasMore,
1300
+ projections: source.projections === void 0 ? {
1301
+ asOfSeq: cursor,
1302
+ values: {}
1303
+ } : projectionBlock(source.projections)
1304
+ };
1305
+ if (address.kind === "session" && source.source === "prepared") {
1306
+ const promotion = source.retain();
1307
+ try {
1308
+ this.promote(promotion);
1309
+ } catch (error) {
1310
+ promotion[Symbol.dispose]();
1311
+ throw error;
1312
+ }
1313
+ }
1314
+ let nextSeq = cursor + 1;
1315
+ while (!follower.closed && !signal.aborted) {
1316
+ const item = buffered.popFront();
1317
+ if (item === void 0) {
1318
+ await new Promise((resolve) => {
1319
+ wake = resolve;
1320
+ });
1321
+ continue;
1322
+ }
1323
+ if (item.seq < nextSeq) continue;
1324
+ if (item.seq !== nextSeq) throw new RemoteError("gateway/internal", `session event stream skipped seq ${String(nextSeq)}`, {});
1325
+ nextSeq++;
1326
+ yield entryFor(item);
1327
+ }
1328
+ } catch (e_2) {
1329
+ env_2.error = e_2;
1330
+ env_2.hasError = true;
1331
+ } finally {
1332
+ __disposeResources$3(env_2);
1333
+ }
1334
+ } finally {
1335
+ this.closeFollowers.delete(close);
1336
+ signal.removeEventListener("abort", onAbort);
1337
+ disposeCreated();
1338
+ disposeEvent();
1339
+ }
1340
+ }
1341
+ async sourceFor(address, signal, withProjections) {
1342
+ const sessionId = addressId(address);
1343
+ try {
1344
+ const observation = await this.ctx.sessionQuery.observeSession(sessionId, {
1345
+ signal,
1346
+ projectionMode: withProjections || address.kind === "subagent" ? "all" : "none"
1347
+ });
1348
+ if (observation.header.cwd === void 0) {
1349
+ observation[Symbol.dispose]();
1350
+ rejectNotFound(address);
1351
+ }
1352
+ try {
1353
+ validateAddress(address, observation.header, observation.projections);
1354
+ } catch (error) {
1355
+ observation[Symbol.dispose]();
1356
+ throw error;
1357
+ }
1358
+ return observation;
1359
+ } catch (error) {
1360
+ if (error instanceof SessionQueryError && error.code === "SESSION_QUERY_SESSION_NOT_FOUND") rejectNotFound(address);
1361
+ throw error;
1362
+ }
1363
+ }
1364
+ };
1365
+ function projectionBlock(snapshot) {
1366
+ return {
1367
+ asOfSeq: snapshot.asOfSeq,
1368
+ values: snapshot.values
1369
+ };
1370
+ }
1371
+ function validatePageRequest(request) {
1372
+ if (!Number.isSafeInteger(request.throughSeq) || request.throughSeq < -1) throw new RemoteError("gateway/bad-request", "throughSeq must be an integer greater than or equal to -1", {});
1373
+ if (request.beforeSeq !== void 0 && (!Number.isSafeInteger(request.beforeSeq) || request.beforeSeq < 0)) throw new RemoteError("gateway/bad-request", "beforeSeq must be a non-negative safe integer", {});
1374
+ if (request.maxMessages !== void 0 && (!Number.isSafeInteger(request.maxMessages) || request.maxMessages <= 0)) throw new RemoteError("gateway/bad-request", "maxMessages must be a positive safe integer", {});
1375
+ }
1376
+ function validateFollowRequest(request) {
1377
+ if (request.maxMessages !== void 0 && (!Number.isSafeInteger(request.maxMessages) || request.maxMessages <= 0)) throw new RemoteError("gateway/bad-request", "maxMessages must be a positive safe integer", {});
1378
+ }
1379
+ function addressId(address) {
1380
+ return address.kind === "session" ? address.sessionId : address.childSessionId;
1381
+ }
1382
+ function validateAddress(address, header, projections) {
1383
+ if (address.kind === "session") {
1384
+ if (header.origin === "subagent") throw new RemoteError("session/agent-busy", "subagent Sessions require their durable parent address", { reason: "use subagent delivery for this child session" });
1385
+ return;
1386
+ }
1387
+ if (header.origin !== "subagent" || header.parentSession !== address.parentSessionId) throw new RemoteError("subagent/unauthorized", "subagent does not belong to the supplied parent", { childSessionId: address.childSessionId });
1388
+ const identity = projections?.values.subagent;
1389
+ if (identity === null) throw new RemoteError("subagent/catalog-diagnostic", "subagent descriptor is corrupt", {
1390
+ parentSessionId: address.parentSessionId,
1391
+ childSessionId: address.childSessionId,
1392
+ reason: "corrupt"
1393
+ });
1394
+ if (identity === void 0 || identity.seq < (header.seedLength ?? 0)) throw new RemoteError("subagent/catalog-diagnostic", "subagent descriptor is unavailable", {
1395
+ parentSessionId: address.parentSessionId,
1396
+ childSessionId: address.childSessionId,
1397
+ reason: "unsupported"
1398
+ });
1399
+ if (identity.mode !== address.mode) throw new RemoteError("subagent/unauthorized", "subagent mode does not match the supplied address", { childSessionId: address.childSessionId });
1400
+ }
1401
+ function rejectNotFound(address) {
1402
+ if (address.kind === "session") throw new RemoteError("session/not-found", `session "${address.sessionId}" not found`, { sessionId: address.sessionId });
1403
+ throw new RemoteError("subagent/not-found", "subagent is unavailable", {
1404
+ parentSessionId: address.parentSessionId,
1405
+ childSessionId: address.childSessionId
1406
+ });
1407
+ }
1408
+ function paginate(events, beforeSeq, maxMessages, throughSeq = events.at(-1)?.seq ?? -1) {
1409
+ const end = Math.min(throughSeq + 1, beforeSeq ?? throughSeq + 1);
1410
+ let count = 0;
1411
+ let cut = 0;
1412
+ for (let index = end - 1; index >= 0; index--) {
1413
+ const event = events[index];
1414
+ if (!MESSAGE_TYPES$1.has(event.type) || !isAppendSurfaceEvent(event)) continue;
1415
+ count++;
1416
+ const sources = event.sourceEventSeqs;
1417
+ let groupStart = event.seq;
1418
+ if (sources !== void 0) for (const source of sources) groupStart = Math.min(groupStart, source);
1419
+ if (count >= maxMessages) {
1420
+ cut = groupStart;
1421
+ break;
1422
+ }
1423
+ }
1424
+ return {
1425
+ events: events.slice(cut, end),
1426
+ hasMore: cut > 0
1427
+ };
1428
+ }
1429
+ function entryFor(event) {
1430
+ return {
1431
+ type: "event",
1432
+ event
1433
+ };
1434
+ }
1435
+ function chunkEntryFor(row) {
1436
+ switch (row.type) {
1437
+ case "text-chunks": return {
1438
+ type: "chunks",
1439
+ event: {
1440
+ type: "chunkrow/text-chunks",
1441
+ seq: row.seq0,
1442
+ time: row.time0,
1443
+ data: row.data
1444
+ }
1445
+ };
1446
+ case "reasoning-chunks": return {
1447
+ type: "chunks",
1448
+ event: {
1449
+ type: "chunkrow/reasoning-chunks",
1450
+ seq: row.seq0,
1451
+ time: row.time0,
1452
+ data: row.data
1453
+ }
1454
+ };
1455
+ case "tool-call-chunks": return {
1456
+ type: "chunks",
1457
+ event: {
1458
+ type: "chunkrow/tool-call-chunks",
1459
+ seq: row.seq0,
1460
+ time: row.time0,
1461
+ data: row.data
1462
+ }
1463
+ };
1464
+ }
1465
+ }
1466
+ /** Encode one bounded logical page without changing its pagination cut. */
1467
+ function pageRecords(events) {
1468
+ return packChunkRuns(events).map((record) => isChunkRow(record) ? chunkEntryFor(record) : entryFor(record));
1469
+ }
1470
+ //#endregion
1471
+ //#region lib/types/file-references.js
1472
+ /** Session Controller adapter for Agent-scoped file-reference discovery. */
1473
+ var __runInitializers$2 = function(thisArg, initializers, value) {
1474
+ var useValue = arguments.length > 2;
1475
+ for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
1476
+ return useValue ? value : void 0;
1477
+ };
1478
+ var __esDecorate$2 = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
1479
+ function accept(f) {
1480
+ if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
1481
+ return f;
1482
+ }
1483
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
1484
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
1485
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
1486
+ var _, done = false;
1487
+ for (var i = decorators.length - 1; i >= 0; i--) {
1488
+ var context = {};
1489
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
1490
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
1491
+ context.addInitializer = function(f) {
1492
+ if (done) throw new TypeError("Cannot add initializers after decoration has completed");
1493
+ extraInitializers.push(accept(f || null));
1494
+ };
1495
+ var result = (0, decorators[i])(kind === "accessor" ? {
1496
+ get: descriptor.get,
1497
+ set: descriptor.set
1498
+ } : descriptor[key], context);
1499
+ if (kind === "accessor") {
1500
+ if (result === void 0) continue;
1501
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
1502
+ if (_ = accept(result.get)) descriptor.get = _;
1503
+ if (_ = accept(result.set)) descriptor.set = _;
1504
+ if (_ = accept(result.init)) initializers.unshift(_);
1505
+ } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_);
1506
+ else descriptor[key] = _;
1507
+ }
1508
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
1509
+ done = true;
1510
+ };
1511
+ /** Host Remote adapter over the composed file-reference provider. */
1512
+ let SessionFileReferences = (() => {
1513
+ let _classSuper = TypertRemoteService;
1514
+ let _instanceExtraInitializers = [];
1515
+ let _list_decorators;
1516
+ return class SessionFileReferences extends _classSuper {
1517
+ static {
1518
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
1519
+ _list_decorators = [Remote];
1520
+ __esDecorate$2(this, null, _list_decorators, {
1521
+ kind: "method",
1522
+ name: "list",
1523
+ static: false,
1524
+ private: false,
1525
+ access: {
1526
+ has: (obj) => "list" in obj,
1527
+ get: (obj) => obj.list
1528
+ },
1529
+ metadata: _metadata
1530
+ }, null, _instanceExtraInitializers);
1531
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, {
1532
+ enumerable: true,
1533
+ configurable: true,
1534
+ writable: true,
1535
+ value: _metadata
1536
+ });
1537
+ }
1538
+ static inject = ["fileReferences", "typert"];
1539
+ /** @param ctx - Host context carrying the selected file-reference provider. */
1540
+ constructor(ctx) {
1541
+ super(ctx, "sessionFileReferences", { namespace: "fileReferences" });
1542
+ __runInitializers$2(this, _instanceExtraInitializers);
1543
+ }
1544
+ /**
1545
+ * List file and directory candidates for one Agent's working directory.
1546
+ * @param agent - target Agent resolved from the Session identity on the wire.
1547
+ * @param query - path text following `@` or `@"`.
1548
+ * @param signal - caller cancellation.
1549
+ * @returns deterministic path-only candidates from the composed provider.
1550
+ */
1551
+ list(agent, query, signal) {
1552
+ return this.ctx.fileReferences.list(agent, query, signal);
1553
+ }
1554
+ };
1555
+ })();
1556
+ //#endregion
1557
+ //#region lib/types/list.js
1558
+ /** Cold-safe Session list and search projection. */
1559
+ var __addDisposableResource$2 = function(env, value, async) {
1560
+ if (value !== null && value !== void 0) {
1561
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
1562
+ var dispose, inner;
1563
+ if (async) {
1564
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
1565
+ dispose = value[Symbol.asyncDispose];
1566
+ }
1567
+ if (dispose === void 0) {
1568
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
1569
+ dispose = value[Symbol.dispose];
1570
+ if (async) inner = dispose;
1571
+ }
1572
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
1573
+ if (inner) dispose = function() {
1574
+ try {
1575
+ inner.call(this);
1576
+ } catch (e) {
1577
+ return Promise.reject(e);
1578
+ }
1579
+ };
1580
+ env.stack.push({
1581
+ value,
1582
+ dispose,
1583
+ async
1584
+ });
1585
+ } else if (async) env.stack.push({ async: true });
1586
+ return value;
1587
+ };
1588
+ var __disposeResources$2 = (function(SuppressedError) {
1589
+ return function(env) {
1590
+ function fail(e) {
1591
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
1592
+ env.hasError = true;
1593
+ }
1594
+ var r, s = 0;
1595
+ function next() {
1596
+ while (r = env.stack.pop()) try {
1597
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
1598
+ if (r.dispose) {
1599
+ var result = r.dispose.call(r.value);
1600
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
1601
+ fail(e);
1602
+ return next();
1603
+ });
1604
+ } else s |= 1;
1605
+ } catch (e) {
1606
+ fail(e);
1607
+ }
1608
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
1609
+ if (env.hasError) throw env.error;
1610
+ }
1611
+ return next();
1612
+ };
1613
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
1614
+ var e = new Error(message);
1615
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1616
+ });
1617
+ /** Default maximum artifact size eligible for one cold projection observation. */
1618
+ const DEFAULT_COLD_BLANK_PROBE_MAX_BYTES = 1024;
1619
+ const COLD_SUMMARY_BATCH_SIZE = 16;
1620
+ const SEARCH_PROVIDER_CALL_LIMIT = 100;
1621
+ const SESSION_SEARCH_QUERY_MAX_CHARS = 500;
1622
+ const MESSAGE_TYPES = new Set(["user/message", "assistant/message"]);
1623
+ const sessionListMetadataSchema = z$1.object({
1624
+ blank: z$1.boolean(),
1625
+ lastPromptAt: z$1.number().nullable()
1626
+ });
1627
+ const imageLimitsSchema = z$1.object({
1628
+ maxImageBytes: z$1.number().int().positive(),
1629
+ maxImagesPerMessage: z$1.number().int().positive(),
1630
+ maxMessageImageBytes: z$1.number().int().positive(),
1631
+ maxImagePixels: z$1.number().int().positive(),
1632
+ maxImageDimension: z$1.number().int().positive(),
1633
+ mediaTypes: z$1.array(z$1.string())
1634
+ });
1635
+ /**
1636
+ * Advance the Session-list metadata projection by one committed event.
1637
+ * @param state - metadata before the event.
1638
+ * @param event - next committed Session event.
1639
+ * @returns the original or advanced metadata value.
1640
+ */
1641
+ function applySessionListMetadata(state, event) {
1642
+ const blank = state.blank && event.type !== "turn/start";
1643
+ const lastPromptAt = event.type === "user/message" && event.data.source.kind === "user" ? event.time : state.lastPromptAt;
1644
+ return blank === state.blank && lastPromptAt === state.lastPromptAt ? state : {
1645
+ blank,
1646
+ lastPromptAt
1647
+ };
1648
+ }
1649
+ /**
1650
+ * Return the longest prefix containing at most `maximum` Unicode code points.
1651
+ * @param value - source text.
1652
+ * @param maximum - maximum number of Unicode code points.
1653
+ * @returns the source text or its longest allowed prefix.
1654
+ */
1655
+ function truncateUnicodeCodePoints(value, maximum) {
1656
+ let count = 0;
1657
+ let end = 0;
1658
+ for (const codePoint of value) {
1659
+ if (count === maximum) return value.slice(0, end);
1660
+ count++;
1661
+ end += codePoint.length;
1662
+ }
1663
+ return value;
1664
+ }
1665
+ /** Owns list projection registration, bounded cold summaries, and authorized search. */
1666
+ var ApiSessionList = class {
1667
+ ctx;
1668
+ coldBlankProbeMaxBytes;
1669
+ /**
1670
+ * @param ctx - Host context carrying Session, query, persistence, and projection services.
1671
+ * @param coldBlankProbeMaxBytes - maximum physical artifact size eligible for a full observation.
1672
+ */
1673
+ constructor(ctx, coldBlankProbeMaxBytes) {
1674
+ this.ctx = ctx;
1675
+ this.coldBlankProbeMaxBytes = coldBlankProbeMaxBytes;
1676
+ ctx.sessionProjections.register({
1677
+ key: "sessionListMetadata",
1678
+ stateSchema: sessionListMetadataSchema,
1679
+ init: () => ({
1680
+ blank: true,
1681
+ lastPromptAt: null
1682
+ }),
1683
+ apply: applySessionListMetadata,
1684
+ wire: {
1685
+ viewSchema: sessionListMetadataSchema,
1686
+ view: (state) => state
1687
+ },
1688
+ stateVersion: 1
1689
+ });
1690
+ ctx.inject(["attachments"], (attachmentCtx) => {
1691
+ ctx.sessionProjections.register({
1692
+ key: "imageLimits",
1693
+ stateSchema: z$1.null(),
1694
+ init: () => null,
1695
+ apply: (state) => state,
1696
+ wire: {
1697
+ viewSchema: imageLimitsSchema,
1698
+ view: () => attachmentCtx.attachments.imageLimits
1699
+ },
1700
+ stateVersion: 1
1701
+ });
1702
+ });
1703
+ }
1704
+ /**
1705
+ * Build one current attached-Session summary.
1706
+ * @param session - attached Session to summarize.
1707
+ * @returns current list metadata and available projections.
1708
+ */
1709
+ summaryFor(session) {
1710
+ const projections = this.projectionsFor(session.header, session);
1711
+ const metadata = projections?.values.sessionListMetadata;
1712
+ return {
1713
+ sessionId: session.id,
1714
+ updatedAt: updatedAt(session.header, metadata),
1715
+ running: this.ctx.agents.get(session.id)?.status === "running",
1716
+ blank: metadata?.blank ?? session.seq === 0,
1717
+ ...listFields(session.header),
1718
+ ...projections === void 0 ? {} : { projections }
1719
+ };
1720
+ }
1721
+ /**
1722
+ * Read every visible attached and persisted Session without activating an Agent.
1723
+ * @param signal - optional cancellation for persistence reads.
1724
+ * @returns visible Session summaries ordered by activity.
1725
+ */
1726
+ async list(signal) {
1727
+ signal?.throwIfAborted();
1728
+ const records = await this.ctx.sessionQuery.listSessions(signal);
1729
+ signal?.throwIfAborted();
1730
+ const items = [];
1731
+ const cold = [];
1732
+ for (const record of records) {
1733
+ const live = this.ctx.sessions.get(record.header.id);
1734
+ if (live !== void 0) {
1735
+ items.push(this.summaryFor(live));
1736
+ continue;
1737
+ }
1738
+ if (record.header.cwd === void 0) continue;
1739
+ cold.push(record.header);
1740
+ }
1741
+ for (let offset = 0; offset < cold.length; offset += COLD_SUMMARY_BATCH_SIZE) {
1742
+ const settled = await Promise.allSettled(cold.slice(offset, offset + COLD_SUMMARY_BATCH_SIZE).map((header) => this.summarizeCold(header, signal)));
1743
+ for (const result of settled) {
1744
+ if (result.status === "rejected") throw result.reason;
1745
+ items.push(result.value);
1746
+ }
1747
+ }
1748
+ items.sort((left, right) => right.updatedAt - left.updatedAt);
1749
+ return items;
1750
+ }
1751
+ async summarizeCold(header, signal) {
1752
+ const cached = this.projectionsFor(header, void 0);
1753
+ const projections = cached?.values.sessionListMetadata?.blank === false ? cached : await this.probeSmallCold(header, signal) ?? cached;
1754
+ const raced = this.ctx.sessions.get(header.id);
1755
+ if (raced !== void 0) return this.summaryFor(raced);
1756
+ const metadata = projections?.values.sessionListMetadata;
1757
+ return {
1758
+ sessionId: header.id,
1759
+ updatedAt: updatedAt(header, metadata),
1760
+ running: false,
1761
+ blank: metadata?.blank ?? false,
1762
+ ...listFields(header),
1763
+ ...projections === void 0 ? {} : { projections }
1764
+ };
1765
+ }
1766
+ async probeSmallCold(header, signal) {
1767
+ if (this.coldBlankProbeMaxBytes === 0) return void 0;
1768
+ const location = this.ctx.get("sessionPersistence")?.locate(header);
1769
+ if (location === void 0) return void 0;
1770
+ signal?.throwIfAborted();
1771
+ try {
1772
+ if ((await stat(location.path)).size > this.coldBlankProbeMaxBytes) return void 0;
1773
+ } catch {
1774
+ signal?.throwIfAborted();
1775
+ return;
1776
+ }
1777
+ try {
1778
+ const env_1 = {
1779
+ stack: [],
1780
+ error: void 0,
1781
+ hasError: false
1782
+ };
1783
+ try {
1784
+ const block = __addDisposableResource$2(env_1, await this.ctx.sessionQuery.observeSession(header.id, {
1785
+ ...signal === void 0 ? {} : { signal },
1786
+ projectionMode: "all"
1787
+ }), false).projections;
1788
+ return block === void 0 ? void 0 : {
1789
+ asOfSeq: block.asOfSeq,
1790
+ values: block.values
1791
+ };
1792
+ } catch (e_1) {
1793
+ env_1.error = e_1;
1794
+ env_1.hasError = true;
1795
+ } finally {
1796
+ __disposeResources$2(env_1);
1797
+ }
1798
+ } catch (error) {
1799
+ signal?.throwIfAborted();
1800
+ this.ctx.logger.warn(`api-session.list: small cold observation for "${header.id}" failed; serving it as visible: ${String(error)}`);
1801
+ return;
1802
+ }
1803
+ }
1804
+ /**
1805
+ * Search current visible message content without activating any matching Session.
1806
+ * @param query - literal message-content query.
1807
+ * @param signal - cancellation for list and search reads.
1808
+ * @returns authorized bounded Session search results.
1809
+ */
1810
+ async search(query, signal) {
1811
+ const normalizedQuery = normalizeSearchQuery(query);
1812
+ signal.throwIfAborted();
1813
+ const provider = this.ctx.get("sessionQuery");
1814
+ if (provider === void 0) throw new RemoteError("gateway/internal", "session search is unavailable: this deployment does not mount @deepseek-ai/dsh-session-query", {});
1815
+ try {
1816
+ const visible = await provider.listSessions(signal);
1817
+ signal.throwIfAborted();
1818
+ const visibleIds = new Set(visible.filter((record) => record.header.cwd !== void 0).map((record) => record.header.id));
1819
+ if (visibleIds.size === 0) return {
1820
+ items: [],
1821
+ hasMore: false
1822
+ };
1823
+ const authorized = [];
1824
+ const acceptedIds = /* @__PURE__ */ new Set();
1825
+ const seenCursors = /* @__PURE__ */ new Set();
1826
+ let cursor;
1827
+ let providerCalls = 0;
1828
+ let pageLimit = 20;
1829
+ while (authorized.length <= 20) {
1830
+ signal.throwIfAborted();
1831
+ if (providerCalls >= SEARCH_PROVIDER_CALL_LIMIT) throw new Error(`session search provider exceeded the ${SEARCH_PROVIDER_CALL_LIMIT}-call work budget`);
1832
+ providerCalls++;
1833
+ const requestedCursor = cursor;
1834
+ const requestedLimit = pageLimit;
1835
+ let page;
1836
+ try {
1837
+ page = await provider.searchSessions({
1838
+ query: normalizedQuery,
1839
+ eventFilters: [{
1840
+ kind: "type",
1841
+ values: ["user/message", "assistant/message"]
1842
+ }, {
1843
+ kind: "surface",
1844
+ values: ["current"]
1845
+ }],
1846
+ limit: requestedLimit,
1847
+ ...requestedCursor === void 0 ? {} : { cursor: requestedCursor }
1848
+ }, { signal });
1849
+ signal.throwIfAborted();
1850
+ } catch (error) {
1851
+ signal.throwIfAborted();
1852
+ if (requestedCursor === void 0 && error instanceof SessionQueryError && error.code === "SESSION_QUERY_INVALID_LIMIT" && requestedLimit > 1) {
1853
+ pageLimit = Math.max(1, Math.floor(requestedLimit / 2));
1854
+ continue;
1855
+ }
1856
+ if (requestedCursor !== void 0 && error instanceof SessionQueryError && error.code === "SESSION_QUERY_STALE_CURSOR") {
1857
+ authorized.length = 0;
1858
+ acceptedIds.clear();
1859
+ seenCursors.clear();
1860
+ cursor = void 0;
1861
+ continue;
1862
+ }
1863
+ throw error;
1864
+ }
1865
+ if (page.items.length > requestedLimit) throw new Error(`session search provider returned ${String(page.items.length)} items; maximum is ${String(requestedLimit)}`);
1866
+ for (const hit of page.items) {
1867
+ if (authorized.length > 20) continue;
1868
+ if (!visibleIds.has(hit.header.id) || hit.bestMatch.sessionId !== hit.header.id || hit.bestMatch.surface !== "current" || !MESSAGE_TYPES.has(hit.bestMatch.type) || acceptedIds.has(hit.header.id)) continue;
1869
+ acceptedIds.add(hit.header.id);
1870
+ authorized.push({
1871
+ sessionId: hit.header.id,
1872
+ snippet: truncateUnicodeCodePoints(hit.bestMatch.snippet, 240)
1873
+ });
1874
+ }
1875
+ if (page.nextCursor !== void 0) {
1876
+ if (seenCursors.has(page.nextCursor)) throw new Error("session search provider repeated a continuation cursor");
1877
+ seenCursors.add(page.nextCursor);
1878
+ }
1879
+ if (authorized.length > 20 || page.nextCursor === void 0) break;
1880
+ cursor = page.nextCursor;
1881
+ }
1882
+ return {
1883
+ items: authorized.slice(0, 20),
1884
+ hasMore: authorized.length > 20
1885
+ };
1886
+ } catch (error) {
1887
+ signal.throwIfAborted();
1888
+ if (error instanceof SessionQueryError && error.code === "SESSION_QUERY_ABORTED") throw new RemoteError("gateway/cancelled", "session search was aborted", {});
1889
+ throw new RemoteError("gateway/internal", `session search failed: ${String(error)}`, {});
1890
+ }
1891
+ }
1892
+ projectionsFor(header, session) {
1893
+ try {
1894
+ const block = session === void 0 ? this.ctx.get("sessionProjectionCache")?.cachedSnapshot(header) : this.ctx.sessionProjections.cachedSnapshot(session);
1895
+ return block !== void 0 && Object.keys(block.values).length > 0 ? {
1896
+ asOfSeq: block.asOfSeq,
1897
+ values: block.values
1898
+ } : void 0;
1899
+ } catch (error) {
1900
+ this.ctx.logger.warn(`api-session.list: projection column for "${header.id}" failed; serving the row without it: ${String(error)}`);
1901
+ return;
1902
+ }
1903
+ }
1904
+ };
1905
+ function normalizeSearchQuery(query) {
1906
+ const normalized = query.trim();
1907
+ if (normalized.length === 0) throw new RemoteError("gateway/bad-request", "session search query must not be empty", {});
1908
+ if (normalized.length > SESSION_SEARCH_QUERY_MAX_CHARS) throw new RemoteError("gateway/bad-request", `session search query must contain at most ${SESSION_SEARCH_QUERY_MAX_CHARS} UTF-16 code units`, {});
1909
+ if (normalized.includes("\0")) throw new RemoteError("gateway/bad-request", "session search query must not contain NUL", {});
1910
+ return normalized;
1911
+ }
1912
+ function updatedAt(header, metadata) {
1913
+ return Math.max(header.createdAt, metadata?.lastPromptAt ?? 0);
1914
+ }
1915
+ function listFields(header) {
1916
+ return {
1917
+ ...header.parentSession === void 0 ? {} : { parentSessionId: header.parentSession },
1918
+ ...header.origin === void 0 ? {} : { origin: header.origin },
1919
+ ...header.cwd === void 0 ? {} : { cwd: header.cwd }
1920
+ };
1921
+ }
1922
+ //#endregion
1923
+ //#region lib/types/catalog.js
1924
+ /** Shared projection of the live LLM registry into the browser model catalog. */
1925
+ /**
1926
+ * Build the browser model catalog without requiring a Session.
1927
+ * @param ctx - Host context carrying the live LLM registry.
1928
+ * @param defaultSelection - deployment default used before a Session selects a model.
1929
+ * @returns successful non-empty provider groups and isolated provider failures.
1930
+ */
1931
+ async function buildModelCatalog(ctx, defaultSelection = ctx.agentDefaultModel.currentSelection()) {
1932
+ const providers = ctx.llm.listProviders();
1933
+ const catalog = await Promise.all(providers.map(async (provider) => {
1934
+ try {
1935
+ const models = await ctx.llm.listModels(provider.id);
1936
+ const entries = await Promise.all(models.map(async (model) => {
1937
+ const resolved = await ctx.llm.resolveModelInfo(provider.id, model.id);
1938
+ const reasoning = resolved.reasoning === void 0 ? void 0 : {
1939
+ efforts: resolved.reasoning.efforts.map((effort) => ({
1940
+ id: effort.id,
1941
+ name: effort.name,
1942
+ ...effort.description === void 0 ? {} : { description: effort.description }
1943
+ })),
1944
+ ...resolved.reasoning.defaultEffort === void 0 ? {} : { defaultEffort: resolved.reasoning.defaultEffort }
1945
+ };
1946
+ return {
1947
+ id: model.id,
1948
+ name: model.name,
1949
+ ...model.description === void 0 ? {} : { description: model.description },
1950
+ ...reasoning === void 0 ? {} : { reasoning }
1951
+ };
1952
+ }));
1953
+ return {
1954
+ kind: "group",
1955
+ group: {
1956
+ id: provider.id,
1957
+ name: provider.name,
1958
+ models: entries
1959
+ }
1960
+ };
1961
+ } catch (error) {
1962
+ return {
1963
+ kind: "failure",
1964
+ failure: {
1965
+ id: provider.id,
1966
+ name: provider.name,
1967
+ message: error instanceof Error ? error.message : String(error)
1968
+ }
1969
+ };
1970
+ }
1971
+ }));
1972
+ return {
1973
+ default: { ...defaultSelection },
1974
+ routableProviders: providers.map((provider) => provider.id),
1975
+ groups: catalog.flatMap((item) => item.kind === "group" ? [item.group] : []).filter((group) => group.models.length > 0),
1976
+ failures: catalog.flatMap((item) => item.kind === "failure" ? [item.failure] : [])
1977
+ };
1978
+ }
1979
+ //#endregion
1980
+ //#region lib/types/model-selection-projection.js
1981
+ /** Durable model-selection intent and request-use projection. */
1982
+ const modelSelectionSchema = z$1.object({
1983
+ provider: z$1.string().min(1),
1984
+ model: z$1.string().min(1),
1985
+ reasoningEffort: z$1.string().min(1).optional()
1986
+ });
1987
+ const modelSelectionProjectionStateSchema = z$1.object({
1988
+ lastUsed: modelSelectionSchema.nullable(),
1989
+ pending: modelSelectionSchema.nullable()
1990
+ });
1991
+ const modelSelectionProjectionSchema = z$1.object({
1992
+ lastUsed: modelSelectionSchema.nullable(),
1993
+ next: modelSelectionSchema.nullable()
1994
+ });
1995
+ /**
1996
+ * Advance durable model-selection state by one Session event.
1997
+ * @param state - selection state before the event.
1998
+ * @param event - next committed Session event.
1999
+ * @returns the original or advanced selection state.
2000
+ */
2001
+ function applyModelSelectionProjection(state, event) {
2002
+ if (event.type === "model/selection") return sameSelection(state.pending, event.data) ? state : {
2003
+ lastUsed: state.lastUsed,
2004
+ pending: event.data
2005
+ };
2006
+ if (event.type !== "request/header") return state;
2007
+ const lastUsed = {
2008
+ provider: event.data.header.config.provider,
2009
+ model: event.data.header.config.model,
2010
+ ...event.data.header.config.reasoningEffort === void 0 ? {} : { reasoningEffort: String(event.data.header.config.reasoningEffort) }
2011
+ };
2012
+ const pending = sameSelection(state.pending, lastUsed) ? null : state.pending;
2013
+ return sameSelection(state.lastUsed, lastUsed) && pending === state.pending ? state : {
2014
+ lastUsed,
2015
+ pending
2016
+ };
2017
+ }
2018
+ const modelSelectionProjection = {
2019
+ key: "modelSelection",
2020
+ stateSchema: modelSelectionProjectionStateSchema,
2021
+ init: () => ({
2022
+ lastUsed: null,
2023
+ pending: null
2024
+ }),
2025
+ apply: applyModelSelectionProjection,
2026
+ wire: {
2027
+ viewSchema: modelSelectionProjectionSchema,
2028
+ view: (state) => ({
2029
+ lastUsed: state.lastUsed,
2030
+ next: state.pending ?? state.lastUsed
2031
+ })
2032
+ },
2033
+ stateVersion: 2
2034
+ };
2035
+ function sameSelection(left, right) {
2036
+ return left === right || left !== null && right !== null && left.provider === right.provider && left.model === right.model && left.reasoningEffort === right.reasoningEffort;
2037
+ }
2038
+ /**
2039
+ * Register the durable model-selection projection when the registry is present.
2040
+ * @param ctx - Session Controller context.
2041
+ */
2042
+ function installModelSelectionProjection(ctx) {
2043
+ ctx.sessionProjections.register(modelSelectionProjection);
2044
+ }
2045
+ //#endregion
2046
+ //#region lib/types/skill-catalog.js
2047
+ /** Session-addressed, cold-readable skill catalog Remote. */
2048
+ var __runInitializers$1 = function(thisArg, initializers, value) {
2049
+ var useValue = arguments.length > 2;
2050
+ for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
2051
+ return useValue ? value : void 0;
2052
+ };
2053
+ var __esDecorate$1 = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2054
+ function accept(f) {
2055
+ if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
2056
+ return f;
2057
+ }
2058
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
2059
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
2060
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
2061
+ var _, done = false;
2062
+ for (var i = decorators.length - 1; i >= 0; i--) {
2063
+ var context = {};
2064
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
2065
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
2066
+ context.addInitializer = function(f) {
2067
+ if (done) throw new TypeError("Cannot add initializers after decoration has completed");
2068
+ extraInitializers.push(accept(f || null));
2069
+ };
2070
+ var result = (0, decorators[i])(kind === "accessor" ? {
2071
+ get: descriptor.get,
2072
+ set: descriptor.set
2073
+ } : descriptor[key], context);
2074
+ if (kind === "accessor") {
2075
+ if (result === void 0) continue;
2076
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
2077
+ if (_ = accept(result.get)) descriptor.get = _;
2078
+ if (_ = accept(result.set)) descriptor.set = _;
2079
+ if (_ = accept(result.init)) initializers.unshift(_);
2080
+ } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_);
2081
+ else descriptor[key] = _;
2082
+ }
2083
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
2084
+ done = true;
2085
+ };
2086
+ var __addDisposableResource$1 = function(env, value, async) {
2087
+ if (value !== null && value !== void 0) {
2088
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
2089
+ var dispose, inner;
2090
+ if (async) {
2091
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
2092
+ dispose = value[Symbol.asyncDispose];
2093
+ }
2094
+ if (dispose === void 0) {
2095
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
2096
+ dispose = value[Symbol.dispose];
2097
+ if (async) inner = dispose;
2098
+ }
2099
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
2100
+ if (inner) dispose = function() {
2101
+ try {
2102
+ inner.call(this);
2103
+ } catch (e) {
2104
+ return Promise.reject(e);
2105
+ }
2106
+ };
2107
+ env.stack.push({
2108
+ value,
2109
+ dispose,
2110
+ async
2111
+ });
2112
+ } else if (async) env.stack.push({ async: true });
2113
+ return value;
2114
+ };
2115
+ var __disposeResources$1 = (function(SuppressedError) {
2116
+ return function(env) {
2117
+ function fail(e) {
2118
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
2119
+ env.hasError = true;
2120
+ }
2121
+ var r, s = 0;
2122
+ function next() {
2123
+ while (r = env.stack.pop()) try {
2124
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
2125
+ if (r.dispose) {
2126
+ var result = r.dispose.call(r.value);
2127
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
2128
+ fail(e);
2129
+ return next();
2130
+ });
2131
+ } else s |= 1;
2132
+ } catch (e) {
2133
+ fail(e);
2134
+ }
2135
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
2136
+ if (env.hasError) throw env.error;
2137
+ }
2138
+ return next();
2139
+ };
2140
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
2141
+ var e = new Error(message);
2142
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
2143
+ });
2144
+ /** Host service backing `ctx.remote.skills` without activating a cold Agent. */
2145
+ let SessionSkillCatalog = (() => {
2146
+ let _classSuper = TypertRemoteService;
2147
+ let _instanceExtraInitializers = [];
2148
+ let _list_decorators;
2149
+ return class SessionSkillCatalog extends _classSuper {
2150
+ static {
2151
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
2152
+ _list_decorators = [Remote];
2153
+ __esDecorate$1(this, null, _list_decorators, {
2154
+ kind: "method",
2155
+ name: "list",
2156
+ static: false,
2157
+ private: false,
2158
+ access: {
2159
+ has: (obj) => "list" in obj,
2160
+ get: (obj) => obj.list
2161
+ },
2162
+ metadata: _metadata
2163
+ }, null, _instanceExtraInitializers);
2164
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, {
2165
+ enumerable: true,
2166
+ configurable: true,
2167
+ writable: true,
2168
+ value: _metadata
2169
+ });
2170
+ }
2171
+ static inject = [
2172
+ "agents",
2173
+ "sessionQuery",
2174
+ "typert"
2175
+ ];
2176
+ /** @param ctx - Host context carrying Session reads and optional skill/preset services. */
2177
+ constructor(ctx) {
2178
+ super(ctx, "sessionSkillCatalog", { namespace: "skills" });
2179
+ __runInitializers$1(this, _instanceExtraInitializers);
2180
+ }
2181
+ /**
2182
+ * List the user-invocable skills visible to one Session composition.
2183
+ * @param request - Session identity whose cwd and preset select the catalog view.
2184
+ * @param signal - caller lifetime carried by the Remote transport; admitted catalog reads retain their existing completion semantics.
2185
+ * @returns user-invocable skill metadata without loading skill bodies.
2186
+ * @throws RemoteError when the Session cannot be inspected or no registry can serve it.
2187
+ */
2188
+ async list(request, signal) {
2189
+ const { sessionId } = request;
2190
+ let cwd;
2191
+ let agentPreset;
2192
+ try {
2193
+ const env_1 = {
2194
+ stack: [],
2195
+ error: void 0,
2196
+ hasError: false
2197
+ };
2198
+ try {
2199
+ const observation = __addDisposableResource$1(env_1, await this.ctx.sessionQuery.observeSession(sessionId), false);
2200
+ if (observation.projections === void 0) throw new Error("skill catalog requires a projected Session observation");
2201
+ cwd = observation.header.cwd;
2202
+ agentPreset = observation.projections.values.agentPreset ?? void 0;
2203
+ } catch (e_1) {
2204
+ env_1.error = e_1;
2205
+ env_1.hasError = true;
2206
+ } finally {
2207
+ __disposeResources$1(env_1);
2208
+ }
2209
+ } catch (error) {
2210
+ if (error instanceof SessionQueryError && error.code === "SESSION_QUERY_SESSION_NOT_FOUND") throw new RemoteError("session/not-found", `session "${sessionId}" not found`, { sessionId });
2211
+ throw new RemoteError("gateway/internal", `session "${sessionId}" could not be inspected: ${String(error)}`, {});
2212
+ }
2213
+ if (cwd === void 0) throw new RemoteError("gateway/internal", `session "${sessionId}" has no project cwd`, {});
2214
+ const live = this.ctx.agents.get(sessionId);
2215
+ const presets = this.ctx.get("agentPresets");
2216
+ const skillRegistry = (live === void 0 ? void 0 : presets?.serviceFor(live, "skills")) ?? this.ctx.get("skills");
2217
+ if (skillRegistry === void 0) throw new RemoteError("gateway/internal", "skill registry is absent: neither this session's agent preset nor the host composition mounts @deepseek-ai/dsh-skill", {});
2218
+ const scope = await this.scopeFor(sessionId, agentPreset);
2219
+ try {
2220
+ return { skills: (await skillRegistry.list({
2221
+ cwd,
2222
+ scope
2223
+ })).filter(isUserInvocable).map((skill) => ({
2224
+ name: skill.name,
2225
+ description: skill.description,
2226
+ ...skill.whenToUse === void 0 ? {} : { whenToUse: skill.whenToUse },
2227
+ modelInvocable: skill.invocation.modelInvocable
2228
+ })) };
2229
+ } catch (error) {
2230
+ throw new RemoteError("gateway/internal", `skill listing failed: ${String(error)}`, {});
2231
+ }
2232
+ }
2233
+ /** Resolve a live or standing preset scope without creating an Agent. */
2234
+ async scopeFor(sessionId, agentPreset) {
2235
+ const live = this.ctx.agents.get(sessionId);
2236
+ if (live !== void 0) return live;
2237
+ const presets = this.ctx.get("agentPresets");
2238
+ if (presets === void 0) return void 0;
2239
+ try {
2240
+ return await presets.standingKeyFor(agentPreset);
2241
+ } catch {
2242
+ return;
2243
+ }
2244
+ }
2245
+ };
2246
+ })();
2247
+ //#endregion
2248
+ //#region lib/types/index.js
2249
+ /** Session Remote owner: cold reads, explicit Agent commands, and live control state. */
2250
+ var __runInitializers = function(thisArg, initializers, value) {
2251
+ var useValue = arguments.length > 2;
2252
+ for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
2253
+ return useValue ? value : void 0;
2254
+ };
2255
+ var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
2256
+ function accept(f) {
2257
+ if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected");
2258
+ return f;
2259
+ }
2260
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
2261
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
2262
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
2263
+ var _, done = false;
2264
+ for (var i = decorators.length - 1; i >= 0; i--) {
2265
+ var context = {};
2266
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
2267
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
2268
+ context.addInitializer = function(f) {
2269
+ if (done) throw new TypeError("Cannot add initializers after decoration has completed");
2270
+ extraInitializers.push(accept(f || null));
2271
+ };
2272
+ var result = (0, decorators[i])(kind === "accessor" ? {
2273
+ get: descriptor.get,
2274
+ set: descriptor.set
2275
+ } : descriptor[key], context);
2276
+ if (kind === "accessor") {
2277
+ if (result === void 0) continue;
2278
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
2279
+ if (_ = accept(result.get)) descriptor.get = _;
2280
+ if (_ = accept(result.set)) descriptor.set = _;
2281
+ if (_ = accept(result.init)) initializers.unshift(_);
2282
+ } else if (_ = accept(result)) if (kind === "field") initializers.unshift(_);
2283
+ else descriptor[key] = _;
2284
+ }
2285
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
2286
+ done = true;
2287
+ };
2288
+ var __addDisposableResource = function(env, value, async) {
2289
+ if (value !== null && value !== void 0) {
2290
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
2291
+ var dispose, inner;
2292
+ if (async) {
2293
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
2294
+ dispose = value[Symbol.asyncDispose];
2295
+ }
2296
+ if (dispose === void 0) {
2297
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
2298
+ dispose = value[Symbol.dispose];
2299
+ if (async) inner = dispose;
2300
+ }
2301
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
2302
+ if (inner) dispose = function() {
2303
+ try {
2304
+ inner.call(this);
2305
+ } catch (e) {
2306
+ return Promise.reject(e);
2307
+ }
2308
+ };
2309
+ env.stack.push({
2310
+ value,
2311
+ dispose,
2312
+ async
2313
+ });
2314
+ } else if (async) env.stack.push({ async: true });
2315
+ return value;
2316
+ };
2317
+ var __disposeResources = (function(SuppressedError) {
2318
+ return function(env) {
2319
+ function fail(e) {
2320
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
2321
+ env.hasError = true;
2322
+ }
2323
+ var r, s = 0;
2324
+ function next() {
2325
+ while (r = env.stack.pop()) try {
2326
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
2327
+ if (r.dispose) {
2328
+ var result = r.dispose.call(r.value);
2329
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
2330
+ fail(e);
2331
+ return next();
2332
+ });
2333
+ } else s |= 1;
2334
+ } catch (e) {
2335
+ fail(e);
2336
+ }
2337
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
2338
+ if (env.hasError) throw env.error;
2339
+ }
2340
+ return next();
2341
+ };
2342
+ })(typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
2343
+ var e = new Error(message);
2344
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
2345
+ });
2346
+ /** Host service backing the generated `ctx.remote.session` namespace. */
2347
+ let SessionController = (() => {
2348
+ let _classSuper = TypertRemoteService;
2349
+ let _instanceExtraInitializers = [];
2350
+ let _list_decorators;
2351
+ let _search_decorators;
2352
+ let _create_decorators;
2353
+ let _selectModel_decorators;
2354
+ let _modelCatalog_decorators;
2355
+ let _canOpenWorkspacePath_decorators;
2356
+ let _openWorkspacePath_decorators;
2357
+ let _rename_decorators;
2358
+ let _fork_decorators;
2359
+ let _prompt_decorators;
2360
+ let _attachment_decorators;
2361
+ let _updateQueue_decorators;
2362
+ let _cancel_decorators;
2363
+ let _page_decorators;
2364
+ let _follow_decorators;
2365
+ let _control_decorators;
2366
+ return class SessionController extends _classSuper {
2367
+ static {
2368
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
2369
+ _list_decorators = [Remote("list")];
2370
+ _search_decorators = [Remote("search")];
2371
+ _create_decorators = [Remote("create")];
2372
+ _selectModel_decorators = [Remote("selectModel")];
2373
+ _modelCatalog_decorators = [Remote("modelCatalog")];
2374
+ _canOpenWorkspacePath_decorators = [Remote];
2375
+ _openWorkspacePath_decorators = [Remote("openWorkspacePath")];
2376
+ _rename_decorators = [Remote("rename")];
2377
+ _fork_decorators = [Remote("fork")];
2378
+ _prompt_decorators = [Remote("prompt")];
2379
+ _attachment_decorators = [Remote("attachment")];
2380
+ _updateQueue_decorators = [Remote("updateQueue")];
2381
+ _cancel_decorators = [Remote("cancel")];
2382
+ _page_decorators = [Remote("page")];
2383
+ _follow_decorators = [Remote({ mode: "stream" })];
2384
+ _control_decorators = [Remote({ mode: "stream" })];
2385
+ __esDecorate(this, null, _list_decorators, {
2386
+ kind: "method",
2387
+ name: "list",
2388
+ static: false,
2389
+ private: false,
2390
+ access: {
2391
+ has: (obj) => "list" in obj,
2392
+ get: (obj) => obj.list
2393
+ },
2394
+ metadata: _metadata
2395
+ }, null, _instanceExtraInitializers);
2396
+ __esDecorate(this, null, _search_decorators, {
2397
+ kind: "method",
2398
+ name: "search",
2399
+ static: false,
2400
+ private: false,
2401
+ access: {
2402
+ has: (obj) => "search" in obj,
2403
+ get: (obj) => obj.search
2404
+ },
2405
+ metadata: _metadata
2406
+ }, null, _instanceExtraInitializers);
2407
+ __esDecorate(this, null, _create_decorators, {
2408
+ kind: "method",
2409
+ name: "create",
2410
+ static: false,
2411
+ private: false,
2412
+ access: {
2413
+ has: (obj) => "create" in obj,
2414
+ get: (obj) => obj.create
2415
+ },
2416
+ metadata: _metadata
2417
+ }, null, _instanceExtraInitializers);
2418
+ __esDecorate(this, null, _selectModel_decorators, {
2419
+ kind: "method",
2420
+ name: "selectModel",
2421
+ static: false,
2422
+ private: false,
2423
+ access: {
2424
+ has: (obj) => "selectModel" in obj,
2425
+ get: (obj) => obj.selectModel
2426
+ },
2427
+ metadata: _metadata
2428
+ }, null, _instanceExtraInitializers);
2429
+ __esDecorate(this, null, _modelCatalog_decorators, {
2430
+ kind: "method",
2431
+ name: "modelCatalog",
2432
+ static: false,
2433
+ private: false,
2434
+ access: {
2435
+ has: (obj) => "modelCatalog" in obj,
2436
+ get: (obj) => obj.modelCatalog
2437
+ },
2438
+ metadata: _metadata
2439
+ }, null, _instanceExtraInitializers);
2440
+ __esDecorate(this, null, _canOpenWorkspacePath_decorators, {
2441
+ kind: "method",
2442
+ name: "canOpenWorkspacePath",
2443
+ static: false,
2444
+ private: false,
2445
+ access: {
2446
+ has: (obj) => "canOpenWorkspacePath" in obj,
2447
+ get: (obj) => obj.canOpenWorkspacePath
2448
+ },
2449
+ metadata: _metadata
2450
+ }, null, _instanceExtraInitializers);
2451
+ __esDecorate(this, null, _openWorkspacePath_decorators, {
2452
+ kind: "method",
2453
+ name: "openWorkspacePath",
2454
+ static: false,
2455
+ private: false,
2456
+ access: {
2457
+ has: (obj) => "openWorkspacePath" in obj,
2458
+ get: (obj) => obj.openWorkspacePath
2459
+ },
2460
+ metadata: _metadata
2461
+ }, null, _instanceExtraInitializers);
2462
+ __esDecorate(this, null, _rename_decorators, {
2463
+ kind: "method",
2464
+ name: "rename",
2465
+ static: false,
2466
+ private: false,
2467
+ access: {
2468
+ has: (obj) => "rename" in obj,
2469
+ get: (obj) => obj.rename
2470
+ },
2471
+ metadata: _metadata
2472
+ }, null, _instanceExtraInitializers);
2473
+ __esDecorate(this, null, _fork_decorators, {
2474
+ kind: "method",
2475
+ name: "fork",
2476
+ static: false,
2477
+ private: false,
2478
+ access: {
2479
+ has: (obj) => "fork" in obj,
2480
+ get: (obj) => obj.fork
2481
+ },
2482
+ metadata: _metadata
2483
+ }, null, _instanceExtraInitializers);
2484
+ __esDecorate(this, null, _prompt_decorators, {
2485
+ kind: "method",
2486
+ name: "prompt",
2487
+ static: false,
2488
+ private: false,
2489
+ access: {
2490
+ has: (obj) => "prompt" in obj,
2491
+ get: (obj) => obj.prompt
2492
+ },
2493
+ metadata: _metadata
2494
+ }, null, _instanceExtraInitializers);
2495
+ __esDecorate(this, null, _attachment_decorators, {
2496
+ kind: "method",
2497
+ name: "attachment",
2498
+ static: false,
2499
+ private: false,
2500
+ access: {
2501
+ has: (obj) => "attachment" in obj,
2502
+ get: (obj) => obj.attachment
2503
+ },
2504
+ metadata: _metadata
2505
+ }, null, _instanceExtraInitializers);
2506
+ __esDecorate(this, null, _updateQueue_decorators, {
2507
+ kind: "method",
2508
+ name: "updateQueue",
2509
+ static: false,
2510
+ private: false,
2511
+ access: {
2512
+ has: (obj) => "updateQueue" in obj,
2513
+ get: (obj) => obj.updateQueue
2514
+ },
2515
+ metadata: _metadata
2516
+ }, null, _instanceExtraInitializers);
2517
+ __esDecorate(this, null, _cancel_decorators, {
2518
+ kind: "method",
2519
+ name: "cancel",
2520
+ static: false,
2521
+ private: false,
2522
+ access: {
2523
+ has: (obj) => "cancel" in obj,
2524
+ get: (obj) => obj.cancel
2525
+ },
2526
+ metadata: _metadata
2527
+ }, null, _instanceExtraInitializers);
2528
+ __esDecorate(this, null, _page_decorators, {
2529
+ kind: "method",
2530
+ name: "page",
2531
+ static: false,
2532
+ private: false,
2533
+ access: {
2534
+ has: (obj) => "page" in obj,
2535
+ get: (obj) => obj.page
2536
+ },
2537
+ metadata: _metadata
2538
+ }, null, _instanceExtraInitializers);
2539
+ __esDecorate(this, null, _follow_decorators, {
2540
+ kind: "method",
2541
+ name: "follow",
2542
+ static: false,
2543
+ private: false,
2544
+ access: {
2545
+ has: (obj) => "follow" in obj,
2546
+ get: (obj) => obj.follow
2547
+ },
2548
+ metadata: _metadata
2549
+ }, null, _instanceExtraInitializers);
2550
+ __esDecorate(this, null, _control_decorators, {
2551
+ kind: "method",
2552
+ name: "control",
2553
+ static: false,
2554
+ private: false,
2555
+ access: {
2556
+ has: (obj) => "control" in obj,
2557
+ get: (obj) => obj.control
2558
+ },
2559
+ metadata: _metadata
2560
+ }, null, _instanceExtraInitializers);
2561
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, {
2562
+ enumerable: true,
2563
+ configurable: true,
2564
+ writable: true,
2565
+ value: _metadata
2566
+ });
2567
+ }
2568
+ static inject = [
2569
+ "agentDefaultModel",
2570
+ "agents",
2571
+ "attachments",
2572
+ "llm",
2573
+ "sessions",
2574
+ "sessionProjections",
2575
+ "sessionQuery",
2576
+ "typert",
2577
+ "workspaceRegistry"
2578
+ ];
2579
+ static Config = z.object({
2580
+ coldBlankProbeMaxBytes: z.natural().default(DEFAULT_COLD_BLANK_PROBE_MAX_BYTES),
2581
+ nativeOpen: z.boolean()
2582
+ });
2583
+ agents = __runInitializers(this, _instanceExtraInitializers);
2584
+ commands;
2585
+ controlState;
2586
+ history;
2587
+ listState;
2588
+ openPath;
2589
+ canOpenPath;
2590
+ promotions = /* @__PURE__ */ new Set();
2591
+ /**
2592
+ * @param ctx - Host context containing the Session capability assembly.
2593
+ * @param config - cold-list observation policy.
2594
+ */
2595
+ constructor(ctx, config, internals = {}) {
2596
+ super(ctx, "sessionController", { namespace: "session" });
2597
+ installModelSelectionProjection(ctx);
2598
+ this.agents = new ApiSessionAgentController(ctx);
2599
+ this.commands = new SessionCommandController(ctx, this.agents, process.cwd());
2600
+ this.controlState = new SessionControlController(ctx);
2601
+ ctx.effect(() => async () => {
2602
+ await Promise.allSettled([...this.promotions]);
2603
+ }, "session-controller.promotions");
2604
+ this.history = new SessionHistoryController(ctx, (observation) => {
2605
+ this.promote(observation);
2606
+ });
2607
+ this.listState = new ApiSessionList(ctx, config.coldBlankProbeMaxBytes ?? 1024);
2608
+ this.openPath = internals.openPath ?? openNativePath;
2609
+ this.canOpenPath = internals.canOpenPath ?? (() => config.nativeOpen ?? (internals.openPath !== void 0 || canOpenNativePath()));
2610
+ ctx.plugin(SessionFileReferences);
2611
+ ctx.plugin(SessionSkillCatalog);
2612
+ ctx.on("session/created", (session) => {
2613
+ ctx.emit("api-session/added", this.listState.summaryFor(session));
2614
+ });
2615
+ ctx.on("session/disposed", (session) => {
2616
+ ctx.emit("api-session/removed", session.id);
2617
+ });
2618
+ ctx.on("agent/status", ({ agent, status }) => {
2619
+ ctx.emit("api-session/status", agent.id, status === "running");
2620
+ });
2621
+ ctx.on("agent/error", ({ agent, error }) => {
2622
+ ctx.emit("api-session/error", agent.id, errorChain(error));
2623
+ });
2624
+ ctx.on("session/event", (session, event) => {
2625
+ if (event.type === "request/header") {
2626
+ const agent = ctx.agents.get(session.id);
2627
+ if (agent?.session === session) this.agents.consumeSelection(agent, event.data.header.config.provider, event.data.header.config.model, event.data.header.config.reasoningEffort);
2628
+ }
2629
+ if (event.type !== "user/message" || event.data.source.kind !== "user") return;
2630
+ ctx.emit("api-session/activity", session.id, event.time);
2631
+ });
2632
+ }
2633
+ promote(observation) {
2634
+ const sessionId = observation.header.id;
2635
+ const task = (async () => {
2636
+ const env_1 = {
2637
+ stack: [],
2638
+ error: void 0,
2639
+ hasError: false
2640
+ };
2641
+ try {
2642
+ const ownedObservation = __addDisposableResource(env_1, observation, false);
2643
+ const result = await this.agents.resolveObservedAgent(ownedObservation);
2644
+ if ("error" in result) this.ctx.emit("api-session/error", sessionId, result.error.message);
2645
+ } catch (e_1) {
2646
+ env_1.error = e_1;
2647
+ env_1.hasError = true;
2648
+ } finally {
2649
+ __disposeResources(env_1);
2650
+ }
2651
+ })().catch((error) => {
2652
+ this.ctx.logger.error(`session-controller: background activation for "${sessionId}" failed: ${errorChain(error)}`);
2653
+ });
2654
+ this.promotions.add(task);
2655
+ task.finally(() => {
2656
+ this.promotions.delete(task);
2657
+ });
2658
+ }
2659
+ /**
2660
+ * Resolve or resume one ordinary Session for another Host API domain.
2661
+ * @param sessionId - Session identity whose Agent owns the operation.
2662
+ * @returns the live Agent or the stable Session-domain failure.
2663
+ */
2664
+ resolveAgent(sessionId) {
2665
+ return this.agents.resolveAgent(sessionId);
2666
+ }
2667
+ /**
2668
+ * Inspect one attached or persisted Session without activating its Agent.
2669
+ * @param sessionId - durable Session identity.
2670
+ * @param signal - optional caller cancellation for persistence reads.
2671
+ * @returns the current attached state or persisted header and event prefix.
2672
+ */
2673
+ inspect(sessionId, signal) {
2674
+ const attached = this.ctx.sessions.get(sessionId);
2675
+ if (attached !== void 0) return Promise.resolve({
2676
+ meta: attached.header,
2677
+ events: [...attached.events]
2678
+ });
2679
+ return inspectApiSession(this.ctx, sessionId, signal);
2680
+ }
2681
+ /**
2682
+ * Read all visible Session rows without resuming an Agent.
2683
+ * @param _request - reserved empty list request.
2684
+ * @param signal - cancellation for persistence reads.
2685
+ * @returns visible Session summaries ordered by activity.
2686
+ */
2687
+ async list(_request, signal) {
2688
+ return { items: await this.listState.list(signal) };
2689
+ }
2690
+ /**
2691
+ * Search visible Session content without resuming an Agent.
2692
+ * @param request - literal message-content query.
2693
+ * @param signal - cancellation for list and search reads.
2694
+ * @returns authorized bounded Session search results.
2695
+ */
2696
+ search(request, signal) {
2697
+ return this.listState.search(request.query, signal);
2698
+ }
2699
+ /**
2700
+ * Create or idempotently adopt one ordinary Session.
2701
+ * @param request - requested identity, location, and Agent preset.
2702
+ * @returns the Session identity and resolved preset when configured.
2703
+ */
2704
+ create(request) {
2705
+ return this.commands.create(request);
2706
+ }
2707
+ /**
2708
+ * Select one Session-local model after explicitly resuming the Session.
2709
+ * @param request - Session identity and requested model selection.
2710
+ * @returns the normalized selection installed for the Session.
2711
+ */
2712
+ selectModel(request) {
2713
+ return this.commands.selectModel(request);
2714
+ }
2715
+ /**
2716
+ * Describe every currently routable model for Host-generation selectors.
2717
+ * @returns provider-grouped models, the deployment default, and isolated provider failures.
2718
+ */
2719
+ modelCatalog() {
2720
+ return buildModelCatalog(this.ctx);
2721
+ }
2722
+ /**
2723
+ * Report whether this deployment can hand a Session workspace path to a native desktop.
2724
+ * @returns true when the matching open operation is available.
2725
+ */
2726
+ canOpenWorkspacePath() {
2727
+ return this.canOpenPath();
2728
+ }
2729
+ /**
2730
+ * Open one path prepared by a Session-aware caller on the Host desktop.
2731
+ * @param request - path after best-effort Session workspace resolution.
2732
+ * @param signal - caller lifetime; abort terminates the native command.
2733
+ * @returns confirmation after the native opener accepts the path.
2734
+ * @throws RemoteError when the request is invalid, cancelled, or the opener fails.
2735
+ */
2736
+ async openWorkspacePath(request, signal) {
2737
+ if (request.path.length === 0) throw new RemoteError("gateway/bad-request", "session.openWorkspacePath requires a non-empty path", {});
2738
+ signal.throwIfAborted();
2739
+ try {
2740
+ await this.openPath(request.path, signal);
2741
+ return { opened: true };
2742
+ } catch (error) {
2743
+ if (signal.aborted) throw new RemoteError("gateway/cancelled", "path open was aborted", {});
2744
+ throw new RemoteError("gateway/internal", `path open failed: ${error instanceof Error ? error.message : String(error)}`, {});
2745
+ }
2746
+ }
2747
+ /**
2748
+ * Rename one Session after explicitly resuming it.
2749
+ * @param request - Session identity and proposed title.
2750
+ * @returns the accepted title and durable event sequence.
2751
+ */
2752
+ rename(request) {
2753
+ return this.commands.rename(request);
2754
+ }
2755
+ /**
2756
+ * Fork one cold-readable completed-turn prefix into a new Session.
2757
+ * @param request - source Session and optional event anchor.
2758
+ * @returns the new Session identity.
2759
+ */
2760
+ fork(request) {
2761
+ return this.commands.fork(request);
2762
+ }
2763
+ /**
2764
+ * Admit one prompt after explicitly resuming its Session.
2765
+ * @param request - Session identity, prompt content, source metadata, and delivery mode.
2766
+ * @param signal - caller cancellation before prompt admission begins.
2767
+ * @returns acknowledgement that the Agent accepted the prompt.
2768
+ */
2769
+ prompt(request, signal) {
2770
+ signal.throwIfAborted();
2771
+ return this.commands.prompt(request);
2772
+ }
2773
+ /**
2774
+ * Read one image proven reachable from the addressed Session log.
2775
+ * @param request - Session and attachment identities used for authorization.
2776
+ * @returns the durable attachment reference and base64-encoded bytes.
2777
+ */
2778
+ attachment(request) {
2779
+ return this.commands.attachment(request);
2780
+ }
2781
+ /**
2782
+ * Mutate one still-pending queue occurrence on a live Agent.
2783
+ * @param request - Session, queue item, and requested mutation.
2784
+ * @returns acknowledgement that the queue mutation was applied.
2785
+ */
2786
+ updateQueue(request) {
2787
+ return this.commands.updateQueue(request);
2788
+ }
2789
+ /**
2790
+ * Cancel one active Agent turn without dropping its pending inbox.
2791
+ * @param request - Session whose active Agent turn is cancelled.
2792
+ * @returns acknowledgement that cancellation was requested.
2793
+ */
2794
+ cancel(request) {
2795
+ return this.commands.cancel(request);
2796
+ }
2797
+ /**
2798
+ * Read one cold-safe, message-aligned Session history page.
2799
+ * @param request - durable address, backward cursor, and page budget.
2800
+ * @param signal - cancellation for persistence reads.
2801
+ * @returns one chronological page.
2802
+ */
2803
+ page(request, signal) {
2804
+ return this.history.page(request, signal);
2805
+ }
2806
+ /**
2807
+ * Follow one Session log from its opening or resume cursor.
2808
+ * @param request - durable address and last committed sequence already held by the caller.
2809
+ * @param signal - cancellation owned by the Remote stream carrier.
2810
+ * @returns a complete opening snapshot followed by gap-free event frames.
2811
+ */
2812
+ follow(request, signal) {
2813
+ return this.history.follow(request, signal);
2814
+ }
2815
+ /**
2816
+ * Stream a complete live-control baseline followed by replacement frames.
2817
+ * @param signal - cancellation owned by the Remote stream carrier.
2818
+ * @returns one complete baseline followed by live replacement frames.
2819
+ */
2820
+ control(signal) {
2821
+ return this.controlState.control(signal);
2822
+ }
2823
+ };
2824
+ })();
2825
+ //#endregion
2826
+ export { ApiSessionNotFound, SessionController, SessionController as default, SessionFileReferences, SessionSkillCatalog, buildModelCatalog };