From 165725fea8a16ef770a44a7102e7db034578d0d5 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Fri, 14 Aug 2026 14:55:17 +0200 Subject: [PATCH] subagent_spawn: rewrite to use 9P agent/new rdwr Replace D-Bus fire-and-forget with blocking ollie-9p rdwr to agent/new. The tool now: - Blocks until the sub-agent completes - Returns the sub-agent's reply directly - Scope: read (multiple spawns run in parallel) - Tier: hot Removed: D-Bus dependency, session renaming, JIT config cleanup. --- data/tools/subagent_spawn | 70 ++++++++++++---------------------- data/tools/subagent_spawn.meta | 14 ++++--- 2 files changed, 32 insertions(+), 52 deletions(-) diff --git a/data/tools/subagent_spawn b/data/tools/subagent_spawn index f776eb3..592ca3e 100755 --- a/data/tools/subagent_spawn +++ b/data/tools/subagent_spawn @@ -1,67 +1,45 @@ #!/usr/bin/env bash -# args_json: {"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Task prompt for the subagent"},"name":{"type":"string","description":"Subagent name (optional)"},"agent":{"type":"string","description":"Agent config (optional)"},"backend":{"type":"string","description":"Backend (optional)"},"model":{"type":"string","description":"Model (optional)"},"cwd":{"type":"string","description":"Working directory (optional)"}}} +# args_json: {"type":"object","required":["prompt"],"properties":{"prompt":{"type":"string","description":"Task prompt for the subagent"},"name":{"type":"string","description":"Subagent display name (optional)"},"profile":{"type":"string","description":"Agent profile (optional, default: default)"},"backend":{"type":"string","description":"Backend (optional)"},"model":{"type":"string","description":"Model (optional)"},"cwd":{"type":"string","description":"Working directory (optional, default: current)"}}} # ollie:prompt # ## subagent_spawn # -# Spawn an independent subagent session with a prompt. Returns immediately. +# Spawn a sub-agent with a task. Blocks until the sub-agent completes and returns its reply. +# The sub-agent gets its own context window and tool access. It is destroyed when done. # # ``` -# subagent_spawn(prompt="implement the login page", name="worker") -# subagent_spawn(prompt="fix the tests in auth/") +# subagent_spawn(prompt="fix the failing tests in auth/") +# subagent_spawn(prompt="implement the login page", cwd="/home/user/project", model="sonnet") # ``` # -# **Returns**: session ID, backend, model. +# Multiple subagent_spawn calls in the same turn run in parallel automatically. # ollie:end +# ollie:scope read +# ollie:tier hot set -euo pipefail source "$(dirname "$0")/_lib/args.sh" -SERVICE="org.ollie.SessionManager" -OBJ="/org/ollie/SessionManager" -IFACE="org.ollie.SessionManager" - -die() { echo "error: $1" >&2; exit 1; } - -dbus_call() { - dbus-send --session --dest=$SERVICE --type=method_call --print-reply \ - $OBJ "$IFACE.$1" "${@:2}" 2>/dev/null -} - -dbus_string() { - dbus_call "$@" | awk -F'"' '/string "/{print $2; exit}' -} - prompt_text=$(arg_require "prompt") -name=$(arg_get "name" "$(/bin/date +%s%N)-$$") -agent=$(arg_get "agent" "default") +name=$(arg_get "name" "") +profile=$(arg_get "profile" "default") backend=$(arg_get "backend" "") model=$(arg_get "model" "") cwd=$(arg_get "cwd" "$(pwd)") -# Prefix with parent session ID for global uniqueness. -[ -n "${OLLIE_SESSION_ID:-}" ] && name="${OLLIE_SESSION_ID}__${name}" +# Escape newlines in prompt for the key=value wire format. +escaped_prompt=$(printf '%s' "$prompt_text" | sed 's/\\/\\\\/g; s/$/\\n/' | tr -d '\n' | sed 's/\\n$//') -prompt="[parent_session_id=${OLLIE_SESSION_ID:-}] -[session_id=${name}] -${prompt_text}" +# Build the payload. +payload="cwd=${cwd} +profile=${profile} +prompt=${escaped_prompt}" -# Create session via D-Bus -session_id=$(dbus_string CreateSession \ - string:"$cwd" string:"$backend" string:"$model" string:"$agent" string:"" string:"") +[ -n "$name" ] && payload="${payload} +name=${name}" +[ -n "$backend" ] && payload="${payload} +backend=${backend}" +[ -n "$model" ] && payload="${payload} +model=${model}" -[ -z "$session_id" ] && die "failed to create session" - -# Rename to our chosen name -dbus_call RenameSession string:"$session_id" string:"$name" > /dev/null 2>&1 - -# Submit prompt -dbus_call Submit string:"$session_id" string:"$prompt" > /dev/null 2>&1 || die "failed to submit prompt" - -# Clean up JIT agent config -[[ "${agent:-}" == jit-* ]] && rm -f "$HOME/.config/ollie/agents/${agent}.json" 2>/dev/null || true - -# Report resolved values -config=$(dbus_string GetConfig string:"$session_id") -resolved_backend=$(printf '%s\n' "$config" | grep -m1 '^backend=' | cut -d= -f2- || echo "${backend:-default}") -resolved_model=$(printf '%s\n' "$config" | grep -m1 '^model=' | cut -d= -f2- || echo "${model:-default}") -printf 'session=%s\nbackend=%s\nmodel=%s\n' "$name" "$resolved_backend" "$resolved_model" +# rdwr to agent/new: blocks until sub-agent completes, returns reply. +printf '%s\n' "$payload" | ollie-9p rdwr "session/${OLLIE_SESSION_ID}/agent/new" diff --git a/data/tools/subagent_spawn.meta b/data/tools/subagent_spawn.meta index 5d1bdf5..82ff98d 100644 --- a/data/tools/subagent_spawn.meta +++ b/data/tools/subagent_spawn.meta @@ -1,6 +1,8 @@ { - "description": "Spawn an independent subagent session with a prompt. Returns immediately.", - "prompt": "## subagent_spawn\n\nSpawn an independent subagent session with a prompt. Returns immediately.\n\n```\nsubagent_spawn(prompt=\"implement the login page\", name=\"worker\")\nsubagent_spawn(prompt=\"fix the tests in auth/\")\n```\n\n**Returns**: session ID, backend, model.", + "description": "Spawn a sub-agent with a task. Blocks until done, returns the reply.", + "prompt": "## subagent_spawn\n\nSpawn a sub-agent with a task. Blocks until the sub-agent completes and returns its reply.\nThe sub-agent gets its own context window and tool access. It is destroyed when done.\n\n```\nsubagent_spawn(prompt=\"fix the failing tests in auth/\")\nsubagent_spawn(prompt=\"implement the login page\", cwd=\"/home/user/project\", model=\"sonnet\")\n```\n\nMultiple subagent_spawn calls in the same turn run in parallel automatically.", + "scope": "read", + "tier": "hot", "args": { "type": "object", "required": [ @@ -13,11 +15,11 @@ }, "name": { "type": "string", - "description": "Subagent name (optional)" + "description": "Subagent display name (optional)" }, - "agent": { + "profile": { "type": "string", - "description": "Agent config (optional)" + "description": "Agent profile (optional, default: default)" }, "backend": { "type": "string", @@ -29,7 +31,7 @@ }, "cwd": { "type": "string", - "description": "Working directory (optional)" + "description": "Working directory (optional, default: current)" } } }