gobby 0.2.5__py3-none-any.whl → 0.2.7__py3-none-any.whl

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 (244) hide show
  1. gobby/__init__.py +1 -1
  2. gobby/adapters/__init__.py +2 -1
  3. gobby/adapters/claude_code.py +13 -4
  4. gobby/adapters/codex_impl/__init__.py +28 -0
  5. gobby/adapters/codex_impl/adapter.py +722 -0
  6. gobby/adapters/codex_impl/client.py +679 -0
  7. gobby/adapters/codex_impl/protocol.py +20 -0
  8. gobby/adapters/codex_impl/types.py +68 -0
  9. gobby/agents/definitions.py +11 -1
  10. gobby/agents/isolation.py +395 -0
  11. gobby/agents/runner.py +8 -0
  12. gobby/agents/sandbox.py +261 -0
  13. gobby/agents/spawn.py +42 -287
  14. gobby/agents/spawn_executor.py +385 -0
  15. gobby/agents/spawners/__init__.py +24 -0
  16. gobby/agents/spawners/command_builder.py +189 -0
  17. gobby/agents/spawners/embedded.py +21 -2
  18. gobby/agents/spawners/headless.py +21 -2
  19. gobby/agents/spawners/prompt_manager.py +125 -0
  20. gobby/cli/__init__.py +6 -0
  21. gobby/cli/clones.py +419 -0
  22. gobby/cli/conductor.py +266 -0
  23. gobby/cli/install.py +4 -4
  24. gobby/cli/installers/antigravity.py +3 -9
  25. gobby/cli/installers/claude.py +15 -9
  26. gobby/cli/installers/codex.py +2 -8
  27. gobby/cli/installers/gemini.py +8 -8
  28. gobby/cli/installers/shared.py +175 -13
  29. gobby/cli/sessions.py +1 -1
  30. gobby/cli/skills.py +858 -0
  31. gobby/cli/tasks/ai.py +0 -440
  32. gobby/cli/tasks/crud.py +44 -6
  33. gobby/cli/tasks/main.py +0 -4
  34. gobby/cli/tui.py +2 -2
  35. gobby/cli/utils.py +12 -5
  36. gobby/clones/__init__.py +13 -0
  37. gobby/clones/git.py +547 -0
  38. gobby/conductor/__init__.py +16 -0
  39. gobby/conductor/alerts.py +135 -0
  40. gobby/conductor/loop.py +164 -0
  41. gobby/conductor/monitors/__init__.py +11 -0
  42. gobby/conductor/monitors/agents.py +116 -0
  43. gobby/conductor/monitors/tasks.py +155 -0
  44. gobby/conductor/pricing.py +234 -0
  45. gobby/conductor/token_tracker.py +160 -0
  46. gobby/config/__init__.py +12 -97
  47. gobby/config/app.py +69 -91
  48. gobby/config/extensions.py +2 -2
  49. gobby/config/features.py +7 -130
  50. gobby/config/search.py +110 -0
  51. gobby/config/servers.py +1 -1
  52. gobby/config/skills.py +43 -0
  53. gobby/config/tasks.py +9 -41
  54. gobby/hooks/__init__.py +0 -13
  55. gobby/hooks/event_handlers.py +188 -2
  56. gobby/hooks/hook_manager.py +50 -4
  57. gobby/hooks/plugins.py +1 -1
  58. gobby/hooks/skill_manager.py +130 -0
  59. gobby/hooks/webhooks.py +1 -1
  60. gobby/install/claude/hooks/hook_dispatcher.py +4 -4
  61. gobby/install/codex/hooks/hook_dispatcher.py +1 -1
  62. gobby/install/gemini/hooks/hook_dispatcher.py +87 -12
  63. gobby/llm/claude.py +22 -34
  64. gobby/llm/claude_executor.py +46 -256
  65. gobby/llm/codex_executor.py +59 -291
  66. gobby/llm/executor.py +21 -0
  67. gobby/llm/gemini.py +134 -110
  68. gobby/llm/litellm_executor.py +143 -6
  69. gobby/llm/resolver.py +98 -35
  70. gobby/mcp_proxy/importer.py +62 -4
  71. gobby/mcp_proxy/instructions.py +56 -0
  72. gobby/mcp_proxy/models.py +15 -0
  73. gobby/mcp_proxy/registries.py +68 -8
  74. gobby/mcp_proxy/server.py +33 -3
  75. gobby/mcp_proxy/services/recommendation.py +43 -11
  76. gobby/mcp_proxy/services/tool_proxy.py +81 -1
  77. gobby/mcp_proxy/stdio.py +2 -1
  78. gobby/mcp_proxy/tools/__init__.py +0 -2
  79. gobby/mcp_proxy/tools/agent_messaging.py +317 -0
  80. gobby/mcp_proxy/tools/agents.py +31 -731
  81. gobby/mcp_proxy/tools/clones.py +518 -0
  82. gobby/mcp_proxy/tools/memory.py +3 -26
  83. gobby/mcp_proxy/tools/metrics.py +65 -1
  84. gobby/mcp_proxy/tools/orchestration/__init__.py +3 -0
  85. gobby/mcp_proxy/tools/orchestration/cleanup.py +151 -0
  86. gobby/mcp_proxy/tools/orchestration/wait.py +467 -0
  87. gobby/mcp_proxy/tools/sessions/__init__.py +14 -0
  88. gobby/mcp_proxy/tools/sessions/_commits.py +232 -0
  89. gobby/mcp_proxy/tools/sessions/_crud.py +253 -0
  90. gobby/mcp_proxy/tools/sessions/_factory.py +63 -0
  91. gobby/mcp_proxy/tools/sessions/_handoff.py +499 -0
  92. gobby/mcp_proxy/tools/sessions/_messages.py +138 -0
  93. gobby/mcp_proxy/tools/skills/__init__.py +616 -0
  94. gobby/mcp_proxy/tools/spawn_agent.py +417 -0
  95. gobby/mcp_proxy/tools/task_orchestration.py +7 -0
  96. gobby/mcp_proxy/tools/task_readiness.py +14 -0
  97. gobby/mcp_proxy/tools/task_sync.py +1 -1
  98. gobby/mcp_proxy/tools/tasks/_context.py +0 -20
  99. gobby/mcp_proxy/tools/tasks/_crud.py +91 -4
  100. gobby/mcp_proxy/tools/tasks/_expansion.py +348 -0
  101. gobby/mcp_proxy/tools/tasks/_factory.py +6 -16
  102. gobby/mcp_proxy/tools/tasks/_lifecycle.py +110 -45
  103. gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +18 -29
  104. gobby/mcp_proxy/tools/workflows.py +1 -1
  105. gobby/mcp_proxy/tools/worktrees.py +0 -338
  106. gobby/memory/backends/__init__.py +6 -1
  107. gobby/memory/backends/mem0.py +6 -1
  108. gobby/memory/extractor.py +477 -0
  109. gobby/memory/ingestion/__init__.py +5 -0
  110. gobby/memory/ingestion/multimodal.py +221 -0
  111. gobby/memory/manager.py +73 -285
  112. gobby/memory/search/__init__.py +10 -0
  113. gobby/memory/search/coordinator.py +248 -0
  114. gobby/memory/services/__init__.py +5 -0
  115. gobby/memory/services/crossref.py +142 -0
  116. gobby/prompts/loader.py +5 -2
  117. gobby/runner.py +37 -16
  118. gobby/search/__init__.py +48 -6
  119. gobby/search/backends/__init__.py +159 -0
  120. gobby/search/backends/embedding.py +225 -0
  121. gobby/search/embeddings.py +238 -0
  122. gobby/search/models.py +148 -0
  123. gobby/search/unified.py +496 -0
  124. gobby/servers/http.py +24 -12
  125. gobby/servers/routes/admin.py +294 -0
  126. gobby/servers/routes/mcp/endpoints/__init__.py +61 -0
  127. gobby/servers/routes/mcp/endpoints/discovery.py +405 -0
  128. gobby/servers/routes/mcp/endpoints/execution.py +568 -0
  129. gobby/servers/routes/mcp/endpoints/registry.py +378 -0
  130. gobby/servers/routes/mcp/endpoints/server.py +304 -0
  131. gobby/servers/routes/mcp/hooks.py +1 -1
  132. gobby/servers/routes/mcp/tools.py +48 -1317
  133. gobby/servers/websocket.py +2 -2
  134. gobby/sessions/analyzer.py +2 -0
  135. gobby/sessions/lifecycle.py +1 -1
  136. gobby/sessions/processor.py +10 -0
  137. gobby/sessions/transcripts/base.py +2 -0
  138. gobby/sessions/transcripts/claude.py +79 -10
  139. gobby/skills/__init__.py +91 -0
  140. gobby/skills/loader.py +685 -0
  141. gobby/skills/manager.py +384 -0
  142. gobby/skills/parser.py +286 -0
  143. gobby/skills/search.py +463 -0
  144. gobby/skills/sync.py +119 -0
  145. gobby/skills/updater.py +385 -0
  146. gobby/skills/validator.py +368 -0
  147. gobby/storage/clones.py +378 -0
  148. gobby/storage/database.py +1 -1
  149. gobby/storage/memories.py +43 -13
  150. gobby/storage/migrations.py +162 -201
  151. gobby/storage/sessions.py +116 -7
  152. gobby/storage/skills.py +782 -0
  153. gobby/storage/tasks/_crud.py +4 -4
  154. gobby/storage/tasks/_lifecycle.py +57 -7
  155. gobby/storage/tasks/_manager.py +14 -5
  156. gobby/storage/tasks/_models.py +8 -3
  157. gobby/sync/memories.py +40 -5
  158. gobby/sync/tasks.py +83 -6
  159. gobby/tasks/__init__.py +1 -2
  160. gobby/tasks/external_validator.py +1 -1
  161. gobby/tasks/validation.py +46 -35
  162. gobby/tools/summarizer.py +91 -10
  163. gobby/tui/api_client.py +4 -7
  164. gobby/tui/app.py +5 -3
  165. gobby/tui/screens/orchestrator.py +1 -2
  166. gobby/tui/screens/tasks.py +2 -4
  167. gobby/tui/ws_client.py +1 -1
  168. gobby/utils/daemon_client.py +2 -2
  169. gobby/utils/project_context.py +2 -3
  170. gobby/utils/status.py +13 -0
  171. gobby/workflows/actions.py +221 -1135
  172. gobby/workflows/artifact_actions.py +31 -0
  173. gobby/workflows/autonomous_actions.py +11 -0
  174. gobby/workflows/context_actions.py +93 -1
  175. gobby/workflows/detection_helpers.py +115 -31
  176. gobby/workflows/enforcement/__init__.py +47 -0
  177. gobby/workflows/enforcement/blocking.py +269 -0
  178. gobby/workflows/enforcement/commit_policy.py +283 -0
  179. gobby/workflows/enforcement/handlers.py +269 -0
  180. gobby/workflows/{task_enforcement_actions.py → enforcement/task_policy.py} +29 -388
  181. gobby/workflows/engine.py +13 -2
  182. gobby/workflows/git_utils.py +106 -0
  183. gobby/workflows/lifecycle_evaluator.py +29 -1
  184. gobby/workflows/llm_actions.py +30 -0
  185. gobby/workflows/loader.py +19 -6
  186. gobby/workflows/mcp_actions.py +20 -1
  187. gobby/workflows/memory_actions.py +154 -0
  188. gobby/workflows/safe_evaluator.py +183 -0
  189. gobby/workflows/session_actions.py +44 -0
  190. gobby/workflows/state_actions.py +60 -1
  191. gobby/workflows/stop_signal_actions.py +55 -0
  192. gobby/workflows/summary_actions.py +111 -1
  193. gobby/workflows/task_sync_actions.py +347 -0
  194. gobby/workflows/todo_actions.py +34 -1
  195. gobby/workflows/webhook_actions.py +185 -0
  196. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/METADATA +87 -21
  197. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/RECORD +201 -172
  198. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/WHEEL +1 -1
  199. gobby/adapters/codex.py +0 -1292
  200. gobby/install/claude/commands/gobby/bug.md +0 -51
  201. gobby/install/claude/commands/gobby/chore.md +0 -51
  202. gobby/install/claude/commands/gobby/epic.md +0 -52
  203. gobby/install/claude/commands/gobby/eval.md +0 -235
  204. gobby/install/claude/commands/gobby/feat.md +0 -49
  205. gobby/install/claude/commands/gobby/nit.md +0 -52
  206. gobby/install/claude/commands/gobby/ref.md +0 -52
  207. gobby/install/codex/prompts/forget.md +0 -7
  208. gobby/install/codex/prompts/memories.md +0 -7
  209. gobby/install/codex/prompts/recall.md +0 -7
  210. gobby/install/codex/prompts/remember.md +0 -13
  211. gobby/llm/gemini_executor.py +0 -339
  212. gobby/mcp_proxy/tools/session_messages.py +0 -1056
  213. gobby/mcp_proxy/tools/task_expansion.py +0 -591
  214. gobby/prompts/defaults/expansion/system.md +0 -119
  215. gobby/prompts/defaults/expansion/user.md +0 -48
  216. gobby/prompts/defaults/external_validation/agent.md +0 -72
  217. gobby/prompts/defaults/external_validation/external.md +0 -63
  218. gobby/prompts/defaults/external_validation/spawn.md +0 -83
  219. gobby/prompts/defaults/external_validation/system.md +0 -6
  220. gobby/prompts/defaults/features/import_mcp.md +0 -22
  221. gobby/prompts/defaults/features/import_mcp_github.md +0 -17
  222. gobby/prompts/defaults/features/import_mcp_search.md +0 -16
  223. gobby/prompts/defaults/features/recommend_tools.md +0 -32
  224. gobby/prompts/defaults/features/recommend_tools_hybrid.md +0 -35
  225. gobby/prompts/defaults/features/recommend_tools_llm.md +0 -30
  226. gobby/prompts/defaults/features/server_description.md +0 -20
  227. gobby/prompts/defaults/features/server_description_system.md +0 -6
  228. gobby/prompts/defaults/features/task_description.md +0 -31
  229. gobby/prompts/defaults/features/task_description_system.md +0 -6
  230. gobby/prompts/defaults/features/tool_summary.md +0 -17
  231. gobby/prompts/defaults/features/tool_summary_system.md +0 -6
  232. gobby/prompts/defaults/research/step.md +0 -58
  233. gobby/prompts/defaults/validation/criteria.md +0 -47
  234. gobby/prompts/defaults/validation/validate.md +0 -38
  235. gobby/storage/migrations_legacy.py +0 -1359
  236. gobby/tasks/context.py +0 -747
  237. gobby/tasks/criteria.py +0 -342
  238. gobby/tasks/expansion.py +0 -626
  239. gobby/tasks/prompts/expand.py +0 -327
  240. gobby/tasks/research.py +0 -421
  241. gobby/tasks/tdd.py +0 -352
  242. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/entry_points.txt +0 -0
  243. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/licenses/LICENSE.md +0 -0
  244. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,269 @@
1
+ """ActionHandler wrappers for enforcement actions.
2
+
3
+ These handlers match the ActionHandler protocol: (context: ActionContext, **kwargs) -> dict | None
4
+ They bridge the workflow engine to the core enforcement functions.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from typing import TYPE_CHECKING, Any
11
+
12
+ from gobby.workflows.enforcement.blocking import block_tools
13
+ from gobby.workflows.enforcement.commit_policy import (
14
+ capture_baseline_dirty_files,
15
+ require_commit_before_stop,
16
+ require_task_review_or_close_before_stop,
17
+ )
18
+ from gobby.workflows.enforcement.task_policy import (
19
+ require_active_task,
20
+ require_task_complete,
21
+ validate_session_task_scope,
22
+ )
23
+
24
+ if TYPE_CHECKING:
25
+ from gobby.storage.tasks import LocalTaskManager
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ __all__ = [
30
+ "handle_block_tools",
31
+ "handle_capture_baseline_dirty_files",
32
+ "handle_require_active_task",
33
+ "handle_require_commit_before_stop",
34
+ "handle_require_task_complete",
35
+ "handle_require_task_review_or_close_before_stop",
36
+ "handle_validate_session_task_scope",
37
+ ]
38
+
39
+
40
+ async def handle_capture_baseline_dirty_files(
41
+ context: Any,
42
+ task_manager: LocalTaskManager | None = None,
43
+ **kwargs: Any,
44
+ ) -> dict[str, Any] | None:
45
+ """ActionHandler wrapper for capture_baseline_dirty_files.
46
+
47
+ Note: project_path comes from session's project lookup or event_data.cwd.
48
+ """
49
+ from gobby.storage.projects import LocalProjectManager
50
+
51
+ # Get project path - prioritize session lookup over hook payload
52
+ project_path = None
53
+
54
+ # 1. Get from session's project (most reliable - session exists by now)
55
+ if context.session_id and context.session_manager:
56
+ session = context.session_manager.get(context.session_id)
57
+ if session and session.project_id:
58
+ project_mgr = LocalProjectManager(context.db)
59
+ project = project_mgr.get(session.project_id)
60
+ if project and project.repo_path:
61
+ project_path = project.repo_path
62
+
63
+ # 2. Fallback to event_data.cwd (from hook payload)
64
+ if not project_path and context.event_data:
65
+ project_path = context.event_data.get("cwd")
66
+
67
+ return await capture_baseline_dirty_files(
68
+ workflow_state=context.state,
69
+ project_path=project_path,
70
+ )
71
+
72
+
73
+ async def handle_require_commit_before_stop(
74
+ context: Any,
75
+ task_manager: LocalTaskManager | None = None,
76
+ **kwargs: Any,
77
+ ) -> dict[str, Any] | None:
78
+ """ActionHandler wrapper for require_commit_before_stop.
79
+
80
+ Note: task_manager must be passed via closure from executor.
81
+ """
82
+ from gobby.storage.projects import LocalProjectManager
83
+
84
+ # Get project path
85
+ project_path = None
86
+
87
+ if context.session_id and context.session_manager:
88
+ session = context.session_manager.get(context.session_id)
89
+ if session and session.project_id:
90
+ project_mgr = LocalProjectManager(context.db)
91
+ project = project_mgr.get(session.project_id)
92
+ if project and project.repo_path:
93
+ project_path = project.repo_path
94
+
95
+ if not project_path and context.event_data:
96
+ project_path = context.event_data.get("cwd")
97
+
98
+ return await require_commit_before_stop(
99
+ workflow_state=context.state,
100
+ project_path=project_path,
101
+ task_manager=task_manager,
102
+ )
103
+
104
+
105
+ async def handle_require_task_review_or_close_before_stop(
106
+ context: Any,
107
+ task_manager: LocalTaskManager | None = None,
108
+ **kwargs: Any,
109
+ ) -> dict[str, Any] | None:
110
+ """ActionHandler wrapper for require_task_review_or_close_before_stop."""
111
+ project_id = None
112
+ if context.session_manager:
113
+ session = context.session_manager.get(context.session_id)
114
+ if session:
115
+ project_id = session.project_id
116
+
117
+ return await require_task_review_or_close_before_stop(
118
+ workflow_state=context.state,
119
+ task_manager=task_manager,
120
+ project_id=project_id,
121
+ )
122
+
123
+
124
+ async def handle_validate_session_task_scope(
125
+ context: Any,
126
+ task_manager: LocalTaskManager | None = None,
127
+ **kwargs: Any,
128
+ ) -> dict[str, Any] | None:
129
+ """ActionHandler wrapper for validate_session_task_scope."""
130
+ return await validate_session_task_scope(
131
+ task_manager=task_manager,
132
+ workflow_state=context.state,
133
+ event_data=context.event_data,
134
+ )
135
+
136
+
137
+ async def handle_block_tools(
138
+ context: Any,
139
+ task_manager: LocalTaskManager | None = None,
140
+ **kwargs: Any,
141
+ ) -> dict[str, Any] | None:
142
+ """ActionHandler wrapper for block_tools.
143
+
144
+ Passes task_manager via closure from register_defaults.
145
+ """
146
+ from gobby.storage.projects import LocalProjectManager
147
+
148
+ # Get project_path for git dirty file checks
149
+ project_path = kwargs.get("project_path")
150
+ if not project_path and context.event_data:
151
+ project_path = context.event_data.get("cwd")
152
+
153
+ # Get source from session for is_plan_file checks
154
+ source = None
155
+ current_session = None
156
+ if context.session_manager:
157
+ current_session = context.session_manager.get(context.session_id)
158
+ if current_session:
159
+ source = current_session.source
160
+
161
+ # Fallback to session's project path
162
+ if not project_path and current_session and context.db:
163
+ project_mgr = LocalProjectManager(context.db)
164
+ project = project_mgr.get(current_session.project_id)
165
+ if project and project.repo_path:
166
+ project_path = project.repo_path
167
+
168
+ return await block_tools(
169
+ rules=kwargs.get("rules"),
170
+ event_data=context.event_data,
171
+ workflow_state=context.state,
172
+ project_path=project_path,
173
+ task_manager=task_manager,
174
+ source=source,
175
+ )
176
+
177
+
178
+ async def handle_require_active_task(
179
+ context: Any,
180
+ task_manager: LocalTaskManager | None = None,
181
+ **kwargs: Any,
182
+ ) -> dict[str, Any] | None:
183
+ """ActionHandler wrapper for require_active_task.
184
+
185
+ DEPRECATED: Use block_tools action with rules instead.
186
+ Kept for backward compatibility with existing workflows.
187
+ """
188
+ # Get project_id from session for project-scoped task filtering
189
+ current_session = None
190
+ project_id = None
191
+ if context.session_manager:
192
+ current_session = context.session_manager.get(context.session_id)
193
+ if current_session:
194
+ project_id = current_session.project_id
195
+
196
+ return await require_active_task(
197
+ task_manager=task_manager,
198
+ session_id=context.session_id,
199
+ config=context.config,
200
+ event_data=context.event_data,
201
+ project_id=project_id,
202
+ workflow_state=context.state,
203
+ session_manager=context.session_manager,
204
+ session_task_manager=context.session_task_manager,
205
+ )
206
+
207
+
208
+ async def handle_require_task_complete(
209
+ context: Any,
210
+ task_manager: LocalTaskManager | None = None,
211
+ template_engine: Any | None = None,
212
+ **kwargs: Any,
213
+ ) -> dict[str, Any] | None:
214
+ """ActionHandler wrapper for require_task_complete.
215
+
216
+ Supports:
217
+ - Single task ID: "#47"
218
+ - List of task IDs: ["#47", "#48"]
219
+ - Wildcard: "*" - work until no ready tasks remain
220
+ """
221
+ project_id = None
222
+ if context.session_manager and context.session_id:
223
+ session = context.session_manager.get(context.session_id)
224
+ if session:
225
+ project_id = session.project_id
226
+
227
+ # Get task_id from kwargs - may be a template that needs resolving
228
+ task_spec = kwargs.get("task_id")
229
+
230
+ # If it's a template reference like "{{ variables.session_task }}", resolve it
231
+ if task_spec and "{{" in str(task_spec) and template_engine:
232
+ task_spec = template_engine.render(
233
+ str(task_spec),
234
+ {"variables": context.state.variables if context.state else {}},
235
+ )
236
+
237
+ # Handle different task_spec types:
238
+ # - None/empty: no enforcement
239
+ # - "*": wildcard - fetch ready tasks
240
+ # - list: multiple specific tasks
241
+ # - string: single task ID
242
+ task_ids: list[str] | None = None
243
+
244
+ if not task_spec:
245
+ return None
246
+ elif task_spec == "*":
247
+ # Wildcard: get all ready tasks for this project
248
+ if task_manager:
249
+ ready_tasks = task_manager.list_ready_tasks(
250
+ project_id=project_id,
251
+ limit=100,
252
+ )
253
+ task_ids = [t.id for t in ready_tasks]
254
+ if not task_ids:
255
+ # No ready tasks - allow stop
256
+ return None
257
+ elif isinstance(task_spec, list):
258
+ task_ids = task_spec
259
+ else:
260
+ task_ids = [str(task_spec)]
261
+
262
+ return await require_task_complete(
263
+ task_manager=task_manager,
264
+ session_id=context.session_id,
265
+ task_ids=task_ids,
266
+ event_data=context.event_data,
267
+ project_id=project_id,
268
+ workflow_state=context.state,
269
+ )