@opengeni/core 0.21.10 → 0.28.0

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 (132) hide show
  1. package/dist/access/index.d.ts +1 -1
  2. package/dist/application/new-session-drafts.d.ts +1 -1
  3. package/dist/application/session-commands.d.ts +2 -2
  4. package/dist/billing/limits.d.ts +1 -1
  5. package/dist/canonical-human-identities.d.ts +12 -0
  6. package/dist/canonical-human-identities.js +23 -0
  7. package/dist/canonical-human-identities.js.map +1 -0
  8. package/dist/chunk-6WKPWE5S.js +2380 -0
  9. package/dist/chunk-6WKPWE5S.js.map +1 -0
  10. package/dist/chunk-IBOEYG6N.js +34 -0
  11. package/dist/chunk-IBOEYG6N.js.map +1 -0
  12. package/dist/chunk-JJU6I5XD.js +2713 -0
  13. package/dist/chunk-JJU6I5XD.js.map +1 -0
  14. package/dist/chunk-NYPMQ7NO.js +2270 -0
  15. package/dist/chunk-NYPMQ7NO.js.map +1 -0
  16. package/dist/dependencies.d.ts +30 -6
  17. package/dist/domain/capabilities.d.ts +28 -3
  18. package/dist/domain/company-profile-durable-learning-adapter.d.ts +39 -0
  19. package/dist/domain/conversation-integrations.d.ts +225 -0
  20. package/dist/domain/durable-learning-slack-publication.d.ts +72 -0
  21. package/dist/domain/editable-artifacts/agent-application.d.ts +192 -0
  22. package/dist/domain/editable-artifacts/durable-export-postgres.d.ts +4 -0
  23. package/dist/domain/editable-artifacts/durable-export.d.ts +212 -0
  24. package/dist/domain/editable-artifacts/errors.d.ts +47 -0
  25. package/dist/domain/editable-artifacts/hash.d.ts +11 -0
  26. package/dist/domain/editable-artifacts/in-memory.d.ts +99 -0
  27. package/dist/domain/editable-artifacts/index.d.ts +14 -0
  28. package/dist/domain/editable-artifacts/ports.d.ts +341 -0
  29. package/dist/domain/editable-artifacts/postgres-adapters.d.ts +13 -0
  30. package/dist/domain/editable-artifacts/service.d.ts +105 -0
  31. package/dist/domain/editable-artifacts/snapshot-compaction.d.ts +44 -0
  32. package/dist/domain/editable-artifacts/snapshot-verifier-genesis.d.ts +50 -0
  33. package/dist/domain/editable-artifacts/snapshot-verifier-materialization.d.ts +21 -0
  34. package/dist/domain/editable-artifacts/snapshot-verifier.d.ts +118 -0
  35. package/dist/domain/editable-artifacts/types.d.ts +410 -0
  36. package/dist/domain/fiken.d.ts +35 -0
  37. package/dist/domain/memory-slack-delivery.d.ts +19 -0
  38. package/dist/domain/packs.d.ts +29 -1
  39. package/dist/domain/personal-connection-delegations.d.ts +9 -1
  40. package/dist/domain/scheduled-tasks.d.ts +2 -2
  41. package/dist/domain/session-tool-policy.d.ts +2 -2
  42. package/dist/domain/sessions.d.ts +24 -8
  43. package/dist/domain/skill-imports.d.ts +32 -0
  44. package/dist/domain/slack-publication-secret-safety.d.ts +8 -0
  45. package/dist/domain/timeline-annotations.d.ts +5 -0
  46. package/dist/domain/video-generation-capabilities.d.ts +10 -0
  47. package/dist/domain/video-generation.d.ts +47 -0
  48. package/dist/editable-artifact-live/application.d.ts +69 -0
  49. package/dist/editable-artifact-live/errors.d.ts +1 -0
  50. package/dist/editable-artifact-live/index.d.ts +8 -0
  51. package/dist/editable-artifact-live/outbox-dispatcher.d.ts +162 -0
  52. package/dist/editable-artifact-live/ports.d.ts +100 -0
  53. package/dist/editable-artifact-live/server.d.ts +71 -0
  54. package/dist/editable-artifact-live/ticket.d.ts +40 -0
  55. package/dist/editable-artifact-live/types.d.ts +213 -0
  56. package/dist/editable-artifact-live/wire.d.ts +34 -0
  57. package/dist/editable-artifact-live.d.ts +2 -0
  58. package/dist/editable-artifact-live.js +58 -0
  59. package/dist/editable-artifact-live.js.map +1 -0
  60. package/dist/editable-artifacts.d.ts +2 -0
  61. package/dist/editable-artifacts.js +179 -0
  62. package/dist/editable-artifacts.js.map +1 -0
  63. package/dist/index.d.ts +37 -26
  64. package/dist/index.js +4145 -959
  65. package/dist/index.js.map +1 -1
  66. package/dist/managed-session.d.ts +6 -2
  67. package/dist/rigs/index.d.ts +1 -1
  68. package/dist/rigs/provider-images.d.ts +31 -0
  69. package/dist/sandbox/fleet.d.ts +8 -5
  70. package/dist/sandbox/routing.d.ts +1 -0
  71. package/dist/session-authorization.d.ts +4 -2
  72. package/dist/transcription.d.ts +5 -0
  73. package/dist/workflow-wake-contract.d.ts +7 -0
  74. package/package.json +22 -10
  75. package/src/access/index.ts +14 -2
  76. package/src/application/new-session-drafts.ts +2 -0
  77. package/src/application/session-commands.ts +188 -107
  78. package/src/canonical-human-identities.ts +27 -0
  79. package/src/dependencies.ts +34 -2
  80. package/src/domain/capabilities.ts +729 -408
  81. package/src/domain/company-profile-durable-learning-adapter.ts +221 -0
  82. package/src/domain/conversation-integrations.ts +1238 -0
  83. package/src/domain/durable-learning-slack-publication.ts +202 -0
  84. package/src/domain/editable-artifacts/agent-application.ts +687 -0
  85. package/src/domain/editable-artifacts/durable-export-postgres.ts +139 -0
  86. package/src/domain/editable-artifacts/durable-export.ts +734 -0
  87. package/src/domain/editable-artifacts/errors.ts +115 -0
  88. package/src/domain/editable-artifacts/hash.ts +131 -0
  89. package/src/domain/editable-artifacts/in-memory.ts +1662 -0
  90. package/src/domain/editable-artifacts/index.ts +14 -0
  91. package/src/domain/editable-artifacts/ports.ts +462 -0
  92. package/src/domain/editable-artifacts/postgres-adapters.ts +49 -0
  93. package/src/domain/editable-artifacts/service.ts +2402 -0
  94. package/src/domain/editable-artifacts/snapshot-compaction.ts +246 -0
  95. package/src/domain/editable-artifacts/snapshot-verifier-genesis.ts +235 -0
  96. package/src/domain/editable-artifacts/snapshot-verifier-materialization.ts +74 -0
  97. package/src/domain/editable-artifacts/snapshot-verifier.ts +687 -0
  98. package/src/domain/editable-artifacts/types.ts +835 -0
  99. package/src/domain/fiken.ts +88 -0
  100. package/src/domain/insights.ts +163 -50
  101. package/src/domain/memory-slack-delivery.ts +204 -0
  102. package/src/domain/memory-slack-publication.ts +5 -2
  103. package/src/domain/packs.ts +266 -5
  104. package/src/domain/personal-connection-delegations.ts +97 -6
  105. package/src/domain/scheduled-tasks.ts +171 -29
  106. package/src/domain/session-tool-policy.ts +8 -2
  107. package/src/domain/sessions.ts +395 -148
  108. package/src/domain/skill-imports.ts +350 -0
  109. package/src/domain/slack-publication-secret-safety.ts +42 -0
  110. package/src/domain/timeline-annotations.ts +204 -0
  111. package/src/domain/video-generation-capabilities.ts +104 -0
  112. package/src/domain/video-generation.ts +249 -0
  113. package/src/editable-artifact-live/application.ts +182 -0
  114. package/src/editable-artifact-live/errors.ts +4 -0
  115. package/src/editable-artifact-live/index.ts +8 -0
  116. package/src/editable-artifact-live/outbox-dispatcher.ts +916 -0
  117. package/src/editable-artifact-live/ports.ts +139 -0
  118. package/src/editable-artifact-live/server.ts +1707 -0
  119. package/src/editable-artifact-live/ticket.ts +217 -0
  120. package/src/editable-artifact-live/types.ts +286 -0
  121. package/src/editable-artifact-live/wire.ts +95 -0
  122. package/src/editable-artifact-live.ts +2 -0
  123. package/src/editable-artifacts.ts +2 -0
  124. package/src/index.ts +15 -0
  125. package/src/managed-session.ts +19 -2
  126. package/src/rigs/index.ts +26 -19
  127. package/src/rigs/provider-images.ts +110 -0
  128. package/src/sandbox/fleet.ts +72 -66
  129. package/src/sandbox/routing.ts +6 -3
  130. package/src/session-authorization.ts +187 -52
  131. package/src/transcription.ts +5 -0
  132. package/src/workflow-wake-contract.ts +8 -0
@@ -16,7 +16,11 @@ import type {
16
16
  WorkspaceInferenceControlRequest,
17
17
  WorkspaceInferenceControlResponse,
18
18
  } from "@opengeni/contracts";
19
- import { latencyModeForMetadata, reasoningEffortForMetadata } from "@opengeni/contracts";
19
+ import {
20
+ DraftTimelineAnnotations,
21
+ latencyModeForMetadata,
22
+ reasoningEffortForMetadata,
23
+ } from "@opengeni/contracts";
20
24
  import {
21
25
  deleteSessionQueueItemInTransaction,
22
26
  editQueuedTurnInTransaction,
@@ -36,8 +40,11 @@ import {
36
40
  steerAgentSessionInTransaction,
37
41
  steerQueuedTurnInTransaction,
38
42
  withWorkspaceRls,
43
+ withWorkspaceSessionActivityRls,
39
44
  withWorkspaceSubjectRls,
45
+ withWorkspaceSubjectSessionActivityRls,
40
46
  type Database,
47
+ type SessionActivityDatabase,
41
48
  type SessionCommandReceiptRow,
42
49
  } from "@opengeni/db";
43
50
  import {
@@ -47,6 +54,7 @@ import {
47
54
  } from "@opengeni/events";
48
55
  import type { SessionWorkflowClient } from "../dependencies";
49
56
  import { normalizeResources } from "../domain/resources";
57
+ import { validateDraftTimelineAnnotations } from "../domain/timeline-annotations";
50
58
  import {
51
59
  requireSessionAuthorization,
52
60
  type ResolvedSessionAuthorization,
@@ -143,17 +151,18 @@ function agentActor(context: AgentSessionCommandContext) {
143
151
  }
144
152
 
145
153
  /**
146
- * Retry only one operation-keyed Agent command transaction. The caller keeps
154
+ * Retry only one operation-keyed session command transaction. Callers keep
147
155
  * event publication and Temporal wake delivery after this returns, so a
148
- * deadlock/serialization retry can never replay an external effect.
156
+ * deadlock/serialization retry can never replay an external effect. Human
157
+ * draft ownership is applied inside every retry attempt when required.
149
158
  */
150
- async function runAgentCommandPersistenceTransaction<T>(
159
+ async function runSessionCommandPersistenceTransaction<T>(
151
160
  deps: { db: Database },
152
- context: AgentSessionCommandContext,
161
+ scope: { workspaceId: string; subjectId?: string },
153
162
  input: {
154
163
  stage: string;
155
164
  eventTypes: string[];
156
- transaction: (tx: Database) => Promise<T>;
165
+ transaction: (tx: SessionActivityDatabase) => Promise<T>;
157
166
  },
158
167
  ): Promise<T> {
159
168
  return await runIdempotentPersistenceTransaction(
@@ -162,10 +171,17 @@ async function runAgentCommandPersistenceTransaction<T>(
162
171
  eventTypes: input.eventTypes,
163
172
  maxAttempts: 3,
164
173
  },
165
- async () =>
166
- await withWorkspaceRls(deps.db, context.workspaceId, async (scoped) =>
167
- scoped.transaction(async (tx) => await input.transaction(tx as unknown as Database)),
168
- ),
174
+ async () => {
175
+ const run = async (scoped: SessionActivityDatabase) => await input.transaction(scoped);
176
+ return scope.subjectId === undefined
177
+ ? await withWorkspaceSessionActivityRls(deps.db, scope.workspaceId, run)
178
+ : await withWorkspaceSubjectSessionActivityRls(
179
+ deps.db,
180
+ scope.workspaceId,
181
+ scope.subjectId,
182
+ run,
183
+ );
184
+ },
169
185
  );
170
186
  }
171
187
 
@@ -282,19 +298,23 @@ export async function sendAgentSessionMessage(
282
298
  input: { targetSessionId: string; text: string; idempotencyKey: string },
283
299
  ) {
284
300
  await authorizeAgentSessionCommand(deps, context, input.targetSessionId, "session.append");
285
- const result = await runAgentCommandPersistenceTransaction(deps, context, {
286
- stage: "session_commands.agent_message",
287
- eventTypes: ["system.update.pending"],
288
- transaction: async (tx) =>
289
- await sendAgentMessageInTransaction(tx, {
290
- accountId: context.accountId,
291
- workspaceId: context.workspaceId,
292
- targetSessionId: input.targetSessionId,
293
- actor: agentActor(context),
294
- operationKey: input.idempotencyKey,
295
- text: input.text,
296
- }),
297
- });
301
+ const result = await runSessionCommandPersistenceTransaction(
302
+ deps,
303
+ { workspaceId: context.workspaceId },
304
+ {
305
+ stage: "session_commands.agent_message",
306
+ eventTypes: ["system.update.pending"],
307
+ transaction: async (tx) =>
308
+ await sendAgentMessageInTransaction(tx, {
309
+ accountId: context.accountId,
310
+ workspaceId: context.workspaceId,
311
+ targetSessionId: input.targetSessionId,
312
+ actor: agentActor(context),
313
+ operationKey: input.idempotencyKey,
314
+ text: input.text,
315
+ }),
316
+ },
317
+ );
298
318
  await publishAndWakeAgentCommand(deps, {
299
319
  accountId: context.accountId,
300
320
  workspaceId: context.workspaceId,
@@ -317,22 +337,30 @@ export async function steerAgentSession(
317
337
  sessionAuthorization?: SessionAuthorizationPort | null;
318
338
  },
319
339
  context: AgentSessionCommandContext,
320
- input: { targetSessionId: string; instruction: string; idempotencyKey: string },
340
+ input: {
341
+ targetSessionId: string;
342
+ instruction: string;
343
+ idempotencyKey: string;
344
+ },
321
345
  ) {
322
346
  await authorizeAgentSessionCommand(deps, context, input.targetSessionId, "session.steer");
323
- const result = await runAgentCommandPersistenceTransaction(deps, context, {
324
- stage: "session_commands.agent_steer",
325
- eventTypes: ["session.control.steer_requested", "system.update.pending", "turn.superseded"],
326
- transaction: async (tx) =>
327
- await steerAgentSessionInTransaction(tx, {
328
- accountId: context.accountId,
329
- workspaceId: context.workspaceId,
330
- targetSessionId: input.targetSessionId,
331
- actor: agentActor(context),
332
- operationKey: input.idempotencyKey,
333
- instruction: input.instruction,
334
- }),
335
- });
347
+ const result = await runSessionCommandPersistenceTransaction(
348
+ deps,
349
+ { workspaceId: context.workspaceId },
350
+ {
351
+ stage: "session_commands.agent_steer",
352
+ eventTypes: ["session.control.steer_requested", "system.update.pending", "turn.superseded"],
353
+ transaction: async (tx) =>
354
+ await steerAgentSessionInTransaction(tx, {
355
+ accountId: context.accountId,
356
+ workspaceId: context.workspaceId,
357
+ targetSessionId: input.targetSessionId,
358
+ actor: agentActor(context),
359
+ operationKey: input.idempotencyKey,
360
+ instruction: input.instruction,
361
+ }),
362
+ },
363
+ );
336
364
  await publishAndWakeAgentCommand(deps, {
337
365
  accountId: context.accountId,
338
366
  workspaceId: context.workspaceId,
@@ -369,18 +397,23 @@ export async function controlAgentSessionWorkstream(
369
397
  input.targetSessionId,
370
398
  "session.control",
371
399
  );
372
- const result = await withWorkspaceRls(deps.db, context.workspaceId, (scoped) =>
373
- scoped.transaction((tx) =>
374
- mutateSessionControlInTransaction(tx as unknown as Database, {
375
- accountId: context.accountId,
376
- workspaceId: context.workspaceId,
377
- sessionId: input.targetSessionId,
378
- actor: agentActor(context),
379
- operationKey: input.idempotencyKey,
380
- action: input.action,
381
- reason: input.reason ?? null,
382
- }),
383
- ),
400
+ const result = await runSessionCommandPersistenceTransaction(
401
+ deps,
402
+ { workspaceId: context.workspaceId },
403
+ {
404
+ stage: "session_commands.agent_control",
405
+ eventTypes: [input.action === "pause" ? "session.control.paused" : "session.control.resumed"],
406
+ transaction: async (tx) =>
407
+ await mutateSessionControlInTransaction(tx, {
408
+ accountId: context.accountId,
409
+ workspaceId: context.workspaceId,
410
+ sessionId: input.targetSessionId,
411
+ actor: agentActor(context),
412
+ operationKey: input.idempotencyKey,
413
+ action: input.action,
414
+ reason: input.reason ?? null,
415
+ }),
416
+ },
384
417
  );
385
418
  await publishSessionEventIds(deps, context.workspaceId, input.targetSessionId, [
386
419
  result.sessionControlEventId,
@@ -412,6 +445,7 @@ function composerDraft(
412
445
  return {
413
446
  revision: row.revision,
414
447
  text: row.text,
448
+ annotations: DraftTimelineAnnotations.parse(row.annotations),
415
449
  resources: row.resources as ComposerDraft["resources"],
416
450
  model: row.model,
417
451
  reasoningEffort: row.reasoningEffort as ComposerDraft["reasoningEffort"],
@@ -441,23 +475,32 @@ async function authoritativeQueue(
441
475
  }
442
476
 
443
477
  export async function moveHumanQueuePrompt(
444
- deps: { db: Database; bus: EventBus; sessionAuthorization?: SessionAuthorizationPort | null },
478
+ deps: {
479
+ db: Database;
480
+ bus: EventBus;
481
+ sessionAuthorization?: SessionAuthorizationPort | null;
482
+ },
445
483
  context: HumanSessionCommandContext,
446
484
  turnId: string,
447
485
  input: MoveSessionQueueItemRequest,
448
486
  ): Promise<SessionQueueMutationResponse> {
449
487
  const authorization = await authorizeHumanSessionCommand(deps, context, "session.queue.control");
450
- const result = await withWorkspaceRls(deps.db, context.workspaceId, (scoped) =>
451
- scoped.transaction((tx) =>
452
- moveQueuedTurnInTransaction(tx as unknown as Database, {
453
- ...context,
454
- turnId,
455
- beforeTurnId: input.beforeTurnId,
456
- expectedQueueVersion: input.expectedQueueVersion,
457
- actor: { type: "human", subjectId: context.subjectId },
458
- operationKey: input.clientEventId,
459
- }),
460
- ),
488
+ const result = await runSessionCommandPersistenceTransaction(
489
+ deps,
490
+ { workspaceId: context.workspaceId },
491
+ {
492
+ stage: "session_commands.human_queue_move",
493
+ eventTypes: ["session.queue.changed"],
494
+ transaction: async (tx) =>
495
+ await moveQueuedTurnInTransaction(tx, {
496
+ ...context,
497
+ turnId,
498
+ beforeTurnId: input.beforeTurnId,
499
+ expectedQueueVersion: input.expectedQueueVersion,
500
+ actor: { type: "human", subjectId: context.subjectId },
501
+ operationKey: input.clientEventId,
502
+ }),
503
+ },
461
504
  );
462
505
  const response = {
463
506
  receipt: receipt(result.receipt),
@@ -473,23 +516,32 @@ export async function moveHumanQueuePrompt(
473
516
  }
474
517
 
475
518
  export async function deleteHumanQueuePrompt(
476
- deps: { db: Database; bus: EventBus; sessionAuthorization?: SessionAuthorizationPort | null },
519
+ deps: {
520
+ db: Database;
521
+ bus: EventBus;
522
+ sessionAuthorization?: SessionAuthorizationPort | null;
523
+ },
477
524
  context: HumanSessionCommandContext,
478
525
  turnId: string,
479
526
  input: DeleteSessionQueueItemRequest,
480
527
  ): Promise<SessionQueueMutationResponse> {
481
528
  const authorization = await authorizeHumanSessionCommand(deps, context, "session.queue.control");
482
- const result = await withWorkspaceRls(deps.db, context.workspaceId, (scoped) =>
483
- scoped.transaction((tx) =>
484
- deleteSessionQueueItemInTransaction(tx as unknown as Database, {
485
- ...context,
486
- turnId,
487
- expectedTurnVersion: input.expectedTurnVersion,
488
- actor: { type: "human", subjectId: context.subjectId },
489
- operationKey: input.clientEventId,
490
- reason: input.reason ?? null,
491
- }),
492
- ),
529
+ const result = await runSessionCommandPersistenceTransaction(
530
+ deps,
531
+ { workspaceId: context.workspaceId },
532
+ {
533
+ stage: "session_commands.human_queue_delete",
534
+ eventTypes: ["session.queue.changed"],
535
+ transaction: async (tx) =>
536
+ await deleteSessionQueueItemInTransaction(tx, {
537
+ ...context,
538
+ turnId,
539
+ expectedTurnVersion: input.expectedTurnVersion,
540
+ actor: { type: "human", subjectId: context.subjectId },
541
+ operationKey: input.clientEventId,
542
+ reason: input.reason ?? null,
543
+ }),
544
+ },
493
545
  );
494
546
  const response = {
495
547
  receipt: receipt(result.receipt),
@@ -505,19 +557,24 @@ export async function deleteHumanQueuePrompt(
505
557
  }
506
558
 
507
559
  export async function editHumanQueuePrompt(
508
- deps: { db: Database; bus: EventBus; sessionAuthorization?: SessionAuthorizationPort | null },
560
+ deps: {
561
+ db: Database;
562
+ bus: EventBus;
563
+ sessionAuthorization?: SessionAuthorizationPort | null;
564
+ },
509
565
  context: HumanSessionCommandContext,
510
566
  turnId: string,
511
567
  input: EditSessionQueueItemRequest,
512
568
  ): Promise<SessionQueueMutationResponse> {
513
569
  const authorization = await authorizeHumanSessionCommand(deps, context, "session.queue.control");
514
- const result = await withWorkspaceSubjectRls(
515
- deps.db,
516
- context.workspaceId,
517
- context.subjectId,
518
- (scoped) =>
519
- scoped.transaction((tx) =>
520
- editQueuedTurnInTransaction(tx as unknown as Database, {
570
+ const result = await runSessionCommandPersistenceTransaction(
571
+ deps,
572
+ { workspaceId: context.workspaceId, subjectId: context.subjectId },
573
+ {
574
+ stage: "session_commands.human_queue_edit",
575
+ eventTypes: ["session.queue.changed"],
576
+ transaction: async (tx) =>
577
+ await editQueuedTurnInTransaction(tx, {
521
578
  ...context,
522
579
  turnId,
523
580
  expectedTurnVersion: input.expectedTurnVersion,
@@ -526,7 +583,7 @@ export async function editHumanQueuePrompt(
526
583
  actor: { type: "human", subjectId: context.subjectId },
527
584
  operationKey: input.clientEventId,
528
585
  }),
529
- ),
586
+ },
530
587
  );
531
588
  const response = {
532
589
  receipt: receipt(result.receipt),
@@ -543,23 +600,32 @@ export async function editHumanQueuePrompt(
543
600
  }
544
601
 
545
602
  export async function steerHumanQueuePrompt(
546
- deps: { db: Database; bus: EventBus; sessionAuthorization?: SessionAuthorizationPort | null },
603
+ deps: {
604
+ db: Database;
605
+ bus: EventBus;
606
+ sessionAuthorization?: SessionAuthorizationPort | null;
607
+ },
547
608
  context: HumanSessionCommandContext,
548
609
  turnId: string,
549
610
  input: SteerSessionQueueItemRequest,
550
611
  ): Promise<SessionQueueMutationResponse> {
551
612
  const authorization = await authorizeHumanSessionCommand(deps, context, "session.queue.control");
552
- const result = await withWorkspaceRls(deps.db, context.workspaceId, (scoped) =>
553
- scoped.transaction((tx) =>
554
- steerQueuedTurnInTransaction(tx as unknown as Database, {
555
- ...context,
556
- turnId,
557
- expectedTurnVersion: input.expectedTurnVersion,
558
- controlEtag: input.controlEtag ?? null,
559
- actor: { type: "human", subjectId: context.subjectId },
560
- operationKey: input.clientEventId,
561
- }),
562
- ),
613
+ const result = await runSessionCommandPersistenceTransaction(
614
+ deps,
615
+ { workspaceId: context.workspaceId },
616
+ {
617
+ stage: "session_commands.human_queue_steer",
618
+ eventTypes: ["session.control.steer_requested", "session.queue.changed", "turn.superseded"],
619
+ transaction: async (tx) =>
620
+ await steerQueuedTurnInTransaction(tx, {
621
+ ...context,
622
+ turnId,
623
+ expectedTurnVersion: input.expectedTurnVersion,
624
+ controlEtag: input.controlEtag ?? null,
625
+ actor: { type: "human", subjectId: context.subjectId },
626
+ operationKey: input.clientEventId,
627
+ }),
628
+ },
563
629
  );
564
630
  const response = {
565
631
  receipt: receipt(result.receipt),
@@ -586,19 +652,26 @@ export async function controlHumanSessionWorkstreamWithOutcome(
586
652
  input: SessionControlRequest,
587
653
  ): Promise<{ response: SessionControlResponse; replay: boolean }> {
588
654
  const authorization = await authorizeHumanSessionCommand(deps, context, "session.control");
589
- const result = await withWorkspaceRls(deps.db, context.workspaceId, (scoped) =>
590
- scoped.transaction((tx) =>
591
- mutateSessionControlInTransaction(tx as unknown as Database, {
592
- accountId: context.accountId,
593
- workspaceId: context.workspaceId,
594
- sessionId: context.sessionId,
595
- actor: { type: "human", subjectId: context.subjectId },
596
- operationKey: input.clientEventId,
597
- action: input.action,
598
- reason: input.reason ?? null,
599
- expectedControlEtag: input.expectedControlEtag ?? null,
600
- }),
601
- ),
655
+ const result = await runSessionCommandPersistenceTransaction(
656
+ deps,
657
+ { workspaceId: context.workspaceId },
658
+ {
659
+ stage: "session_commands.human_control",
660
+ eventTypes: [
661
+ input.action === "resume" ? "session.control.resumed" : "session.control.paused",
662
+ ],
663
+ transaction: async (tx) =>
664
+ await mutateSessionControlInTransaction(tx, {
665
+ accountId: context.accountId,
666
+ workspaceId: context.workspaceId,
667
+ sessionId: context.sessionId,
668
+ actor: { type: "human", subjectId: context.subjectId },
669
+ operationKey: input.clientEventId,
670
+ action: input.action,
671
+ reason: input.reason ?? null,
672
+ expectedControlEtag: input.expectedControlEtag ?? null,
673
+ }),
674
+ },
602
675
  );
603
676
  const response = {
604
677
  receipt: receipt(result.receipt),
@@ -686,6 +759,7 @@ export async function getHumanComposerDraft(
686
759
  return {
687
760
  revision: 0,
688
761
  text: "",
762
+ annotations: [],
689
763
  resources: [],
690
764
  model: session.model,
691
765
  reasoningEffort: reasoningEffortForMetadata(session.metadata, "medium"),
@@ -702,6 +776,12 @@ export async function saveHumanComposerDraft(
702
776
  input: SaveComposerDraftRequest,
703
777
  ): Promise<ComposerDraft> {
704
778
  await authorizeHumanSessionCommand(deps, context, "session.composer.write");
779
+ const annotations = await validateDraftTimelineAnnotations(
780
+ deps.db,
781
+ context.workspaceId,
782
+ context.sessionId,
783
+ input.annotations ?? [],
784
+ );
705
785
  const row = await withWorkspaceSubjectRls(
706
786
  deps.db,
707
787
  context.workspaceId,
@@ -711,6 +791,7 @@ export async function saveHumanComposerDraft(
711
791
  saveComposerDraftInTransaction(tx as unknown as Database, {
712
792
  ...context,
713
793
  ...input,
794
+ annotations,
714
795
  resources: normalizeResources(input.resources),
715
796
  subjectId: context.subjectId,
716
797
  }),
@@ -0,0 +1,27 @@
1
+ import type { Database } from "@opengeni/db";
2
+ import type { Context } from "hono";
3
+ import { HTTPException } from "hono/http-exception";
4
+ import type { ManagedAuth } from "./managed-auth-type";
5
+ import { getManagedSession } from "./managed-session";
6
+
7
+ export type CanonicalHumanRequestIdentity = {
8
+ authUserId: string;
9
+ authSessionId: string;
10
+ };
11
+
12
+ export async function requireCanonicalHumanRequestIdentity(
13
+ context: Context,
14
+ input: { db: Database; managedAuth?: ManagedAuth | null; allowRecovery?: boolean },
15
+ ): Promise<CanonicalHumanRequestIdentity> {
16
+ if (!input.managedAuth) {
17
+ throw new HTTPException(404, { message: "Canonical human identity is unavailable" });
18
+ }
19
+ const session = await getManagedSession(context, input.managedAuth, {
20
+ db: input.db,
21
+ ...(input.allowRecovery === undefined ? {} : { allowIdentityRecovery: input.allowRecovery }),
22
+ });
23
+ if (!session?.user || typeof session.session?.id !== "string") {
24
+ throw new HTTPException(401, { message: "Managed human authentication required" });
25
+ }
26
+ return { authUserId: session.user.id, authSessionId: session.session.id };
27
+ }
@@ -5,6 +5,7 @@ import type {
5
5
  DocumentAuthorityKind,
6
6
  GitHubAppApiPort,
7
7
  ScheduledTask,
8
+ ScheduledTaskTriggerType,
8
9
  SessionAuthorizationPort,
9
10
  TurnInitiator,
10
11
  } from "@opengeni/contracts";
@@ -16,6 +17,12 @@ import type { createObjectStorage } from "@opengeni/storage";
16
17
  import type { ManagedAuth } from "./managed-auth-type";
17
18
  import type { ApiSandboxClient, ResumeBoxByIdInput, ResumedSandboxSession } from "./sandbox-types";
18
19
  import type { TranscriptionSegmenter, TranscriptionService } from "./transcription";
20
+ import type { EditableArtifactApplicationPort } from "./editable-artifact-live";
21
+ import type {
22
+ EditableArtifactAgentApplication,
23
+ EditableArtifactDurableExportService,
24
+ EditableArtifactOfficeImportPort,
25
+ } from "./editable-artifacts";
19
26
 
20
27
  export type SessionWorkflowClient = {
21
28
  signalUserMessage: (input: {
@@ -59,6 +66,10 @@ export type SessionWorkflowClient = {
59
66
  agentRunUsageIdempotencyKey: string;
60
67
  triggerWorkflowId: string;
61
68
  initiator: TurnInitiator;
69
+ triggerType?: Extract<
70
+ ScheduledTaskTriggerType,
71
+ "manual" | "initial" | "provider_event" | "retry" | "repair"
72
+ >;
62
73
  }) => Promise<void>;
63
74
  startRigVerification: (input: {
64
75
  workspaceId: string;
@@ -83,8 +94,22 @@ export type DocumentIndexClient = {
83
94
  export type AppDependencies = {
84
95
  settings: Settings;
85
96
  db: Database;
97
+ /**
98
+ * Host-composed editable artifact engine. Standalone startup binds the same
99
+ * native kernel/DB/object-store implementation; embedded hosts may inject an
100
+ * equivalent deployment-scoped composition.
101
+ */
102
+ editableArtifacts?: EditableArtifactApplicationPort;
103
+ /** Durable immutable version/materialization API paired with editableArtifacts. */
104
+ editableArtifactExports?: EditableArtifactDurableExportService;
105
+ /** Canonical agent-facing artifact use cases shared by MCP and Codemode. */
106
+ editableArtifactAgent?: EditableArtifactAgentApplication;
107
+ /** Trusted Office-file to canonical sequence-zero import boundary. */
108
+ editableArtifactOfficeImports?: EditableArtifactOfficeImportPort;
86
109
  bus: EventBus;
87
110
  workflowClient: SessionWorkflowClient;
111
+ /** Injectable structural seam for replayable prompt fanout and wake work. */
112
+ schedulePromptPostCommit?: (task: () => Promise<void>) => void;
88
113
  /** Optional provider override for deterministic API/object-storage tests. */
89
114
  objectStorage?: ObjectStorageDependency;
90
115
  documentIndexer?: DocumentIndexClient;
@@ -100,7 +125,7 @@ export type AppDependencies = {
100
125
  githubAppApi?: GitHubAppApiPort;
101
126
  /**
102
127
  * Optional host-owned connection credential seam. API-side consumers use
103
- * the MCP leg for Toolspace/Code Mode; worker consumers bind the same port
128
+ * the MCP leg for Codemode/Code Mode; worker consumers bind the same port
104
129
  * for model MCP, Git, and sandbox-secret resolution.
105
130
  */
106
131
  connectionCredentials?: ConnectionCredentialsPort | null;
@@ -113,10 +138,17 @@ export type AppDependencies = {
113
138
  managedAuth?: ManagedAuth | null;
114
139
  /** Injectable Codex HTTP transport for deterministic API/provider tests. */
115
140
  codexFetch?: typeof fetch;
141
+ /** Injectable xAI OAuth/subscription transport for deterministic API/provider tests. */
142
+ xaiFetch?: typeof fetch;
116
143
  /** Injectable Slack Web API transport for deterministic bot-connection tests. */
117
144
  slackFetch?: typeof fetch;
118
145
  /** Injectable Google OAuth/Drive transport for deterministic connector tests. */
119
146
  googleDriveFetch?: typeof fetch;
147
+ /** Injectable Fiken API transport for deterministic connector tests. */
148
+ fikenFetch?: typeof fetch;
149
+ /** Injectable Integration Definition OAuth/API transport for deterministic tests. */
150
+ apiIntegrationOAuthFetch?: typeof fetch;
151
+ atlassianFetch?: typeof fetch;
120
152
  /** Injectable MCP OAuth setup deadline for deterministic stalled-provider tests. */
121
153
  oauthStartDeadlineMs?: number;
122
154
  /** Injectable MCP OAuth callback deadline for deterministic stalled-provider tests. */
@@ -163,7 +195,7 @@ export type ApiRouteDeps = AppDependencies & {
163
195
  */
164
196
  export type AcceptSessionUserMessageDependencies = Pick<
165
197
  AppDependencies,
166
- "settings" | "db" | "bus" | "sessionAuthorization"
198
+ "settings" | "db" | "bus" | "sessionAuthorization" | "schedulePromptPostCommit"
167
199
  > & {
168
200
  workflowClient: Pick<SessionWorkflowClient, "wakeSessionWorkflow">;
169
201
  objectStorage: ObjectStorageDependency;