@deepseek-ai/dsh-api-session-controller 0.1.5-rc.2 → 0.1.6-alpha.2

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 (39) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +20 -4
  3. package/README.zh.md +26 -10
  4. package/lib/client.js +432 -474
  5. package/lib/index.js +18 -49
  6. package/lib/typert.host.js +242 -200
  7. package/lib/typert.remote-client.js +195 -165
  8. package/lib/types/agent.d.ts +1 -1
  9. package/lib/types/agent.js +8 -1
  10. package/lib/types/client/contract/sessions.d.ts +55 -20
  11. package/lib/types/client/contract/snapshot.d.ts +0 -14
  12. package/lib/types/client/index.d.ts +11 -2
  13. package/lib/types/client/index.js +16 -5
  14. package/lib/types/client/scope.d.ts +13 -3
  15. package/lib/types/client/scope.js +15 -22
  16. package/lib/types/client/sessions/lineage.d.ts +1 -4
  17. package/lib/types/client/sessions/lineage.js +1 -3
  18. package/lib/types/client/sessions/manager.d.ts +28 -49
  19. package/lib/types/client/sessions/manager.js +75 -174
  20. package/lib/types/client/sessions/projection-store.d.ts +5 -11
  21. package/lib/types/client/sessions/projection-store.js +6 -14
  22. package/lib/types/client/sessions/service.d.ts +34 -119
  23. package/lib/types/client/sessions/service.js +259 -244
  24. package/lib/types/client/sessions/session.d.ts +7 -20
  25. package/lib/types/client/sessions/session.js +29 -33
  26. package/lib/types/client/time-zone.d.ts +1 -1
  27. package/lib/types/client/time-zone.js +1 -1
  28. package/lib/types/commands.d.ts +2 -2
  29. package/lib/types/commands.js +13 -8
  30. package/lib/types/control.d.ts +1 -1
  31. package/lib/types/control.js +1 -41
  32. package/lib/types/history.js +1 -0
  33. package/lib/types/index.d.ts +2 -2
  34. package/lib/types/index.js +2 -1
  35. package/lib/types/skill-catalog.js +1 -0
  36. package/lib/types/types.d.ts +5 -17
  37. package/package.json +72 -69
  38. package/lib/types/client/sessions/queue-mirror.d.ts +0 -26
  39. package/lib/types/client/sessions/queue-mirror.js +0 -61
package/lib/index.js CHANGED
@@ -227,7 +227,8 @@ var ApiSessionAgentController = class {
227
227
  this.resumes.set(sessionId, resume);
228
228
  }
229
229
  try {
230
- return { agent: await resume };
230
+ const agent = await resume;
231
+ return this.liveAgent(sessionId) ?? { agent };
231
232
  } catch (error) {
232
233
  if (error instanceof ApiSessionNotFound) return { error: new RemoteError("session/not-found", error.message, { sessionId }) };
233
234
  if (error instanceof ApiSessionSubagentOwnership) return { error: apiSessionSubagentOwnershipError(error.sessionId) };
@@ -235,6 +236,7 @@ var ApiSessionAgentController = class {
235
236
  if (raced !== void 0) return raced;
236
237
  const racedSession = this.ctx.sessions.get(sessionId);
237
238
  if (racedSession !== void 0 && hasApiSessionSubagentOwner(this.ctx, racedSession, void 0)) return { error: apiSessionSubagentOwnershipError(sessionId) };
239
+ if (error instanceof Error && error.name === "SessionAlreadyOwnedError") return { error: new RemoteError("session/writer-held", error.message, { sessionId }) };
238
240
  return { error: new RemoteError("gateway/internal", `resume failed for session "${sessionId}": ${String(error)}`, {}) };
239
241
  }
240
242
  }
@@ -681,8 +683,7 @@ var SessionCommandController = class {
681
683
  const lastSeq = source.events.at(-1)?.seq ?? -1;
682
684
  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);
683
685
  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 });
684
- let cut = SessionLogOffset(boundary.seq + 1);
685
- while (cut < source.events.length && source.events[cut]?.type !== "turn/start") cut = SessionLogOffset(cut + 1);
686
+ const cut = SessionLogOffset(boundary.seq + 1);
686
687
  let workspace;
687
688
  try {
688
689
  workspace = await this.forkWorkspace(source.header);
@@ -815,17 +816,24 @@ var SessionCommandController = class {
815
816
  }
816
817
  }
817
818
  /**
818
- * Mutate one still-pending queue occurrence without resuming a cold Agent.
819
+ * Mutate one pending Inbox occurrence, restoring an ordinary cold Agent when needed.
819
820
  * @param request - Session, queue item, and requested mutation.
820
821
  * @returns acknowledgement that the queue mutation was applied.
821
822
  */
822
- updateQueue(request) {
823
+ async updateQueue(request) {
823
824
  if (request.action.kind === "edit") {
824
825
  if (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" });
825
826
  if (!hasPromptContent(request.action.content)) throw new RemoteError("gateway/bad-request", "queue edit content must include non-whitespace text", {});
826
827
  }
827
- const agent = this.ctx.agents.get(request.sessionId);
828
- if (agent === void 0) throw new RemoteError("session/queue-item-not-found", "queued item is no longer pending", { itemId: request.itemId });
828
+ let agent = this.ctx.agents.get(request.sessionId);
829
+ if (agent === void 0) {
830
+ const found = await this.agents.resolveAgent(request.sessionId);
831
+ if ("error" in found) {
832
+ if (found.error.code !== "session/not-found") throw found.error;
833
+ throw new RemoteError("session/queue-item-not-found", "queued item is no longer pending", { itemId: request.itemId });
834
+ }
835
+ agent = found.agent;
836
+ }
829
837
  if (hasApiSessionSubagentOwner(this.ctx, agent.session, agent)) {
830
838
  const identity = this.ctx.sessionProjections.snapshot(agent.session, ["subagent"]).values.subagent;
831
839
  if (identity?.mode !== "continuable" || !agent.session.isOwnSeq(identity.seq)) throw apiSessionSubagentOwnershipError(request.sessionId);
@@ -990,7 +998,7 @@ function routeServed(ctx, provider) {
990
998
  }
991
999
  //#endregion
992
1000
  //#region lib/types/control.js
993
- /** Live Session queue, jobs, and projection state with reconnect baselines. */
1001
+ /** Live Session jobs and projection state with reconnect baselines. */
994
1002
  /** Owns the Host-wide Session control stream. */
995
1003
  var SessionControlController = class {
996
1004
  ctx;
@@ -1006,13 +1014,6 @@ var SessionControlController = class {
1006
1014
  value,
1007
1015
  seq
1008
1016
  });
1009
- if (key !== "inbox") return;
1010
- if (this.ctx.agents.get(session.id)?.session !== session) return;
1011
- this.broadcast({
1012
- type: "queue",
1013
- sessionId: session.id,
1014
- items: queueItemsFromInbox(value)
1015
- });
1016
1017
  });
1017
1018
  ctx.inject(["jobs"], (jobsCtx) => {
1018
1019
  jobsCtx.jobs.onJobsChanged((owner) => {
@@ -1054,15 +1055,12 @@ var SessionControlController = class {
1054
1055
  }
1055
1056
  baseline() {
1056
1057
  const sessions = this.ctx.sessions.list();
1057
- const queues = Object.create(null);
1058
1058
  const jobs = Object.create(null);
1059
1059
  for (const session of sessions) {
1060
1060
  const agent = this.ctx.agents.get(session.id);
1061
- queues[session.id] = agent?.session === session ? queueItems(agent) : [];
1062
1061
  jobs[session.id] = this.jobsFor(agent);
1063
1062
  }
1064
1063
  return {
1065
- queues,
1066
1064
  jobs,
1067
1065
  projections: this.projectionBaseline(sessions)
1068
1066
  };
@@ -1142,36 +1140,6 @@ var ControlQueue = class {
1142
1140
  }
1143
1141
  }
1144
1142
  };
1145
- function queueItems(agent) {
1146
- return queueItemsFromInbox({
1147
- "next-turn": agent.inbox.nextTurn,
1148
- "next-step": agent.inbox.nextStep
1149
- });
1150
- }
1151
- function queueItemsFromInbox(inbox) {
1152
- return [...inbox["next-turn"].map((message) => ({
1153
- id: message.id,
1154
- placement: "queued",
1155
- ...promptRpcId(message),
1156
- message: {
1157
- id: message.id,
1158
- content: message.content
1159
- }
1160
- })), ...inbox["next-step"].map((message) => ({
1161
- id: message.id,
1162
- placement: message.source.kind === "user" ? "steering" : "context",
1163
- ...promptRpcId(message),
1164
- message: {
1165
- id: message.id,
1166
- content: message.content
1167
- }
1168
- }))];
1169
- }
1170
- /** Prompt-RPC identity carried by a browser-submitted message's user source. */
1171
- function promptRpcId(message) {
1172
- const source = message.source;
1173
- return source.kind === "user" && "rpcId" in source ? { rpcId: source.rpcId } : {};
1174
- }
1175
1143
  function jobView(job) {
1176
1144
  return {
1177
1145
  id: job.id,
@@ -2279,6 +2247,7 @@ let SessionSkillCatalog = (() => {
2279
2247
  scope
2280
2248
  })).filter(isUserInvocable).map((skill) => ({
2281
2249
  name: skill.name,
2250
+ ...skill.path === void 0 ? {} : { path: skill.path },
2282
2251
  description: skill.description,
2283
2252
  ...skill.whenToUse === void 0 ? {} : { whenToUse: skill.whenToUse },
2284
2253
  modelInvocable: skill.invocation.modelInvocable
@@ -2930,7 +2899,7 @@ let SessionController = (() => {
2930
2899
  return this.commands.attachment(request);
2931
2900
  }
2932
2901
  /**
2933
- * Mutate one still-pending queue occurrence on a live Agent.
2902
+ * Mutate one still-pending queue occurrence, resuming a cold Agent first.
2934
2903
  * @param request - Session, queue item, and requested mutation.
2935
2904
  * @returns acknowledgement that the queue mutation was applied.
2936
2905
  */