@sjawhar/pi-legion-envoy 6.0.2 → 6.0.4
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/dist/envoy.js +52 -29
- package/dist/legion.js +42 -21
- package/package.json +1 -1
package/dist/envoy.js
CHANGED
|
@@ -35463,7 +35463,7 @@ function sourceSession(sessionID) {
|
|
|
35463
35463
|
}
|
|
35464
35464
|
|
|
35465
35465
|
// extensions/envoy.ts
|
|
35466
|
-
import { logger } from "@oh-my-pi/pi-utils";
|
|
35466
|
+
import { logger as logger2 } from "@oh-my-pi/pi-utils";
|
|
35467
35467
|
var import_nats2 = __toESM(require_mod4(), 1);
|
|
35468
35468
|
|
|
35469
35469
|
// src/agent-stream.ts
|
|
@@ -35941,33 +35941,56 @@ function sideTurn(pi, context) {
|
|
|
35941
35941
|
import fs from "fs";
|
|
35942
35942
|
import path3 from "path";
|
|
35943
35943
|
import * as host from "@oh-my-pi/pi-coding-agent";
|
|
35944
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
35944
35945
|
var LEGION_BOOTSTRAPPED_SESSION = Symbol.for("legion.pi-envoy.bootstrapped-session");
|
|
35945
35946
|
var bootstrappedSessionStore = globalThis;
|
|
35946
35947
|
function recordBootstrappedSession(sessionFile) {
|
|
35947
35948
|
bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION] = sessionFile;
|
|
35948
35949
|
}
|
|
35949
35950
|
async function isSubagentSession(context) {
|
|
35950
|
-
|
|
35951
|
+
const registered = registeredSubagent(context);
|
|
35952
|
+
if (registered !== undefined)
|
|
35953
|
+
return { subagent: registered, settled: true };
|
|
35954
|
+
try {
|
|
35955
|
+
await context.sessionManager.ensureOnDisk();
|
|
35956
|
+
} catch (error48) {
|
|
35957
|
+
const subagent = transcriptSaysSubagent(context);
|
|
35958
|
+
logger.warn("subagent check: publishing the transcript failed; answered from the transcript on disk, and the next call asks again", { sessionFile: context.sessionManager.getSessionFile(), subagent, error: messageFor(error48) });
|
|
35959
|
+
return { subagent, settled: false };
|
|
35960
|
+
}
|
|
35961
|
+
return { subagent: transcriptSaysSubagent(context), settled: true };
|
|
35962
|
+
}
|
|
35963
|
+
function transcriptSaysSubagent(context) {
|
|
35951
35964
|
const sessionFile = context.sessionManager.getSessionFile();
|
|
35952
|
-
if (sessionFile !== undefined
|
|
35953
|
-
|
|
35965
|
+
if (sessionFile !== undefined) {
|
|
35966
|
+
if (fs.existsSync(`${path3.dirname(sessionFile)}.jsonl`))
|
|
35967
|
+
return true;
|
|
35968
|
+
if (fs.existsSync(sessionFile))
|
|
35969
|
+
return false;
|
|
35954
35970
|
}
|
|
35955
35971
|
const bootstrapped = bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION];
|
|
35956
35972
|
return bootstrapped !== undefined && bootstrapped !== sessionFile;
|
|
35957
35973
|
}
|
|
35958
|
-
function
|
|
35974
|
+
function registeredSubagent(context) {
|
|
35959
35975
|
const registry2 = host.AgentRegistry?.global();
|
|
35960
35976
|
if (registry2 === undefined)
|
|
35961
|
-
return
|
|
35977
|
+
return;
|
|
35962
35978
|
const sessionID = context.sessionManager.getSessionId();
|
|
35963
35979
|
const sessionFile = context.sessionManager.getSessionFile();
|
|
35964
|
-
|
|
35980
|
+
const own = registry2.list().filter((ref) => ref.session === null ? sessionFile !== undefined && ref.sessionFile === sessionFile : ref.session.sessionManager.getSessionId() === sessionID);
|
|
35981
|
+
if (own.length === 0)
|
|
35982
|
+
return;
|
|
35983
|
+
return own.some((ref) => ref.kind !== "main");
|
|
35965
35984
|
}
|
|
35966
35985
|
function subagentSessionCheck() {
|
|
35967
|
-
let
|
|
35968
|
-
return (context) => {
|
|
35969
|
-
|
|
35970
|
-
|
|
35986
|
+
let settled;
|
|
35987
|
+
return async (context) => {
|
|
35988
|
+
if (settled !== undefined)
|
|
35989
|
+
return settled;
|
|
35990
|
+
const answer = await isSubagentSession(context);
|
|
35991
|
+
if (answer.settled)
|
|
35992
|
+
settled = answer.subagent;
|
|
35993
|
+
return answer.subagent;
|
|
35971
35994
|
};
|
|
35972
35995
|
}
|
|
35973
35996
|
|
|
@@ -36127,7 +36150,7 @@ function resolveSkillsDirectory() {
|
|
|
36127
36150
|
var SKILLS_DIRECTORY = resolveSkillsDirectory();
|
|
36128
36151
|
var DISPATCH_FIRST_CONTEXT = readDispatchFirstContext(dispatchFirstSkillFile(SKILLS_DIRECTORY));
|
|
36129
36152
|
function envoyExtension(pi) {
|
|
36130
|
-
|
|
36153
|
+
logger2.debug("extension instance loaded", { extension: import.meta.url });
|
|
36131
36154
|
const defaults = envoyDefaultsFromEnvironment(process.env);
|
|
36132
36155
|
const dispatchConfig = resolveDispatchConfig(process.env, { cwd: process.cwd() });
|
|
36133
36156
|
const currentDispatchConfig = () => {
|
|
@@ -36190,7 +36213,7 @@ function envoyExtension(pi) {
|
|
|
36190
36213
|
if (selfCheckWarningSessionIDs.has(failedSessionID))
|
|
36191
36214
|
return;
|
|
36192
36215
|
selfCheckWarningSessionIDs.add(failedSessionID);
|
|
36193
|
-
|
|
36216
|
+
logger2.warn("envoy: run-end waiting self-check failed; no reminder was sent", {
|
|
36194
36217
|
sessionID: failedSessionID,
|
|
36195
36218
|
error: messageFor(error48)
|
|
36196
36219
|
});
|
|
@@ -36258,7 +36281,7 @@ function envoyExtension(pi) {
|
|
|
36258
36281
|
const { delivery } = rendered;
|
|
36259
36282
|
const key = handledAttemptKey(delivery.id, delivery.attempt);
|
|
36260
36283
|
if (handledDispatchAttempts.has(key)) {
|
|
36261
|
-
|
|
36284
|
+
logger2.warn("envoy: a frame names a Dispatch attempt this session already delivered; it arrives as a card", { attempt: delivery.attempt, messageID: delivery.id });
|
|
36262
36285
|
return;
|
|
36263
36286
|
}
|
|
36264
36287
|
handledDispatchAttempts.add(key);
|
|
@@ -36272,11 +36295,11 @@ function envoyExtension(pi) {
|
|
|
36272
36295
|
});
|
|
36273
36296
|
const turn = turnFromAccept(accepted);
|
|
36274
36297
|
if (turn === undefined) {
|
|
36275
|
-
|
|
36298
|
+
logger2.warn("envoy: Dispatch accepted a direct message without the stored body and mode to inject; it arrives as a card", { attempt: delivery.attempt, messageID: delivery.id });
|
|
36276
36299
|
}
|
|
36277
36300
|
return turn;
|
|
36278
36301
|
} catch (error48) {
|
|
36279
|
-
|
|
36302
|
+
logger2.warn("envoy: Dispatch did not accept a direct message as this session's turn; it arrives as a card", { attempt: delivery.attempt, messageID: delivery.id, error: messageFor(error48) });
|
|
36280
36303
|
return;
|
|
36281
36304
|
}
|
|
36282
36305
|
};
|
|
@@ -36435,7 +36458,7 @@ function envoyExtension(pi) {
|
|
|
36435
36458
|
continue;
|
|
36436
36459
|
connection?.publish(reply, codec2.encode(answer));
|
|
36437
36460
|
} catch (error48) {
|
|
36438
|
-
|
|
36461
|
+
logger2.warn("envoy: agent stream control message failed", {
|
|
36439
36462
|
error: messageFor(error48),
|
|
36440
36463
|
sessionID: session
|
|
36441
36464
|
});
|
|
@@ -36548,7 +36571,7 @@ function envoyExtension(pi) {
|
|
|
36548
36571
|
}
|
|
36549
36572
|
if (!result.claimed) {
|
|
36550
36573
|
endRole();
|
|
36551
|
-
|
|
36574
|
+
logger2.warn("envoy: role re-assertion refused; held by another live session", {
|
|
36552
36575
|
role,
|
|
36553
36576
|
sessionID: id,
|
|
36554
36577
|
holder: result.holder
|
|
@@ -36556,7 +36579,7 @@ function envoyExtension(pi) {
|
|
|
36556
36579
|
context.ui.notify(`envoy: role ${role} is now held by session ${result.holder}; this session no longer holds it`, "warning");
|
|
36557
36580
|
return;
|
|
36558
36581
|
}
|
|
36559
|
-
|
|
36582
|
+
logger2.warn("envoy: role re-asserted after the listener lost the claim", {
|
|
36560
36583
|
role,
|
|
36561
36584
|
sessionID: id,
|
|
36562
36585
|
previousHolder: holder ?? null
|
|
@@ -36567,7 +36590,7 @@ function envoyExtension(pi) {
|
|
|
36567
36590
|
if (regained === undefined)
|
|
36568
36591
|
return;
|
|
36569
36592
|
Promise.resolve().then(() => regained(role, reason)).catch((error48) => {
|
|
36570
|
-
|
|
36593
|
+
logger2.warn("envoy: role regain hook failed", { role, reason, error: messageFor(error48) });
|
|
36571
36594
|
});
|
|
36572
36595
|
};
|
|
36573
36596
|
const ensureHeartbeat = (context) => {
|
|
@@ -36624,7 +36647,7 @@ function envoyExtension(pi) {
|
|
|
36624
36647
|
previousSessionID: options.previousSessionID
|
|
36625
36648
|
});
|
|
36626
36649
|
if (!result.claimed) {
|
|
36627
|
-
|
|
36650
|
+
logger2.warn("envoy: role held by another live session; not reclaimed", {
|
|
36628
36651
|
role,
|
|
36629
36652
|
sessionID,
|
|
36630
36653
|
holder: result.holder
|
|
@@ -36679,7 +36702,7 @@ function envoyExtension(pi) {
|
|
|
36679
36702
|
return;
|
|
36680
36703
|
const continued = carryPreviousSessionRole && previousSessionID !== "" && previousSessionID !== sessionID ? previousSessionID : undefined;
|
|
36681
36704
|
await setEnvoyRole(role, { soft: true, previousSessionID: continued }).catch((error48) => {
|
|
36682
|
-
|
|
36705
|
+
logger2.warn("envoy: role reclaim failed", { role, sessionID, error: messageFor(error48) });
|
|
36683
36706
|
});
|
|
36684
36707
|
};
|
|
36685
36708
|
let sessionEstablishment = Promise.resolve();
|
|
@@ -36755,12 +36778,11 @@ function envoyExtension(pi) {
|
|
|
36755
36778
|
sessionID: () => activeSessionContext?.sessionManager.getSessionId() ?? sessionID
|
|
36756
36779
|
};
|
|
36757
36780
|
bridge.instances.push(claimInstance);
|
|
36758
|
-
const
|
|
36759
|
-
const
|
|
36760
|
-
const replyAddress = async (context, liveSessionID = "") => {
|
|
36781
|
+
const isSubagent = subagentSessionCheck();
|
|
36782
|
+
const replyAddress = async (context, liveSessionID = "", subagent) => {
|
|
36761
36783
|
if (sessionID !== "")
|
|
36762
36784
|
return liveSessionID || sessionID;
|
|
36763
|
-
if (!await isSubagent(context))
|
|
36785
|
+
if (!(subagent ?? await isSubagent(context)))
|
|
36764
36786
|
return liveSessionID;
|
|
36765
36787
|
return resolveEnvoySession(context.sessionManager.getSessionFile());
|
|
36766
36788
|
};
|
|
@@ -37125,14 +37147,15 @@ Warnings: ${warnings.join("; ")}`, {
|
|
|
37125
37147
|
}
|
|
37126
37148
|
case EnvoyToolOperation.publish: {
|
|
37127
37149
|
const topic = stringFor(parameters, "topic");
|
|
37128
|
-
const
|
|
37150
|
+
const inSubagent = await isSubagent(context);
|
|
37151
|
+
const source = await replyAddress(context, "", inSubagent);
|
|
37129
37152
|
const result = await client.publish({
|
|
37130
37153
|
sourceSessionID: source,
|
|
37131
37154
|
topic,
|
|
37132
37155
|
message: stringFor(parameters, "message"),
|
|
37133
37156
|
...toMessageMetadata(parameters)
|
|
37134
37157
|
});
|
|
37135
|
-
const undelivered = source !== "" && result.holder === source &&
|
|
37158
|
+
const undelivered = source !== "" && result.holder === source && inSubagent;
|
|
37136
37159
|
const published = result.holder === undefined ? `published ${result.envelope.event_id}` : `published ${result.envelope.event_id}; holder ${result.holder}`;
|
|
37137
37160
|
return toolSuccess(undelivered ? `${published}
|
|
37138
37161
|
Not delivered: that holder is the session this subagent sends as, and the listener drops a message whose source session is its recipient, so the agent that spawned you did not receive it. Reach it over hub instead.` : published, {
|
|
@@ -37153,7 +37176,7 @@ Not delivered: that holder is the session this subagent sends as, and the listen
|
|
|
37153
37176
|
}
|
|
37154
37177
|
case EnvoyToolOperation.whoami: {
|
|
37155
37178
|
const inSubagent = await isSubagent(context);
|
|
37156
|
-
const address = await replyAddress(context);
|
|
37179
|
+
const address = await replyAddress(context, "", inSubagent);
|
|
37157
37180
|
const subagent = inSubagent ? {
|
|
37158
37181
|
session_id: context.sessionManager.getSessionId(),
|
|
37159
37182
|
note: address === "" ? "This session is a task subagent and registers no Envoy session of its own, and this process records no top-level session its transcript traces back to, so it has no reply address at all: say who you are in the message body, and reach the agent that spawned you over hub." : "This session is a task subagent and registers no Envoy session of its own; a reply to session_id reaches the agent that spawned it, which relays over hub. Your own envoy_publish never reaches that agent \u2014 use hub for that hop."
|
package/dist/legion.js
CHANGED
|
@@ -17744,7 +17744,7 @@ function asObject(value) {
|
|
|
17744
17744
|
}
|
|
17745
17745
|
|
|
17746
17746
|
// extensions/legion.ts
|
|
17747
|
-
import { logger } from "@oh-my-pi/pi-utils";
|
|
17747
|
+
import { logger as logger2 } from "@oh-my-pi/pi-utils";
|
|
17748
17748
|
|
|
17749
17749
|
// src/dispatch-user-turn.ts
|
|
17750
17750
|
function isUserTurnCandidate(rendered) {
|
|
@@ -17843,7 +17843,7 @@ function endInjectedUserTurns(sessionID) {
|
|
|
17843
17843
|
// package.json
|
|
17844
17844
|
var package_default = {
|
|
17845
17845
|
name: "@sjawhar/pi-legion-envoy",
|
|
17846
|
-
version: "6.0.
|
|
17846
|
+
version: "6.0.4",
|
|
17847
17847
|
type: "module",
|
|
17848
17848
|
omp: {
|
|
17849
17849
|
extensions: [
|
|
@@ -17891,33 +17891,56 @@ var package_default = {
|
|
|
17891
17891
|
import fs from "fs";
|
|
17892
17892
|
import path2 from "path";
|
|
17893
17893
|
import * as host from "@oh-my-pi/pi-coding-agent";
|
|
17894
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
17894
17895
|
var LEGION_BOOTSTRAPPED_SESSION = Symbol.for("legion.pi-envoy.bootstrapped-session");
|
|
17895
17896
|
var bootstrappedSessionStore = globalThis;
|
|
17896
17897
|
function recordBootstrappedSession(sessionFile) {
|
|
17897
17898
|
bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION] = sessionFile;
|
|
17898
17899
|
}
|
|
17899
17900
|
async function isSubagentSession(context) {
|
|
17900
|
-
|
|
17901
|
+
const registered = registeredSubagent(context);
|
|
17902
|
+
if (registered !== undefined)
|
|
17903
|
+
return { subagent: registered, settled: true };
|
|
17904
|
+
try {
|
|
17905
|
+
await context.sessionManager.ensureOnDisk();
|
|
17906
|
+
} catch (error48) {
|
|
17907
|
+
const subagent = transcriptSaysSubagent(context);
|
|
17908
|
+
logger.warn("subagent check: publishing the transcript failed; answered from the transcript on disk, and the next call asks again", { sessionFile: context.sessionManager.getSessionFile(), subagent, error: messageFor(error48) });
|
|
17909
|
+
return { subagent, settled: false };
|
|
17910
|
+
}
|
|
17911
|
+
return { subagent: transcriptSaysSubagent(context), settled: true };
|
|
17912
|
+
}
|
|
17913
|
+
function transcriptSaysSubagent(context) {
|
|
17901
17914
|
const sessionFile = context.sessionManager.getSessionFile();
|
|
17902
|
-
if (sessionFile !== undefined
|
|
17903
|
-
|
|
17915
|
+
if (sessionFile !== undefined) {
|
|
17916
|
+
if (fs.existsSync(`${path2.dirname(sessionFile)}.jsonl`))
|
|
17917
|
+
return true;
|
|
17918
|
+
if (fs.existsSync(sessionFile))
|
|
17919
|
+
return false;
|
|
17904
17920
|
}
|
|
17905
17921
|
const bootstrapped = bootstrappedSessionStore[LEGION_BOOTSTRAPPED_SESSION];
|
|
17906
17922
|
return bootstrapped !== undefined && bootstrapped !== sessionFile;
|
|
17907
17923
|
}
|
|
17908
|
-
function
|
|
17924
|
+
function registeredSubagent(context) {
|
|
17909
17925
|
const registry2 = host.AgentRegistry?.global();
|
|
17910
17926
|
if (registry2 === undefined)
|
|
17911
|
-
return
|
|
17927
|
+
return;
|
|
17912
17928
|
const sessionID = context.sessionManager.getSessionId();
|
|
17913
17929
|
const sessionFile = context.sessionManager.getSessionFile();
|
|
17914
|
-
|
|
17930
|
+
const own = registry2.list().filter((ref) => ref.session === null ? sessionFile !== undefined && ref.sessionFile === sessionFile : ref.session.sessionManager.getSessionId() === sessionID);
|
|
17931
|
+
if (own.length === 0)
|
|
17932
|
+
return;
|
|
17933
|
+
return own.some((ref) => ref.kind !== "main");
|
|
17915
17934
|
}
|
|
17916
17935
|
function subagentSessionCheck() {
|
|
17917
|
-
let
|
|
17918
|
-
return (context) => {
|
|
17919
|
-
|
|
17920
|
-
|
|
17936
|
+
let settled;
|
|
17937
|
+
return async (context) => {
|
|
17938
|
+
if (settled !== undefined)
|
|
17939
|
+
return settled;
|
|
17940
|
+
const answer = await isSubagentSession(context);
|
|
17941
|
+
if (answer.settled)
|
|
17942
|
+
settled = answer.subagent;
|
|
17943
|
+
return answer.subagent;
|
|
17921
17944
|
};
|
|
17922
17945
|
}
|
|
17923
17946
|
|
|
@@ -18504,7 +18527,7 @@ function createClaimSession(deps) {
|
|
|
18504
18527
|
|
|
18505
18528
|
// src/legion/controller-session.ts
|
|
18506
18529
|
function createControllerSession(deps) {
|
|
18507
|
-
const { daemon, persistedTranscript
|
|
18530
|
+
const { daemon, persistedTranscript } = deps;
|
|
18508
18531
|
let controllerSessionID;
|
|
18509
18532
|
let controllerCapability;
|
|
18510
18533
|
let mintControllerGrant;
|
|
@@ -18555,8 +18578,6 @@ function createControllerSession(deps) {
|
|
|
18555
18578
|
}
|
|
18556
18579
|
};
|
|
18557
18580
|
const reclaimAfterSessionChange = async (context) => {
|
|
18558
|
-
if (await checkSubagentSession(context))
|
|
18559
|
-
return;
|
|
18560
18581
|
if (classifySession(process.env).kind !== "controller")
|
|
18561
18582
|
return;
|
|
18562
18583
|
if (context.sessionManager.getSessionId() === controllerSessionID && context.sessionManager.getSessionFile() === controllerTranscript) {
|
|
@@ -19225,7 +19246,7 @@ function isToolDeviceInvocation(toolCall) {
|
|
|
19225
19246
|
}
|
|
19226
19247
|
function legionExtension(pi) {
|
|
19227
19248
|
const instance = randomUUID2().slice(0, 8);
|
|
19228
|
-
|
|
19249
|
+
logger2.debug("extension instance loaded", { extension: import.meta.url, instance });
|
|
19229
19250
|
globalThis[LEGION_LOADED_MARKER] = import.meta.url;
|
|
19230
19251
|
const checkSubagentSession = subagentSessionCheck();
|
|
19231
19252
|
let paneRules;
|
|
@@ -19254,8 +19275,7 @@ function legionExtension(pi) {
|
|
|
19254
19275
|
});
|
|
19255
19276
|
const controllerSession = createControllerSession({
|
|
19256
19277
|
daemon: roleDaemon,
|
|
19257
|
-
persistedTranscript
|
|
19258
|
-
checkSubagentSession
|
|
19278
|
+
persistedTranscript
|
|
19259
19279
|
});
|
|
19260
19280
|
const titleSession = async (context) => {
|
|
19261
19281
|
const title = legionSessionTitle(classifySession(process.env), process.env.LEGION_PROJECT);
|
|
@@ -19279,16 +19299,17 @@ function legionExtension(pi) {
|
|
|
19279
19299
|
await activateLegionTool();
|
|
19280
19300
|
});
|
|
19281
19301
|
const afterSessionChange = async (context) => {
|
|
19282
|
-
if (
|
|
19302
|
+
if (await checkSubagentSession(context))
|
|
19303
|
+
return;
|
|
19304
|
+
if (classifySession(process.env).kind === "controller")
|
|
19283
19305
|
await titleSession(context);
|
|
19284
|
-
}
|
|
19285
19306
|
await controllerSession.reclaimAfterSessionChange(context);
|
|
19286
19307
|
};
|
|
19287
19308
|
pi.on("session_switch", (_event, context) => afterSessionChange(context));
|
|
19288
19309
|
pi.on("session_branch", (_event, context) => afterSessionChange(context));
|
|
19289
19310
|
pi.on("session_tree", (_event, context) => afterSessionChange(context));
|
|
19290
19311
|
pi.on("tool_call", async (toolCall, context) => {
|
|
19291
|
-
|
|
19312
|
+
logger2.debug("legion tool_call hook", {
|
|
19292
19313
|
instance,
|
|
19293
19314
|
toolCallId: toolCall.toolCallId,
|
|
19294
19315
|
toolName: toolCall.toolName
|