thinkpool-pair 0.7.224 → 0.7.226
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/account.mjs +4 -4
- package/bridge.mjs +10 -7
- package/event-bounds.mjs +1 -1
- package/package.json +1 -1
package/account.mjs
CHANGED
|
@@ -778,7 +778,7 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
778
778
|
if (!tc || roomPartner.get(target) !== partnerUid) return reply({ error: `Room ${target} is not a room this device shares with you.` })
|
|
779
779
|
const reqId = randomUUID()
|
|
780
780
|
pairPending.set(reqId, { reply: (mm) => reply({ ok: mm.ok, ref: mm.ref, error: mm.error }), askerRoom: null })
|
|
781
|
-
try { tc.send({ t: 'pair-post-local', reqId, fromRoom: payload.fromRoom, fromHost: payload.fromHost, text: payload.text, terminal: payload.terminal }) }
|
|
781
|
+
try { tc.send({ t: 'pair-post-local', reqId, fromRoom: payload.fromRoom, fromHost: payload.fromHost, fromTerminalName: payload.fromTerminalName, text: payload.text, terminal: payload.terminal }) }
|
|
782
782
|
catch { pairPending.delete(reqId); reply({ error: `Could not reach room ${target}.` }) }
|
|
783
783
|
}
|
|
784
784
|
// Join the per-pair bus for `partnerUid` (idempotent). The channel is PRIVATE so
|
|
@@ -801,7 +801,7 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
801
801
|
// Forward a local child's cross-room request to the bus (Tier 2 peek / Tier 3 post)
|
|
802
802
|
// when the target room is NOT served on this machine. Used inside the child handler.
|
|
803
803
|
const busPeek = (targetRoom, terminal, lines) => busRequestFirst('peer-peek-req', { targetRoom, terminal, lines }, CROSSROOM_BUS.busTimeoutMs)
|
|
804
|
-
const busPost = (targetRoom, terminal, text, fromRoom) => busRequestFirst('peer-post-req', { targetRoom, terminal, text, fromRoom, fromHost: machine }, 180_000)
|
|
804
|
+
const busPost = (targetRoom, terminal, text, fromRoom, fromTerminalName) => busRequestFirst('peer-post-req', { targetRoom, terminal, text, fromRoom, fromHost: machine, fromTerminalName }, 180_000)
|
|
805
805
|
|
|
806
806
|
// Re-entrancy guard: bind-room fires tick() AND a 15s interval fires tick(); tick
|
|
807
807
|
// awaits a code_sessions query before children.set(), so two overlapping runs can
|
|
@@ -953,13 +953,13 @@ export async function runAccount(SUPABASE_URL, SUPABASE_ANON) {
|
|
|
953
953
|
if (tc) { // LOCAL target — the target child raises its own receipt card
|
|
954
954
|
const reqId = randomUUID()
|
|
955
955
|
pairPending.set(reqId, { reply: (mm) => reply({ ok: mm.ok, ref: mm.ref, error: mm.error }), askerRoom: room })
|
|
956
|
-
try { tc.send({ t: 'pair-post-local', reqId, fromRoom: room, fromHost: machine, text: m.text, terminal: m.terminal }) }
|
|
956
|
+
try { tc.send({ t: 'pair-post-local', reqId, fromRoom: room, fromHost: machine, fromTerminalName: m.fromTerminalName, text: m.text, terminal: m.terminal }) }
|
|
957
957
|
catch { pairPending.delete(reqId); reply({ error: `Could not reach session ${target}.` }) }
|
|
958
958
|
return
|
|
959
959
|
}
|
|
960
960
|
// REMOTE target — over the pair bus.
|
|
961
961
|
if (!pairChannels.size) return reply({ error: `Room ${target} is not on this machine, and no pair bus is open to reach it.` })
|
|
962
|
-
const res = await busPost(target, m.terminal, m.text, room)
|
|
962
|
+
const res = await busPost(target, m.terminal, m.text, room, m.fromTerminalName)
|
|
963
963
|
if (!res) return reply({ error: `Room ${target} did not respond to the hand-off in time.` })
|
|
964
964
|
reply({ ok: res.ok, ref: res.ref, error: res.error })
|
|
965
965
|
})()
|
package/bridge.mjs
CHANGED
|
@@ -1123,7 +1123,7 @@ function raiseCard(entry, req) {
|
|
|
1123
1123
|
// the target agent lane, raise the receipt card, and on approval inject the turn one
|
|
1124
1124
|
// room-hop deep (so the reached agent can read/peek but cannot post onward to a third
|
|
1125
1125
|
// room — crossRoomPostDecision blocks roomHop≥1). Returns { ok, ref } or { error }.
|
|
1126
|
-
async function receiveCrossRoomPost({ fromRoom, fromHost, text, terminal }) {
|
|
1126
|
+
async function receiveCrossRoomPost({ fromRoom, fromHost, fromTerminalName, text, terminal }) {
|
|
1127
1127
|
if (process.env.TP_PAIRBUS_OFF === '1') return { error: 'Cross-room posting is turned off in this room.' }
|
|
1128
1128
|
const body = String(text || '').trim()
|
|
1129
1129
|
if (!body) return { error: 'Empty cross-room post ignored.' }
|
|
@@ -1145,13 +1145,13 @@ async function receiveCrossRoomPost({ fromRoom, fromHost, text, terminal }) {
|
|
|
1145
1145
|
if (!te?.session) return { error: `That terminal in room ${room} is no longer live.` }
|
|
1146
1146
|
const fromLabel = `${fromRoom}${fromHost ? ` on ${fromHost}` : ''}`
|
|
1147
1147
|
let decision = 'deny'
|
|
1148
|
-
try { decision = await raiseCard(te, { id: randomUUID(), toolName: 'mcp__thinkpool__post_to_session', input: { session: fromRoom, host: fromHost, text: body, incoming: true }, risk: 'high' }) } catch { decision = 'deny' }
|
|
1148
|
+
try { decision = await raiseCard(te, { id: randomUUID(), toolName: 'mcp__thinkpool__post_to_session', input: { session: fromRoom, host: fromHost, terminalName: fromTerminalName, text: body, incoming: true }, risk: 'high' }) } catch { decision = 'deny' }
|
|
1149
1149
|
if (decision !== 'allow') return { error: `The people in room ${room} declined the incoming task from ${fromLabel}.` }
|
|
1150
1150
|
// Injected turn: one room-hop deep, fresh in-room budgets (the loop-breaker reset
|
|
1151
1151
|
// point is code-turn — a real human turn — which this is NOT, so the deeper hop sticks).
|
|
1152
1152
|
te.roomHop = 1; te.hop = (te.hop || 0) + 1; te.peekCount = 0; te.postCount = 0; te.pairPeekCount = 0; te.crossRoomPostCount = 0
|
|
1153
1153
|
const msg = `[From: room ${fromLabel} — relayed via the ThinkPool cross-room Ensemble, approved by a person in this room]\n${body}`
|
|
1154
|
-
const evt = { kind: 'you', text: msg, by: `room ${fromRoom}`, crosspost: true }
|
|
1154
|
+
const evt = { kind: 'you', text: msg, by: `room ${fromRoom}`, crosspost: true, relaySourceName: String(fromTerminalName || '').trim().slice(0, 80) || undefined }
|
|
1155
1155
|
stampEvent(evt); pushLog(te, evt); bcast('code-event', { term: targetId, evt })
|
|
1156
1156
|
try { te.session.sendTurn(msg) } catch { return { error: `Could not deliver to room ${room} — the lane may have just closed.` } }
|
|
1157
1157
|
return { ok: true, ref: String(targetId).slice(0, 8) }
|
|
@@ -1671,8 +1671,11 @@ function openStructured({ id, runtime = 'claude', model, effort, resume, log, co
|
|
|
1671
1671
|
// `claude-fable-5` → 400 [1211][Unknown Model]. One value, one truth.
|
|
1672
1672
|
// undefined → omit the SDK option entirely and let the provider env/endpoint default.
|
|
1673
1673
|
const codexModels = runtime === 'codex' ? readCodexModels() : []
|
|
1674
|
+
const codexRequestedModel = runtime === 'codex' ? (model || readCodexDefaultModel() || undefined) : undefined
|
|
1674
1675
|
const laneModel = runtime === 'codex'
|
|
1675
|
-
?
|
|
1676
|
+
? (codexRequestedModel
|
|
1677
|
+
? resolveCodexModel(codexRequestedModel, codexModels)
|
|
1678
|
+
: flowLaneModelFor({ sliceType: 'feature', runtime: 'codex', catalog: codexModels }))
|
|
1676
1679
|
: effectiveLaneModel({ provider, model, configuredModel: resolveProviderEnv(provider)?.ANTHROPIC_MODEL })
|
|
1677
1680
|
// spawnedBy: set when this lane was Dispatched (spawn_terminal). Restored from the
|
|
1678
1681
|
// session store so the Ensemble flag survives a bridge restart (else a respin
|
|
@@ -2044,7 +2047,7 @@ function openStructured({ id, runtime = 'claude', model, effort, resume, log, co
|
|
|
2044
2047
|
entry.crossRoomPostCount = (entry.crossRoomPostCount || 0) + 1
|
|
2045
2048
|
// Generous timeout: the TARGET room's person must approve a receipt card,
|
|
2046
2049
|
// which can take a while. Fails soft (never hangs the turn) past the window.
|
|
2047
|
-
const res = await pairRequest('pair-post-req', { targetRoom: target, terminal: args?.terminal, text, fromRoom: room }, 180_000)
|
|
2050
|
+
const res = await pairRequest('pair-post-req', { targetRoom: target, terminal: args?.terminal, text, fromRoom: room, fromTerminalName: termNames[id] || undefined }, 180_000)
|
|
2048
2051
|
if (res?.error) return okText(res.error)
|
|
2049
2052
|
return okText(res?.ok ? `Delivered to room ${target}${res.ref ? ` (lane ${res.ref})` : ''} — it will respond in its own room; check back with read_session.` : `Room ${target} did not accept the message.`)
|
|
2050
2053
|
},
|
|
@@ -2084,7 +2087,7 @@ function openStructured({ id, runtime = 'claude', model, effort, resume, log, co
|
|
|
2084
2087
|
te.postCount = 0
|
|
2085
2088
|
// Echo the injected prompt into the TARGET lane so both people see what
|
|
2086
2089
|
// arrived (rides the existing code-event 'you' path — no new topic).
|
|
2087
|
-
const evt = { kind: 'you', text: msg, by: `terminal ${fromRef} (agent)`, crosspost: true }
|
|
2090
|
+
const evt = { kind: 'you', text: msg, by: `terminal ${fromRef} (agent)`, crosspost: true, relaySourceName: termNames[id] || undefined }
|
|
2088
2091
|
stampEvent(evt)
|
|
2089
2092
|
pushLog(te, evt)
|
|
2090
2093
|
bcast('code-event', { term: target.id, evt })
|
|
@@ -2174,7 +2177,7 @@ function openStructured({ id, runtime = 'claude', model, effort, resume, log, co
|
|
|
2174
2177
|
// to any lane still resets it to hop 0 (code-turn). Mirrors Tier C injection.
|
|
2175
2178
|
ne.hop = (entry.hop || 0) + 1; ne.peekCount = 0; ne.postCount = 0; ne.spawnTimes = []
|
|
2176
2179
|
const msg = `[Task from terminal ${fromRef}'s agent — relayed via ThinkPool cross-terminal; you are a fresh lane it opened for you]\n${args.task}`
|
|
2177
|
-
const evt = { kind: 'you', text: msg, by: `terminal ${fromRef} (agent)`, crosspost: true }
|
|
2180
|
+
const evt = { kind: 'you', text: msg, by: `terminal ${fromRef} (agent)`, crosspost: true, relaySourceName: termNames[id] || undefined }
|
|
2178
2181
|
stampEvent(evt); pushLog(ne, evt); bcast('code-event', { term: newId, evt })
|
|
2179
2182
|
try { ne.session.sendTurn(msg) } catch { return okText(`Opened lane ${newRef}${args?.name ? ` ("${args.name}")` : ''}, but it may still be starting — could not hand off the task. Try post_to_terminal shortly.`) }
|
|
2180
2183
|
return okText(`Opened agent lane ${newRef}${args?.name ? ` ("${args.name}")` : ''} and handed it the task. It runs in its own lane — check back with read_terminal, then close_terminal when done.`)
|
package/event-bounds.mjs
CHANGED
|
@@ -83,7 +83,7 @@ export function boundStructuredEvent(event, cap = STRUCTURED_EVENT_CAP) {
|
|
|
83
83
|
|
|
84
84
|
// Hard fallback: retain ordering/dedup identity and recognisable tool blocks.
|
|
85
85
|
const identity = {}
|
|
86
|
-
for (const key of ['kind', 'seq', 'cid', 'ts', 'term', 'toolUseId', 'isError']) {
|
|
86
|
+
for (const key of ['kind', 'seq', 'cid', 'ts', 'term', 'toolUseId', 'isError', 'by', 'crosspost', 'relaySourceName']) {
|
|
87
87
|
if (out[key] != null) identity[key] = out[key]
|
|
88
88
|
}
|
|
89
89
|
if (Array.isArray(out.blocks)) identity.blocks = out.blocks.slice(0, 4).map(block => compactBlock(block, 6000))
|