Skip to content
10 changes: 8 additions & 2 deletions app/api/v2/managers/operation_api_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ async def create_potential_link(self, operation_id: str, data: dict, access: Bas
agent = await self.get_agent(operation, data)
if data['executor']['name'] not in agent.executors:
raise JsonHttpBadRequest(f'Agent {agent.paw} missing specified executor')
encoded_command = self._encode_string(agent.replace(self._encode_string(data['executor']['command']),
file_svc=self.services['file_svc']))
executor = self.build_executor(data=data.pop('executor', {}), agent=agent)
ability = self.build_ability(data=data.pop('ability', {}), executor=executor)
self._call_ability_plugin_hooks(ability, executor)
encoded_command = self._encode_string(agent.replace(self._encode_string(data['executor']['command']),
file_svc=self.services['file_svc']))
link = Link.load(dict(command=encoded_command, plaintext_command=encoded_command, paw=agent.paw, ability=ability, executor=executor,
status=operation.link_status(), score=data.get('score', 0), jitter=data.get('jitter', 0),
cleanup=data.get('cleanup', 0), pin=data.get('pin', 0),
Expand Down Expand Up @@ -170,6 +171,11 @@ async def _construct_and_dump_source(self, source_id: str):
if not source:
source = (await self.services['data_svc'].locate('sources', match=dict(name='basic')))
return SourceSchema().dump(source[0])

async def _call_ability_plugin_hooks(self, ability, executor):
"""Calls any plugin hooks (at runtime) that exist for the ability and executor."""
for _hook, fcall in executor.HOOKS.items():
await fcall(ability, executor)
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code will fail with an AttributeError if executor.HOOKS is None or undefined. Add a null check before iterating: if executor.HOOKS: before the for loop.

Suggested change
for _hook, fcall in executor.HOOKS.items():
await fcall(ability, executor)
if executor.HOOKS:
for _hook, fcall in executor.HOOKS.items():
await fcall(ability, executor)

Copilot uses AI. Check for mistakes.

async def validate_operation_state(self, data: dict, existing: Operation = None):
if not existing:
Expand Down
9 changes: 6 additions & 3 deletions app/service/planning_svc.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,7 @@ async def _generate_new_links(self, operation, agent, abilities, link_status):
executor = await agent.get_preferred_executor(ability)
if not executor:
continue

if executor.HOOKS and executor.language and executor.language in executor.HOOKS:
await executor.HOOKS[executor.language](ability, executor)
self._call_ability_plugin_hooks(ability, executor)
if executor.command:
link = Link.load(dict(command=self.encode_string(executor.test), paw=agent.paw, score=0,
ability=ability, executor=executor, status=link_status,
Expand Down Expand Up @@ -391,6 +389,11 @@ async def _generate_cleanup_links(self, operation, agent, link_status):
lnk.apply_id(agent.host)
links.append(lnk)
return links

async def _call_ability_plugin_hooks(self, ability, executor):
"""Calls any plugin hooks (at runtime) that exist for the ability and executor."""
for _hook, fcall in executor.HOOKS.items():
await fcall(ability, executor)
Copy link

Copilot AI Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code will fail with an AttributeError if executor.HOOKS is None or undefined. Add a null check before iterating: if executor.HOOKS: before the for loop.

Suggested change
for _hook, fcall in executor.HOOKS.items():
await fcall(ability, executor)
if executor.HOOKS:
for _hook, fcall in executor.HOOKS.items():
await fcall(ability, executor)

Copilot uses AI. Check for mistakes.

@staticmethod
async def _apply_adjustments(operation, links):
Expand Down
Loading