fix(fleet): export MOSAIC_AGENT_CLASS into the agent pane so personas inject
A3a/A3b ship a per-agent persona contract that the launcher composes from process.env.MOSAIC_AGENT_CLASS (compose-contract -> readPersonaContractBlock, launch.js). generateAgentEnv already writes MOSAIC_AGENT_CLASS to agents/<name>.env, but start-agent-session.sh only re-exported MOSAIC_AGENT_NAME into the pane snippet — never the class. The pane inherits the tmux SERVER environment, not this script's env nor the systemd unit's EnvironmentFile, so the class set in the .env was invisible in-pane. The launcher then saw an undefined class and silently injected NO persona contract: every fleet agent came up class-less while `fleet ps` reported healthy. The comms block kept working only because it keys on MOSAIC_AGENT_NAME (which IS re-exported). Fix: re-export MOSAIC_AGENT_CLASS into PANE_SHELL_SNIPPET exactly as MOSAIC_AGENT_NAME, %q-quoted (empty/unset class -> '' is a harmless no-op, matching readPersonaContractBlock's empty-class contract). Verified live: a relaunched agent now carries MOSAIC_AGENT_CLASS in its pane env and the matching `# Persona Contract (<class>)` block in its composed prompt. Adds a regression guard to test-start-agent-session.sh asserting the pane snippet exports both MOSAIC_AGENT_NAME and the per-agent MOSAIC_AGENT_CLASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -114,10 +114,21 @@ MOSAIC_RUNTIME_BIN_PREFIX=$(_build_runtime_bin_prefix)
|
||||
# safe single bash token regardless of the name's characters.
|
||||
AGENT_NAME_Q=$(printf '%q' "$AGENT_NAME")
|
||||
|
||||
# MOSAIC_AGENT_CLASS must ALSO be exported INTO the pane, for the same reason as
|
||||
# MOSAIC_AGENT_NAME above: the pane inherits the tmux SERVER environment (not this
|
||||
# script's env, and not the systemd unit's EnvironmentFile), so the per-agent class
|
||||
# written to agents/<name>.env would otherwise be invisible in-pane. The launcher
|
||||
# composes the persona contract from process.env.MOSAIC_AGENT_CLASS at launch
|
||||
# (compose-contract -> readPersonaContractBlock); without this export it sees an
|
||||
# undefined class and silently injects NO persona contract. %q-quote it so it is a
|
||||
# safe single bash token; an empty/unset class %q-quotes to '' and is a harmless
|
||||
# no-op downstream (readPersonaContractBlock returns '' for an empty class).
|
||||
AGENT_CLASS_Q=$(printf '%q' "${MOSAIC_AGENT_CLASS:-}")
|
||||
|
||||
if [ -n "$MOSAIC_RUNTIME_BIN_PREFIX" ]; then
|
||||
PANE_SHELL_SNIPPET="export MOSAIC_AGENT_NAME=${AGENT_NAME_Q}; export PATH=\"${MOSAIC_RUNTIME_BIN_PREFIX}:\${PATH}\"; exec ${MOSAIC_AGENT_COMMAND}"
|
||||
PANE_SHELL_SNIPPET="export MOSAIC_AGENT_NAME=${AGENT_NAME_Q}; export MOSAIC_AGENT_CLASS=${AGENT_CLASS_Q}; export PATH=\"${MOSAIC_RUNTIME_BIN_PREFIX}:\${PATH}\"; exec ${MOSAIC_AGENT_COMMAND}"
|
||||
else
|
||||
PANE_SHELL_SNIPPET="export MOSAIC_AGENT_NAME=${AGENT_NAME_Q}; exec ${MOSAIC_AGENT_COMMAND}"
|
||||
PANE_SHELL_SNIPPET="export MOSAIC_AGENT_NAME=${AGENT_NAME_Q}; export MOSAIC_AGENT_CLASS=${AGENT_CLASS_Q}; exec ${MOSAIC_AGENT_COMMAND}"
|
||||
fi
|
||||
|
||||
mkdir -p "$MOSAIC_AGENT_WORKDIR"
|
||||
|
||||
Reference in New Issue
Block a user