@openma/deepseek-harness-acp 0.4.14 → 0.4.16
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/README.md +22 -0
- package/dist/bridge.js +61 -9
- package/dist/index.js +3 -1
- package/dist/plugin.js +61 -9
- package/dist/server.js +61 -9
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -104,6 +104,28 @@ owns the composition.
|
|
|
104
104
|
|
|
105
105
|
There are two independent ways to extend an ACP-backed surface.
|
|
106
106
|
|
|
107
|
+
To use portable Agent Plugins, Codex plugins, Claude Code plugins, or Pi
|
|
108
|
+
packages through an ACP client, add the
|
|
109
|
+
[Agent Plugins Bridge](https://github.com/openma-ai/dsh-agents-plugins-bridge) to the
|
|
110
|
+
same profile:
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
dsh plugin --profile acp add @openma/dsh-agents-plugins-bridge@latest
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The Bridge contributes ordinary Host rows. Imported commands, skills, tools,
|
|
117
|
+
hooks, MCP connections, agents, and Pi extensions therefore reach ACP through
|
|
118
|
+
this adapter's existing projections; there is no ACP-specific plugin import
|
|
119
|
+
runtime. The Bridge's Web management panel and MCP Apps HTML renderer remain
|
|
120
|
+
Web surfaces and are not sent over ACP.
|
|
121
|
+
|
|
122
|
+
For extensions that need a session-owned background lifecycle without an open
|
|
123
|
+
terminal UI, use
|
|
124
|
+
[Martty owner](https://github.com/openma-ai/deepseek-harness-tui/blob/main/README.en.md#martty-owner-long-lived-headless-acp--pi-rpc).
|
|
125
|
+
It is a generic ACP `rpc` client: this package remains the server/transport,
|
|
126
|
+
while Martty owns the long-lived Session and explicit startup/shutdown slash
|
|
127
|
+
commands.
|
|
128
|
+
|
|
107
129
|
### Extend the Host composition
|
|
108
130
|
|
|
109
131
|
The ACP adapter rides the Cordis tree that the profile already owns. Add dsh
|
package/dist/bridge.js
CHANGED
|
@@ -961,6 +961,35 @@ function buildReplay(events) {
|
|
|
961
961
|
return { updates, title, contextWindow: projection.contextWindow };
|
|
962
962
|
}
|
|
963
963
|
|
|
964
|
+
// src/bridge/latest-publication.ts
|
|
965
|
+
var LatestPublication = class {
|
|
966
|
+
revisions = /* @__PURE__ */ new Map();
|
|
967
|
+
async run(key, produce, publish) {
|
|
968
|
+
const revision = (this.revisions.get(key) ?? 0) + 1;
|
|
969
|
+
this.revisions.set(key, revision);
|
|
970
|
+
const value = await produce();
|
|
971
|
+
if (this.revisions.get(key) !== revision) return;
|
|
972
|
+
publish(value);
|
|
973
|
+
}
|
|
974
|
+
invalidate(key) {
|
|
975
|
+
this.revisions.set(key, (this.revisions.get(key) ?? 0) + 1);
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
// src/bridge/interaction-mode.ts
|
|
980
|
+
function interactionModeFromClientMeta(meta) {
|
|
981
|
+
if (meta === null || typeof meta !== "object") return void 0;
|
|
982
|
+
const dsh = meta["dsh"];
|
|
983
|
+
if (dsh === null || typeof dsh !== "object") return void 0;
|
|
984
|
+
const interaction = dsh["interaction"];
|
|
985
|
+
if (interaction === null || typeof interaction !== "object") return void 0;
|
|
986
|
+
const mode = interaction["mode"];
|
|
987
|
+
return mode === "interactive" || mode === "rpc" ? mode : void 0;
|
|
988
|
+
}
|
|
989
|
+
function withInteractionMode(options, mode) {
|
|
990
|
+
return mode === void 0 ? options : { ...options, interactionMode: mode };
|
|
991
|
+
}
|
|
992
|
+
|
|
964
993
|
// src/bridge/prompt.ts
|
|
965
994
|
function deliverPrompt(target, message, running) {
|
|
966
995
|
if (running) {
|
|
@@ -1721,9 +1750,15 @@ function apply2(ctx, config) {
|
|
|
1721
1750
|
}
|
|
1722
1751
|
|
|
1723
1752
|
// src/bridge/presets.ts
|
|
1753
|
+
var BUILT_IN_PRESET_NAMES = {
|
|
1754
|
+
standard: "Standard",
|
|
1755
|
+
code: "Code",
|
|
1756
|
+
minimal: "Minimal",
|
|
1757
|
+
cordis: "Creator"
|
|
1758
|
+
};
|
|
1724
1759
|
function presetDisplayName(preset) {
|
|
1725
|
-
|
|
1726
|
-
if (
|
|
1760
|
+
const builtInName = BUILT_IN_PRESET_NAMES[preset.id];
|
|
1761
|
+
if (builtInName !== void 0) return builtInName;
|
|
1727
1762
|
const name5 = preset.name?.trim();
|
|
1728
1763
|
return name5 !== void 0 && name5.length > 0 ? name5 : preset.id;
|
|
1729
1764
|
}
|
|
@@ -1767,6 +1802,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1767
1802
|
const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
|
|
1768
1803
|
const SANDBOX_MODES2 = harness.sandboxModes;
|
|
1769
1804
|
const sessions = /* @__PURE__ */ new Map();
|
|
1805
|
+
const commandPublications = new LatestPublication();
|
|
1770
1806
|
const subagentByChild = /* @__PURE__ */ new Map();
|
|
1771
1807
|
const subagentByRun = /* @__PURE__ */ new Map();
|
|
1772
1808
|
const watchedSubagentParents = /* @__PURE__ */ new WeakSet();
|
|
@@ -1775,6 +1811,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1775
1811
|
let clientTerminalOutput = false;
|
|
1776
1812
|
let clientSubagentTranscript = false;
|
|
1777
1813
|
let clientElicitationForm = false;
|
|
1814
|
+
let clientInteractionMode;
|
|
1778
1815
|
const tuiClient = { advertised: false };
|
|
1779
1816
|
const rpc = new AcpRpc();
|
|
1780
1817
|
const findAgent = (agentId) => {
|
|
@@ -1970,6 +2007,11 @@ async function apply3(ctx, config = {}) {
|
|
|
1970
2007
|
}
|
|
1971
2008
|
setApprovalPolicy(record, record.approvals);
|
|
1972
2009
|
};
|
|
2010
|
+
const mutateSession = (record, mutation) => {
|
|
2011
|
+
const run = record.mutationTail.then(mutation);
|
|
2012
|
+
record.mutationTail = run.catch(() => void 0);
|
|
2013
|
+
return run;
|
|
2014
|
+
};
|
|
1973
2015
|
const listProviderRoutes = async () => {
|
|
1974
2016
|
try {
|
|
1975
2017
|
const raw2 = llm.listProviders();
|
|
@@ -2003,11 +2045,11 @@ async function apply3(ctx, config = {}) {
|
|
|
2003
2045
|
'no credential found for this provider: call authenticate with `_meta["api-key"].apiKey` or `_meta.gateway`, use the browser method, run `dsh-acp login`, or save a key in the dsh Web UI (Settings \u2192 Models)'
|
|
2004
2046
|
);
|
|
2005
2047
|
};
|
|
2006
|
-
const agentOptionsFor = (model, provider) => ({
|
|
2048
|
+
const agentOptionsFor = (model, provider) => withInteractionMode({
|
|
2007
2049
|
...provider !== void 0 ? { provider } : config.provider !== void 0 ? { provider: config.provider } : {},
|
|
2008
2050
|
...model !== void 0 ? { model } : {},
|
|
2009
2051
|
...config.maxTokens !== void 0 ? { maxTokens: config.maxTokens } : {}
|
|
2010
|
-
});
|
|
2052
|
+
}, clientInteractionMode);
|
|
2011
2053
|
const ownedRecord = (agent) => {
|
|
2012
2054
|
const record = sessions.get(String(agent.session.id));
|
|
2013
2055
|
return record?.agent === agent ? record : void 0;
|
|
@@ -2481,12 +2523,20 @@ async function apply3(ctx, config = {}) {
|
|
|
2481
2523
|
const publishCommands = (sessionId, record) => {
|
|
2482
2524
|
const target = record ?? sessions.get(sessionId);
|
|
2483
2525
|
if (target === void 0) return;
|
|
2484
|
-
void availableCommandsFor(target)
|
|
2526
|
+
void commandPublications.run(sessionId, () => availableCommandsFor(target), (availableCommands) => {
|
|
2527
|
+
if (sessions.get(sessionId) !== target) return;
|
|
2528
|
+
logDebug(
|
|
2529
|
+
`available commands ${sessionId}: ${availableCommands.map((command) => command.name).join(", ")}`
|
|
2530
|
+
);
|
|
2485
2531
|
notify(sessionId, { sessionUpdate: "available_commands_update", availableCommands });
|
|
2486
2532
|
}).catch((error) => {
|
|
2487
2533
|
logWarn(`publishing commands failed: ${String(error)}`);
|
|
2488
2534
|
});
|
|
2489
2535
|
};
|
|
2536
|
+
ctx.on("commands/change", () => {
|
|
2537
|
+
logDebug(`commands/change: ${sessions.size} live ACP session(s)`);
|
|
2538
|
+
for (const [sessionId, record] of sessions) publishCommands(sessionId, record);
|
|
2539
|
+
});
|
|
2490
2540
|
const publishConfigOptions = (sessionId, record) => {
|
|
2491
2541
|
void configOptions(record).then((options) => {
|
|
2492
2542
|
notify(sessionId, {
|
|
@@ -2586,7 +2636,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2586
2636
|
}
|
|
2587
2637
|
const target = matches[0];
|
|
2588
2638
|
if (target.value === currentValue) return `already on ${target.label}`;
|
|
2589
|
-
await switchModel(record, acpSessionId, target.value);
|
|
2639
|
+
await mutateSession(record, () => switchModel(record, acpSessionId, target.value));
|
|
2590
2640
|
publishCommands(acpSessionId, record);
|
|
2591
2641
|
publishConfigOptions(acpSessionId, record);
|
|
2592
2642
|
return `model \u2192 ${target.label}`;
|
|
@@ -2625,7 +2675,8 @@ async function apply3(ctx, config = {}) {
|
|
|
2625
2675
|
model,
|
|
2626
2676
|
approvals: modeId === "danger-full-access" ? "never" : "ask",
|
|
2627
2677
|
cancelled: false,
|
|
2628
|
-
inflight: void 0
|
|
2678
|
+
inflight: void 0,
|
|
2679
|
+
mutationTail: Promise.resolve()
|
|
2629
2680
|
};
|
|
2630
2681
|
sessions.set(sessionId, record);
|
|
2631
2682
|
watchSubagentParent(agent);
|
|
@@ -2699,6 +2750,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2699
2750
|
const capsMeta = params.clientCapabilities?.["_meta"];
|
|
2700
2751
|
clientTerminalOutput = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["terminal_output"] === true : false;
|
|
2701
2752
|
clientSubagentTranscript = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["subagent-transcript"] === true : false;
|
|
2753
|
+
clientInteractionMode = interactionModeFromClientMeta(capsMeta);
|
|
2702
2754
|
clientElicitationForm = params.clientCapabilities?.elicitation?.form !== void 0 && params.clientCapabilities.elicitation.form !== null;
|
|
2703
2755
|
tuiClient.advertised = advertisesCordis(capsMeta);
|
|
2704
2756
|
const providers = await listProviderRoutes();
|
|
@@ -2985,7 +3037,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2985
3037
|
}
|
|
2986
3038
|
case "agent":
|
|
2987
3039
|
case "preset": {
|
|
2988
|
-
await switchPreset(record, params.sessionId, value);
|
|
3040
|
+
await mutateSession(record, () => switchPreset(record, params.sessionId, value));
|
|
2989
3041
|
break;
|
|
2990
3042
|
}
|
|
2991
3043
|
case "effort": {
|
|
@@ -3024,7 +3076,7 @@ async function apply3(ctx, config = {}) {
|
|
|
3024
3076
|
break;
|
|
3025
3077
|
}
|
|
3026
3078
|
case "model": {
|
|
3027
|
-
await switchModel(record, params.sessionId, value);
|
|
3079
|
+
await mutateSession(record, () => switchModel(record, params.sessionId, value));
|
|
3028
3080
|
break;
|
|
3029
3081
|
}
|
|
3030
3082
|
default:
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ ${probed.map((p) => ` ${p}`).join("\n")}` : ""
|
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
46
|
var ANCHOR = "@deepseek-ai/dsh-agent";
|
|
47
|
+
var PROFILE_LAUNCHER = "@deepseek-ai/dsh";
|
|
47
48
|
function packageDirFrom(base, name) {
|
|
48
49
|
let dir = resolve(base);
|
|
49
50
|
for (; ; ) {
|
|
@@ -66,7 +67,8 @@ function versionOf(packageDir) {
|
|
|
66
67
|
}
|
|
67
68
|
function hostAt(base, source) {
|
|
68
69
|
const anchor = packageDirFrom(base, ANCHOR);
|
|
69
|
-
|
|
70
|
+
const launcher = packageDirFrom(base, PROFILE_LAUNCHER);
|
|
71
|
+
if (anchor === void 0 || launcher === void 0) return void 0;
|
|
70
72
|
return { base: resolve(base), version: versionOf(anchor), source };
|
|
71
73
|
}
|
|
72
74
|
function hostFromExplicit(explicit) {
|
package/dist/plugin.js
CHANGED
|
@@ -962,6 +962,35 @@ function buildReplay(events) {
|
|
|
962
962
|
return { updates, title, contextWindow: projection.contextWindow };
|
|
963
963
|
}
|
|
964
964
|
|
|
965
|
+
// src/bridge/latest-publication.ts
|
|
966
|
+
var LatestPublication = class {
|
|
967
|
+
revisions = /* @__PURE__ */ new Map();
|
|
968
|
+
async run(key, produce, publish) {
|
|
969
|
+
const revision = (this.revisions.get(key) ?? 0) + 1;
|
|
970
|
+
this.revisions.set(key, revision);
|
|
971
|
+
const value = await produce();
|
|
972
|
+
if (this.revisions.get(key) !== revision) return;
|
|
973
|
+
publish(value);
|
|
974
|
+
}
|
|
975
|
+
invalidate(key) {
|
|
976
|
+
this.revisions.set(key, (this.revisions.get(key) ?? 0) + 1);
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
// src/bridge/interaction-mode.ts
|
|
981
|
+
function interactionModeFromClientMeta(meta) {
|
|
982
|
+
if (meta === null || typeof meta !== "object") return void 0;
|
|
983
|
+
const dsh = meta["dsh"];
|
|
984
|
+
if (dsh === null || typeof dsh !== "object") return void 0;
|
|
985
|
+
const interaction = dsh["interaction"];
|
|
986
|
+
if (interaction === null || typeof interaction !== "object") return void 0;
|
|
987
|
+
const mode = interaction["mode"];
|
|
988
|
+
return mode === "interactive" || mode === "rpc" ? mode : void 0;
|
|
989
|
+
}
|
|
990
|
+
function withInteractionMode(options, mode) {
|
|
991
|
+
return mode === void 0 ? options : { ...options, interactionMode: mode };
|
|
992
|
+
}
|
|
993
|
+
|
|
965
994
|
// src/bridge/prompt.ts
|
|
966
995
|
function deliverPrompt(target, message, running) {
|
|
967
996
|
if (running) {
|
|
@@ -1722,9 +1751,15 @@ function apply2(ctx, config) {
|
|
|
1722
1751
|
}
|
|
1723
1752
|
|
|
1724
1753
|
// src/bridge/presets.ts
|
|
1754
|
+
var BUILT_IN_PRESET_NAMES = {
|
|
1755
|
+
standard: "Standard",
|
|
1756
|
+
code: "Code",
|
|
1757
|
+
minimal: "Minimal",
|
|
1758
|
+
cordis: "Creator"
|
|
1759
|
+
};
|
|
1725
1760
|
function presetDisplayName(preset) {
|
|
1726
|
-
|
|
1727
|
-
if (
|
|
1761
|
+
const builtInName = BUILT_IN_PRESET_NAMES[preset.id];
|
|
1762
|
+
if (builtInName !== void 0) return builtInName;
|
|
1728
1763
|
const name6 = preset.name?.trim();
|
|
1729
1764
|
return name6 !== void 0 && name6.length > 0 ? name6 : preset.id;
|
|
1730
1765
|
}
|
|
@@ -1768,6 +1803,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1768
1803
|
const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
|
|
1769
1804
|
const SANDBOX_MODES2 = harness.sandboxModes;
|
|
1770
1805
|
const sessions = /* @__PURE__ */ new Map();
|
|
1806
|
+
const commandPublications = new LatestPublication();
|
|
1771
1807
|
const subagentByChild = /* @__PURE__ */ new Map();
|
|
1772
1808
|
const subagentByRun = /* @__PURE__ */ new Map();
|
|
1773
1809
|
const watchedSubagentParents = /* @__PURE__ */ new WeakSet();
|
|
@@ -1776,6 +1812,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1776
1812
|
let clientTerminalOutput = false;
|
|
1777
1813
|
let clientSubagentTranscript = false;
|
|
1778
1814
|
let clientElicitationForm = false;
|
|
1815
|
+
let clientInteractionMode;
|
|
1779
1816
|
const tuiClient = { advertised: false };
|
|
1780
1817
|
const rpc = new AcpRpc();
|
|
1781
1818
|
const findAgent = (agentId) => {
|
|
@@ -1971,6 +2008,11 @@ async function apply3(ctx, config = {}) {
|
|
|
1971
2008
|
}
|
|
1972
2009
|
setApprovalPolicy(record, record.approvals);
|
|
1973
2010
|
};
|
|
2011
|
+
const mutateSession = (record, mutation) => {
|
|
2012
|
+
const run = record.mutationTail.then(mutation);
|
|
2013
|
+
record.mutationTail = run.catch(() => void 0);
|
|
2014
|
+
return run;
|
|
2015
|
+
};
|
|
1974
2016
|
const listProviderRoutes = async () => {
|
|
1975
2017
|
try {
|
|
1976
2018
|
const raw2 = llm.listProviders();
|
|
@@ -2004,11 +2046,11 @@ async function apply3(ctx, config = {}) {
|
|
|
2004
2046
|
'no credential found for this provider: call authenticate with `_meta["api-key"].apiKey` or `_meta.gateway`, use the browser method, run `dsh-acp login`, or save a key in the dsh Web UI (Settings \u2192 Models)'
|
|
2005
2047
|
);
|
|
2006
2048
|
};
|
|
2007
|
-
const agentOptionsFor = (model, provider) => ({
|
|
2049
|
+
const agentOptionsFor = (model, provider) => withInteractionMode({
|
|
2008
2050
|
...provider !== void 0 ? { provider } : config.provider !== void 0 ? { provider: config.provider } : {},
|
|
2009
2051
|
...model !== void 0 ? { model } : {},
|
|
2010
2052
|
...config.maxTokens !== void 0 ? { maxTokens: config.maxTokens } : {}
|
|
2011
|
-
});
|
|
2053
|
+
}, clientInteractionMode);
|
|
2012
2054
|
const ownedRecord = (agent) => {
|
|
2013
2055
|
const record = sessions.get(String(agent.session.id));
|
|
2014
2056
|
return record?.agent === agent ? record : void 0;
|
|
@@ -2482,12 +2524,20 @@ async function apply3(ctx, config = {}) {
|
|
|
2482
2524
|
const publishCommands = (sessionId, record) => {
|
|
2483
2525
|
const target = record ?? sessions.get(sessionId);
|
|
2484
2526
|
if (target === void 0) return;
|
|
2485
|
-
void availableCommandsFor(target)
|
|
2527
|
+
void commandPublications.run(sessionId, () => availableCommandsFor(target), (availableCommands) => {
|
|
2528
|
+
if (sessions.get(sessionId) !== target) return;
|
|
2529
|
+
logDebug(
|
|
2530
|
+
`available commands ${sessionId}: ${availableCommands.map((command) => command.name).join(", ")}`
|
|
2531
|
+
);
|
|
2486
2532
|
notify(sessionId, { sessionUpdate: "available_commands_update", availableCommands });
|
|
2487
2533
|
}).catch((error) => {
|
|
2488
2534
|
logWarn(`publishing commands failed: ${String(error)}`);
|
|
2489
2535
|
});
|
|
2490
2536
|
};
|
|
2537
|
+
ctx.on("commands/change", () => {
|
|
2538
|
+
logDebug(`commands/change: ${sessions.size} live ACP session(s)`);
|
|
2539
|
+
for (const [sessionId, record] of sessions) publishCommands(sessionId, record);
|
|
2540
|
+
});
|
|
2491
2541
|
const publishConfigOptions = (sessionId, record) => {
|
|
2492
2542
|
void configOptions(record).then((options) => {
|
|
2493
2543
|
notify(sessionId, {
|
|
@@ -2587,7 +2637,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2587
2637
|
}
|
|
2588
2638
|
const target = matches[0];
|
|
2589
2639
|
if (target.value === currentValue) return `already on ${target.label}`;
|
|
2590
|
-
await switchModel(record, acpSessionId, target.value);
|
|
2640
|
+
await mutateSession(record, () => switchModel(record, acpSessionId, target.value));
|
|
2591
2641
|
publishCommands(acpSessionId, record);
|
|
2592
2642
|
publishConfigOptions(acpSessionId, record);
|
|
2593
2643
|
return `model \u2192 ${target.label}`;
|
|
@@ -2626,7 +2676,8 @@ async function apply3(ctx, config = {}) {
|
|
|
2626
2676
|
model,
|
|
2627
2677
|
approvals: modeId === "danger-full-access" ? "never" : "ask",
|
|
2628
2678
|
cancelled: false,
|
|
2629
|
-
inflight: void 0
|
|
2679
|
+
inflight: void 0,
|
|
2680
|
+
mutationTail: Promise.resolve()
|
|
2630
2681
|
};
|
|
2631
2682
|
sessions.set(sessionId, record);
|
|
2632
2683
|
watchSubagentParent(agent);
|
|
@@ -2700,6 +2751,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2700
2751
|
const capsMeta = params.clientCapabilities?.["_meta"];
|
|
2701
2752
|
clientTerminalOutput = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["terminal_output"] === true : false;
|
|
2702
2753
|
clientSubagentTranscript = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["subagent-transcript"] === true : false;
|
|
2754
|
+
clientInteractionMode = interactionModeFromClientMeta(capsMeta);
|
|
2703
2755
|
clientElicitationForm = params.clientCapabilities?.elicitation?.form !== void 0 && params.clientCapabilities.elicitation.form !== null;
|
|
2704
2756
|
tuiClient.advertised = advertisesCordis(capsMeta);
|
|
2705
2757
|
const providers = await listProviderRoutes();
|
|
@@ -2986,7 +3038,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2986
3038
|
}
|
|
2987
3039
|
case "agent":
|
|
2988
3040
|
case "preset": {
|
|
2989
|
-
await switchPreset(record, params.sessionId, value);
|
|
3041
|
+
await mutateSession(record, () => switchPreset(record, params.sessionId, value));
|
|
2990
3042
|
break;
|
|
2991
3043
|
}
|
|
2992
3044
|
case "effort": {
|
|
@@ -3025,7 +3077,7 @@ async function apply3(ctx, config = {}) {
|
|
|
3025
3077
|
break;
|
|
3026
3078
|
}
|
|
3027
3079
|
case "model": {
|
|
3028
|
-
await switchModel(record, params.sessionId, value);
|
|
3080
|
+
await mutateSession(record, () => switchModel(record, params.sessionId, value));
|
|
3029
3081
|
break;
|
|
3030
3082
|
}
|
|
3031
3083
|
default:
|
package/dist/server.js
CHANGED
|
@@ -957,6 +957,35 @@ function buildReplay(events) {
|
|
|
957
957
|
return { updates, title, contextWindow: projection.contextWindow };
|
|
958
958
|
}
|
|
959
959
|
|
|
960
|
+
// src/bridge/latest-publication.ts
|
|
961
|
+
var LatestPublication = class {
|
|
962
|
+
revisions = /* @__PURE__ */ new Map();
|
|
963
|
+
async run(key, produce, publish) {
|
|
964
|
+
const revision = (this.revisions.get(key) ?? 0) + 1;
|
|
965
|
+
this.revisions.set(key, revision);
|
|
966
|
+
const value = await produce();
|
|
967
|
+
if (this.revisions.get(key) !== revision) return;
|
|
968
|
+
publish(value);
|
|
969
|
+
}
|
|
970
|
+
invalidate(key) {
|
|
971
|
+
this.revisions.set(key, (this.revisions.get(key) ?? 0) + 1);
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
|
|
975
|
+
// src/bridge/interaction-mode.ts
|
|
976
|
+
function interactionModeFromClientMeta(meta) {
|
|
977
|
+
if (meta === null || typeof meta !== "object") return void 0;
|
|
978
|
+
const dsh = meta["dsh"];
|
|
979
|
+
if (dsh === null || typeof dsh !== "object") return void 0;
|
|
980
|
+
const interaction = dsh["interaction"];
|
|
981
|
+
if (interaction === null || typeof interaction !== "object") return void 0;
|
|
982
|
+
const mode = interaction["mode"];
|
|
983
|
+
return mode === "interactive" || mode === "rpc" ? mode : void 0;
|
|
984
|
+
}
|
|
985
|
+
function withInteractionMode(options, mode) {
|
|
986
|
+
return mode === void 0 ? options : { ...options, interactionMode: mode };
|
|
987
|
+
}
|
|
988
|
+
|
|
960
989
|
// src/bridge/prompt.ts
|
|
961
990
|
function deliverPrompt(target, message, running) {
|
|
962
991
|
if (running) {
|
|
@@ -1717,9 +1746,15 @@ function apply2(ctx, config) {
|
|
|
1717
1746
|
}
|
|
1718
1747
|
|
|
1719
1748
|
// src/bridge/presets.ts
|
|
1749
|
+
var BUILT_IN_PRESET_NAMES = {
|
|
1750
|
+
standard: "Standard",
|
|
1751
|
+
code: "Code",
|
|
1752
|
+
minimal: "Minimal",
|
|
1753
|
+
cordis: "Creator"
|
|
1754
|
+
};
|
|
1720
1755
|
function presetDisplayName(preset) {
|
|
1721
|
-
|
|
1722
|
-
if (
|
|
1756
|
+
const builtInName = BUILT_IN_PRESET_NAMES[preset.id];
|
|
1757
|
+
if (builtInName !== void 0) return builtInName;
|
|
1723
1758
|
const name5 = preset.name?.trim();
|
|
1724
1759
|
return name5 !== void 0 && name5.length > 0 ? name5 : preset.id;
|
|
1725
1760
|
}
|
|
@@ -1763,6 +1798,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1763
1798
|
const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
|
|
1764
1799
|
const SANDBOX_MODES2 = harness.sandboxModes;
|
|
1765
1800
|
const sessions = /* @__PURE__ */ new Map();
|
|
1801
|
+
const commandPublications = new LatestPublication();
|
|
1766
1802
|
const subagentByChild = /* @__PURE__ */ new Map();
|
|
1767
1803
|
const subagentByRun = /* @__PURE__ */ new Map();
|
|
1768
1804
|
const watchedSubagentParents = /* @__PURE__ */ new WeakSet();
|
|
@@ -1771,6 +1807,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1771
1807
|
let clientTerminalOutput = false;
|
|
1772
1808
|
let clientSubagentTranscript = false;
|
|
1773
1809
|
let clientElicitationForm = false;
|
|
1810
|
+
let clientInteractionMode;
|
|
1774
1811
|
const tuiClient = { advertised: false };
|
|
1775
1812
|
const rpc = new AcpRpc();
|
|
1776
1813
|
const findAgent = (agentId) => {
|
|
@@ -1966,6 +2003,11 @@ async function apply3(ctx, config = {}) {
|
|
|
1966
2003
|
}
|
|
1967
2004
|
setApprovalPolicy(record, record.approvals);
|
|
1968
2005
|
};
|
|
2006
|
+
const mutateSession = (record, mutation) => {
|
|
2007
|
+
const run = record.mutationTail.then(mutation);
|
|
2008
|
+
record.mutationTail = run.catch(() => void 0);
|
|
2009
|
+
return run;
|
|
2010
|
+
};
|
|
1969
2011
|
const listProviderRoutes = async () => {
|
|
1970
2012
|
try {
|
|
1971
2013
|
const raw2 = llm.listProviders();
|
|
@@ -1999,11 +2041,11 @@ async function apply3(ctx, config = {}) {
|
|
|
1999
2041
|
'no credential found for this provider: call authenticate with `_meta["api-key"].apiKey` or `_meta.gateway`, use the browser method, run `dsh-acp login`, or save a key in the dsh Web UI (Settings \u2192 Models)'
|
|
2000
2042
|
);
|
|
2001
2043
|
};
|
|
2002
|
-
const agentOptionsFor = (model, provider) => ({
|
|
2044
|
+
const agentOptionsFor = (model, provider) => withInteractionMode({
|
|
2003
2045
|
...provider !== void 0 ? { provider } : config.provider !== void 0 ? { provider: config.provider } : {},
|
|
2004
2046
|
...model !== void 0 ? { model } : {},
|
|
2005
2047
|
...config.maxTokens !== void 0 ? { maxTokens: config.maxTokens } : {}
|
|
2006
|
-
});
|
|
2048
|
+
}, clientInteractionMode);
|
|
2007
2049
|
const ownedRecord = (agent) => {
|
|
2008
2050
|
const record = sessions.get(String(agent.session.id));
|
|
2009
2051
|
return record?.agent === agent ? record : void 0;
|
|
@@ -2477,12 +2519,20 @@ async function apply3(ctx, config = {}) {
|
|
|
2477
2519
|
const publishCommands = (sessionId, record) => {
|
|
2478
2520
|
const target = record ?? sessions.get(sessionId);
|
|
2479
2521
|
if (target === void 0) return;
|
|
2480
|
-
void availableCommandsFor(target)
|
|
2522
|
+
void commandPublications.run(sessionId, () => availableCommandsFor(target), (availableCommands) => {
|
|
2523
|
+
if (sessions.get(sessionId) !== target) return;
|
|
2524
|
+
logDebug(
|
|
2525
|
+
`available commands ${sessionId}: ${availableCommands.map((command) => command.name).join(", ")}`
|
|
2526
|
+
);
|
|
2481
2527
|
notify(sessionId, { sessionUpdate: "available_commands_update", availableCommands });
|
|
2482
2528
|
}).catch((error) => {
|
|
2483
2529
|
logWarn(`publishing commands failed: ${String(error)}`);
|
|
2484
2530
|
});
|
|
2485
2531
|
};
|
|
2532
|
+
ctx.on("commands/change", () => {
|
|
2533
|
+
logDebug(`commands/change: ${sessions.size} live ACP session(s)`);
|
|
2534
|
+
for (const [sessionId, record] of sessions) publishCommands(sessionId, record);
|
|
2535
|
+
});
|
|
2486
2536
|
const publishConfigOptions = (sessionId, record) => {
|
|
2487
2537
|
void configOptions(record).then((options) => {
|
|
2488
2538
|
notify(sessionId, {
|
|
@@ -2582,7 +2632,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2582
2632
|
}
|
|
2583
2633
|
const target = matches[0];
|
|
2584
2634
|
if (target.value === currentValue) return `already on ${target.label}`;
|
|
2585
|
-
await switchModel(record, acpSessionId, target.value);
|
|
2635
|
+
await mutateSession(record, () => switchModel(record, acpSessionId, target.value));
|
|
2586
2636
|
publishCommands(acpSessionId, record);
|
|
2587
2637
|
publishConfigOptions(acpSessionId, record);
|
|
2588
2638
|
return `model \u2192 ${target.label}`;
|
|
@@ -2621,7 +2671,8 @@ async function apply3(ctx, config = {}) {
|
|
|
2621
2671
|
model,
|
|
2622
2672
|
approvals: modeId === "danger-full-access" ? "never" : "ask",
|
|
2623
2673
|
cancelled: false,
|
|
2624
|
-
inflight: void 0
|
|
2674
|
+
inflight: void 0,
|
|
2675
|
+
mutationTail: Promise.resolve()
|
|
2625
2676
|
};
|
|
2626
2677
|
sessions.set(sessionId, record);
|
|
2627
2678
|
watchSubagentParent(agent);
|
|
@@ -2695,6 +2746,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2695
2746
|
const capsMeta = params.clientCapabilities?.["_meta"];
|
|
2696
2747
|
clientTerminalOutput = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["terminal_output"] === true : false;
|
|
2697
2748
|
clientSubagentTranscript = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["subagent-transcript"] === true : false;
|
|
2749
|
+
clientInteractionMode = interactionModeFromClientMeta(capsMeta);
|
|
2698
2750
|
clientElicitationForm = params.clientCapabilities?.elicitation?.form !== void 0 && params.clientCapabilities.elicitation.form !== null;
|
|
2699
2751
|
tuiClient.advertised = advertisesCordis(capsMeta);
|
|
2700
2752
|
const providers = await listProviderRoutes();
|
|
@@ -2981,7 +3033,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2981
3033
|
}
|
|
2982
3034
|
case "agent":
|
|
2983
3035
|
case "preset": {
|
|
2984
|
-
await switchPreset(record, params.sessionId, value);
|
|
3036
|
+
await mutateSession(record, () => switchPreset(record, params.sessionId, value));
|
|
2985
3037
|
break;
|
|
2986
3038
|
}
|
|
2987
3039
|
case "effort": {
|
|
@@ -3020,7 +3072,7 @@ async function apply3(ctx, config = {}) {
|
|
|
3020
3072
|
break;
|
|
3021
3073
|
}
|
|
3022
3074
|
case "model": {
|
|
3023
|
-
await switchModel(record, params.sessionId, value);
|
|
3075
|
+
await mutateSession(record, () => switchModel(record, params.sessionId, value));
|
|
3024
3076
|
break;
|
|
3025
3077
|
}
|
|
3026
3078
|
default:
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.4.
|
|
6
|
+
"version": "0.4.16",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/openma-ai/deepseek-harness-acp.git"
|
|
@@ -110,7 +110,8 @@
|
|
|
110
110
|
"pnpm": "11.22.0",
|
|
111
111
|
"tsx": "^4.23.1",
|
|
112
112
|
"typescript": "^7.0.2",
|
|
113
|
-
"vitest": "^4.1.10"
|
|
113
|
+
"vitest": "^4.1.10",
|
|
114
|
+
"yaml": "^2.9.0"
|
|
114
115
|
},
|
|
115
116
|
"dependencies": {
|
|
116
117
|
"@agentclientprotocol/sdk": "^1.3.0",
|