@desplega.ai/agent-swarm 1.113.0 → 1.115.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 (237) hide show
  1. package/README.md +2 -2
  2. package/dist/{actions-q4n7cz6e.js → actions-17ya5wde.js} +8 -9
  3. package/dist/{app-es4nzc71.js → app-4f718yk0.js} +6 -6
  4. package/dist/{assistant-0x8ey0vs.js → assistant-ah7csnjz.js} +19 -18
  5. package/dist/{boot-reembed-69agkhv6.js → boot-reembed-4jpxhb25.js} +6 -6
  6. package/dist/{boot-reembed-p0ny05t8.js → boot-reembed-qata34xa.js} +5 -5
  7. package/dist/{boot-scrub-logs-yybrkmvr.js → boot-scrub-logs-tv48nn3z.js} +4 -4
  8. package/dist/{claude-adapter-mma9a1yr.js → claude-adapter-3csn5bks.js} +3 -3
  9. package/dist/{claude-managed-adapter-pv2nbqy4.js → claude-managed-adapter-kysmkz89.js} +2 -2
  10. package/dist/cli-0pygq9r1.js +429 -0
  11. package/dist/{cli-hsetkkd3.js → cli-12vb0xg6.js} +33 -9
  12. package/dist/{cli-ncfgsqbd.js → cli-15y7qhzp.js} +262 -33
  13. package/dist/{cli-7ga43spr.js → cli-1yjrbg1f.js} +1 -1
  14. package/dist/{cli-36ymmpmp.js → cli-3samkyap.js} +2 -2
  15. package/dist/cli-52fg7s7x.js +269 -0
  16. package/dist/{cli-hjhvekf4.js → cli-65ekje01.js} +11 -8
  17. package/dist/{cli-h3k622d0.js → cli-6aq8xhvm.js} +90 -3
  18. package/dist/{cli-f3qa069v.js → cli-7xje5amz.js} +1 -1
  19. package/dist/cli-86fdnerz.js +405 -0
  20. package/dist/{cli-9cy6nc5m.js → cli-8fjwym53.js} +1 -1
  21. package/dist/{cli-c3frqf65.js → cli-b23axgz4.js} +3 -3
  22. package/dist/{cli-a0t7vapf.js → cli-bc89my0z.js} +1 -1
  23. package/dist/{cli-bnzbn8j8.js → cli-beea4a3y.js} +73 -24
  24. package/dist/{cli-q21d49ac.js → cli-bw80ck94.js} +1 -1
  25. package/dist/{cli-pwc5e83c.js → cli-cchksf5q.js} +12 -7
  26. package/dist/{cli-30bbaveh.js → cli-cmw9rzy5.js} +2 -2
  27. package/dist/{cli-y6mrptcn.js → cli-cnwssmsr.js} +1 -1
  28. package/dist/{cli-r5g6ngtn.js → cli-dcca6j8m.js} +46 -5
  29. package/dist/{cli-tkmm5nf9.js → cli-e61fs2hp.js} +59 -2
  30. package/dist/{cli-6wscj9z0.js → cli-e7306swv.js} +14 -14
  31. package/dist/{cli-dcfyyh3t.js → cli-ftyf58xj.js} +2 -2
  32. package/dist/{cli-4xyj9jtq.js → cli-hrhye2rm.js} +1062 -478
  33. package/dist/cli-jkhwmmgg.js +136 -0
  34. package/dist/{cli-y4ycrnjc.js → cli-k3y4z3h5.js} +1 -1
  35. package/dist/{cli-6xd0bvf8.js → cli-ma04faw5.js} +1 -1
  36. package/dist/{cli-2fc97xm5.js → cli-mnbgv3w7.js} +4 -4
  37. package/dist/{cli-trmapn9k.js → cli-pet3aev6.js} +95 -10
  38. package/dist/{cli-z46pnksz.js → cli-q1rx7g0d.js} +175 -28
  39. package/dist/{cli-qwgtacd6.js → cli-r9f6ngrf.js} +1244 -336
  40. package/dist/{cli-gtkqc144.js → cli-shvaxw27.js} +13 -7
  41. package/dist/{cli-ywez6yps.js → cli-sq7f72d6.js} +1 -1
  42. package/dist/cli-t0vqevnm.js +393 -0
  43. package/dist/{cli-tbw13sx8.js → cli-tece6zgm.js} +1 -1
  44. package/dist/{cli-bgvskydy.js → cli-tffvrh6j.js} +1 -1
  45. package/dist/cli-wh91zby6.js +187222 -0
  46. package/dist/{cli-anrj584m.js → cli-xz9aq0rf.js} +1 -1
  47. package/dist/{cli-mq580e06.js → cli-zsrdty74.js} +18 -18
  48. package/dist/cli.js +32 -15
  49. package/dist/{codex-adapter-5cmy858w.js → codex-adapter-de3w0nch.js} +10 -10
  50. package/dist/{codex-session-runner-46q8mrba.js → codex-session-runner-bnw8cysk.js} +10 -10
  51. package/dist/{commands-z5dbwta3.js → commands-hch4e2k1.js} +4 -4
  52. package/dist/{db-bbgahh4z.js → db-p3h2j06x.js} +14 -4
  53. package/dist/{handlers-6b44317z.js → handlers-9er4zx9q.js} +17 -31
  54. package/dist/{hook-sbp5fmps.js → hook-4axs756z.js} +7 -7
  55. package/dist/{http-2xz43gz3.js → http-809fvtz2.js} +1934 -886
  56. package/dist/{index-wz1ea15p.js → index-2dgfj9av.js} +3 -3
  57. package/dist/{index-nhat35em.js → index-47em3d2n.js} +14 -11
  58. package/dist/{index-5ghxn8s6.js → index-9fqaktjr.js} +12 -9
  59. package/dist/{index-0gzmqj4k.js → index-9ht8gr56.js} +13 -10
  60. package/dist/{index-vfedgdw6.js → index-rm85cfdx.js} +368 -40
  61. package/dist/{index-ykvs43z4.js → index-t2snazez.js} +4 -4
  62. package/dist/{keepalive-62gfj91d.js → keepalive-3cps6e3e.js} +7 -6
  63. package/dist/{lead-ag0akn0v.js → lead-fkk95wgq.js} +36 -32
  64. package/dist/{maintenance-xxrrzk5x.js → maintenance-fweqh0yj.js} +6 -6
  65. package/dist/{mistral-conversations-26yrnbf1.js → mistral-conversations-7gqnz2wt.js} +7 -7
  66. package/dist/oauth-refresh-sweep-sycqtbph.js +114 -0
  67. package/dist/{onboard-64zyfcbs.js → onboard-cy0rkgvx.js} +2 -2
  68. package/dist/{opencode-adapter-mqsxr170.js → opencode-adapter-p6bxnbm4.js} +2 -2
  69. package/dist/{otel-zjd9zaxs.js → otel-g299k41b.js} +2 -2
  70. package/dist/{otel-impl-b86qseaa.js → otel-impl-wbns8hf7.js} +1 -1
  71. package/dist/{pi-mono-adapter-kxjxpfgy.js → pi-mono-adapter-05sck1ds.js} +17 -109
  72. package/dist/{pricing-refresh-cgtkffpa.js → pricing-refresh-0hvazmkf.js} +6 -6
  73. package/dist/rbac-roles-kfesjy9y.js +28 -0
  74. package/dist/rbac-roles-mwcwhbxc.js +283 -0
  75. package/dist/{seed-pricing-1r1y1xkq.js → seed-pricing-h2kdq4cq.js} +5 -5
  76. package/dist/{setup-mkcgkjf7.js → setup-8506q97w.js} +2 -2
  77. package/dist/{worker-351sze63.js → worker-4r5c6zyb.js} +36 -32
  78. package/openapi.json +1327 -20
  79. package/package.json +3 -3
  80. package/src/agentmail/handlers.ts +16 -6
  81. package/src/agentmail/templates.ts +25 -5
  82. package/src/be/audit-user.ts +28 -4
  83. package/src/be/db-queries/oauth.ts +42 -0
  84. package/src/be/db.ts +314 -28
  85. package/src/be/identity.ts +79 -0
  86. package/src/be/mcp-proxy.ts +132 -0
  87. package/src/be/migrations/109_rbac_roles.sql +79 -0
  88. package/src/be/migrations/111_oauth_credential_bindings.sql +6 -0
  89. package/src/be/migrations/112_script_connections_graphql.sql +96 -0
  90. package/src/be/migrations/113_task_routing_affinity.sql +9 -0
  91. package/src/be/migrations/114_backfill_gpt_5_6_pricing.sql +15 -0
  92. package/src/be/modelsdev-cache.json +135 -0
  93. package/src/be/oauth-credential-bindings.ts +35 -0
  94. package/src/be/oauth-refresh-sweep.ts +159 -0
  95. package/src/be/rbac-audit.ts +52 -13
  96. package/src/be/rbac-roles.ts +424 -0
  97. package/src/be/script-connections.ts +459 -40
  98. package/src/be/script-credential-broker.ts +29 -3
  99. package/src/be/scripts/typecheck.ts +51 -7
  100. package/src/be/seed-scripts/catalog/catalog-report.inline.ts +325 -24
  101. package/src/be/seed-scripts/catalog/catalog-report.ts +325 -24
  102. package/src/be/users.ts +24 -0
  103. package/src/cli.tsx +17 -0
  104. package/src/github/handlers.ts +10 -9
  105. package/src/github/templates.ts +45 -9
  106. package/src/gitlab/handlers.ts +20 -8
  107. package/src/gitlab/templates.ts +18 -6
  108. package/src/heartbeat/heartbeat.ts +143 -21
  109. package/src/http/all-routes.ts +3 -0
  110. package/src/http/approval-requests.ts +12 -0
  111. package/src/http/config.ts +44 -10
  112. package/src/http/core.ts +30 -3
  113. package/src/http/favorites.ts +1 -5
  114. package/src/http/index.ts +25 -1
  115. package/src/http/mcp-oauth.ts +2 -0
  116. package/src/http/mcp-servers.ts +44 -3
  117. package/src/http/oauth-generic.ts +105 -0
  118. package/src/http/poll.ts +20 -3
  119. package/src/http/script-connection-proxy.ts +116 -0
  120. package/src/http/script-connections.ts +1657 -0
  121. package/src/http/scripts.ts +27 -7
  122. package/src/http/skills.ts +11 -0
  123. package/src/http/tasks.ts +27 -13
  124. package/src/http/x.ts +6 -2
  125. package/src/integrations/kapso/inbound.ts +23 -6
  126. package/src/jira/sync.ts +111 -17
  127. package/src/jira/templates.ts +10 -2
  128. package/src/mcp-client/http-client.ts +194 -0
  129. package/src/oauth/app-validation.ts +16 -0
  130. package/src/oauth/ensure-token.ts +69 -14
  131. package/src/oauth/mcp-wrapper.ts +15 -0
  132. package/src/oauth/wrapper.ts +48 -20
  133. package/src/prompts/session-templates.ts +3 -3
  134. package/src/providers/codex-models.ts +100 -30
  135. package/src/providers/modelsdev-reasoning.json +51 -0
  136. package/src/providers/pi-mono-mcp-client.ts +2 -133
  137. package/src/providers/reasoning-effort.ts +11 -5
  138. package/src/rbac/admission.ts +68 -0
  139. package/src/rbac/index.ts +2 -0
  140. package/src/rbac/legacy-policy.ts +12 -0
  141. package/src/rbac/permissions.ts +48 -0
  142. package/src/scheduler/scheduler.ts +9 -1
  143. package/src/scripts-runtime/api-client.ts +151 -19
  144. package/src/scripts-runtime/api-types.ts +38 -6
  145. package/src/scripts-runtime/credential-broker/default-bindings.ts +1 -0
  146. package/src/scripts-runtime/credential-broker/types.ts +8 -0
  147. package/src/scripts-runtime/ctx.ts +11 -1
  148. package/src/scripts-runtime/eval-harness.ts +5 -1
  149. package/src/scripts-runtime/executors/types.ts +2 -1
  150. package/src/scripts-runtime/loader.ts +3 -1
  151. package/src/scripts-runtime/mcp-client.ts +87 -0
  152. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  153. package/src/scripts-runtime/types/stdlib.d.ts +6 -0
  154. package/src/scripts-runtime/types/swarm-sdk.d.ts +19 -0
  155. package/src/server-user.ts +114 -59
  156. package/src/server.ts +12 -0
  157. package/src/slack/assistant.ts +14 -6
  158. package/src/slack/enrich.ts +17 -0
  159. package/src/slack/handlers.ts +8 -22
  160. package/src/slack/responses.ts +91 -1
  161. package/src/slack/thread-buffer.ts +6 -3
  162. package/src/slack/watcher.ts +9 -6
  163. package/src/tasks/worker-follow-up.ts +100 -3
  164. package/src/tests/agentmail-handlers.test.ts +32 -3
  165. package/src/tests/approval-requests.test.ts +61 -0
  166. package/src/tests/audit-user.test.ts +47 -1
  167. package/src/tests/codex-adapter.test.ts +46 -23
  168. package/src/tests/credential-broker.test.ts +5 -2
  169. package/src/tests/delete-page-tool.test.ts +197 -0
  170. package/src/tests/github-handlers.test.ts +28 -2
  171. package/src/tests/gitlab-handlers.test.ts +125 -0
  172. package/src/tests/heartbeat.test.ts +48 -3
  173. package/src/tests/identity.test.ts +117 -0
  174. package/src/tests/jira-sync.test.ts +99 -1
  175. package/src/tests/kapso-inbound.test.ts +7 -0
  176. package/src/tests/mcp-tools-user.test.ts +60 -6
  177. package/src/tests/model-control.test.ts +8 -2
  178. package/src/tests/oauth-credential-bindings.test.ts +490 -0
  179. package/src/tests/oauth-refresh-sweep.test.ts +160 -0
  180. package/src/tests/pool-affinity.test.ts +401 -0
  181. package/src/tests/prompt-template-remaining.test.ts +2 -2
  182. package/src/tests/rbac-admission-e2e.test.ts +386 -0
  183. package/src/tests/rbac-admission.test.ts +492 -0
  184. package/src/tests/rbac-e2e-helpers.ts +3 -0
  185. package/src/tests/rbac-engine.test.ts +50 -0
  186. package/src/tests/rbac-mcp-admission-e2e.test.ts +362 -0
  187. package/src/tests/rbac-roles.test.ts +328 -0
  188. package/src/tests/reasoning-effort.test.ts +15 -2
  189. package/src/tests/schedule-target-type.test.ts +50 -0
  190. package/src/tests/scheduled-tasks.test.ts +40 -0
  191. package/src/tests/script-apis-mcp.test.ts +37 -13
  192. package/src/tests/script-connections-http.test.ts +1158 -0
  193. package/src/tests/script-connections-mcp.test.ts +894 -0
  194. package/src/tests/script-connections.test.ts +754 -6
  195. package/src/tests/scripts-external-api.test.ts +49 -1
  196. package/src/tests/scripts-runtime-secret-egress.test.ts +1 -0
  197. package/src/tests/scripts-runtime.test.ts +291 -0
  198. package/src/tests/seed-scripts.test.ts +36 -0
  199. package/src/tests/slack-identity-resolution.test.ts +37 -3
  200. package/src/tests/slack-inline-output.test.ts +65 -0
  201. package/src/tests/slack-thread-buffer.test.ts +28 -0
  202. package/src/tests/tool-annotations.test.ts +1 -0
  203. package/src/tests/user-token-rest-auth.test.ts +140 -1
  204. package/src/tests/workflow-swarm-script.test.ts +44 -0
  205. package/src/tests/workflow-triggers-v2.test.ts +300 -1
  206. package/src/tools/credential-bindings/tool.ts +277 -18
  207. package/src/tools/delete-page.ts +145 -0
  208. package/src/tools/mcp-servers/mcp-server-delete.ts +7 -4
  209. package/src/tools/request-human-input.ts +2 -0
  210. package/src/tools/resolve-user.ts +77 -27
  211. package/src/tools/script-apis.ts +62 -3
  212. package/src/tools/script-connections/tool.ts +275 -31
  213. package/src/tools/send-task.ts +15 -1
  214. package/src/tools/task-action.ts +34 -2
  215. package/src/tools/templates.ts +53 -1
  216. package/src/tools/tool-config.ts +2 -1
  217. package/src/tools/utils.ts +2 -0
  218. package/src/tools/workflows/create-workflow.ts +8 -1
  219. package/src/tools/workflows/update-workflow.ts +11 -2
  220. package/src/types.ts +90 -11
  221. package/src/utils/scoped-resource.ts +25 -0
  222. package/src/workflows/executors/human-in-the-loop.ts +1 -0
  223. package/src/workflows/executors/swarm-script.ts +7 -1
  224. package/src/workflows/triggers.ts +146 -18
  225. package/templates/skills/swarm-scripts/content.md +33 -8
  226. package/dist/cli-bgef578c.js +0 -771
  227. package/dist/cli-c9mtm09b.js +0 -43
  228. package/dist/cli-ceewqajw.js +0 -1698
  229. package/dist/{anthropic-messages-8nc6r2dw.js → anthropic-messages-kq3pjhbp.js} +6 -6
  230. package/dist/{azure-openai-responses-6yfzw3qw.js → azure-openai-responses-gm1ejtmn.js} +7 -7
  231. package/dist/{cli-vbraamxr.js → cli-6b4wwmm8.js} +9 -9
  232. package/dist/{cli-2r7s8jhp.js → cli-sznberje.js} +3 -3
  233. package/dist/{google-generative-ai-vfq6ymz9.js → google-generative-ai-hyrra2jm.js} +3 -3
  234. package/dist/{google-vertex-mj5y5rfj.js → google-vertex-8bs2pzgn.js} +3 -3
  235. package/dist/{openai-codex-responses-8h6kvfv8.js → openai-codex-responses-3nkvje79.js} +4 -4
  236. package/dist/{openai-completions-x6kjnqjd.js → openai-completions-0asftkwg.js} +11 -11
  237. package/dist/{openai-responses-7jwyz3ds.js → openai-responses-pmatek45.js} +10 -10
@@ -780,6 +780,57 @@
780
780
  ]
781
781
  }
782
782
  ]
783
+ },
784
+ "gpt-5.6-sol": {
785
+ "id": "gpt-5.6-sol",
786
+ "reasoning": true,
787
+ "reasoningOptions": [
788
+ {
789
+ "type": "effort",
790
+ "values": [
791
+ "none",
792
+ "low",
793
+ "medium",
794
+ "high",
795
+ "xhigh",
796
+ "max"
797
+ ]
798
+ }
799
+ ]
800
+ },
801
+ "gpt-5.6-terra": {
802
+ "id": "gpt-5.6-terra",
803
+ "reasoning": true,
804
+ "reasoningOptions": [
805
+ {
806
+ "type": "effort",
807
+ "values": [
808
+ "none",
809
+ "low",
810
+ "medium",
811
+ "high",
812
+ "xhigh",
813
+ "max"
814
+ ]
815
+ }
816
+ ]
817
+ },
818
+ "gpt-5.6-luna": {
819
+ "id": "gpt-5.6-luna",
820
+ "reasoning": true,
821
+ "reasoningOptions": [
822
+ {
823
+ "type": "effort",
824
+ "values": [
825
+ "none",
826
+ "low",
827
+ "medium",
828
+ "high",
829
+ "xhigh",
830
+ "max"
831
+ ]
832
+ }
833
+ ]
783
834
  }
784
835
  },
785
836
  "openrouter": {
@@ -1,133 +1,2 @@
1
- /**
2
- * Minimal MCP client for Streamable HTTP transport.
3
- *
4
- * Connects to the swarm's HTTP MCP endpoint, performs the handshake,
5
- * discovers tools, and forwards tool calls. This avoids depending on
6
- * a separate MCP client library for pi-mono.
7
- */
8
-
9
- interface McpTool {
10
- name: string;
11
- description?: string;
12
- inputSchema: Record<string, unknown>;
13
- }
14
-
15
- interface McpToolCallResult {
16
- content: Array<{ type: string; text?: string }>;
17
- isError?: boolean;
18
- }
19
-
20
- export class McpHttpClient {
21
- private sessionId: string | null = null;
22
- private nextId = 1;
23
- /** Additional headers merged into every request (e.g. for installed MCP servers) */
24
- public customHeaders: Record<string, string> = {};
25
- /**
26
- * When true, baseUrl is used as-is for requests (external MCP servers).
27
- * When false (default), /mcp is appended (swarm convention).
28
- */
29
- public useRawUrl = false;
30
-
31
- constructor(
32
- private baseUrl: string,
33
- private apiKey: string,
34
- private agentId: string,
35
- private taskId?: string,
36
- ) {}
37
-
38
- private async send(body: unknown): Promise<{ data: unknown; headers: Headers }> {
39
- const headers: Record<string, string> = {
40
- "Content-Type": "application/json",
41
- Accept: "application/json, text/event-stream",
42
- Authorization: `Bearer ${this.apiKey}`,
43
- "X-Agent-ID": this.agentId,
44
- ...this.customHeaders,
45
- };
46
- if (this.taskId) {
47
- headers["X-Source-Task-Id"] = this.taskId;
48
- }
49
- if (this.sessionId) {
50
- headers["mcp-session-id"] = this.sessionId;
51
- }
52
-
53
- const url = this.useRawUrl ? this.baseUrl : `${this.baseUrl}/mcp`;
54
- const res = await fetch(url, {
55
- method: "POST",
56
- headers,
57
- body: JSON.stringify(body),
58
- });
59
-
60
- if (!res.ok) {
61
- throw new Error(`MCP request failed: ${res.status} ${res.statusText}`);
62
- }
63
-
64
- // Capture session ID from response
65
- const sid = res.headers.get("mcp-session-id");
66
- if (sid) this.sessionId = sid;
67
-
68
- // Handle SSE responses (extract JSON from event stream)
69
- const contentType = res.headers.get("content-type") || "";
70
- if (contentType.includes("text/event-stream")) {
71
- const text = await res.text();
72
- const dataLines = text
73
- .split("\n")
74
- .filter((l) => l.startsWith("data: "))
75
- .map((l) => l.slice(6));
76
- const lastData = dataLines[dataLines.length - 1];
77
- return { data: lastData ? JSON.parse(lastData) : null, headers: res.headers };
78
- }
79
-
80
- const data = await res.json();
81
- return { data, headers: res.headers };
82
- }
83
-
84
- /** Perform MCP initialize + initialized handshake */
85
- async initialize(): Promise<void> {
86
- const { data } = await this.send({
87
- jsonrpc: "2.0",
88
- id: this.nextId++,
89
- method: "initialize",
90
- params: {
91
- protocolVersion: "2025-03-26",
92
- capabilities: {},
93
- clientInfo: { name: "agent-swarm-pi-mono", version: "1.0.0" },
94
- },
95
- });
96
-
97
- if (!data || typeof data !== "object" || !("result" in (data as Record<string, unknown>))) {
98
- throw new Error(`MCP initialize failed: ${JSON.stringify(data)}`);
99
- }
100
-
101
- // Send initialized notification (no response expected for notifications)
102
- await this.send({
103
- jsonrpc: "2.0",
104
- method: "notifications/initialized",
105
- });
106
- }
107
-
108
- /** Discover all available MCP tools */
109
- async listTools(): Promise<McpTool[]> {
110
- const { data } = await this.send({
111
- jsonrpc: "2.0",
112
- id: this.nextId++,
113
- method: "tools/list",
114
- params: {},
115
- });
116
-
117
- const result = data as { result?: { tools?: McpTool[] } };
118
- return result?.result?.tools ?? [];
119
- }
120
-
121
- /** Call an MCP tool */
122
- async callTool(name: string, args: Record<string, unknown>): Promise<McpToolCallResult> {
123
- const { data } = await this.send({
124
- jsonrpc: "2.0",
125
- id: this.nextId++,
126
- method: "tools/call",
127
- params: { name, arguments: args },
128
- });
129
-
130
- const result = data as { result?: McpToolCallResult };
131
- return result?.result ?? { content: [{ type: "text", text: "No result" }] };
132
- }
133
- }
1
+ export type { McpTool, McpToolCallResult } from "@/mcp-client/http-client";
2
+ export { McpHttpClient } from "@/mcp-client/http-client";
@@ -14,8 +14,8 @@
14
14
 
15
15
  import reasoningSnapshotJson from "./modelsdev-reasoning.json";
16
16
 
17
- /** Closed, normalized enum. `minimal` and `max` are intentionally out of scope for v1 (see plan). */
18
- export const REASONING_EFFORT_LEVELS = ["off", "low", "medium", "high", "xhigh"] as const;
17
+ /** Closed, normalized enum. `minimal` remains out of scope; GPT-5.6 Codex adds `max`. */
18
+ export const REASONING_EFFORT_LEVELS = ["off", "low", "medium", "high", "xhigh", "max"] as const;
19
19
  export type ReasoningEffort = (typeof REASONING_EFFORT_LEVELS)[number];
20
20
 
21
21
  /** The four local harnesses this feature covers (Devin / claude-managed are out of scope). */
@@ -74,13 +74,14 @@ const SNAPSHOT = reasoningSnapshotJson as ReasoningSnapshot;
74
74
  /** Shared-safe subset accepted by all four harnesses on at least their default models (see research doc). */
75
75
  const FALLBACK_LEVELS: ReasoningEffort[] = ["low", "medium", "high"];
76
76
 
77
- /** models.dev `reasoning_options[].type === "effort"` value → our normalized enum. `minimal`/`max` intentionally dropped. */
77
+ /** models.dev `reasoning_options[].type === "effort"` value → our normalized enum. `minimal` intentionally dropped. */
78
78
  const EFFORT_VALUE_MAP: Partial<Record<string, ReasoningEffort>> = {
79
79
  none: "off",
80
80
  low: "low",
81
81
  medium: "medium",
82
82
  high: "high",
83
83
  xhigh: "xhigh",
84
+ max: "max",
84
85
  };
85
86
 
86
87
  function splitProviderModel(model: string): { providerId: string; modelId: string } {
@@ -143,6 +144,10 @@ function applyHarnessOverrides(
143
144
  }
144
145
  }
145
146
 
147
+ if (harness !== "codex") {
148
+ result = result.filter((l) => l !== "max");
149
+ }
150
+
146
151
  if (harness === "codex") {
147
152
  // The cache already tends to encode this correctly per model (verified:
148
153
  // `gpt-5.1-codex` excludes xhigh, `gpt-5.1-codex-max` includes it). This
@@ -173,7 +178,7 @@ function pickDefault(levels: ReasoningEffort[]): ReasoningEffort | null {
173
178
  * models absent from the snapshot) → unsupported.
174
179
  * 2. `reasoning: false` → unsupported, regardless of the override table.
175
180
  * 3. `reasoning_options` has a usable `type: "effort"` entry → levels come
176
- * from its `values` (mapped/filtered — `none`→`off`, `minimal`/`max` dropped).
181
+ * from its `values` (mapped/filtered — `none`→`off`, `minimal` dropped).
177
182
  * 4. Otherwise (`reasoning: true`, no usable effort entry) → the shared-safe
178
183
  * fallback subset `{low, medium, high}`.
179
184
  * 5. Harness-specific override table applied on top for known quirks.
@@ -222,7 +227,7 @@ function applyPiEffort(level: ReasoningEffort): ReasoningEffortApplication {
222
227
  }
223
228
 
224
229
  /** Level → numeric thinking budget, only used for Opencode's Anthropic provider (see below). Internal transport detail, not a user-facing knob. */
225
- const ANTHROPIC_BUDGET_TOKENS_BY_LEVEL: Record<Exclude<ReasoningEffort, "off">, number> = {
230
+ const ANTHROPIC_BUDGET_TOKENS_BY_LEVEL: Record<Exclude<ReasoningEffort, "off" | "max">, number> = {
226
231
  low: 4096,
227
232
  medium: 10240,
228
233
  high: 32768,
@@ -238,6 +243,7 @@ function buildOpencodeReasoningOptions(
238
243
  // qualitative level — translate internally (see "What We're NOT Doing" in
239
244
  // the plan: no numeric budget surface for operators, only this
240
245
  // adapter-internal transport detail).
246
+ if (level === "max") return { reasoningEffort: level };
241
247
  return { thinking: { type: "enabled", budgetTokens: ANTHROPIC_BUDGET_TOKENS_BY_LEVEL[level] } };
242
248
  }
243
249
  if (providerId === "openrouter") {
@@ -0,0 +1,68 @@
1
+ import type { PermissionVerb } from "./permissions";
2
+
3
+ export type AdmissionGrant = {
4
+ grantsAll: boolean;
5
+ verbs: {
6
+ has(verb: PermissionVerb): boolean;
7
+ };
8
+ };
9
+
10
+ export type AdmissionRbac = { permission: PermissionVerb } | { ungated: string };
11
+
12
+ export type AdmissionDecision =
13
+ | { allow: true; verb?: PermissionVerb }
14
+ | { allow: false; reason: string; verb?: PermissionVerb };
15
+
16
+ export function isRbacEnabled(): boolean {
17
+ return process.env.RBAC_ENABLED === "true";
18
+ }
19
+
20
+ export function decideAdmission(input: {
21
+ method: string;
22
+ rbac: AdmissionRbac | undefined;
23
+ routeKnown: boolean;
24
+ grant: AdmissionGrant;
25
+ }): AdmissionDecision {
26
+ if (input.grant.grantsAll) {
27
+ return { allow: true };
28
+ }
29
+
30
+ if (input.rbac && "permission" in input.rbac) {
31
+ const verb = input.rbac.permission;
32
+ if (input.grant.verbs.has(verb)) {
33
+ return { allow: true, verb };
34
+ }
35
+ return { allow: false, reason: `admission: missing permission '${verb}'`, verb };
36
+ }
37
+
38
+ const method = input.method.toUpperCase();
39
+ if (method === "GET" || method === "HEAD") {
40
+ return { allow: true };
41
+ }
42
+
43
+ return { allow: false, reason: "admission: route has no permission verb (operator-only)" };
44
+ }
45
+
46
+ export function decideToolAdmission(input: {
47
+ rbac: AdmissionRbac | undefined;
48
+ readOnly: boolean;
49
+ grant: AdmissionGrant;
50
+ }): AdmissionDecision {
51
+ if (input.grant.grantsAll) {
52
+ return { allow: true };
53
+ }
54
+
55
+ if (input.rbac && "permission" in input.rbac) {
56
+ const verb = input.rbac.permission;
57
+ if (input.grant.verbs.has(verb)) {
58
+ return { allow: true, verb };
59
+ }
60
+ return { allow: false, reason: `admission: missing permission '${verb}'`, verb };
61
+ }
62
+
63
+ if (input.readOnly) {
64
+ return { allow: true };
65
+ }
66
+
67
+ return { allow: false, reason: "admission: tool has no permission verb (operator-only)" };
68
+ }
package/src/rbac/index.ts CHANGED
@@ -4,6 +4,8 @@
4
4
  * Import from here at call sites: `import { can } from "@/rbac"`.
5
5
  */
6
6
 
7
+ export type { AdmissionDecision, AdmissionGrant, AdmissionRbac } from "./admission";
8
+ export { decideAdmission, decideToolAdmission, isRbacEnabled } from "./admission";
7
9
  export type { AuditSink } from "./can";
8
10
  export { can, clearAuditSink, setAuditSink } from "./can";
9
11
  export type { LegacyRule } from "./legacy-policy";
@@ -147,10 +147,12 @@ export const LEGACY_POLICY = {
147
147
  "agent.profile.update.any": leadOnly,
148
148
  "agent.context.read.any": leadOnly,
149
149
  "task.cancel.any": leadOrTaskCreator,
150
+ "task.create.own": anyAuthenticated,
150
151
  "task.read.own": requesterOwnsTask,
151
152
  "task.cancel.own": requesterOwnsTask,
152
153
  "task.action.own": requesterOwnsTask,
153
154
  "task.fs.mutate": taskFsMutate,
155
+ "favorite.write.own": anyAuthenticated,
154
156
  "memory.learning.inject": leadOnly,
155
157
  "memory.delete.any": memoryOwnerOrLeadSwarm,
156
158
  "channel.delete": leadOnly,
@@ -163,6 +165,7 @@ export const LEGACY_POLICY = {
163
165
  "integration.slack.update": leadOnly,
164
166
  "credential-binding.manage": leadOnly,
165
167
  "script-connection.manage": leadOnly,
168
+ "script-connection.invoke": anyAuthenticated,
166
169
  "config.credential-bindings.write": leadOnly,
167
170
  "config.write.any": leadOnly,
168
171
  "config.delete.any": leadOnly,
@@ -179,7 +182,16 @@ export const LEGACY_POLICY = {
179
182
  "mcp-server.uninstall.any": leadOnly,
180
183
  "mcp-server.delete.any": leadOrResourceOwner,
181
184
  "mcp-server.update.any": leadOrResourceOwner,
185
+ "mcp-server.read.secrets": leadOnly,
186
+ "mcp-oauth.authorize.any": anyAuthenticated,
182
187
  "kv.write.any": leadOrOwnNamespace,
188
+ "page.delete.any": leadOrResourceOwner,
183
189
  "script.global.write": leadOnly,
184
190
  "script.global.delete": leadOnly,
191
+ "script.search": anyAuthenticated,
192
+ "script.api.read.secrets": leadOnly,
193
+ "script.api.create": leadOnly,
194
+ "script.api.update": leadOnly,
195
+ "script.api.rotate": leadOnly,
196
+ "script.api.delete": leadOnly,
185
197
  } as const satisfies Record<PermissionVerb, LegacyRule>;
@@ -33,6 +33,10 @@ export const PERMISSIONS = {
33
33
  description: "Cancel any task (beyond tasks the caller created).",
34
34
  namespace: "task",
35
35
  },
36
+ "task.create.own": {
37
+ description: "Create a task the caller owns.",
38
+ namespace: "task",
39
+ },
36
40
  "task.read.own": {
37
41
  description: "Read details of a task the principal requested.",
38
42
  namespace: "task",
@@ -49,6 +53,10 @@ export const PERMISSIONS = {
49
53
  description: "Mutate a task's filesystem artifacts and attachments.",
50
54
  namespace: "task",
51
55
  },
56
+ "favorite.write.own": {
57
+ description: "Set a favorite the caller owns.",
58
+ namespace: "favorite",
59
+ },
52
60
  "memory.learning.inject": {
53
61
  description: "Inject a learning into another agent's memory.",
54
62
  namespace: "memory",
@@ -97,6 +105,10 @@ export const PERMISSIONS = {
97
105
  description: "Manage script connections.",
98
106
  namespace: "script-connection",
99
107
  },
108
+ "script-connection.invoke": {
109
+ description: "Invoke a script MCP connection through the server-side proxy.",
110
+ namespace: "script-connection",
111
+ },
100
112
  "config.credential-bindings.write": {
101
113
  description: "Write the SCRIPT_CREDENTIAL_BINDINGS swarm-config key.",
102
114
  namespace: "config",
@@ -161,10 +173,22 @@ export const PERMISSIONS = {
161
173
  description: "Update an MCP server the caller does not own.",
162
174
  namespace: "mcp-server",
163
175
  },
176
+ "mcp-server.read.secrets": {
177
+ description: "Read resolved MCP server secret env/header values.",
178
+ namespace: "mcp-server",
179
+ },
180
+ "mcp-oauth.authorize.any": {
181
+ description: "Start an MCP-server OAuth authorize flow for a caller-supplied user scope.",
182
+ namespace: "mcp-oauth",
183
+ },
164
184
  "kv.write.any": {
165
185
  description: "Write another agent's task:agent: KV namespace.",
166
186
  namespace: "kv",
167
187
  },
188
+ "page.delete.any": {
189
+ description: "Delete a page the caller does not own.",
190
+ namespace: "page",
191
+ },
168
192
  "script.global.write": {
169
193
  description: "Create or update a global-scope script.",
170
194
  namespace: "script",
@@ -173,6 +197,30 @@ export const PERMISSIONS = {
173
197
  description: "Delete a global-scope script.",
174
198
  namespace: "script",
175
199
  },
200
+ "script.search": {
201
+ description: "Search reusable scripts visible to the caller.",
202
+ namespace: "script",
203
+ },
204
+ "script.api.read.secrets": {
205
+ description: "Reveal an external script API endpoint bearer token.",
206
+ namespace: "script",
207
+ },
208
+ "script.api.create": {
209
+ description: "Expose a script as an external HTTP API endpoint.",
210
+ namespace: "script",
211
+ },
212
+ "script.api.update": {
213
+ description: "Update an external script API endpoint.",
214
+ namespace: "script",
215
+ },
216
+ "script.api.rotate": {
217
+ description: "Rotate an external script API endpoint bearer token.",
218
+ namespace: "script",
219
+ },
220
+ "script.api.delete": {
221
+ description: "Delete an external script API endpoint.",
222
+ namespace: "script",
223
+ },
176
224
  } as const satisfies Record<string, { description: string; namespace: string }>;
177
225
 
178
226
  export type PermissionVerb = keyof typeof PERMISSIONS;
@@ -7,6 +7,10 @@ import {
7
7
  getWorkflow,
8
8
  updateScheduledTask,
9
9
  } from "@/be/db";
10
+ import {
11
+ getScriptApiConnectionDescriptors,
12
+ getScriptMcpConnectionDescriptors,
13
+ } from "@/be/script-connections";
10
14
  import { buildScriptCredentialBindings } from "@/be/script-credential-broker";
11
15
  import { getScript } from "@/be/scripts/db";
12
16
  import { runScript } from "@/scripts-runtime/loader";
@@ -56,6 +60,7 @@ export function createStandaloneScheduleTask(
56
60
  modelTier: schedule.modelTier,
57
61
  scheduleId: schedule.id,
58
62
  source: "schedule",
63
+ requestedByUserId: schedule.createdBy,
59
64
  contextKey: scheduleContextKey({ scheduleId: schedule.id }),
60
65
  });
61
66
  }
@@ -81,7 +86,9 @@ async function executeScheduleScript(schedule: ScheduledTask): Promise<void> {
81
86
  args: schedule.scriptArgs ?? {},
82
87
  fsMode: "none",
83
88
  agentId,
84
- egressSecrets: buildScriptCredentialBindings({ agentId }),
89
+ egressSecrets: await buildScriptCredentialBindings({ agentId }),
90
+ apiConnections: getScriptApiConnectionDescriptors({ agentId }),
91
+ mcpConnections: getScriptMcpConnectionDescriptors({ agentId }),
85
92
  timeoutMs: 60_000,
86
93
  });
87
94
 
@@ -136,6 +143,7 @@ export async function dispatchScheduleTarget(
136
143
  };
137
144
  const runId = await startWorkflowExecution(workflow, triggerData, registry, {
138
145
  triggerType: "schedule",
146
+ requestedByUserId: schedule.createdBy,
139
147
  });
140
148
  console.log(
141
149
  `[Scheduler] Schedule "${schedule.name}" → triggered workflow "${workflow.name}"`,