feat(miniapp): conductor status bubble and user-waiting state
- Conductor is now permanent (alive=true always); GC transitions to user_waiting state instead of hiding the character - Status emoji floats above conductor head: 🤔 thinking, ⌨ toolcall, ⏳ user_waiting - user_waiting renders with a subtle lavender glow (rgba 167,139,250) - _orchSetState accepts optional tool param; agent_state events now pass ev.tool - Secretary remains plan-mode-dependent (alive=false on GC) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ec0a90ef02
commit
3356993775
1 changed files with 24 additions and 2 deletions
|
|
@ -1826,6 +1826,7 @@ function _orchInitChars() {
|
||||||
_orchSecretary = _orchMakeChar('secretary', '👩💼', MAP_POSITIONS.secretary);
|
_orchSecretary = _orchMakeChar('secretary', '👩💼', MAP_POSITIONS.secretary);
|
||||||
_orchHeartbeat = _orchMakeChar('heartbeat', '🕊️', MAP_POSITIONS.heartbeat);
|
_orchHeartbeat = _orchMakeChar('heartbeat', '🕊️', MAP_POSITIONS.heartbeat);
|
||||||
_orchConductor.alive = true; _orchSecretary.alive = true; _orchHeartbeat.alive = true;
|
_orchConductor.alive = true; _orchSecretary.alive = true; _orchHeartbeat.alive = true;
|
||||||
|
_orchConductor.statusText = null;
|
||||||
_orchHeartbeat.facing = 1; _orchHeartbeat.flipTimer = 0;
|
_orchHeartbeat.facing = 1; _orchHeartbeat.flipTimer = 0;
|
||||||
var ps = [{id:'s0',emoji:'🔍'},{id:'s1',emoji:'📊'},{id:'s2',emoji:'💻'},
|
var ps = [{id:'s0',emoji:'🔍'},{id:'s1',emoji:'📊'},{id:'s2',emoji:'💻'},
|
||||||
{id:'s3',emoji:'🔧'},{id:'s4',emoji:'🎯'}];
|
{id:'s3',emoji:'🔧'},{id:'s4',emoji:'🎯'}];
|
||||||
|
|
@ -1845,7 +1846,15 @@ function _orchSyncBadge(id, state, alive) {
|
||||||
+ (state==='toolcall'? ' toolcall' : '')
|
+ (state==='toolcall'? ' toolcall' : '')
|
||||||
+ (state==='waiting' ? ' waiting' : '');
|
+ (state==='waiting' ? ' waiting' : '');
|
||||||
}
|
}
|
||||||
function _orchSetState(c, state) { c.state=state; _orchSyncBadge(c.id, state, c.alive); }
|
function _orchSetState(c, state, tool) {
|
||||||
|
c.state=state; _orchSyncBadge(c.id, state, c.alive);
|
||||||
|
if (c === _orchConductor) {
|
||||||
|
if (state==='waiting') c.statusText='🤔';
|
||||||
|
else if (state==='toolcall') c.statusText='⌨';
|
||||||
|
else if (state==='user_waiting') c.statusText='⏳';
|
||||||
|
else c.statusText=null;
|
||||||
|
}
|
||||||
|
}
|
||||||
function _orchMoveTo(c, pos, cb) { c.target=pos; c._onArrive=cb||null; }
|
function _orchMoveTo(c, pos, cb) { c.target=pos; c._onArrive=cb||null; }
|
||||||
function _orchSay(c, text, ttl) { c.bubble={text:text, ttl:ttl||2200}; }
|
function _orchSay(c, text, ttl) { c.bubble={text:text, ttl:ttl||2200}; }
|
||||||
|
|
||||||
|
|
@ -1876,6 +1885,9 @@ function _orchGC(id) {
|
||||||
if (ch === _orchHeartbeat) {
|
if (ch === _orchHeartbeat) {
|
||||||
// Heartbeat pigeon is permanent — keep alive, just return to idle.
|
// Heartbeat pigeon is permanent — keep alive, just return to idle.
|
||||||
_orchSetState(ch,'idle');
|
_orchSetState(ch,'idle');
|
||||||
|
} else if (ch === _orchConductor) {
|
||||||
|
// Conductor is permanent — keep alive, show ⏳ waiting for user.
|
||||||
|
_orchSetState(ch,'user_waiting');
|
||||||
} else {
|
} else {
|
||||||
ch.alive=false; _orchSetState(ch,'idle');
|
ch.alive=false; _orchSetState(ch,'idle');
|
||||||
}
|
}
|
||||||
|
|
@ -1920,6 +1932,12 @@ function _orchUpdate(dt) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function _orchDrawStatus(c) {
|
||||||
|
if (!c.statusText) return;
|
||||||
|
var yOff=_orchBOB[c.frame], cx=Math.floor(c.x), cy=Math.floor(c.y+yOff)-20;
|
||||||
|
orchCtx.font='11px serif'; orchCtx.textAlign='center'; orchCtx.textBaseline='middle';
|
||||||
|
orchCtx.fillText(c.statusText, cx, cy);
|
||||||
|
}
|
||||||
function _orchDrawBubble(c) {
|
function _orchDrawBubble(c) {
|
||||||
if (!c.bubble) return;
|
if (!c.bubble) return;
|
||||||
var yOff=_orchBOB[c.frame], bx=c.x, by=c.y+yOff-18;
|
var yOff=_orchBOB[c.frame], bx=c.x, by=c.y+yOff-18;
|
||||||
|
|
@ -1941,6 +1959,9 @@ function _orchDrawChar(c) {
|
||||||
} else if (c.state==='waiting'){
|
} else if (c.state==='waiting'){
|
||||||
orchCtx.fillStyle='rgba(96,165,250,0.25)'; orchCtx.beginPath();
|
orchCtx.fillStyle='rgba(96,165,250,0.25)'; orchCtx.beginPath();
|
||||||
orchCtx.arc(cx,cy,11,0,Math.PI*2); orchCtx.fill();
|
orchCtx.arc(cx,cy,11,0,Math.PI*2); orchCtx.fill();
|
||||||
|
} else if (c.state==='user_waiting'){
|
||||||
|
orchCtx.fillStyle='rgba(167,139,250,0.18)'; orchCtx.beginPath();
|
||||||
|
orchCtx.arc(cx,cy,10,0,Math.PI*2); orchCtx.fill();
|
||||||
}
|
}
|
||||||
orchCtx.font='18px serif'; orchCtx.textAlign='center'; orchCtx.textBaseline='middle';
|
orchCtx.font='18px serif'; orchCtx.textAlign='center'; orchCtx.textBaseline='middle';
|
||||||
if (c.facing === -1) {
|
if (c.facing === -1) {
|
||||||
|
|
@ -1954,6 +1975,7 @@ function _orchDrawChar(c) {
|
||||||
orchCtx.font='6px Silkscreen,monospace'; orchCtx.textAlign='center'; orchCtx.textBaseline='top';
|
orchCtx.font='6px Silkscreen,monospace'; orchCtx.textAlign='center'; orchCtx.textBaseline='top';
|
||||||
orchCtx.fillStyle=c.state==='talking'?'#facc15':'#3a4a7a';
|
orchCtx.fillStyle=c.state==='talking'?'#facc15':'#3a4a7a';
|
||||||
orchCtx.fillText(c.id.toUpperCase(), cx, cy+11);
|
orchCtx.fillText(c.id.toUpperCase(), cx, cy+11);
|
||||||
|
_orchDrawStatus(c);
|
||||||
_orchDrawBubble(c);
|
_orchDrawBubble(c);
|
||||||
}
|
}
|
||||||
function _orchRender(ts) {
|
function _orchRender(ts) {
|
||||||
|
|
@ -1995,7 +2017,7 @@ function connectOrchWs() {
|
||||||
} else if (msg.type==='event') {
|
} else if (msg.type==='event') {
|
||||||
var ev=msg.event||{};
|
var ev=msg.event||{};
|
||||||
if (ev.type==='agent_spawn') _orchSpawn(ev.id);
|
if (ev.type==='agent_spawn') _orchSpawn(ev.id);
|
||||||
if (ev.type==='agent_state') { var c=_orchCharForId(ev.id); if(c) _orchSetState(c,ev.state); }
|
if (ev.type==='agent_state') { var c=_orchCharForId(ev.id); if(c) _orchSetState(c,ev.state,ev.tool); }
|
||||||
if (ev.type==='agent_gc') _orchGC(ev.id);
|
if (ev.type==='agent_gc') _orchGC(ev.id);
|
||||||
if (ev.type==='conversation') _orchConverse(ev.from, ev.to, ev.text);
|
if (ev.type==='conversation') _orchConverse(ev.from, ev.to, ev.text);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue