pi2dsh 0.16.0 → 0.16.2
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/{analyzer-dRAMYI3l.mjs → analyzer-B-b4C_5O.mjs} +2 -2
- package/dist/{analyzer-dRAMYI3l.mjs.map → analyzer-B-b4C_5O.mjs.map} +1 -1
- package/dist/cli.mjs +2 -2
- package/dist/compat/pi-coding-agent.mjs +1 -1
- package/dist/credentials-oauth.mjs +1 -1
- package/dist/host.mjs +1 -1
- package/dist/index.mjs +3 -3
- package/dist/{mcp-config-2s_i_H3R.mjs → mcp-config-BNL_uhE8.mjs} +2 -2
- package/dist/mcp-config-BNL_uhE8.mjs.map +1 -0
- package/dist/pi-coding-agent-69yY0ke-.d.mts.map +1 -1
- package/dist/{pi-coding-agent-f3_hNCpd.mjs → pi-coding-agent-DXJ_Jzo0.mjs} +0 -0
- package/dist/{pi-coding-agent-f3_hNCpd.mjs.map → pi-coding-agent-DXJ_Jzo0.mjs.map} +1 -1
- package/dist/{runtime-C6_pOPmL.mjs → runtime-t-5iWtFO.mjs} +394 -37
- package/dist/runtime-t-5iWtFO.mjs.map +1 -0
- package/dist/runtime.d.mts +68 -0
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/package.json +1 -1
- package/dist/mcp-config-2s_i_H3R.mjs.map +0 -1
- package/dist/runtime-C6_pOPmL.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import { En as PiCapabilityError, F as generateBranchSummary, Tn as CapabilityLedger, b as Theme, d as ExtensionRunner, w as __runWithSubagentSessionFactory } from "./pi-coding-agent-
|
|
2
|
+
import { En as PiCapabilityError, F as generateBranchSummary, Tn as CapabilityLedger, b as Theme, d as ExtensionRunner, w as __runWithSubagentSessionFactory } from "./pi-coding-agent-DXJ_Jzo0.mjs";
|
|
3
3
|
import { t as getAgentDir } from "./pi-config-shim-CZ1wFzqM.mjs";
|
|
4
4
|
import { $ as AssistantMessageEventStream, S as getSupportedThinkingLevels, c as builtinProviders, et as isContextOverflow, o as __runWithPiAiRuntime, r as __createPiAiRuntimeRegistry } from "./pi-ai-DQPHUR9S.mjs";
|
|
5
5
|
import { W as getKeybindings, _t as stripTerminalSequences } from "./pi-tui-DruSeKmd.mjs";
|
|
@@ -7,7 +7,7 @@ import { c as resolvePiProviderAuth, i as oauthCredentialRef, l as storedOAuthCr
|
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
8
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
9
9
|
import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
10
|
-
import { join } from "node:path";
|
|
10
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { EventEmitter } from "node:events";
|
|
@@ -69,6 +69,37 @@ var PiSessionBridge = class {
|
|
|
69
69
|
const safe = sessionId.replace(/[^a-zA-Z0-9._-]+/gu, "_");
|
|
70
70
|
return join(sidecarDir(), `${safe}.jsonl`);
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* The Pi-visible archive file for one DSH session — the established
|
|
74
|
+
* `<id>.jsonl` convention (getSessionFile/switchSession use the same one).
|
|
75
|
+
* Guaranteed to EXIST on return: Pi consumers treat the session file as the
|
|
76
|
+
* durable identity a conversation can be reopened by (pi-subagents guards
|
|
77
|
+
* its tombstone resurrect with existsSync, and Pi's SessionManager.open
|
|
78
|
+
* tolerates an empty file), so a merely virtual path would read as "the
|
|
79
|
+
* conversation is gone".
|
|
80
|
+
*/
|
|
81
|
+
archiveFileFor(sessionId) {
|
|
82
|
+
const path = this.sidecarPath(sessionId);
|
|
83
|
+
if (!existsSync(path)) {
|
|
84
|
+
mkdirSync(sidecarDir(), { recursive: true });
|
|
85
|
+
appendFileSync(path, "");
|
|
86
|
+
}
|
|
87
|
+
return path;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The DSH session id an archive-file path names, or undefined for any path
|
|
91
|
+
* this bridge did not mint (a genuine Pi session file, an in-memory
|
|
92
|
+
* manager's undefined). The reverse of {@link archiveFileFor} — ids that
|
|
93
|
+
* survive its sanitization round-trip exactly, which every id this bridge
|
|
94
|
+
* mints does.
|
|
95
|
+
*/
|
|
96
|
+
sessionIdOfArchiveFile(path) {
|
|
97
|
+
if (typeof path !== "string" || path.length === 0) return void 0;
|
|
98
|
+
const resolved = resolve(path);
|
|
99
|
+
if (resolve(dirname(resolved)) !== resolve(sidecarDir())) return void 0;
|
|
100
|
+
const base = basename(resolved);
|
|
101
|
+
return base.endsWith(".jsonl") ? base.slice(0, -6) : void 0;
|
|
102
|
+
}
|
|
72
103
|
load(sessionId) {
|
|
73
104
|
if (this.loaded.has(sessionId)) return;
|
|
74
105
|
this.loaded.add(sessionId);
|
|
@@ -307,7 +338,7 @@ var PiSessionBridge = class {
|
|
|
307
338
|
getCwd: () => cwd,
|
|
308
339
|
getSessionDir: () => sidecarDir(),
|
|
309
340
|
getSessionId: () => session.id,
|
|
310
|
-
getSessionFile: () => this.
|
|
341
|
+
getSessionFile: () => this.archiveFileFor(session.id),
|
|
311
342
|
getLeafId: () => leafOf()?.id ?? null,
|
|
312
343
|
getLeafEntry: () => leafOf(),
|
|
313
344
|
getEntry: (id) => entriesOf().find((entry) => entry.id === id),
|
|
@@ -359,6 +390,26 @@ var PiSessionBridge = class {
|
|
|
359
390
|
//#region src/subagent-bridge.ts
|
|
360
391
|
let subagentSerial = 0;
|
|
361
392
|
/**
|
|
393
|
+
* Pi built-in tool name → the DSH native tool that serves it. The two
|
|
394
|
+
* vocabularies coincide (read/bash/edit/write/grep); Pi's find and ls are
|
|
395
|
+
* both served by the host's glob.
|
|
396
|
+
*/
|
|
397
|
+
function nativeToolNameOf(name) {
|
|
398
|
+
return name === "find" || name === "ls" ? "glob" : name;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* The tool schemas a CHILD agent actually resolves — its scoped view when the
|
|
402
|
+
* service answers for the agent being built, else the global layer. On
|
|
403
|
+
* roster-owned surfaces the preset tools live above the global layer, so the
|
|
404
|
+
* scoped read is the one that sees them.
|
|
405
|
+
*/
|
|
406
|
+
function childSchemas(toolsService, childCtx) {
|
|
407
|
+
try {
|
|
408
|
+
if (childCtx.agent !== void 0) return toolsService.schemas(childCtx.agent);
|
|
409
|
+
} catch {}
|
|
410
|
+
return toolsService.schemas();
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
362
413
|
* Cross-scope subscription base. Session events dispatch under the OWNING
|
|
363
414
|
* session's scope; a package instance mounted per Agent registers listeners
|
|
364
415
|
* inside its own Agent's scope and would never see a child session's events.
|
|
@@ -385,6 +436,12 @@ function piMessageText(message) {
|
|
|
385
436
|
var PiBridgedAgentSession = class {
|
|
386
437
|
agent = {};
|
|
387
438
|
messages = [];
|
|
439
|
+
/**
|
|
440
|
+
* Pi's AgentSession.sessionManager surface, projected over the child's DSH
|
|
441
|
+
* session. getSessionFile() names the durable archive — what pi-subagents
|
|
442
|
+
* stores as the conversation's reopenable identity (tombstone resurrect).
|
|
443
|
+
*/
|
|
444
|
+
sessionManager;
|
|
388
445
|
#seed = [];
|
|
389
446
|
#carried = /* @__PURE__ */ new WeakSet();
|
|
390
447
|
#host;
|
|
@@ -398,8 +455,11 @@ var PiBridgedAgentSession = class {
|
|
|
398
455
|
#model;
|
|
399
456
|
#streaming = false;
|
|
400
457
|
#pendingToolCalls = /* @__PURE__ */ new Set();
|
|
458
|
+
/** callId → tool name, so tool_execution_end can name the tool its result belongs to. */
|
|
459
|
+
#toolCallNames = /* @__PURE__ */ new Map();
|
|
401
460
|
#sessionName = "";
|
|
402
461
|
#turns = 0;
|
|
462
|
+
#restrictionDispose;
|
|
403
463
|
/** Keeps message projections (which await attachment reads) in log order. */
|
|
404
464
|
#messageProjection = Promise.resolve();
|
|
405
465
|
#aborted = false;
|
|
@@ -407,6 +467,7 @@ var PiBridgedAgentSession = class {
|
|
|
407
467
|
this.#host = host;
|
|
408
468
|
this.#handle = handle;
|
|
409
469
|
this.#session = handle.agent.session ?? {};
|
|
470
|
+
this.sessionManager = host.sessionManagerFor?.(this.#session);
|
|
410
471
|
this.#tools = tools;
|
|
411
472
|
this.#activeToolNames = tools.map((tool) => tool?.name).filter((name) => typeof name === "string");
|
|
412
473
|
const cordis = unscopedEventContext(host.cordis);
|
|
@@ -493,6 +554,10 @@ var PiBridgedAgentSession = class {
|
|
|
493
554
|
handler(piEvent);
|
|
494
555
|
} catch {}
|
|
495
556
|
};
|
|
557
|
+
if (this.#aborted && (type === "turn/start" || type === "step/start" || type === "request/header")) {
|
|
558
|
+
this.#cancelChild();
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
496
561
|
if (type === "turn/start") {
|
|
497
562
|
this.#streaming = true;
|
|
498
563
|
emit({
|
|
@@ -509,11 +574,32 @@ var PiBridgedAgentSession = class {
|
|
|
509
574
|
}
|
|
510
575
|
if (type === "tools/result" || type === "tool/result") {
|
|
511
576
|
const data = event.data;
|
|
512
|
-
|
|
577
|
+
const message = data.message;
|
|
578
|
+
const blocks = Array.isArray(message?.content) ? message.content : [];
|
|
579
|
+
for (const block of blocks) {
|
|
580
|
+
const record = block;
|
|
581
|
+
if (record?.type !== "tool-result") continue;
|
|
582
|
+
const callId = String(record.toolCallId ?? (message?.source)?.callId ?? data.callId ?? "");
|
|
583
|
+
this.#pendingToolCalls.delete(callId);
|
|
584
|
+
const isError = record.isError === true;
|
|
585
|
+
emit({
|
|
586
|
+
type: "tool_execution_end",
|
|
587
|
+
toolCallId: callId,
|
|
588
|
+
toolName: this.#toolCallNames.get(callId) ?? "",
|
|
589
|
+
result: {
|
|
590
|
+
content: record.content ?? [],
|
|
591
|
+
isError
|
|
592
|
+
},
|
|
593
|
+
isError
|
|
594
|
+
});
|
|
595
|
+
this.#toolCallNames.delete(callId);
|
|
596
|
+
}
|
|
597
|
+
if (blocks.length === 0) this.#pendingToolCalls.delete(String(data.callId ?? ""));
|
|
513
598
|
}
|
|
514
599
|
if (type === "tool/call") {
|
|
515
600
|
const data = event.data;
|
|
516
601
|
this.#pendingToolCalls.add(String(data.callId ?? ""));
|
|
602
|
+
this.#toolCallNames.set(String(data.callId ?? ""), String(data.name ?? ""));
|
|
517
603
|
let args = {};
|
|
518
604
|
try {
|
|
519
605
|
args = JSON.parse(String(data.arguments ?? "{}"));
|
|
@@ -582,6 +668,7 @@ var PiBridgedAgentSession = class {
|
|
|
582
668
|
return () => this.#subscribers.delete(handler);
|
|
583
669
|
}
|
|
584
670
|
async prompt(text) {
|
|
671
|
+
this.#aborted = false;
|
|
585
672
|
if (this.#seed.length > 0) {
|
|
586
673
|
const seeded = this.#seed;
|
|
587
674
|
this.#seed = [];
|
|
@@ -645,13 +732,28 @@ var PiBridgedAgentSession = class {
|
|
|
645
732
|
}
|
|
646
733
|
abort() {
|
|
647
734
|
this.#aborted = true;
|
|
735
|
+
this.#cancelChild();
|
|
736
|
+
}
|
|
737
|
+
/** One official Agent.cancel, contained but LOUD: a swallowed cancel is a
|
|
738
|
+
* child that keeps running after its parent was interrupted. */
|
|
739
|
+
#cancelChild() {
|
|
740
|
+
const cancel = this.#handle.agent.cancel;
|
|
741
|
+
if (cancel === void 0) {
|
|
742
|
+
const message = "[pi2dsh] subagent abort(): the child agent handle has no cancel — the child cannot be stopped";
|
|
743
|
+
console.warn(message);
|
|
744
|
+
this.#host.cordis.logger?.warn?.(message);
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
648
747
|
try {
|
|
649
|
-
|
|
650
|
-
cancel?.({
|
|
748
|
+
cancel.call(this.#handle.agent, {
|
|
651
749
|
kind: "hook",
|
|
652
750
|
reason: "pi2dsh subagent abort()"
|
|
653
751
|
});
|
|
654
|
-
} catch {
|
|
752
|
+
} catch (error) {
|
|
753
|
+
const message = `[pi2dsh] subagent abort(): Agent.cancel failed (${error instanceof Error ? error.message : String(error)}) — already disposed, or the child kept running`;
|
|
754
|
+
console.warn(message);
|
|
755
|
+
this.#host.cordis.logger?.warn?.(message);
|
|
756
|
+
}
|
|
655
757
|
}
|
|
656
758
|
setSessionName(name) {
|
|
657
759
|
this.#sessionName = String(name);
|
|
@@ -666,14 +768,44 @@ var PiBridgedAgentSession = class {
|
|
|
666
768
|
aborted: this.#aborted
|
|
667
769
|
};
|
|
668
770
|
}
|
|
771
|
+
/** The child scope's REAL tool schemas (native + scoped custom), in Pi tool shape. */
|
|
772
|
+
#scopeTools() {
|
|
773
|
+
const agentCtx = this.#handle.agent.ctx;
|
|
774
|
+
const toolsService = typeof agentCtx?.get === "function" ? agentCtx.get("tools") : void 0;
|
|
775
|
+
try {
|
|
776
|
+
return [...toolsService?.schemas?.(this.#handle.agent) ?? []];
|
|
777
|
+
} catch {
|
|
778
|
+
return [];
|
|
779
|
+
}
|
|
780
|
+
}
|
|
669
781
|
getAllTools() {
|
|
670
|
-
|
|
782
|
+
const custom = new Map(this.#tools.filter((tool) => typeof tool?.name === "string").map((tool) => [String(tool.name), tool]));
|
|
783
|
+
return this.#scopeTools().map((schema) => custom.get(schema.name) ?? schema);
|
|
671
784
|
}
|
|
672
785
|
getActiveToolNames() {
|
|
673
|
-
|
|
786
|
+
const fromScope = this.#scopeTools().map((schema) => schema.name);
|
|
787
|
+
return fromScope.length > 0 ? fromScope : [...this.#activeToolNames];
|
|
788
|
+
}
|
|
789
|
+
/** Hand over the creation-time restriction so a later setActiveToolsByName
|
|
790
|
+
* retires it instead of intersecting with it. */
|
|
791
|
+
adoptRestriction(dispose) {
|
|
792
|
+
this.#restrictionDispose = dispose;
|
|
674
793
|
}
|
|
675
794
|
setActiveToolsByName(names) {
|
|
676
795
|
this.#activeToolNames = names.filter((name) => typeof name === "string");
|
|
796
|
+
const agentCtx = this.#handle.agent.ctx;
|
|
797
|
+
const toolsService = typeof agentCtx?.get === "function" ? agentCtx.get("tools") : void 0;
|
|
798
|
+
if (toolsService === void 0) return;
|
|
799
|
+
try {
|
|
800
|
+
this.#restrictionDispose?.();
|
|
801
|
+
let known;
|
|
802
|
+
try {
|
|
803
|
+
known = new Set(toolsService.schemas(this.#handle.agent).map((schema) => schema.name));
|
|
804
|
+
} catch {
|
|
805
|
+
known = new Set(toolsService.schemas().map((schema) => schema.name));
|
|
806
|
+
}
|
|
807
|
+
this.#restrictionDispose = toolsService.restrict({ allow: this.#activeToolNames.map(nativeToolNameOf).filter((name) => known.has(name)) });
|
|
808
|
+
} catch {}
|
|
677
809
|
}
|
|
678
810
|
async bindExtensions(_bindings = {}) {}
|
|
679
811
|
async dispose() {
|
|
@@ -708,45 +840,111 @@ function childLabel(requested, packageName) {
|
|
|
708
840
|
async function createBridgedAgentSession(host, options) {
|
|
709
841
|
const agents = host.cordis.get("agents");
|
|
710
842
|
if (agents?.create === void 0) throw new Error("pi2dsh: createAgentSession() needs the DSH agent registry in the host composition");
|
|
843
|
+
const providedManager = options.sessionManager;
|
|
844
|
+
const archiveFile = typeof providedManager?.getSessionFile === "function" ? providedManager.getSessionFile() : void 0;
|
|
845
|
+
const resumeSessionId = host.resumeSessionIdFor?.(archiveFile);
|
|
711
846
|
subagentSerial += 1;
|
|
712
847
|
const sessionId = `pi2dsh-sub-${Date.now().toString(36)}-${subagentSerial}`;
|
|
713
848
|
let handle;
|
|
849
|
+
let initialRestrictionDispose;
|
|
714
850
|
try {
|
|
715
851
|
const requestedModel = options.model;
|
|
716
852
|
const loader = options.resourceLoader;
|
|
717
853
|
const overrideText = typeof options.systemPrompt === "string" && options.systemPrompt.length > 0 ? options.systemPrompt : typeof loader?.getSystemPrompt === "function" ? loader.getSystemPrompt() : void 0;
|
|
718
854
|
const appendTexts = (typeof loader?.getAppendSystemPrompt === "function" ? loader.getAppendSystemPrompt() : []).filter((text) => typeof text === "string" && text.length > 0);
|
|
719
855
|
const systemPrompt = overrideText !== void 0 && overrideText.length > 0 ? [overrideText, ...appendTexts].join("\n\n") : void 0;
|
|
720
|
-
|
|
856
|
+
const customTools = Array.isArray(options.customTools) ? [...options.customTools] : [];
|
|
857
|
+
const requestedNames = Array.isArray(options.tools) ? options.tools.filter((name) => typeof name === "string") : void 0;
|
|
858
|
+
const parentCtx = host.parentAgentContext();
|
|
859
|
+
const roster = (typeof parentCtx?.get === "function" ? parentCtx.get("agentPresets") : void 0) ?? host.cordis.get?.("agentPresets");
|
|
860
|
+
let composedPreset = roster?.composedPreset?.(parentCtx);
|
|
861
|
+
if (roster !== void 0 && composedPreset === void 0 && typeof roster.resolve === "function") composedPreset = await roster.resolve(void 0).then((preset) => preset?.id).catch(() => void 0);
|
|
862
|
+
const delegated = host.delegatedPolicyOverrides();
|
|
863
|
+
const route = typeof requestedModel?.id === "string" && requestedModel.id.length > 0 ? {
|
|
864
|
+
model: requestedModel.id,
|
|
865
|
+
...typeof requestedModel.provider === "string" && requestedModel.provider.length > 0 ? { provider: requestedModel.provider } : {}
|
|
866
|
+
} : host.parentModelRoute?.();
|
|
867
|
+
const agentOptionsFragment = typeof route?.model === "string" && route.model.length > 0 ? { agentOptions: route } : {};
|
|
868
|
+
const setup = async (childCtx) => {
|
|
869
|
+
const childSession = childCtx.agent?.session;
|
|
870
|
+
if (typeof childSession?.append === "function") {
|
|
871
|
+
if (delegated.sandboxMode !== void 0) childSession.append("sandbox/mode", {
|
|
872
|
+
mode: delegated.sandboxMode,
|
|
873
|
+
source: "delegation"
|
|
874
|
+
});
|
|
875
|
+
if (delegated.approvalPolicy !== void 0) childSession.append("approval/policy", {
|
|
876
|
+
policy: delegated.approvalPolicy,
|
|
877
|
+
source: "delegation"
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
if (roster !== void 0) {
|
|
881
|
+
let joined;
|
|
882
|
+
try {
|
|
883
|
+
joined = roster.composeFrom?.(childCtx, parentCtx);
|
|
884
|
+
} catch {
|
|
885
|
+
joined = void 0;
|
|
886
|
+
}
|
|
887
|
+
if (joined === void 0 && composedPreset !== void 0 && typeof roster.mount === "function") try {
|
|
888
|
+
await roster.mount(childCtx, composedPreset);
|
|
889
|
+
joined = composedPreset;
|
|
890
|
+
} catch {
|
|
891
|
+
joined = void 0;
|
|
892
|
+
}
|
|
893
|
+
if (joined === void 0) host.cordis.logger?.warn?.("[pi2dsh] child agent joined no preset composition; on roster-owned surfaces its tools resolve against the empty global layer");
|
|
894
|
+
}
|
|
895
|
+
const restriction = requestedNames !== void 0 ? requestedNames.map(nativeToolNameOf) : options.noTools === "all" || options.noTools === true || options.noTools === "builtin" ? [] : void 0;
|
|
896
|
+
if (restriction !== void 0) {
|
|
897
|
+
const toolsService = typeof childCtx.get === "function" ? childCtx.get("tools") : void 0;
|
|
898
|
+
if (toolsService !== void 0) {
|
|
899
|
+
const known = new Set(childSchemas(toolsService, childCtx).map((schema) => schema.name));
|
|
900
|
+
initialRestrictionDispose = toolsService.restrict({ allow: restriction.filter((name) => known.has(name)) });
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
const excluded = Array.isArray(options.excludeTools) ? options.excludeTools.filter((name) => typeof name === "string") : [];
|
|
904
|
+
if (excluded.length > 0) {
|
|
905
|
+
const toolsService = typeof childCtx.get === "function" ? childCtx.get("tools") : void 0;
|
|
906
|
+
if (toolsService !== void 0) {
|
|
907
|
+
const known = new Set(childSchemas(toolsService, childCtx).map((schema) => schema.name));
|
|
908
|
+
toolsService.restrict({ deny: excluded.map(nativeToolNameOf).filter((name) => known.has(name)) });
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
if (customTools.length > 0 && options.noTools !== "all") host.registerChildTools(childCtx, customTools);
|
|
912
|
+
if (systemPrompt !== void 0) {
|
|
913
|
+
const prompt = typeof childCtx.get === "function" ? childCtx.get("systemPrompt") : void 0;
|
|
914
|
+
if (prompt === void 0) throw new Error("pi2dsh: createAgentSession() got a system prompt but the DSH composition has no systemPrompt service to carry it");
|
|
915
|
+
prompt.section({
|
|
916
|
+
name: "pi2dsh:subagent-system-prompt",
|
|
917
|
+
order: -1e6,
|
|
918
|
+
text: systemPrompt,
|
|
919
|
+
complete: true
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
if (resumeSessionId !== void 0) {
|
|
924
|
+
if (typeof agents.resume !== "function") throw new Error("pi2dsh: reopening a child conversation needs the DSH agent registry's persisted-resume seam, which this composition does not provide");
|
|
925
|
+
handle = await agents.resume({
|
|
926
|
+
resumeSessionId,
|
|
927
|
+
...agentOptionsFragment,
|
|
928
|
+
setup
|
|
929
|
+
});
|
|
930
|
+
} else handle = await agents.create({
|
|
721
931
|
sessionId,
|
|
722
932
|
meta: {
|
|
723
933
|
cwd: typeof options.cwd === "string" ? options.cwd : host.cwd(),
|
|
724
934
|
origin: "subagent",
|
|
725
935
|
delegationDepth: host.parentDelegationDepth() + 1,
|
|
726
|
-
...host.parentSessionId() !== void 0 ? { parentSession: host.parentSessionId() } : {}
|
|
936
|
+
...host.parentSessionId() !== void 0 ? { parentSession: host.parentSessionId() } : {},
|
|
937
|
+
...typeof composedPreset === "string" && composedPreset.length > 0 ? { agentPreset: composedPreset } : {}
|
|
727
938
|
},
|
|
728
|
-
...
|
|
729
|
-
|
|
730
|
-
...typeof requestedModel.provider === "string" && requestedModel.provider.length > 0 ? { provider: requestedModel.provider } : {}
|
|
731
|
-
} } : {}
|
|
939
|
+
...agentOptionsFragment,
|
|
940
|
+
setup
|
|
732
941
|
});
|
|
733
|
-
if (systemPrompt !== void 0) {
|
|
734
|
-
const agentCtx = handle.agent.ctx;
|
|
735
|
-
const prompt = typeof agentCtx?.get === "function" ? agentCtx.get("systemPrompt") : void 0;
|
|
736
|
-
if (prompt === void 0) throw new Error("pi2dsh: createAgentSession() got a system prompt but the DSH composition has no systemPrompt service to carry it");
|
|
737
|
-
prompt.section({
|
|
738
|
-
name: "pi2dsh:subagent-system-prompt",
|
|
739
|
-
order: -1e6,
|
|
740
|
-
text: systemPrompt,
|
|
741
|
-
complete: true
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
942
|
} catch (error) {
|
|
745
|
-
throw new Error(`pi2dsh: subagent creation needs the DSH host loop (model runtime) to provide the agent factory; this composition cannot run one (${error instanceof Error ? error.message : String(error)})`);
|
|
943
|
+
throw new Error(resumeSessionId !== void 0 ? `pi2dsh: reopening child session ${JSON.stringify(resumeSessionId)} failed — its persisted log may be gone or this composition has no session persistence (${error instanceof Error ? error.message : String(error)})` : `pi2dsh: subagent creation needs the DSH host loop (model runtime) to provide the agent factory; this composition cannot run one (${error instanceof Error ? error.message : String(error)})`);
|
|
746
944
|
}
|
|
747
945
|
const tools = [...Array.isArray(options.tools) ? options.tools : [], ...Array.isArray(options.customTools) ? options.customTools : []];
|
|
748
946
|
const childSession = handle.agent.session;
|
|
749
|
-
if (typeof childSession?.append === "function") try {
|
|
947
|
+
if (resumeSessionId === void 0 && typeof childSession?.append === "function") try {
|
|
750
948
|
childSession.append("subagent/descriptor", {
|
|
751
949
|
version: 2,
|
|
752
950
|
mode: "continuable",
|
|
@@ -756,7 +954,9 @@ async function createBridgedAgentSession(host, options) {
|
|
|
756
954
|
} catch (error) {
|
|
757
955
|
host.cordis.logger?.warn?.(`[pi2dsh] child session could not record its subagent identity: ${error instanceof Error ? error.message : String(error)}`);
|
|
758
956
|
}
|
|
759
|
-
|
|
957
|
+
const session = new PiBridgedAgentSession(host, handle, tools);
|
|
958
|
+
session.adoptRestriction(initialRestrictionDispose);
|
|
959
|
+
return { session };
|
|
760
960
|
}
|
|
761
961
|
//#endregion
|
|
762
962
|
//#region src/compat/vendor/pi-open-browser.ts
|
|
@@ -2892,12 +3092,91 @@ function mountTuiSurfaceAdapter(ctx, packageName, publish, instanceKey) {
|
|
|
2892
3092
|
}
|
|
2893
3093
|
}
|
|
2894
3094
|
/**
|
|
2895
|
-
* dsh-TUI
|
|
2896
|
-
*
|
|
2897
|
-
*
|
|
3095
|
+
* dsh-TUI dispatches its LOCAL commands before it asks DSH's command
|
|
3096
|
+
* registry ("locals win on name collisions" — its own commands.ts contract),
|
|
3097
|
+
* so a registry command sharing a local name is unreachable from that
|
|
3098
|
+
* surface. The host command keeps its name; the incoming command gets a
|
|
3099
|
+
* `pi-` source prefix — and ONLY on a composition where dsh-TUI is present;
|
|
3100
|
+
* everywhere else the original name stands.
|
|
3101
|
+
*
|
|
3102
|
+
* The reserved-name list is dsh-TUI's `LOCAL_COMMANDS`, which it exports in
|
|
3103
|
+
* code but not through its package exports map (upstream ask filed). Until
|
|
3104
|
+
* that lands, the list is pinned per generation from the published sources:
|
|
3105
|
+
* 0.8.x reserved only /mcp; 0.9.0 reserves the full set below. Generation is
|
|
3106
|
+
* read off the installed package's public ./package.json subpath.
|
|
2898
3107
|
*/
|
|
3108
|
+
const DSH_TUI_LOCAL_COMMANDS_0_9 = /* @__PURE__ */ new Set([
|
|
3109
|
+
"new",
|
|
3110
|
+
"clear",
|
|
3111
|
+
"compact",
|
|
3112
|
+
"resume",
|
|
3113
|
+
"rename",
|
|
3114
|
+
"rewind",
|
|
3115
|
+
"export",
|
|
3116
|
+
"btw",
|
|
3117
|
+
"trace",
|
|
3118
|
+
"context",
|
|
3119
|
+
"status",
|
|
3120
|
+
"cost",
|
|
3121
|
+
"config",
|
|
3122
|
+
"settings",
|
|
3123
|
+
"doctor",
|
|
3124
|
+
"init",
|
|
3125
|
+
"agents",
|
|
3126
|
+
"activity",
|
|
3127
|
+
"preset",
|
|
3128
|
+
"theme",
|
|
3129
|
+
"lang",
|
|
3130
|
+
"model",
|
|
3131
|
+
"effort",
|
|
3132
|
+
"thinking",
|
|
3133
|
+
"tokens",
|
|
3134
|
+
"provider",
|
|
3135
|
+
"login",
|
|
3136
|
+
"logout",
|
|
3137
|
+
"add-dir",
|
|
3138
|
+
"hooks",
|
|
3139
|
+
"mcp",
|
|
3140
|
+
"skills",
|
|
3141
|
+
"plugins",
|
|
3142
|
+
"update",
|
|
3143
|
+
"audit",
|
|
3144
|
+
"bug",
|
|
3145
|
+
"practice",
|
|
3146
|
+
"review",
|
|
3147
|
+
"release-notes",
|
|
3148
|
+
"vuln-check",
|
|
3149
|
+
"vim",
|
|
3150
|
+
"terminal-setup",
|
|
3151
|
+
"connect",
|
|
3152
|
+
"workspace",
|
|
3153
|
+
"help",
|
|
3154
|
+
"tips",
|
|
3155
|
+
"exit",
|
|
3156
|
+
"quit",
|
|
3157
|
+
"q",
|
|
3158
|
+
"deepseek"
|
|
3159
|
+
]);
|
|
3160
|
+
const DSH_TUI_LOCAL_COMMANDS_LEGACY = /* @__PURE__ */ new Set(["mcp"]);
|
|
3161
|
+
/** The reserved set for one installed dsh-tui version (undefined = unknown,
|
|
3162
|
+
* assume the current generation). */
|
|
3163
|
+
function tuiLocalCommandsForVersion(version) {
|
|
3164
|
+
if (version === void 0) return DSH_TUI_LOCAL_COMMANDS_0_9;
|
|
3165
|
+
const [major = 0, minor = 0] = version.split(".").map((part) => Number.parseInt(part, 10));
|
|
3166
|
+
return major > 0 || minor >= 9 ? DSH_TUI_LOCAL_COMMANDS_0_9 : DSH_TUI_LOCAL_COMMANDS_LEGACY;
|
|
3167
|
+
}
|
|
3168
|
+
let cachedTuiLocalCommands;
|
|
3169
|
+
function dshTuiLocalCommands() {
|
|
3170
|
+
if (cachedTuiLocalCommands !== void 0) return cachedTuiLocalCommands;
|
|
3171
|
+
let version;
|
|
3172
|
+
try {
|
|
3173
|
+
version = createRequire(import.meta.url)("@deepseek-harness-tui/dsh-tui/package.json").version;
|
|
3174
|
+
} catch {}
|
|
3175
|
+
cachedTuiLocalCommands = tuiLocalCommandsForVersion(version);
|
|
3176
|
+
return cachedTuiLocalCommands;
|
|
3177
|
+
}
|
|
2899
3178
|
function commandNameForDshTui(name, tuiAvailable) {
|
|
2900
|
-
return tuiAvailable && name
|
|
3179
|
+
return tuiAvailable && dshTuiLocalCommands().has(name) ? `pi-${name}` : name;
|
|
2901
3180
|
}
|
|
2902
3181
|
//#endregion
|
|
2903
3182
|
//#region src/runtime.ts
|
|
@@ -5441,6 +5720,50 @@ function registerTool(ctx, state, tool) {
|
|
|
5441
5720
|
state.toolDisposers.set(tool.name, dispose);
|
|
5442
5721
|
if (isKnownImageTool(state.packageName, tool.name)) state.shared.browserSurfaces?.registerImageTool(tool.name);
|
|
5443
5722
|
}
|
|
5723
|
+
/**
|
|
5724
|
+
* Register ONE Pi custom tool into a child agent's scope (createAgentSession
|
|
5725
|
+
* customTools). Same translation as {@link registerTool}'s definition, but:
|
|
5726
|
+
* the registration goes through the CHILD ctx (a scoped registration that
|
|
5727
|
+
* unwinds with the child, invisible to the parent and siblings), and the
|
|
5728
|
+
* package's own Pi tool ledger is untouched — a child session's custom tools
|
|
5729
|
+
* belong to that session in Pi, not to the extension's registered set.
|
|
5730
|
+
* Partial-result updates have no Pi-side consumer on this path yet (the
|
|
5731
|
+
* façade projects durable events only), so the update callback is a no-op —
|
|
5732
|
+
* never a fake dispatch.
|
|
5733
|
+
*/
|
|
5734
|
+
function registerChildPiTool(childCtx, state, tool) {
|
|
5735
|
+
const normalized = normalizeToolSchema(tool.parameters);
|
|
5736
|
+
for (const warning of normalized.warnings) logger(childCtx).warn(`[pi2dsh] subagent tool ${tool.name}: ${warning}`);
|
|
5737
|
+
const definition = {
|
|
5738
|
+
name: tool.name,
|
|
5739
|
+
description: tool.description,
|
|
5740
|
+
parameters: normalized.schema,
|
|
5741
|
+
output: {
|
|
5742
|
+
schema: {},
|
|
5743
|
+
render: (_args, value) => value.content,
|
|
5744
|
+
presentationMeta: (_args, value) => jsonValue(value.details)
|
|
5745
|
+
},
|
|
5746
|
+
isConcurrencySafe: () => tool.executionMode === "parallel",
|
|
5747
|
+
async execute(args, exec) {
|
|
5748
|
+
const agent = exec.agent;
|
|
5749
|
+
const prepared = validateToolArguments({
|
|
5750
|
+
name: tool.name,
|
|
5751
|
+
parameters: tool.parameters
|
|
5752
|
+
}, {
|
|
5753
|
+
name: tool.name,
|
|
5754
|
+
arguments: tool.prepareArguments?.(cloneJson(args)) ?? args
|
|
5755
|
+
});
|
|
5756
|
+
const result = await normalizeToolResultForDsh(childCtx, await runInPiRuntime(state, agent, () => tool.execute(String(exec.callId), prepared, exec.signal, () => {}, contextFor(childCtx, state, agent, exec.signal))));
|
|
5757
|
+
if (result.terminate === true) exec.concludeTurn();
|
|
5758
|
+
if (result.isError === true) {
|
|
5759
|
+
const message = textBlocks(result.content).map((block) => block.text).filter(Boolean).join("\n");
|
|
5760
|
+
throw new Error(message || `Pi tool ${tool.name} failed`);
|
|
5761
|
+
}
|
|
5762
|
+
return result;
|
|
5763
|
+
}
|
|
5764
|
+
};
|
|
5765
|
+
childCtx.tools.register(definition);
|
|
5766
|
+
}
|
|
5444
5767
|
function unregisterTool(state, name) {
|
|
5445
5768
|
const dispose = state.toolDisposers.get(name);
|
|
5446
5769
|
if (dispose === void 0) return false;
|
|
@@ -5689,9 +6012,10 @@ function normalizedPiCommandName(piName) {
|
|
|
5689
6012
|
return normalized.length > 0 ? normalized : "pi-command";
|
|
5690
6013
|
}
|
|
5691
6014
|
function dshCommandName(ctx, state, piName) {
|
|
5692
|
-
const
|
|
6015
|
+
const validName = normalizedPiCommandName(piName);
|
|
6016
|
+
const name = commandNameForDshTui(validName, state.tuiSurfaces?.available === true || optionalService(ctx, "tuiScenes") !== void 0);
|
|
5693
6017
|
if (name !== piName) {
|
|
5694
|
-
const reason = name ===
|
|
6018
|
+
const reason = name === `pi-${validName}` ? `because dsh-TUI reserves /${validName} for its own local command (locals win on name collisions)` : "to satisfy DSH command naming";
|
|
5695
6019
|
logger(ctx).warn(`[pi2dsh] Pi command /${piName} registered as /${name} ${reason}`);
|
|
5696
6020
|
}
|
|
5697
6021
|
return name;
|
|
@@ -6383,7 +6707,39 @@ async function applyPiPackage(ctx, options) {
|
|
|
6383
6707
|
deliver: (agent, message, mode) => deliverAgentMessage(agent, message, mode),
|
|
6384
6708
|
messageFromSessionEvent: (event) => messageFromSessionEvent(ctx, event),
|
|
6385
6709
|
messageSource: state.messageSource,
|
|
6386
|
-
packageName: state.packageName
|
|
6710
|
+
packageName: state.packageName,
|
|
6711
|
+
parentAgentContext: () => currentAgent(state)?.ctx,
|
|
6712
|
+
registerChildTools: (childCtx, tools) => {
|
|
6713
|
+
for (const tool of tools) registerChildPiTool(childCtx, state, tool);
|
|
6714
|
+
},
|
|
6715
|
+
delegatedPolicyOverrides: () => {
|
|
6716
|
+
const parent = currentAgent(state);
|
|
6717
|
+
const sandboxPolicy = typeof parent?.ctx?.get === "function" ? parent.ctx.get("sandboxPolicy") : void 0;
|
|
6718
|
+
const approval = typeof parent?.ctx?.get === "function" ? parent.ctx.get("approval") : void 0;
|
|
6719
|
+
const sandboxMode = sandboxPolicy?.overrideOf?.(parent?.session);
|
|
6720
|
+
return {
|
|
6721
|
+
...sandboxMode !== void 0 ? { sandboxMode } : {},
|
|
6722
|
+
...approval !== void 0 ? { approvalPolicy: "never" } : {}
|
|
6723
|
+
};
|
|
6724
|
+
},
|
|
6725
|
+
sessionManagerFor: (session) => {
|
|
6726
|
+
const typed = session;
|
|
6727
|
+
const cwd = typeof typed.meta?.cwd === "string" ? typed.meta.cwd : cwdOf(currentAgent(state));
|
|
6728
|
+
return state.bridge.readonlySessionManager(session, cwd);
|
|
6729
|
+
},
|
|
6730
|
+
resumeSessionIdFor: (file) => state.bridge.sessionIdOfArchiveFile(file),
|
|
6731
|
+
parentModelRoute: () => {
|
|
6732
|
+
const parent = currentAgent(state);
|
|
6733
|
+
if (parent === void 0) return void 0;
|
|
6734
|
+
const live = currentPiModel(state, parent);
|
|
6735
|
+
const model = live?.id;
|
|
6736
|
+
if (typeof model !== "string" || model.length === 0) return void 0;
|
|
6737
|
+
const provider = live?.provider;
|
|
6738
|
+
return {
|
|
6739
|
+
model,
|
|
6740
|
+
...typeof provider === "string" && provider.length > 0 ? { provider } : {}
|
|
6741
|
+
};
|
|
6742
|
+
}
|
|
6387
6743
|
});
|
|
6388
6744
|
await registerPromptCommands(ctx, state, rootDir, options.manifest);
|
|
6389
6745
|
const onExtensionError = (failure) => logger(ctx).warn(`[pi2dsh] extension entry failed and was skipped (matching Pi's per-extension error isolation): ${failure}`);
|
|
@@ -6425,6 +6781,7 @@ async function applyPiPackage(ctx, options) {
|
|
|
6425
6781
|
const runtimeInternals = {
|
|
6426
6782
|
compactionReason,
|
|
6427
6783
|
resolveOfferedChoice,
|
|
6784
|
+
currentPiModel,
|
|
6428
6785
|
dshToPiContent,
|
|
6429
6786
|
expandPrompt,
|
|
6430
6787
|
isKnownImageTool,
|
|
@@ -6437,4 +6794,4 @@ const runtimeInternals = {
|
|
|
6437
6794
|
//#endregion
|
|
6438
6795
|
export { registerVisionCompanions as a, overlayProviderConfig as i, mergeProviderRegistration as n, runtimeInternals as o, normalizeToolSchema as r, applyPiPackage as t };
|
|
6439
6796
|
|
|
6440
|
-
//# sourceMappingURL=runtime-
|
|
6797
|
+
//# sourceMappingURL=runtime-t-5iWtFO.mjs.map
|