cc-codeconductor 0.2.8 → 0.2.10
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.
- package/README.md +113 -26
- package/dist/index.js +1752 -81
- package/package.json +1 -1
- package/presets/agy/AGENTS.md +354 -0
- package/presets/agy/README.md +47 -0
- package/presets/agy/hooks.json +30 -0
- package/presets/agy/mcp_config.json +3 -0
- package/presets/agy/rules/commit-style.md +1 -0
- package/presets/agy/rules/graphify.md +14 -0
- package/presets/agy/scripts/post-tool.sh +25 -0
- package/presets/agy/scripts/pre-tool.sh +56 -0
- package/presets/agy/settings.json +8 -0
- package/presets/agy/skills/cc-api-contract/SKILL.md +71 -0
- package/presets/agy/skills/cc-db-migration/SKILL.md +70 -0
- package/presets/agy/skills/cc-feature/SKILL.md +115 -0
- package/presets/agy/skills/cc-fix/SKILL.md +124 -0
- package/presets/agy/skills/cc-pagespeed/SKILL.md +101 -0
- package/presets/agy/skills/cc-refactor/SKILL.md +149 -0
- package/presets/agy/skills/cc-review/SKILL.md +142 -0
- package/presets/agy/skills/cc-tdd-cycle/SKILL.md +226 -0
- package/presets/agy/skills/cc-test-plan/SKILL.md +145 -0
- package/presets/agy/skills/commit/SKILL.md +5 -0
- package/presets/agy/workflows/cc-api-contract.md +71 -0
- package/presets/agy/workflows/cc-db-migration.md +70 -0
- package/presets/agy/workflows/cc-feature.md +115 -0
- package/presets/agy/workflows/cc-fix.md +124 -0
- package/presets/agy/workflows/cc-pagespeed.md +101 -0
- package/presets/agy/workflows/cc-refactor.md +149 -0
- package/presets/agy/workflows/cc-review.md +142 -0
- package/presets/agy/workflows/cc-tdd-cycle.md +226 -0
- package/presets/agy/workflows/cc-test-plan.md +145 -0
- package/presets/agy/workflows/commit.md +1 -0
- package/presets/claude/CLAUDE.md +13 -3
- package/presets/claude/claude.json +6 -0
- package/presets/claude/commands/cc/pagespeed.md +103 -0
- package/presets/claude/settings.json +249 -2
- package/presets/claude/skills/conductor-setup/SKILL.md +125 -0
- package/presets/claude/skills/find-skills/SKILL.md +142 -0
- package/presets/claude/skills/multi-agent-orchestration/README.md +144 -0
- package/presets/claude/skills/multi-agent-orchestration/SKILL.md +579 -0
- package/presets/claude/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
- package/presets/claude/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
- package/presets/claude/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
- package/presets/claude/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
- package/presets/claude/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
- package/presets/claude/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/claude/skills/pagespeed-insights/reference.md +50 -0
- package/presets/claude/skills/pagespeed-perf/SKILL.md +279 -0
- package/presets/claude/skills/workflow-orchestration-patterns/SKILL.md +98 -0
- package/presets/claude/skills/workflow-orchestration-patterns/references/details.md +223 -0
- package/presets/codex/AGENTS.md +19 -14
- package/presets/codex/skills/conductor-setup/SKILL.md +125 -0
- package/presets/codex/skills/find-skills/SKILL.md +142 -0
- package/presets/codex/skills/multi-agent-orchestration/README.md +144 -0
- package/presets/codex/skills/multi-agent-orchestration/SKILL.md +579 -0
- package/presets/codex/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
- package/presets/codex/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
- package/presets/codex/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
- package/presets/codex/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
- package/presets/codex/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
- package/presets/codex/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/codex/skills/pagespeed-insights/reference.md +50 -0
- package/presets/codex/skills/pagespeed-perf/SKILL.md +279 -0
- package/presets/codex/skills/workflow-orchestration-patterns/SKILL.md +98 -0
- package/presets/codex/skills/workflow-orchestration-patterns/references/details.md +223 -0
- package/presets/opencode/README.md +11 -10
- package/presets/opencode/commands/cc-pagespeed.md +100 -0
- package/presets/opencode/skills/conductor-setup/SKILL.md +125 -0
- package/presets/opencode/skills/find-skills/SKILL.md +142 -0
- package/presets/opencode/skills/multi-agent-orchestration/README.md +144 -0
- package/presets/opencode/skills/multi-agent-orchestration/SKILL.md +579 -0
- package/presets/opencode/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
- package/presets/opencode/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
- package/presets/opencode/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
- package/presets/opencode/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
- package/presets/opencode/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
- package/presets/opencode/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/opencode/skills/pagespeed-insights/reference.md +50 -0
- package/presets/opencode/skills/pagespeed-perf/SKILL.md +279 -0
- package/presets/opencode/skills/workflow-orchestration-patterns/SKILL.md +98 -0
- package/presets/opencode/skills/workflow-orchestration-patterns/references/details.md +223 -0
- package/presets/seo-hotel/commands/cc-seo-audit.md +17 -9
- package/presets/seo-hotel/commands/cc-seo-llms.md +64 -0
- package/presets/seo-hotel/seo-hotel.yml +55 -0
- package/presets/seo-hotel/settings.json +225 -0
- package/presets/seo-hotel/skills/find-skills/SKILL.md +142 -0
- package/presets/seo-hotel/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/seo-hotel/skills/pagespeed-insights/reference.md +50 -0
- package/src/presets/manifests/agy.yml +36 -2
- package/src/presets/manifests/claude.yml +5 -0
- package/src/presets/manifests/opencode.yml +4 -0
- package/src/presets/models/agy.yml +16 -0
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Multi-Agent Orchestration Patterns
|
|
3
|
+
|
|
4
|
+
Implements sequential, parallel, hierarchical, and consensus orchestration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Dict, Any, Optional
|
|
8
|
+
import asyncio
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Agent(ABC):
|
|
13
|
+
"""Base agent class."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, name: str, role: str, goal: str):
|
|
16
|
+
"""Initialize agent."""
|
|
17
|
+
self.name = name
|
|
18
|
+
self.role = role
|
|
19
|
+
self.goal = goal
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def work(self, task: str) -> str:
|
|
23
|
+
"""Execute task."""
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
async def work_async(self, task: str) -> str:
|
|
27
|
+
"""Execute task asynchronously."""
|
|
28
|
+
return self.work(task)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SimpleAgent(Agent):
|
|
32
|
+
"""Simple agent implementation."""
|
|
33
|
+
|
|
34
|
+
def __init__(self, name: str, role: str, goal: str):
|
|
35
|
+
"""Initialize simple agent."""
|
|
36
|
+
super().__init__(name, role, goal)
|
|
37
|
+
|
|
38
|
+
def work(self, task: str) -> str:
|
|
39
|
+
"""Simulate agent work."""
|
|
40
|
+
return f"{self.name}: Completed task - {task[:50]}..."
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class SequentialOrchestrator:
|
|
44
|
+
"""Orchestrate agents to work sequentially."""
|
|
45
|
+
|
|
46
|
+
def __init__(self, agents: List[Agent]):
|
|
47
|
+
"""
|
|
48
|
+
Initialize orchestrator with agents.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
agents: List of agents to orchestrate
|
|
52
|
+
"""
|
|
53
|
+
self.agents = agents
|
|
54
|
+
self.execution_log = []
|
|
55
|
+
|
|
56
|
+
def execute(self, initial_task: str) -> Dict[str, Any]:
|
|
57
|
+
"""
|
|
58
|
+
Execute agents sequentially.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
initial_task: Initial task description
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Execution results dictionary
|
|
65
|
+
"""
|
|
66
|
+
current_input = initial_task
|
|
67
|
+
results = {}
|
|
68
|
+
|
|
69
|
+
for agent in self.agents:
|
|
70
|
+
result = agent.work(current_input)
|
|
71
|
+
results[agent.name] = result
|
|
72
|
+
self.execution_log.append({
|
|
73
|
+
"agent": agent.name,
|
|
74
|
+
"role": agent.role,
|
|
75
|
+
"task": current_input,
|
|
76
|
+
"result": result,
|
|
77
|
+
})
|
|
78
|
+
# Next agent uses this agent's output
|
|
79
|
+
current_input = result
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
"type": "sequential",
|
|
83
|
+
"results": results,
|
|
84
|
+
"final_output": current_input,
|
|
85
|
+
"execution_log": self.execution_log,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class ParallelOrchestrator:
|
|
90
|
+
"""Orchestrate agents to work in parallel."""
|
|
91
|
+
|
|
92
|
+
def __init__(self, agents: List[Agent]):
|
|
93
|
+
"""Initialize parallel orchestrator."""
|
|
94
|
+
self.agents = agents
|
|
95
|
+
self.execution_log = []
|
|
96
|
+
|
|
97
|
+
async def execute_async(self, task: str) -> Dict[str, Any]:
|
|
98
|
+
"""
|
|
99
|
+
Execute agents in parallel.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
task: Task description
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Execution results dictionary
|
|
106
|
+
"""
|
|
107
|
+
# Create async tasks for all agents
|
|
108
|
+
tasks = [agent.work_async(task) for agent in self.agents]
|
|
109
|
+
|
|
110
|
+
# Execute all in parallel
|
|
111
|
+
results_list = await asyncio.gather(*tasks)
|
|
112
|
+
|
|
113
|
+
results = {
|
|
114
|
+
agent.name: result
|
|
115
|
+
for agent, result in zip(self.agents, results_list)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
self.execution_log.append({
|
|
119
|
+
"type": "parallel",
|
|
120
|
+
"task": task,
|
|
121
|
+
"agents": [a.name for a in self.agents],
|
|
122
|
+
"results": results,
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
"type": "parallel",
|
|
127
|
+
"results": results,
|
|
128
|
+
"execution_log": self.execution_log,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
def execute(self, task: str) -> Dict[str, Any]:
|
|
132
|
+
"""Execute agents synchronously (sequential fallback)."""
|
|
133
|
+
return asyncio.run(self.execute_async(task))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class HierarchicalOrchestrator:
|
|
137
|
+
"""Orchestrate agents in hierarchical structure."""
|
|
138
|
+
|
|
139
|
+
def __init__(self, manager_agent: Agent, specialist_teams: Dict[str, List[Agent]]):
|
|
140
|
+
"""
|
|
141
|
+
Initialize hierarchical orchestrator.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
manager_agent: Manager agent
|
|
145
|
+
specialist_teams: Dict of team names to lists of agents
|
|
146
|
+
"""
|
|
147
|
+
self.manager = manager_agent
|
|
148
|
+
self.specialist_teams = specialist_teams
|
|
149
|
+
self.execution_log = []
|
|
150
|
+
|
|
151
|
+
def execute(self, main_task: str) -> Dict[str, Any]:
|
|
152
|
+
"""
|
|
153
|
+
Execute with hierarchical structure.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
main_task: Main task for manager
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Execution results
|
|
160
|
+
"""
|
|
161
|
+
team_results = {}
|
|
162
|
+
|
|
163
|
+
# Manager assigns tasks to teams
|
|
164
|
+
for team_name, agents in self.specialist_teams.items():
|
|
165
|
+
# Each team works on their aspect
|
|
166
|
+
team_task = f"{main_task} - Team: {team_name}"
|
|
167
|
+
team_result = {}
|
|
168
|
+
|
|
169
|
+
for agent in agents:
|
|
170
|
+
result = agent.work(team_task)
|
|
171
|
+
team_result[agent.name] = result
|
|
172
|
+
|
|
173
|
+
team_results[team_name] = team_result
|
|
174
|
+
|
|
175
|
+
self.execution_log.append({
|
|
176
|
+
"team": team_name,
|
|
177
|
+
"agents": [a.name for a in agents],
|
|
178
|
+
"results": team_result,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
# Manager synthesizes results
|
|
182
|
+
manager_result = self.manager.work(
|
|
183
|
+
f"Synthesize findings from: {list(team_results.keys())}"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
"type": "hierarchical",
|
|
188
|
+
"team_results": team_results,
|
|
189
|
+
"manager_synthesis": manager_result,
|
|
190
|
+
"execution_log": self.execution_log,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class ConsensusOrchestrator:
|
|
195
|
+
"""Orchestrate agent debate and consensus."""
|
|
196
|
+
|
|
197
|
+
def __init__(self, agents: List[Agent], mediator_agent: Agent):
|
|
198
|
+
"""Initialize consensus orchestrator."""
|
|
199
|
+
self.agents = agents
|
|
200
|
+
self.mediator = mediator_agent
|
|
201
|
+
self.debate_history = []
|
|
202
|
+
|
|
203
|
+
def execute(self, question: str, rounds: int = 2) -> Dict[str, Any]:
|
|
204
|
+
"""
|
|
205
|
+
Execute debate and reach consensus.
|
|
206
|
+
|
|
207
|
+
Args:
|
|
208
|
+
question: Question for debate
|
|
209
|
+
rounds: Number of debate rounds
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Consensus results
|
|
213
|
+
"""
|
|
214
|
+
# Round 1: Initial positions
|
|
215
|
+
positions = {}
|
|
216
|
+
for agent in self.agents:
|
|
217
|
+
position = agent.work(f"Argue your position on: {question}")
|
|
218
|
+
positions[agent.name] = position
|
|
219
|
+
self.debate_history.append({
|
|
220
|
+
"round": 1,
|
|
221
|
+
"agent": agent.name,
|
|
222
|
+
"position": position,
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
# Additional rounds: Response to others
|
|
226
|
+
for round_num in range(2, rounds + 1):
|
|
227
|
+
for agent in self.agents:
|
|
228
|
+
other_positions = {
|
|
229
|
+
name: pos
|
|
230
|
+
for name, pos in positions.items()
|
|
231
|
+
if name != agent.name
|
|
232
|
+
}
|
|
233
|
+
response = agent.work(
|
|
234
|
+
f"Respond to these positions: {str(other_positions)}"
|
|
235
|
+
)
|
|
236
|
+
self.debate_history.append({
|
|
237
|
+
"round": round_num,
|
|
238
|
+
"agent": agent.name,
|
|
239
|
+
"response": response,
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
# Mediator reaches consensus
|
|
243
|
+
consensus = self.mediator.work(
|
|
244
|
+
f"Synthesize consensus from debate on: {question}"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
"type": "consensus",
|
|
249
|
+
"question": question,
|
|
250
|
+
"initial_positions": positions,
|
|
251
|
+
"debate_rounds": rounds,
|
|
252
|
+
"consensus": consensus,
|
|
253
|
+
"debate_history": self.debate_history,
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class AdaptiveOrchestrator:
|
|
258
|
+
"""Adapt orchestration based on progress."""
|
|
259
|
+
|
|
260
|
+
def __init__(self, agents: List[Agent]):
|
|
261
|
+
"""Initialize adaptive orchestrator."""
|
|
262
|
+
self.agents = agents
|
|
263
|
+
self.execution_log = []
|
|
264
|
+
|
|
265
|
+
def execute_with_adaptation(
|
|
266
|
+
self,
|
|
267
|
+
initial_task: str,
|
|
268
|
+
progress_threshold: float = 0.7,
|
|
269
|
+
quality_threshold: float = 0.6,
|
|
270
|
+
) -> Dict[str, Any]:
|
|
271
|
+
"""
|
|
272
|
+
Execute with adaptive workflow changes.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
initial_task: Initial task
|
|
276
|
+
progress_threshold: Threshold for adding resources
|
|
277
|
+
quality_threshold: Threshold for adding validation
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
Adaptive execution results
|
|
281
|
+
"""
|
|
282
|
+
results = {}
|
|
283
|
+
current_task = initial_task
|
|
284
|
+
active_agents = self.agents.copy()
|
|
285
|
+
|
|
286
|
+
for iteration in range(3):
|
|
287
|
+
# Execute with current agents
|
|
288
|
+
iteration_results = {}
|
|
289
|
+
for agent in active_agents:
|
|
290
|
+
result = agent.work(current_task)
|
|
291
|
+
iteration_results[agent.name] = result
|
|
292
|
+
|
|
293
|
+
results[f"iteration_{iteration}"] = iteration_results
|
|
294
|
+
|
|
295
|
+
# Assess progress
|
|
296
|
+
progress = self._calculate_progress(iteration_results)
|
|
297
|
+
quality = self._calculate_quality(iteration_results)
|
|
298
|
+
|
|
299
|
+
log_entry = {
|
|
300
|
+
"iteration": iteration,
|
|
301
|
+
"agents": [a.name for a in active_agents],
|
|
302
|
+
"progress": progress,
|
|
303
|
+
"quality": quality,
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
# Adapt based on progress
|
|
307
|
+
if progress < progress_threshold and iteration < 2:
|
|
308
|
+
# Add more agents
|
|
309
|
+
log_entry["adaptation"] = "Added specialist agent"
|
|
310
|
+
self.execution_log.append(log_entry)
|
|
311
|
+
elif quality < quality_threshold and iteration < 2:
|
|
312
|
+
# Add validation step
|
|
313
|
+
log_entry["adaptation"] = "Added validation agent"
|
|
314
|
+
self.execution_log.append(log_entry)
|
|
315
|
+
else:
|
|
316
|
+
self.execution_log.append(log_entry)
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
"type": "adaptive",
|
|
320
|
+
"results": results,
|
|
321
|
+
"adaptations": self.execution_log,
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
@staticmethod
|
|
325
|
+
def _calculate_progress(results: Dict) -> float:
|
|
326
|
+
"""Calculate progress score."""
|
|
327
|
+
# Simple heuristic based on results
|
|
328
|
+
return min(len(results) / 3.0, 1.0)
|
|
329
|
+
|
|
330
|
+
@staticmethod
|
|
331
|
+
def _calculate_quality(results: Dict) -> float:
|
|
332
|
+
"""Calculate quality score."""
|
|
333
|
+
# Simple heuristic
|
|
334
|
+
return 0.7 # Placeholder
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class WorkflowGraph:
|
|
338
|
+
"""Define workflow as directed acyclic graph (DAG)."""
|
|
339
|
+
|
|
340
|
+
def __init__(self):
|
|
341
|
+
"""Initialize workflow graph."""
|
|
342
|
+
self.nodes = {}
|
|
343
|
+
self.edges = []
|
|
344
|
+
|
|
345
|
+
def add_node(self, node_id: str, agent: Agent) -> None:
|
|
346
|
+
"""Add agent node."""
|
|
347
|
+
self.nodes[node_id] = agent
|
|
348
|
+
|
|
349
|
+
def add_edge(self, from_node: str, to_node: str) -> None:
|
|
350
|
+
"""Add dependency edge."""
|
|
351
|
+
self.edges.append((from_node, to_node))
|
|
352
|
+
|
|
353
|
+
def execute_dag(self, initial_task: str) -> Dict[str, Any]:
|
|
354
|
+
"""
|
|
355
|
+
Execute workflow as DAG.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
initial_task: Initial task
|
|
359
|
+
|
|
360
|
+
Returns:
|
|
361
|
+
Execution results
|
|
362
|
+
"""
|
|
363
|
+
results = {}
|
|
364
|
+
ready_nodes = self._find_ready_nodes()
|
|
365
|
+
|
|
366
|
+
while ready_nodes:
|
|
367
|
+
for node_id in ready_nodes:
|
|
368
|
+
agent = self.nodes[node_id]
|
|
369
|
+
# Get input from dependencies
|
|
370
|
+
task_input = self._get_node_input(node_id, results, initial_task)
|
|
371
|
+
result = agent.work(task_input)
|
|
372
|
+
results[node_id] = result
|
|
373
|
+
|
|
374
|
+
ready_nodes = self._find_ready_nodes(completed=set(results.keys()))
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
"type": "dag",
|
|
378
|
+
"results": results,
|
|
379
|
+
"nodes": list(self.nodes.keys()),
|
|
380
|
+
"edges": self.edges,
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
def _find_ready_nodes(self, completed: Optional[set] = None) -> List[str]:
|
|
384
|
+
"""Find nodes with all dependencies completed."""
|
|
385
|
+
if completed is None:
|
|
386
|
+
completed = set()
|
|
387
|
+
|
|
388
|
+
ready = []
|
|
389
|
+
for node_id in self.nodes:
|
|
390
|
+
if node_id not in completed:
|
|
391
|
+
dependencies = [
|
|
392
|
+
from_node
|
|
393
|
+
for from_node, to_node in self.edges
|
|
394
|
+
if to_node == node_id
|
|
395
|
+
]
|
|
396
|
+
if all(dep in completed for dep in dependencies):
|
|
397
|
+
ready.append(node_id)
|
|
398
|
+
|
|
399
|
+
return ready
|
|
400
|
+
|
|
401
|
+
def _get_node_input(
|
|
402
|
+
self, node_id: str, results: Dict, initial_task: str
|
|
403
|
+
) -> str:
|
|
404
|
+
"""Get input for node from dependencies."""
|
|
405
|
+
dependencies = [
|
|
406
|
+
from_node for from_node, to_node in self.edges if to_node == node_id
|
|
407
|
+
]
|
|
408
|
+
if not dependencies:
|
|
409
|
+
return initial_task
|
|
410
|
+
# Combine outputs from dependencies
|
|
411
|
+
return " + ".join(results.get(dep, "") for dep in dependencies)
|