Skip to content

Fix #5: Add sub-agent event streaming and fine-grained permissive control#6

Merged
ZhiXiao-Lin merged 1 commit intoA3S-Lab:mainfrom
ZhiXiao-Lin:fix/issue-5-orchestrator-improvements
Mar 9, 2026
Merged

Fix #5: Add sub-agent event streaming and fine-grained permissive control#6
ZhiXiao-Lin merged 1 commit intoA3S-Lab:mainfrom
ZhiXiao-Lin:fix/issue-5-orchestrator-improvements

Conversation

@ZhiXiao-Lin
Copy link
Contributor

Fix #5: Add sub-agent event streaming and fine-grained permissive control

This PR addresses both issues raised in #5 regarding the Orchestrator API.

Issue 1: Sub-agent event streaming ✅

Problem

SubAgentActivity only exposed basic activity types (idle, requesting_llm, calling_tool) with minimal data. There was no way to access:

  • LLM thinking/reasoning text as it streams
  • Tool call arguments (input parameters)
  • Tool call results (output/response)
  • Text output deltas from the sub-agent

Solution

  • Added event_tx field to SubAgentHandle to enable event subscriptions
  • Added events() method to SubAgentHandle that returns a filtered event stream
  • Forward TextDelta and TurnStart events as SubAgentInternalEvent in wrapper
  • Updated spawn_subagent() to pass event transmitter to handle

Usage Example

# Option A: iterator on handle
handle = orchestrator.spawn_subagent(config)
for event in handle.events():  # non-blocking iterator
    if event.type == EventType.TOOL_START:
        print(f"Tool: {event.tool_name}, Args: {event.args}")
    elif event.type == EventType.TOOL_END:
        print(f"Result: {event.result}")
    elif event.type == EventType.TEXT_DELTA:
        print(event.text, end="")

Issue 2: Fine-grained permissive control ✅

Problem

SubAgentConfig(permissive=True) completely bypassed the agent .md file's permissions.deny lists. There was no middle ground - it was all-or-nothing.

Solution

  • Added permissive_deny field to both SubAgentConfig and AgentSlot
  • Added with_permissive_deny() builder methods
  • Modified wrapper to build permissive policy that respects deny rules from:
    • The permissive_deny config field
    • The agent definition's deny rules

Usage Example

# Option A: permissive respects deny rules from agent definition
SubAgentConfig(
    agent_type="my-agent",
    prompt="...",
    permissive=True,  # allow all tools EXCEPT those in agent's deny list
)

# Option B: permissive with explicit exceptions
SubAgentConfig(
    agent_type="my-agent",
    prompt="...",
    permissive=True,
    permissive_deny=["mcp__longvt__*"],  # block specific tools even in permissive mode
)

SDK Updates

Both Python and Node.js SDKs have been updated to expose the new permissive_deny parameter:

Python:

config = SubAgentConfig(
    agent_type="general",
    prompt="Analyze code",
    permissive=True,
    permissive_deny=["mcp__longvt__*"]
)

Node.js:

const config: SubAgentConfig = {
    agent_type: "general",
    prompt: "Analyze code",
    permissive: true,
    permissive_deny: ["mcp__longvt__*"]
};

Files Changed

  • core/src/orchestrator/config.rs - Added permissive_deny field and builders
  • core/src/orchestrator/handle.rs - Added event_tx and events() method
  • core/src/orchestrator/agent.rs - Pass event_tx to handle
  • core/src/orchestrator/wrapper.rs - Forward events, fix permissive mode
  • sdk/python/src/lib.rs - Expose permissive_deny parameter
  • sdk/node/src/lib.rs - Expose permissive_deny parameter

Testing

The changes maintain backward compatibility:

  • Existing code without permissive_deny continues to work (defaults to empty list)
  • Existing code without calling events() continues to work
  • The permissive mode behavior is improved but doesn't break existing usage

Breaking Changes

None. All changes are additive and backward compatible.

…trol

This commit addresses both issues raised in #5:

## Issue 1: Sub-agent event streaming

- Added `event_tx` field to `SubAgentHandle` to enable event subscriptions
- Added `events()` method to `SubAgentHandle` for filtered event streams
- Forward `TextDelta` and `TurnStart` events as `SubAgentInternalEvent` in wrapper
- Updated `spawn_subagent()` to pass event transmitter to handle

Now users can call `handle.events()` to get a stream of all events for that
specific sub-agent, including LLM thinking text, tool calls, and state changes.

## Issue 2: Fine-grained permissive control

- Added `permissive_deny` field to `SubAgentConfig` and `AgentSlot`
- Added `with_permissive_deny()` builder methods
- Modified wrapper to build permissive policy that respects deny rules
- When `permissive=true`, deny rules from both config and agent definition are enforced

Now users can use `permissive=true` for broad permissions while still blocking
specific tools via `permissive_deny` (e.g., ["mcp__longvt__*"]).

## SDK Updates

- Updated Python SDK to expose `permissive_deny` parameter
- Updated Node.js SDK to expose `permissive_deny` parameter

Both SDKs now support the new fine-grained permissive control.
@ZhiXiao-Lin ZhiXiao-Lin merged commit 7003323 into A3S-Lab:main Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Orchestrator API: sub-agent event streaming and fine-grained permissive control

1 participant