intutic_clawde.gate.adapters.autogen_workbench
Microsoft AutoGen adapter, in-process half: IntuticWorkbench.
autogen.py's IntuticInterventionHandler sees only runtime-routed messages. AssistantAgent (autogen_agentchat.agents._assistant_agent) never routes its own tool calls through the runtime: _execute_tool_call walks self._workbench and calls wb.call_tool(...) directly (wb.call_tool_stream(...) when the entry is a StaticStreamWorkbench). The workbench is therefore the in-process veto point, and this module wraps it.
IntuticWorkbench is a Workbench that delegates everything to the one it wraps and guards call_tool with Gate.guard(name, dict(arguments)), the same core pydantic_ai.py's IntuticWrapperToolset.call_tool uses. On deny it returns ToolResult(is_error=True) carrying the [Intutic Governance] BLOCKED: ... text rather than raising: AutoGen turns that into a FunctionExecutionResult the model reads on its next turn, so the run continues and the model can change approach, while the tool body never runs. Raising would abort the whole agent.run().
guard_assistant_agent(agent) wraps each entry of an existing AssistantAgent's _workbench list in place, idempotently.
Verified against autogen-core/autogen-agentchat 0.7.5:
Workbench.call_tool(self, name, arguments=None, cancellation_token=None, call_id=None) -> ToolResult._execute_tool_calldispatches onisinstance(wb, StaticStreamWorkbench); a wrapper that is not one goes throughcall_tool, so wrapping aStaticStreamWorkbenchtrades its intermediate streamed events for governance. The finalToolResultis unchanged.- Handoff tools (
handoffs=[...]) are run throughhandoff_tool.run_jsonat_assistant_agent.pyand never touch the workbench: they are not governed here. A handoff transfers control between agents and executes no user tool, so the reachable tool calls are still every one that goes through a workbench.
Optional import: this module imports without autogen-core; only instantiating IntuticWorkbench requires it (pip install intutic-clawde[autogen]).
Classes
IntuticWorkbench
class IntuticWorkbench(wrapped: Any, gate: Optional[Gate] = None)Bases: Workbench
A Workbench that vetoes a tool call before the wrapped one runs it.
Usage:
from autogen_agentchat.agents import AssistantAgent
from autogen_core.tools import StaticWorkbench
from intutic_clawde.gate.adapters.autogen_workbench import IntuticWorkbench
agent = AssistantAgent(
"helper", model_client,
workbench=IntuticWorkbench(StaticWorkbench([my_tool])),
)gate overrides the process-wide instance registered with install().
Attributes
| Name | Type | Default | Description |
|---|---|---|---|
component_provider_override | — | 'intutic_clawde.gate.adapters.autogen_workbench.IntuticWorkbench' | |
component_type | — | 'workbench' |
Methods
IntuticWorkbench.call_tool()
async def call_tool(
name: str,
arguments: Mapping[str, Any] | None = None,
cancellation_token: Any = None,
call_id: str | None = None,
) -> AnyIntuticWorkbench.list_tools()
async def list_tools() -> AnyIntuticWorkbench.load_state()
async def load_state(state: Mapping[str, Any]) -> NoneIntuticWorkbench.reset()
async def reset() -> NoneIntuticWorkbench.save_state()
async def save_state() -> Mapping[str, Any]IntuticWorkbench.start()
async def start() -> NoneIntuticWorkbench.stop()
async def stop() -> NoneFunctions
guard_assistant_agent()
def guard_assistant_agent(agent: Any, gate: Optional[Gate] = None) -> List[Any]Wrap every workbench an AssistantAgent holds in an IntuticWorkbench.
Edits agent._workbench in place (the list _execute_tool_call walks) and returns it. Idempotent: an entry that is already an IntuticWorkbench is left alone. The agent must have been built with tools= or workbench=; an agent with no workbench has nothing to govern and is returned unchanged.