create-workframe 0.1.11 → 0.1.13

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 (195) hide show
  1. package/README.md +1 -1
  2. package/bin/create-workframe.js +2 -2
  3. package/bin/workframe.js +130 -2
  4. package/docs/security.md +85 -0
  5. package/package.json +1 -1
  6. package/scripts/bundle-workframe-ui.mjs +9 -0
  7. package/scripts/sync-canonical-to-package.mjs +9 -0
  8. package/scripts/verify-public-deploy.sh +121 -3
  9. package/workframe-api/action_proxy.py +23 -17
  10. package/workframe-api/activity_feed.py +798 -0
  11. package/workframe-api/api_meta.py +157 -0
  12. package/workframe-api/auth_gate.py +566 -0
  13. package/workframe-api/avatar_registry.py +343 -0
  14. package/workframe-api/broker_audit.py +164 -0
  15. package/workframe-api/cell_authority.py +231 -0
  16. package/workframe-api/chat_bind.py +319 -0
  17. package/workframe-api/chat_sessions.py +509 -0
  18. package/workframe-api/chat_stream.py +694 -0
  19. package/workframe-api/cleanup_dogfood_smoke.py +252 -0
  20. package/workframe-api/credential_broker.py +162 -0
  21. package/workframe-api/credential_resolve.py +202 -0
  22. package/workframe-api/credential_store.py +245 -0
  23. package/workframe-api/crew_registry.py +250 -0
  24. package/workframe-api/db_schema.py +755 -0
  25. package/workframe-api/docker_gateway.py +166 -0
  26. package/workframe-api/doctor_runtime.py +109 -0
  27. package/workframe-api/domain/__init__.py +47 -0
  28. package/workframe-api/domain/entities.py +252 -0
  29. package/workframe-api/domain/schema/workframe-domain.schema.json +278 -0
  30. package/workframe-api/egress_policy.py +42 -0
  31. package/workframe-api/handler_modules/__init__.py +17 -0
  32. package/workframe-api/handler_modules/handler_admin.py +542 -0
  33. package/workframe-api/handler_modules/handler_auth.py +512 -0
  34. package/workframe-api/handler_modules/handler_chat.py +641 -0
  35. package/workframe-api/handler_modules/handler_install.py +178 -0
  36. package/workframe-api/handler_modules/handler_provider.py +325 -0
  37. package/workframe-api/handler_modules/handler_workspace.py +1420 -0
  38. package/workframe-api/health_monitor.py +80 -0
  39. package/workframe-api/hermes_admin.py +756 -0
  40. package/workframe-api/hermes_profiles.py +1328 -0
  41. package/workframe-api/install_api.py +123 -0
  42. package/workframe-api/kanban_cron.py +473 -0
  43. package/workframe-api/lane_bindings.py +423 -0
  44. package/workframe-api/llm_proxy.py +17 -43
  45. package/workframe-api/mention_helpers.py +180 -0
  46. package/workframe-api/mention_invoke.py +431 -0
  47. package/workframe-api/model_surface.py +1139 -0
  48. package/workframe-api/oauth_pending.py +85 -0
  49. package/workframe-api/oauth_redirect.py +381 -0
  50. package/workframe-api/openrouter_catalog.py +4 -4
  51. package/workframe-api/package.json +2 -2
  52. package/workframe-api/profile_api_lifecycle.py +66 -0
  53. package/workframe-api/profile_config_yaml.py +126 -0
  54. package/workframe-api/profile_gateway.py +436 -0
  55. package/workframe-api/provider_bindings.py +673 -0
  56. package/workframe-api/provider_bootstrap.py +347 -0
  57. package/workframe-api/provider_catalog.py +180 -0
  58. package/workframe-api/rooms.py +1613 -0
  59. package/workframe-api/route_registry.py +470 -0
  60. package/workframe-api/run-typecheck.mjs +26 -0
  61. package/workframe-api/run_authority.py +287 -0
  62. package/workframe-api/run_ledger.py +470 -0
  63. package/workframe-api/run_surface_wiring.py +344 -0
  64. package/workframe-api/runtime_cohort.py +752 -0
  65. package/workframe-api/runtime_tokens.py +127 -0
  66. package/workframe-api/server.py +1376 -19305
  67. package/workframe-api/snapshot_feed.py +49 -0
  68. package/workframe-api/stack_config.py +33 -1
  69. package/workframe-api/supervisor_client.py +154 -0
  70. package/workframe-api/test_api_meta_build_stamp.py +34 -0
  71. package/workframe-api/test_cell_authority.py +79 -0
  72. package/workframe-api/test_chat_bind.py +48 -0
  73. package/workframe-api/test_credential_lease_matrix.py +171 -0
  74. package/workframe-api/test_credential_resolve.py +51 -0
  75. package/workframe-api/test_credential_store.py +27 -0
  76. package/workframe-api/test_dogfood_flows.py +346 -0
  77. package/workframe-api/test_domain_entities.py +152 -0
  78. package/workframe-api/test_exception_hygiene.py +12 -0
  79. package/workframe-api/test_hermes_admin.py +72 -0
  80. package/workframe-api/test_install_wizard_resume.py +78 -0
  81. package/workframe-api/test_local_bootstrap.py +67 -0
  82. package/workframe-api/test_mention_helpers.py +35 -0
  83. package/workframe-api/test_mention_invoke.py +26 -0
  84. package/workframe-api/test_model_surface_consistency.py +117 -0
  85. package/workframe-api/test_oauth_pending.py +41 -0
  86. package/workframe-api/test_profile_model_yaml.py +99 -0
  87. package/workframe-api/test_provider_bindings.py +52 -0
  88. package/workframe-api/test_provider_catalog.py +28 -0
  89. package/workframe-api/test_public_routes.py +41 -0
  90. package/workframe-api/test_route_registry.py +245 -0
  91. package/workframe-api/test_run_authority.py +112 -0
  92. package/workframe-api/test_run_ledger.py +157 -0
  93. package/workframe-api/test_run_surface_wiring.py +130 -0
  94. package/workframe-api/test_runtime_cohort.py +85 -0
  95. package/workframe-api/test_secure_mode_docker_boundary.py +39 -0
  96. package/workframe-api/test_server_reexports.py +99 -0
  97. package/workframe-api/test_stack_config_install_smtp.py +7 -0
  98. package/workframe-api/time-bind-steps.py +75 -0
  99. package/workframe-api/time-perf.py +81 -0
  100. package/workframe-api/time-warm.py +107 -0
  101. package/workframe-api/turn_credentials.py +28 -13
  102. package/workframe-api/turn_overlay.py +715 -0
  103. package/workframe-api/updates.py +16 -1
  104. package/workframe-api/user_prefs.py +387 -0
  105. package/workframe-api/wf032_extract_remaining_handlers.py +417 -0
  106. package/workframe-api/workspace_bootstrap.py +536 -0
  107. package/workframe-api/workspace_files.py +344 -0
  108. package/workframe-api/workspace_messaging.py +206 -0
  109. package/workframe-api/zk_auth.py +3 -2
  110. package/workframe-supervisor/server.py +10 -1
  111. package/workframe-supervisor/test_supervisor_negative.py +75 -0
  112. package/workframe-ui/public/assets/{arc-DjpS9a2b.js → arc-aUUffclm.js} +1 -1
  113. package/workframe-ui/public/assets/architecture-7EHR7CIX-BSUP4S8J.js +1 -0
  114. package/workframe-ui/public/assets/{architectureDiagram-3BPJPVTR-puCKmKHV.js → architectureDiagram-3BPJPVTR-DU6oaqIb.js} +1 -1
  115. package/workframe-ui/public/assets/{blockDiagram-GPEHLZMM-C2P0g-eH.js → blockDiagram-GPEHLZMM-D2p8BU6-.js} +1 -1
  116. package/workframe-ui/public/assets/{c4Diagram-AAUBKEIU-DdvYEITH.js → c4Diagram-AAUBKEIU-ouwyPmTJ.js} +1 -1
  117. package/workframe-ui/public/assets/channel-DOunZZ0X.js +1 -0
  118. package/workframe-ui/public/assets/{chunk-2J33WTMH-Cxe8QsEF.js → chunk-2J33WTMH-DsE7U5dj.js} +1 -1
  119. package/workframe-ui/public/assets/{chunk-3OPIFGDE-DPNyTwR3.js → chunk-3OPIFGDE-DM0kkZ9h.js} +1 -1
  120. package/workframe-ui/public/assets/{chunk-4BX2VUAB-XKG9gfRN.js → chunk-4BX2VUAB-CQ8mAyXp.js} +1 -1
  121. package/workframe-ui/public/assets/{chunk-55IACEB6-oPMTulgb.js → chunk-55IACEB6-DN1BDtbH.js} +1 -1
  122. package/workframe-ui/public/assets/{chunk-5ZQYHXKU-BWwXvpa_.js → chunk-5ZQYHXKU-BzK2KqOt.js} +1 -1
  123. package/workframe-ui/public/assets/{chunk-727SXJPM-Cml2twO_.js → chunk-727SXJPM-C3AxtOi9.js} +1 -1
  124. package/workframe-ui/public/assets/{chunk-AQP2D5EJ-DzrRBhQu.js → chunk-AQP2D5EJ-4mVwEFuD.js} +1 -1
  125. package/workframe-ui/public/assets/{chunk-BSJP7CBP-EZ7STU6h.js → chunk-BSJP7CBP-23kN2q0A.js} +1 -1
  126. package/workframe-ui/public/assets/{chunk-CSCIHK7Q-BGTQzWYw.js → chunk-CSCIHK7Q-CPBKVW-L.js} +2 -2
  127. package/workframe-ui/public/assets/{chunk-FMBD7UC4-Cm4stfRa.js → chunk-FMBD7UC4-CKqcYq7K.js} +1 -1
  128. package/workframe-ui/public/assets/{chunk-KSCS5N6A-exbMijjy.js → chunk-KSCS5N6A-JRQnhxQE.js} +1 -1
  129. package/workframe-ui/public/assets/{chunk-L5ZTLDWV-C75kbQwN.js → chunk-L5ZTLDWV-BLZrdIwa.js} +1 -1
  130. package/workframe-ui/public/assets/chunk-LZXEDZCA-DisG0XJT.js +2 -0
  131. package/workframe-ui/public/assets/{chunk-ND2GUHAM-D84zyIu2.js → chunk-ND2GUHAM-ClAOxArS.js} +1 -1
  132. package/workframe-ui/public/assets/{chunk-NZK2D7GU-CUNNo1bj.js → chunk-NZK2D7GU-XUE1aNkm.js} +1 -1
  133. package/workframe-ui/public/assets/{chunk-O5CBEL6O-DN6WEIh-.js → chunk-O5CBEL6O-DDN-Ifon.js} +1 -1
  134. package/workframe-ui/public/assets/chunk-QZHKN3VN-EVQ0VMd5.js +1 -0
  135. package/workframe-ui/public/assets/chunk-WU5MYG2G-k_-ZsLOS.js +1 -0
  136. package/workframe-ui/public/assets/{chunk-XPW4576I-Ct5VQv2D.js → chunk-XPW4576I-B4_iYZ6r.js} +1 -1
  137. package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-W9WVQsby.js +1 -0
  138. package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-W9WVQsby.js +1 -0
  139. package/workframe-ui/public/assets/{cose-bilkent-S5V4N54A-Bj4W5oMk.js → cose-bilkent-S5V4N54A-Cy1HhS7j.js} +1 -1
  140. package/workframe-ui/public/assets/{dagre-BM42HDAG-DAjHBkAy.js → dagre-BM42HDAG-Bjal81Ie.js} +1 -1
  141. package/workframe-ui/public/assets/{diagram-2AECGRRQ-Ch2gGFPG.js → diagram-2AECGRRQ-v5Gdvzp_.js} +1 -1
  142. package/workframe-ui/public/assets/{diagram-5GNKFQAL-BzIIvgYH.js → diagram-5GNKFQAL-DuyRdfmY.js} +1 -1
  143. package/workframe-ui/public/assets/{diagram-KO2AKTUF-Df0Q8nv6.js → diagram-KO2AKTUF-WwWCGbIW.js} +1 -1
  144. package/workframe-ui/public/assets/{diagram-LMA3HP47-D-G3ekmF.js → diagram-LMA3HP47-DTYwZALT.js} +1 -1
  145. package/workframe-ui/public/assets/{diagram-OG6HWLK6-TBHhT9f5.js → diagram-OG6HWLK6-B46kBIqE.js} +1 -1
  146. package/workframe-ui/public/assets/{dist-CPbiDkEZ.js → dist-mQWmB3z6.js} +1 -1
  147. package/workframe-ui/public/assets/{erDiagram-TEJ5UH35-YxkUmLLV.js → erDiagram-TEJ5UH35-__40xO-y.js} +1 -1
  148. package/workframe-ui/public/assets/eventmodeling-FCH6USID-Cm1uRTxU.js +1 -0
  149. package/workframe-ui/public/assets/{flowDiagram-I6XJVG4X-kfZ7-RSd.js → flowDiagram-I6XJVG4X-Cwj6dVUz.js} +1 -1
  150. package/workframe-ui/public/assets/{ganttDiagram-6RSMTGT7-DmTx3hzR.js → ganttDiagram-6RSMTGT7-D_IOSwAS.js} +1 -1
  151. package/workframe-ui/public/assets/{gitGraph-WXDBUCRP-BXa0ewp3.js → gitGraph-WXDBUCRP-C1vGecee.js} +1 -1
  152. package/workframe-ui/public/assets/{gitGraphDiagram-PVQCEYII-CQr2qMxU.js → gitGraphDiagram-PVQCEYII-DMTxFJxn.js} +1 -1
  153. package/workframe-ui/public/assets/index-BdiM4-lI.js +130 -0
  154. package/workframe-ui/public/assets/index-Fnad47vV.css +1 -0
  155. package/workframe-ui/public/assets/{info-J43DQDTF-t-Qlx8zv.js → info-J43DQDTF-CwjmyPmD.js} +1 -1
  156. package/workframe-ui/public/assets/{infoDiagram-5YYISTIA-CzkYofPx.js → infoDiagram-5YYISTIA-BGzh7ZL2.js} +1 -1
  157. package/workframe-ui/public/assets/{ishikawaDiagram-YF4QCWOH-djK3Oxgb.js → ishikawaDiagram-YF4QCWOH-BLXdnR_5.js} +1 -1
  158. package/workframe-ui/public/assets/{journeyDiagram-JHISSGLW-CWxYXxdF.js → journeyDiagram-JHISSGLW-BK3behMe.js} +1 -1
  159. package/workframe-ui/public/assets/{kanban-definition-UN3LZRKU-D7leCAD9.js → kanban-definition-UN3LZRKU-Bx172cCl.js} +1 -1
  160. package/workframe-ui/public/assets/{line-BSFj2OC5.js → line-BTCEHb7l.js} +1 -1
  161. package/workframe-ui/public/assets/{linear-pfPwnu-o.js → linear-CkbydpnK.js} +1 -1
  162. package/workframe-ui/public/assets/{mermaid-parser.core-Dm2L9Ib_.js → mermaid-parser.core-DvrtArpk.js} +2 -2
  163. package/workframe-ui/public/assets/{mermaid.core-Bevx9bif.js → mermaid.core-yj_1x_qj.js} +3 -3
  164. package/workframe-ui/public/assets/{mindmap-definition-RKZ34NQL-UkjDssmP.js → mindmap-definition-RKZ34NQL-BXbMltQ0.js} +1 -1
  165. package/workframe-ui/public/assets/{packet-YPE3B663-JO2ezH3_.js → packet-YPE3B663-9pVCBQ7S.js} +1 -1
  166. package/workframe-ui/public/assets/{pie-LRSECV5Y-DdMFsfR8.js → pie-LRSECV5Y-CdqoWesP.js} +1 -1
  167. package/workframe-ui/public/assets/{pieDiagram-4H26LBE5-CEPHFBU1.js → pieDiagram-4H26LBE5-kGs-VfXd.js} +1 -1
  168. package/workframe-ui/public/assets/{quadrantDiagram-W4KKPZXB-_RF9_86k.js → quadrantDiagram-W4KKPZXB-D9D8gQw5.js} +1 -1
  169. package/workframe-ui/public/assets/{radar-GUYGQ44K-Cb-YfdaA.js → radar-GUYGQ44K-d4zMZpQS.js} +1 -1
  170. package/workframe-ui/public/assets/{requirementDiagram-4Y6WPE33-DBVOxmBn.js → requirementDiagram-4Y6WPE33-BI7EQ9zc.js} +1 -1
  171. package/workframe-ui/public/assets/{sankeyDiagram-5OEKKPKP-BTpxsGUA.js → sankeyDiagram-5OEKKPKP-Bcz19jQB.js} +1 -1
  172. package/workframe-ui/public/assets/{sequenceDiagram-3UESZ5HK-DHP_Bq3l.js → sequenceDiagram-3UESZ5HK-iQiCEfYp.js} +1 -1
  173. package/workframe-ui/public/assets/{src-CY_By-r7.js → src-D6mvlP96.js} +1 -1
  174. package/workframe-ui/public/assets/{stateDiagram-AJRCARHV-BVtp_LPR.js → stateDiagram-AJRCARHV-CxaTXs02.js} +1 -1
  175. package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-CXikj9xi.js +1 -0
  176. package/workframe-ui/public/assets/{timeline-definition-PNZ67QCA-D38HJhop.js → timeline-definition-PNZ67QCA-Bej-EAnf.js} +1 -1
  177. package/workframe-ui/public/assets/{treeView-BLDUP644-CFCG3Sc_.js → treeView-BLDUP644-C7PnnzwX.js} +1 -1
  178. package/workframe-ui/public/assets/{treemap-LRROVOQU-BeiMs_dF.js → treemap-LRROVOQU-CqISLmkO.js} +1 -1
  179. package/workframe-ui/public/assets/{vennDiagram-CIIHVFJN-CKMeT6PW.js → vennDiagram-CIIHVFJN-eJMTTEW-.js} +1 -1
  180. package/workframe-ui/public/assets/{wardley-L42UT6IY-BljDy8ph.js → wardley-L42UT6IY-D4sMroBF.js} +1 -1
  181. package/workframe-ui/public/assets/{wardleyDiagram-YWT4CUSO-DEE8D94J.js → wardleyDiagram-YWT4CUSO-DC3DCUs7.js} +1 -1
  182. package/workframe-ui/public/assets/{xychartDiagram-2RQKCTM6-BRaAWV_g.js → xychartDiagram-2RQKCTM6-BeMaM6Aq.js} +1 -1
  183. package/workframe-ui/public/index.html +7 -6
  184. package/workframe-ui/public/workframe-build.json +5 -0
  185. package/workframe-ui/public/assets/architecture-7EHR7CIX-CvhbXEvt.js +0 -1
  186. package/workframe-ui/public/assets/channel-D63s_yN9.js +0 -1
  187. package/workframe-ui/public/assets/chunk-LZXEDZCA-CsRdBqUB.js +0 -2
  188. package/workframe-ui/public/assets/chunk-QZHKN3VN-Dj_Yxhgo.js +0 -1
  189. package/workframe-ui/public/assets/chunk-WU5MYG2G-AFchshb6.js +0 -1
  190. package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-Opj8t01I.js +0 -1
  191. package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-Opj8t01I.js +0 -1
  192. package/workframe-ui/public/assets/eventmodeling-FCH6USID-LQOYL50n.js +0 -1
  193. package/workframe-ui/public/assets/index-B08aShJy.css +0 -1
  194. package/workframe-ui/public/assets/index-DCF3W3G_.js +0 -129
  195. package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-CvJhS_BJ.js +0 -1
@@ -0,0 +1,287 @@
1
+ """RunAuthorityGate — single pre-run authority decision (WF-009)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from dataclasses import dataclass, field
7
+ from typing import Any, Mapping
8
+
9
+ from domain.entities import (
10
+ ActorType,
11
+ FundingSource,
12
+ Grant,
13
+ GrantCapability,
14
+ RunSurface,
15
+ )
16
+
17
+ DENY_NO_ACTOR = "no_actor"
18
+ DENY_NO_CREDENTIAL_BYOK = "no_credential_byok"
19
+ DENY_NO_CREDENTIAL_COMPANY = "no_credential_company"
20
+ DENY_PROVIDER_USER_ONLY = "provider_user_only_no_fallback"
21
+ DENY_DELEGATION = "delegation_no_grantor_credential"
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class RunAuthorityRequest:
26
+ surface: RunSurface
27
+ actor_type: ActorType
28
+ actor_id: str
29
+ triggering_user_id: str
30
+ profile_slug: str
31
+ workspace_id: str
32
+ provider: str
33
+ room_id: str | None = None
34
+ agent_id: str = ""
35
+ runtime_binding_id: str = ""
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class RunAuthorityContext:
40
+ workspace_credential_mode: str = "byok"
41
+ provider_user_only: bool = False
42
+ user_has_credential: bool = False
43
+ workspace_has_credential: bool = False
44
+ grantor_has_credential: Mapping[str, bool] = field(default_factory=dict)
45
+ oauth_connected: bool = False
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class RunAuthorityDecision:
50
+ allowed: bool
51
+ deny_reason: str | None
52
+ payer_user_id: str
53
+ funding_source: FundingSource
54
+ credential_ref_id: str | None
55
+ credential_scope: str | None
56
+ grants: tuple[Grant, ...]
57
+
58
+ def to_dict(self) -> dict[str, Any]:
59
+ return {
60
+ "allowed": self.allowed,
61
+ "deny_reason": self.deny_reason,
62
+ "payer_user_id": self.payer_user_id,
63
+ "funding_source": self.funding_source.value,
64
+ "credential_ref_id": self.credential_ref_id,
65
+ "credential_scope": self.credential_scope,
66
+ "grants": [g.to_dict() for g in self.grants],
67
+ }
68
+
69
+
70
+ def _credential_available(ctx: RunAuthorityContext) -> bool:
71
+ return bool(ctx.user_has_credential or ctx.oauth_connected)
72
+
73
+
74
+ def _grant_llm_turn(run_id: str) -> Grant:
75
+ return Grant(
76
+ grant_id=str(uuid.uuid4()),
77
+ run_id=run_id,
78
+ capability=GrantCapability.LLM_TURN,
79
+ scope={"provider": "pending"},
80
+ granted_by="run_authority_gate",
81
+ )
82
+
83
+
84
+ def evaluate_run_authority(
85
+ request: RunAuthorityRequest,
86
+ ctx: RunAuthorityContext,
87
+ *,
88
+ run_id: str | None = None,
89
+ ) -> RunAuthorityDecision:
90
+ """Pure gate — no I/O. Caller supplies credential probes."""
91
+ rid = str(run_id or uuid.uuid4())
92
+ actor = str(request.triggering_user_id or "").strip()
93
+ if not actor:
94
+ return RunAuthorityDecision(
95
+ allowed=False,
96
+ deny_reason=DENY_NO_ACTOR,
97
+ payer_user_id="",
98
+ funding_source=FundingSource.BYOK,
99
+ credential_ref_id=None,
100
+ credential_scope=None,
101
+ grants=(),
102
+ )
103
+
104
+ mode = str(ctx.workspace_credential_mode or "byok").strip().lower()
105
+ provider = str(request.provider or "openrouter").strip().lower()
106
+
107
+ if ctx.provider_user_only:
108
+ if _credential_available(ctx):
109
+ return RunAuthorityDecision(
110
+ allowed=True,
111
+ deny_reason=None,
112
+ payer_user_id=actor,
113
+ funding_source=FundingSource.BYOK,
114
+ credential_ref_id=None,
115
+ credential_scope="user",
116
+ grants=(_grant_llm_turn(rid),),
117
+ )
118
+ return RunAuthorityDecision(
119
+ allowed=False,
120
+ deny_reason=DENY_PROVIDER_USER_ONLY,
121
+ payer_user_id=actor,
122
+ funding_source=FundingSource.BYOK,
123
+ credential_ref_id=None,
124
+ credential_scope=None,
125
+ grants=(),
126
+ )
127
+
128
+ if _credential_available(ctx):
129
+ return RunAuthorityDecision(
130
+ allowed=True,
131
+ deny_reason=None,
132
+ payer_user_id=actor,
133
+ funding_source=FundingSource.BYOK,
134
+ credential_ref_id=None,
135
+ credential_scope="user",
136
+ grants=(_grant_llm_turn(rid),),
137
+ )
138
+
139
+ if mode == "workspace" and ctx.workspace_has_credential:
140
+ return RunAuthorityDecision(
141
+ allowed=True,
142
+ deny_reason=None,
143
+ payer_user_id=actor,
144
+ funding_source=FundingSource.COMPANY,
145
+ credential_ref_id=None,
146
+ credential_scope="workspace",
147
+ grants=(_grant_llm_turn(rid),),
148
+ )
149
+
150
+ for grantor_id, has_cred in ctx.grantor_has_credential.items():
151
+ gid = str(grantor_id or "").strip()
152
+ if gid and has_cred:
153
+ return RunAuthorityDecision(
154
+ allowed=True,
155
+ deny_reason=None,
156
+ payer_user_id=gid,
157
+ funding_source=FundingSource.BYOK,
158
+ credential_ref_id=None,
159
+ credential_scope="user",
160
+ grants=(_grant_llm_turn(rid),),
161
+ )
162
+
163
+ if mode == "workspace":
164
+ deny = DENY_NO_CREDENTIAL_COMPANY
165
+ else:
166
+ deny = DENY_NO_CREDENTIAL_BYOK
167
+ return RunAuthorityDecision(
168
+ allowed=False,
169
+ deny_reason=deny,
170
+ payer_user_id=actor,
171
+ funding_source=FundingSource.BYOK,
172
+ credential_ref_id=None,
173
+ credential_scope=None,
174
+ grants=(),
175
+ )
176
+
177
+
178
+ def chat_run_request(
179
+ *,
180
+ triggering_user_id: str,
181
+ profile_slug: str,
182
+ workspace_id: str,
183
+ provider: str,
184
+ room_id: str | None = None,
185
+ ) -> RunAuthorityRequest:
186
+ return RunAuthorityRequest(
187
+ surface=RunSurface.CHAT,
188
+ actor_type=ActorType.USER,
189
+ actor_id=triggering_user_id,
190
+ triggering_user_id=triggering_user_id,
191
+ profile_slug=profile_slug,
192
+ workspace_id=workspace_id,
193
+ provider=provider,
194
+ room_id=room_id,
195
+ agent_id=profile_slug,
196
+ runtime_binding_id=profile_slug,
197
+ )
198
+
199
+
200
+ def mention_run_request(
201
+ *,
202
+ triggering_user_id: str,
203
+ profile_slug: str,
204
+ workspace_id: str,
205
+ provider: str,
206
+ room_id: str | None = None,
207
+ ) -> RunAuthorityRequest:
208
+ return RunAuthorityRequest(
209
+ surface=RunSurface.MENTION,
210
+ actor_type=ActorType.USER,
211
+ actor_id=triggering_user_id,
212
+ triggering_user_id=triggering_user_id,
213
+ profile_slug=profile_slug,
214
+ workspace_id=workspace_id,
215
+ provider=provider,
216
+ room_id=room_id,
217
+ agent_id=profile_slug,
218
+ runtime_binding_id=profile_slug,
219
+ )
220
+
221
+
222
+ def slash_run_request(
223
+ *,
224
+ triggering_user_id: str,
225
+ profile_slug: str,
226
+ workspace_id: str,
227
+ provider: str,
228
+ room_id: str | None = None,
229
+ ) -> RunAuthorityRequest:
230
+ return RunAuthorityRequest(
231
+ surface=RunSurface.SLASH,
232
+ actor_type=ActorType.USER,
233
+ actor_id=triggering_user_id,
234
+ triggering_user_id=triggering_user_id,
235
+ profile_slug=profile_slug,
236
+ workspace_id=workspace_id,
237
+ provider=provider,
238
+ room_id=room_id,
239
+ agent_id=profile_slug,
240
+ runtime_binding_id=profile_slug,
241
+ )
242
+
243
+
244
+ def cron_run_request(
245
+ *,
246
+ triggering_user_id: str,
247
+ profile_slug: str,
248
+ workspace_id: str,
249
+ provider: str,
250
+ actor_id: str = "cron",
251
+ room_id: str | None = None,
252
+ ) -> RunAuthorityRequest:
253
+ return RunAuthorityRequest(
254
+ surface=RunSurface.CRON,
255
+ actor_type=ActorType.SYSTEM,
256
+ actor_id=actor_id,
257
+ triggering_user_id=triggering_user_id,
258
+ profile_slug=profile_slug,
259
+ workspace_id=workspace_id,
260
+ provider=provider,
261
+ room_id=room_id,
262
+ agent_id=profile_slug,
263
+ runtime_binding_id=profile_slug,
264
+ )
265
+
266
+
267
+ def webhook_run_request(
268
+ *,
269
+ triggering_user_id: str,
270
+ profile_slug: str,
271
+ workspace_id: str,
272
+ provider: str,
273
+ actor_id: str,
274
+ room_id: str | None = None,
275
+ ) -> RunAuthorityRequest:
276
+ return RunAuthorityRequest(
277
+ surface=RunSurface.WEBHOOK,
278
+ actor_type=ActorType.WEBHOOK,
279
+ actor_id=actor_id,
280
+ triggering_user_id=triggering_user_id,
281
+ profile_slug=profile_slug,
282
+ workspace_id=workspace_id,
283
+ provider=provider,
284
+ room_id=room_id,
285
+ agent_id=profile_slug,
286
+ runtime_binding_id=profile_slug,
287
+ )