@desplega.ai/agent-swarm 1.85.0 → 1.87.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 (129) hide show
  1. package/README.md +1 -0
  2. package/openapi.json +72 -1
  3. package/package.json +10 -6
  4. package/src/be/db-queries/tracker.ts +21 -0
  5. package/src/be/db.ts +279 -14
  6. package/src/be/migrations/078_backfill_gpt_5_5_pricing.sql +15 -0
  7. package/src/be/migrations/079_task_followup_config.sql +1 -0
  8. package/src/be/modelsdev-cache.json +155618 -0
  9. package/src/be/modelsdev-cache.ts +46 -0
  10. package/src/be/seed-pricing.ts +7 -44
  11. package/src/cli.tsx +38 -2
  12. package/src/commands/codex-session-runner.ts +132 -0
  13. package/src/commands/context-preamble.ts +272 -0
  14. package/src/commands/credential-wait.ts +2 -2
  15. package/src/commands/e2b.ts +728 -0
  16. package/src/commands/provider-credentials.ts +10 -5
  17. package/src/commands/resume-session.ts +35 -78
  18. package/src/commands/runner.ts +128 -16
  19. package/src/e2b/dispatch.ts +429 -0
  20. package/src/e2b/env.ts +206 -0
  21. package/src/heartbeat/heartbeat.ts +145 -30
  22. package/src/heartbeat/templates.ts +11 -7
  23. package/src/http/session-data.ts +8 -1
  24. package/src/http/tasks.ts +152 -3
  25. package/src/jira/sync.ts +4 -4
  26. package/src/linear/sync.ts +6 -5
  27. package/src/prompts/base-prompt.ts +49 -3
  28. package/src/providers/claude-adapter.ts +76 -61
  29. package/src/providers/claude-managed-adapter.ts +61 -75
  30. package/src/providers/claude-managed-models.ts +18 -2
  31. package/src/providers/codex-adapter.ts +429 -112
  32. package/src/providers/codex-models.ts +9 -2
  33. package/src/providers/codex-oauth/auth-json.ts +18 -1
  34. package/src/providers/codex-oauth/flow.ts +24 -1
  35. package/src/providers/index.ts +28 -19
  36. package/src/providers/pricing-sources.md +7 -4
  37. package/src/providers/swarm-events-shared.ts +14 -0
  38. package/src/providers/types.ts +6 -0
  39. package/src/slack/HEURISTICS.md +5 -1
  40. package/src/slack/handlers.test.ts +35 -0
  41. package/src/slack/handlers.ts +79 -2
  42. package/src/tasks/worker-follow-up.ts +162 -2
  43. package/src/telemetry.ts +11 -1
  44. package/src/tests/base-prompt.test.ts +46 -8
  45. package/src/tests/claude-adapter.test.ts +5 -27
  46. package/src/tests/claude-managed-adapter.test.ts +42 -56
  47. package/src/tests/codex-adapter-otel.test.ts +4 -4
  48. package/src/tests/codex-adapter.test.ts +25 -37
  49. package/src/tests/codex-oauth.test.ts +149 -3
  50. package/src/tests/codex-pool.test.ts +14 -3
  51. package/src/tests/codex-swarm-events.test.ts +35 -0
  52. package/src/tests/context-window.test.ts +1 -0
  53. package/src/tests/credential-check.test.ts +48 -29
  54. package/src/tests/e2b-dispatch.test.ts +330 -0
  55. package/src/tests/entrypoint-config-env-export.test.ts +81 -0
  56. package/src/tests/follow-up-redelivery-guard.test.ts +165 -0
  57. package/src/tests/heartbeat-supersede-resume.test.ts +285 -0
  58. package/src/tests/heartbeat.test.ts +26 -16
  59. package/src/tests/migration-046-budgets.test.ts +6 -5
  60. package/src/tests/pricing-routes.test.ts +6 -5
  61. package/src/tests/prompt-template-remaining.test.ts +4 -0
  62. package/src/tests/provider-adapter.test.ts +10 -10
  63. package/src/tests/provider-command-format.test.ts +4 -4
  64. package/src/tests/resume-session.test.ts +42 -50
  65. package/src/tests/session-costs-codex-recompute.test.ts +25 -0
  66. package/src/tests/structured-output.test.ts +69 -0
  67. package/src/tests/task-completion-idempotency.test.ts +185 -2
  68. package/src/tests/task-supersede-resume.test.ts +722 -0
  69. package/src/tests/telemetry-init.test.ts +69 -0
  70. package/src/tests/vcs-tracking.test.ts +39 -0
  71. package/src/tools/send-task.ts +42 -10
  72. package/src/tools/store-progress.ts +2 -2
  73. package/src/tools/templates.ts +14 -2
  74. package/src/types.ts +46 -1
  75. package/src/utils/context-window.ts +1 -0
  76. package/src/workflows/executors/agent-task.ts +3 -0
  77. package/templates/schedules/daily-blocker-digest/config.json +13 -0
  78. package/templates/schedules/daily-blocker-digest/content.md +150 -0
  79. package/templates/schedules/daily-compounding-reflection/config.json +21 -0
  80. package/templates/schedules/daily-compounding-reflection/content.md +210 -0
  81. package/templates/schedules/daily-hn-briefing/config.json +13 -0
  82. package/templates/schedules/daily-hn-briefing/content.md +97 -0
  83. package/templates/schedules/daily-workflow-health-audit/config.json +13 -0
  84. package/templates/schedules/daily-workflow-health-audit/content.md +189 -0
  85. package/templates/schedules/gtm-weekly-review/config.json +13 -0
  86. package/templates/schedules/gtm-weekly-review/content.md +58 -0
  87. package/templates/schedules/weekly-dependabot-triage/config.json +13 -0
  88. package/templates/schedules/weekly-dependabot-triage/content.md +45 -0
  89. package/templates/schema.ts +26 -0
  90. package/templates/skills/agentmail-sending/config.json +13 -0
  91. package/templates/skills/agentmail-sending/content.md +48 -0
  92. package/templates/skills/artifacts/config.json +13 -0
  93. package/templates/skills/artifacts/content.md +87 -0
  94. package/templates/skills/browser-use-cloud/config.json +13 -0
  95. package/templates/skills/browser-use-cloud/content.md +155 -0
  96. package/templates/skills/desloppify/config.json +13 -0
  97. package/templates/skills/desloppify/content.md +201 -0
  98. package/templates/skills/exa-search/config.json +13 -0
  99. package/templates/skills/exa-search/content.md +106 -0
  100. package/templates/skills/jira-interaction/config.json +13 -0
  101. package/templates/skills/jira-interaction/content.md +252 -0
  102. package/templates/skills/kapso-whatsapp/config.json +13 -0
  103. package/templates/skills/kapso-whatsapp/content.md +369 -0
  104. package/templates/skills/kv-storage/config.json +13 -0
  105. package/templates/skills/kv-storage/content.md +111 -0
  106. package/templates/skills/linear-interaction/config.json +20 -0
  107. package/templates/skills/linear-interaction/content.md +230 -0
  108. package/templates/skills/pages/config.json +18 -0
  109. package/templates/skills/pages/content.md +85 -0
  110. package/templates/skills/profile-corruption-escalation/config.json +13 -0
  111. package/templates/skills/profile-corruption-escalation/content.md +105 -0
  112. package/templates/skills/scheduled-task-resilience/config.json +13 -0
  113. package/templates/skills/scheduled-task-resilience/content.md +95 -0
  114. package/templates/skills/sprite-cli/config.json +13 -0
  115. package/templates/skills/sprite-cli/content.md +133 -0
  116. package/templates/skills/turso-interaction/config.json +13 -0
  117. package/templates/skills/turso-interaction/content.md +192 -0
  118. package/templates/skills/workflow-iterate/config.json +18 -0
  119. package/templates/skills/workflow-iterate/content.md +399 -0
  120. package/templates/skills/workflow-structured-output/config.json +13 -0
  121. package/templates/skills/workflow-structured-output/content.md +101 -0
  122. package/templates/skills/x-api-interactions/config.json +13 -0
  123. package/templates/skills/x-api-interactions/content.md +109 -0
  124. package/templates/workflows/autopilot/config.json +13 -0
  125. package/templates/workflows/autopilot/content.md +58 -0
  126. package/templates/workflows/linear-drain-loop/config.json +21 -0
  127. package/templates/workflows/linear-drain-loop/content.md +72 -0
  128. package/templates/workflows/ralph-loop/config.json +13 -0
  129. package/templates/workflows/ralph-loop/content.md +75 -0
@@ -318,6 +318,30 @@ export function buildClaudeCodeOtelEnv(
318
318
  return otelEnv;
319
319
  }
320
320
 
321
+ /**
322
+ * Resolve the path at which the per-task system prompt is staged on disk.
323
+ *
324
+ * Pushing the prompt as `--append-system-prompt <value>` makes the entire
325
+ * prompt one argv element. Linux's per-arg limit is `MAX_ARG_STRLEN = 131072`
326
+ * bytes — and the system prompt (CLAUDE.md + TOOLS.md + identity files +
327
+ * repo CLAUDE.md) routinely runs 50–80 KB. A few growth nudges push us
328
+ * across the cliff and `posix_spawn` returns E2BIG, killing the worker
329
+ * (Picateclas attempts 4-6, 2026-05-28).
330
+ *
331
+ * `claude --append-system-prompt-file <path>` reads the prompt from disk,
332
+ * so the argv stays bounded by the filename length and the system prompt
333
+ * size is decoupled from the kernel's argv ceiling.
334
+ *
335
+ * Exported for unit testing.
336
+ */
337
+ export function getSystemPromptFilePath(taskId: string): string {
338
+ // The taskId is a UUID; safe to embed in a /tmp filename. Mirrors the
339
+ // existing /tmp/agent-swarm-task-${pid}.json + /tmp/mcp-${taskId}.json
340
+ // convention so a janitor sweeping /tmp can find all session-scoped state
341
+ // under the same prefix.
342
+ return `/tmp/agent-swarm-system-prompt-${taskId}.txt`;
343
+ }
344
+
321
345
  class ClaudeSession implements ProviderSession {
322
346
  private proc: ReturnType<typeof Bun.spawn>;
323
347
  private listeners: Array<(event: ProviderEvent) => void> = [];
@@ -327,6 +351,8 @@ class ClaudeSession implements ProviderSession {
327
351
  private errorTracker = new SessionErrorTracker();
328
352
  private taskFilePid: number;
329
353
  private contextWindowSize: number;
354
+ /** Path to the system-prompt temp file when one was staged for this session. */
355
+ private systemPromptFile: string | null;
330
356
 
331
357
  constructor(
332
358
  private config: ProviderSessionConfig,
@@ -335,9 +361,11 @@ class ClaudeSession implements ProviderSession {
335
361
  taskFilePid: number,
336
362
  private sessionMcpConfig: string | null = null,
337
363
  private claudeBinaryArgv: readonly string[] = ["claude"],
364
+ systemPromptFile: string | null = null,
338
365
  ) {
339
366
  this.taskFilePid = taskFilePid;
340
367
  this.contextWindowSize = getContextWindowSize(model);
368
+ this.systemPromptFile = systemPromptFile;
341
369
  const cmd = this.buildCommand();
342
370
 
343
371
  console.log(
@@ -395,15 +423,17 @@ class ClaudeSession implements ProviderSession {
395
423
  this.config.prompt,
396
424
  ];
397
425
 
398
- if (this.config.resumeSessionId) {
399
- cmd.push("--resume", this.config.resumeSessionId);
400
- }
401
-
402
426
  if (this.config.additionalArgs?.length) {
403
427
  cmd.push(...this.config.additionalArgs);
404
428
  }
405
429
 
406
- if (this.config.systemPrompt) {
430
+ // System prompt is staged on disk and read via the file-flag — see
431
+ // `getSystemPromptFilePath` for the rationale (argv E2BIG hardening,
432
+ // Picateclas spawn-OOM, 2026-05-28). The legacy inline form is kept as
433
+ // a fallback for the (unlikely) case where the file couldn't be staged.
434
+ if (this.systemPromptFile) {
435
+ cmd.push("--append-system-prompt-file", this.systemPromptFile);
436
+ } else if (this.config.systemPrompt) {
407
437
  cmd.push("--append-system-prompt", this.config.systemPrompt);
408
438
  }
409
439
 
@@ -490,7 +520,7 @@ class ClaudeSession implements ProviderSession {
490
520
  await logFileHandle.end();
491
521
  const exitCode = await this.proc.exited;
492
522
 
493
- // Cleanup task file and per-session MCP config
523
+ // Cleanup task file, per-session MCP config, and per-task system prompt
494
524
  await cleanupTaskFile(this.taskFilePid);
495
525
  if (this.sessionMcpConfig) {
496
526
  try {
@@ -499,6 +529,13 @@ class ClaudeSession implements ProviderSession {
499
529
  // ignore — temp file may already be gone
500
530
  }
501
531
  }
532
+ if (this.systemPromptFile) {
533
+ try {
534
+ await unlink(this.systemPromptFile);
535
+ } catch {
536
+ // ignore — temp file may already be gone
537
+ }
538
+ }
502
539
 
503
540
  if (exitCode !== 0 && stderrOutput) {
504
541
  console.error(
@@ -687,61 +724,7 @@ class ClaudeSession implements ProviderSession {
687
724
  }
688
725
 
689
726
  async waitForCompletion(): Promise<ProviderResult> {
690
- const result = await this.completionPromise;
691
-
692
- // Stale session retry: if process failed because session not found and we used --resume,
693
- // strip --resume and retry with a fresh session
694
- if (result.exitCode !== 0 && this.errorTracker.isSessionNotFound()) {
695
- const hasResume =
696
- !!this.config.resumeSessionId || (this.config.additionalArgs || []).includes("--resume");
697
- if (hasResume) {
698
- console.log(
699
- `\x1b[33m[${this.config.role}] Session resume failed for task ${this.config.taskId.slice(0, 8)} — retrying without --resume\x1b[0m`,
700
- );
701
-
702
- const freshArgs = (this.config.additionalArgs || []).filter((arg, idx, arr) => {
703
- if (arg === "--resume") return false;
704
- if (idx > 0 && arr[idx - 1] === "--resume") return false;
705
- return true;
706
- });
707
-
708
- const logDir = this.config.logFile.substring(0, this.config.logFile.lastIndexOf("/"));
709
- const retryTimestamp = new Date().toISOString().replace(/[:.]/g, "-");
710
- const retryLogFile = `${logDir}/${retryTimestamp}-retry-${this.config.taskId.slice(0, 8)}.jsonl`;
711
-
712
- const retryConfig: ProviderSessionConfig = {
713
- ...this.config,
714
- additionalArgs: freshArgs,
715
- logFile: retryLogFile,
716
- resumeSessionId: undefined,
717
- };
718
-
719
- // Write new task file for retry
720
- const taskFilePath = await writeTaskFile(this.taskFilePid, {
721
- taskId: this.config.taskId,
722
- agentId: this.config.agentId,
723
- startedAt: new Date().toISOString(),
724
- });
725
-
726
- const retrySession = new ClaudeSession(
727
- retryConfig,
728
- this.model,
729
- taskFilePath,
730
- this.taskFilePid,
731
- null,
732
- this.claudeBinaryArgv,
733
- );
734
-
735
- // Forward events from retry to our listeners
736
- for (const listener of this.listeners) {
737
- retrySession.onEvent(listener);
738
- }
739
-
740
- return retrySession.waitForCompletion();
741
- }
742
- }
743
-
744
- return result;
727
+ return this.completionPromise;
745
728
  }
746
729
 
747
730
  async abort(): Promise<void> {
@@ -754,6 +737,15 @@ export class ClaudeAdapter implements ProviderAdapter {
754
737
  readonly traits = { hasMcp: true, hasLocalEnvironment: true };
755
738
 
756
739
  async createSession(config: ProviderSessionConfig): Promise<ProviderSession> {
740
+ // Native resume is deprecated. Follow-up continuity is delivered via the
741
+ // context preamble (see src/commands/context-preamble.ts). Any stray
742
+ // resumeSessionId is logged and ignored — we always spawn a fresh session.
743
+ if (config.resumeSessionId) {
744
+ console.warn(
745
+ "[claude-adapter] resumeSessionId ignored — native resume is disabled by deprecation plan",
746
+ );
747
+ }
748
+
757
749
  const model = config.model || "opus";
758
750
 
759
751
  const credType = validateClaudeCredentials(config.env || process.env);
@@ -832,6 +824,28 @@ export class ClaudeAdapter implements ProviderAdapter {
832
824
  installedServers,
833
825
  );
834
826
 
827
+ // Stage the system prompt on disk so it can be passed as a file path
828
+ // instead of one giant argv element. This is the structural fix for
829
+ // posix_spawn E2BIG once the prompt grows past MAX_ARG_STRLEN (131,072
830
+ // bytes) — see `getSystemPromptFilePath` and PR description for the
831
+ // Picateclas spawn-OOM saga. Soft-fail (`systemPromptFile = null`) makes
832
+ // the session fall back to the inline `--append-system-prompt` argv;
833
+ // good enough since `BOOTSTRAP_TOTAL_MAX_CHARS` (now 120,000) already
834
+ // caps the worst-case argv element below the kernel limit even without
835
+ // the file path.
836
+ let systemPromptFile: string | null = null;
837
+ if (config.systemPrompt) {
838
+ const candidate = getSystemPromptFilePath(config.taskId);
839
+ try {
840
+ await writeFile(candidate, config.systemPrompt);
841
+ systemPromptFile = candidate;
842
+ } catch (err) {
843
+ console.warn(
844
+ `\x1b[33m[claude]\x1b[0m Failed to stage system prompt to ${candidate} (${err}); falling back to --append-system-prompt argv. Argv may approach MAX_ARG_STRLEN if the prompt is large.`,
845
+ );
846
+ }
847
+ }
848
+
835
849
  return new ClaudeSession(
836
850
  config,
837
851
  model,
@@ -839,6 +853,7 @@ export class ClaudeAdapter implements ProviderAdapter {
839
853
  taskFilePid,
840
854
  sessionMcpConfig,
841
855
  claudeBinaryArgv,
856
+ systemPromptFile,
842
857
  );
843
858
  }
844
859
 
@@ -808,85 +808,71 @@ export class ClaudeManagedAdapter implements ProviderAdapter {
808
808
  }
809
809
 
810
810
  async createSession(config: ProviderSessionConfig): Promise<ProviderSession> {
811
- let sessionId: string;
812
- let userMessageContent: BetaManagedAgentsTextBlock[] | null;
811
+ // Native resume is deprecated. Follow-up continuity is delivered via the
812
+ // context preamble (see src/commands/context-preamble.ts). Any stray
813
+ // resumeSessionId is logged and ignored — we always create a fresh session.
814
+ if (config.resumeSessionId) {
815
+ console.warn(
816
+ "[claude-managed-adapter] resumeSessionId ignored — native resume is disabled by deprecation plan",
817
+ );
818
+ }
819
+
813
820
  const seenEventIds = new Set<string>();
814
821
 
815
- if (config.resumeSessionId) {
816
- // Resume path: skip `sessions.create`. Pre-fetch event history via
817
- // `events.list` so the SSE loop can skip duplicates that the live
818
- // stream replays. NO new `user.message` is sent (the agent already
819
- // has one in flight).
820
- sessionId = config.resumeSessionId;
821
- userMessageContent = null;
822
- try {
823
- const list = await Promise.resolve(this.client.beta.sessions.events.list(sessionId));
824
- for await (const evt of list) {
825
- if ("id" in evt && evt.id) {
826
- seenEventIds.add(evt.id);
827
- }
828
- }
829
- } catch {
830
- // If history fetch fails, fall through with an empty `seenEventIds`
831
- // the worst case is that the listener sees a few duplicate events
832
- // (which the runner-side dedup handles).
833
- }
834
- } else {
835
- // Fresh session. Compose the cache-control-annotated user message and
836
- // open the managed session against the pre-existing agent + env.
837
- userMessageContent = composeManagedUserMessage(config);
838
- // Phase 4: derive `resources` from `config.vcsRepo` (which the runner
839
- // copies from `task.vcsRepo` at the spawn site, see
840
- // src/commands/runner.ts:3296). The SDK contract is
841
- // `BetaManagedAgentsGitHubRepositoryResourceParams`:
842
- // { type: 'github_repository', url, authorization_token, checkout?: { type: 'branch', name } }
843
- // We default `branch` to "main" since `ProviderSessionConfig` only
844
- // carries the repo identifier as a string.
845
- //
846
- // GitHub auth: prefer the operator-side `MANAGED_GITHUB_VAULT_ID`
847
- // (passed via `vault_ids` on the session — see runbook §"Claude Managed
848
- // Agents — GitHub access"). If a literal PAT is supplied via
849
- // `MANAGED_GITHUB_TOKEN`, use that instead. Without either, the SDK's
850
- // required `authorization_token` field gets an empty string and the
851
- // operator sees an authentication error from Anthropic — which is
852
- // strictly better than silently dropping `resources`.
853
- const createParams: Record<string, unknown> = {
854
- agent: this.agentId,
855
- environment_id: this.environmentId,
856
- title: `Task ${config.taskId}`,
857
- metadata: {
858
- swarmAgentId: config.agentId,
859
- swarmTaskId: config.taskId,
822
+ // Fresh session. Compose the cache-control-annotated user message and
823
+ // open the managed session against the pre-existing agent + env.
824
+ const userMessageContent: BetaManagedAgentsTextBlock[] | null =
825
+ composeManagedUserMessage(config);
826
+ // Phase 4: derive `resources` from `config.vcsRepo` (which the runner
827
+ // copies from `task.vcsRepo` at the spawn site, see
828
+ // src/commands/runner.ts:3296). The SDK contract is
829
+ // `BetaManagedAgentsGitHubRepositoryResourceParams`:
830
+ // { type: 'github_repository', url, authorization_token, checkout?: { type: 'branch', name } }
831
+ // We default `branch` to "main" since `ProviderSessionConfig` only
832
+ // carries the repo identifier as a string.
833
+ //
834
+ // GitHub auth: prefer the operator-side `MANAGED_GITHUB_VAULT_ID`
835
+ // (passed via `vault_ids` on the session — see runbook §"Claude Managed
836
+ // Agents — GitHub access"). If a literal PAT is supplied via
837
+ // `MANAGED_GITHUB_TOKEN`, use that instead. Without either, the SDK's
838
+ // required `authorization_token` field gets an empty string and the
839
+ // operator sees an authentication error from Anthropic — which is
840
+ // strictly better than silently dropping `resources`.
841
+ const createParams: Record<string, unknown> = {
842
+ agent: this.agentId,
843
+ environment_id: this.environmentId,
844
+ title: `Task ${config.taskId}`,
845
+ metadata: {
846
+ swarmAgentId: config.agentId,
847
+ swarmTaskId: config.taskId,
848
+ },
849
+ };
850
+ if (config.vcsRepo) {
851
+ const repoUrl = normalizeRepoUrl(config.vcsRepo);
852
+ const branch = "main"; // ProviderSessionConfig doesn't carry per-task branch info today.
853
+ const githubToken = process.env.MANAGED_GITHUB_TOKEN ?? "";
854
+ createParams.resources = [
855
+ {
856
+ type: "github_repository",
857
+ url: repoUrl,
858
+ authorization_token: githubToken,
859
+ checkout: { type: "branch", name: branch },
860
860
  },
861
- };
862
- if (config.vcsRepo) {
863
- const repoUrl = normalizeRepoUrl(config.vcsRepo);
864
- const branch = "main"; // ProviderSessionConfig doesn't carry per-task branch info today.
865
- const githubToken = process.env.MANAGED_GITHUB_TOKEN ?? "";
866
- createParams.resources = [
867
- {
868
- type: "github_repository",
869
- url: repoUrl,
870
- authorization_token: githubToken,
871
- checkout: { type: "branch", name: branch },
872
- },
873
- ];
874
- }
875
- // Multiple vaults can be linked to a single session — `vault_ids` is an
876
- // array. The MCP vault holds the static-bearer credential for our
877
- // `/mcp` endpoint (provisioned by `claude-managed-setup`); the GitHub
878
- // vault holds the credential used by the `github_repository` resource.
879
- // Either or both may be unset.
880
- const vaultIds = [
881
- process.env.MANAGED_MCP_VAULT_ID,
882
- process.env.MANAGED_GITHUB_VAULT_ID,
883
- ].filter((v): v is string => !!v && v.length > 0);
884
- if (vaultIds.length > 0) {
885
- createParams.vault_ids = Array.from(new Set(vaultIds));
886
- }
887
- const created = await Promise.resolve(this.client.beta.sessions.create(createParams));
888
- sessionId = created.id;
861
+ ];
862
+ }
863
+ // Multiple vaults can be linked to a single session — `vault_ids` is an
864
+ // array. The MCP vault holds the static-bearer credential for our
865
+ // `/mcp` endpoint (provisioned by `claude-managed-setup`); the GitHub
866
+ // vault holds the credential used by the `github_repository` resource.
867
+ // Either or both may be unset.
868
+ const vaultIds = [process.env.MANAGED_MCP_VAULT_ID, process.env.MANAGED_GITHUB_VAULT_ID].filter(
869
+ (v): v is string => !!v && v.length > 0,
870
+ );
871
+ if (vaultIds.length > 0) {
872
+ createParams.vault_ids = Array.from(new Set(vaultIds));
889
873
  }
874
+ const created = await Promise.resolve(this.client.beta.sessions.create(createParams));
875
+ const sessionId = created.id;
890
876
 
891
877
  return new ClaudeManagedSession(
892
878
  this.client,
@@ -26,7 +26,9 @@
26
26
  /** Models supported by the managed-agents surface for the swarm worker. */
27
27
  export const CLAUDE_MANAGED_MODELS = [
28
28
  "claude-sonnet-4-6",
29
+ "claude-opus-4-8",
29
30
  "claude-opus-4-7",
31
+ "claude-opus-4-6",
30
32
  "claude-haiku-4-5",
31
33
  ] as const;
32
34
 
@@ -45,11 +47,13 @@ export interface ClaudeManagedModelPricing {
45
47
  }
46
48
 
47
49
  /**
48
- * Anthropic public list pricing as of 2026-04-28. Source:
50
+ * Anthropic public list pricing. Source:
49
51
  * https://platform.claude.com/docs/en/about-claude/pricing
50
52
  *
51
53
  * - claude-sonnet-4-6: $3 / $15 / $0.30 / $3.75 (in / out / cache-read / cache-write)
52
- * - claude-opus-4-7: $15 / $75 / $1.50 / $18.75
54
+ * - claude-opus-4-8: $5 / $25 / $0.50 / $6.25 (verified 2026-05-28)
55
+ * - claude-opus-4-7: $15 / $75 / $1.50 / $18.75 (STALE — was correct at launch, Anthropic has since dropped Opus to $5/$25)
56
+ * - claude-opus-4-6: $5 / $25 / $0.50 / $6.25 (verified 2026-05-28)
53
57
  * - claude-haiku-4-5: $1 / $5 / $0.10 / $1.25
54
58
  */
55
59
  export const CLAUDE_MANAGED_MODEL_PRICING: Record<ClaudeManagedModel, ClaudeManagedModelPricing> = {
@@ -59,12 +63,24 @@ export const CLAUDE_MANAGED_MODEL_PRICING: Record<ClaudeManagedModel, ClaudeMana
59
63
  cacheReadPerMillion: 0.3,
60
64
  cacheWritePerMillion: 3.75,
61
65
  },
66
+ "claude-opus-4-8": {
67
+ inputPerMillion: 5.0,
68
+ outputPerMillion: 25.0,
69
+ cacheReadPerMillion: 0.5,
70
+ cacheWritePerMillion: 6.25,
71
+ },
62
72
  "claude-opus-4-7": {
63
73
  inputPerMillion: 15.0,
64
74
  outputPerMillion: 75.0,
65
75
  cacheReadPerMillion: 1.5,
66
76
  cacheWritePerMillion: 18.75,
67
77
  },
78
+ "claude-opus-4-6": {
79
+ inputPerMillion: 5.0,
80
+ outputPerMillion: 25.0,
81
+ cacheReadPerMillion: 0.5,
82
+ cacheWritePerMillion: 6.25,
83
+ },
68
84
  "claude-haiku-4-5": {
69
85
  inputPerMillion: 1.0,
70
86
  outputPerMillion: 5.0,