@openma/deepseek-harness-acp 0.4.13 → 0.4.15
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 +48 -25
- package/dist/bridge.js +43 -3
- package/dist/index.js +3 -1
- package/dist/plugin.js +43 -3
- package/dist/server.js +43 -3
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -31,13 +31,13 @@ touch your editor config — it reuses the key you saved in the dsh Web UI, or
|
|
|
31
31
|
|
|
32
32
|
## Two entry points, one embeddable plugin
|
|
33
33
|
|
|
34
|
-
| | **A ·
|
|
34
|
+
| | **A · dsh profile plugin (recommended)** | **B · Standalone server** |
|
|
35
35
|
|---|---|---|
|
|
36
|
-
| Best for |
|
|
37
|
-
| Install | `
|
|
38
|
-
| Zed runs | `dsh
|
|
39
|
-
| Harness | Your installed dsh — or the npm-installed peer when none exists |
|
|
40
|
-
| Composition | dsh-base + this bundle
|
|
36
|
+
| Best for | Normal installation and upgrades | Connecting an ACP client without managing a dsh profile |
|
|
37
|
+
| Install | `dsh plugin --profile acp add @openma/deepseek-harness-acp@latest` | `npm i -g @openma/deepseek-harness-acp` |
|
|
38
|
+
| Zed runs | `dsh --profile acp` | `dsh-acp` |
|
|
39
|
+
| Harness | The dsh that owns the profile | Your installed dsh — or the npm-installed peer when none exists |
|
|
40
|
+
| Composition | dsh-base + this bundle + your profile's own patches | dsh-base + this bundle (profile machinery booted in-process) |
|
|
41
41
|
|
|
42
42
|
Both shapes share `$DSH_HOME`: the same credential store, settings, presets,
|
|
43
43
|
and session logs as `dsh web` — conversations started in the Web UI can be
|
|
@@ -54,55 +54,78 @@ plugin used by other dsh applications: one Host composition can expose the
|
|
|
54
54
|
same sessions, tools, presets, skills, and persistence through a transport
|
|
55
55
|
chosen by the surface.
|
|
56
56
|
|
|
57
|
-
### A ·
|
|
57
|
+
### A · dsh profile plugin (recommended)
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
npm install -g @
|
|
61
|
-
dsh
|
|
60
|
+
npm install -g @deepseek-ai/dsh
|
|
61
|
+
dsh web # save your API key once
|
|
62
|
+
dsh plugin --profile acp add @openma/deepseek-harness-acp@latest
|
|
62
63
|
```
|
|
63
64
|
|
|
64
65
|
```jsonc
|
|
65
66
|
// Zed settings.json
|
|
66
67
|
{
|
|
67
68
|
"agent_servers": {
|
|
68
|
-
"DeepSeek Harness": { "command": "dsh
|
|
69
|
+
"DeepSeek Harness": { "command": "dsh", "args": ["--profile", "acp"] }
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
```
|
|
72
73
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`$DSH_HOME/profiles/acp`
|
|
74
|
+
The plugin command creates `$DSH_HOME/profiles/acp`, installs or upgrades the
|
|
75
|
+
adapter, and registers its `dsh.bundle` patch. The bridge mounts over
|
|
76
|
+
`@deepseek-ai/dsh-base` — the same product baseline as `dsh web`, with the
|
|
77
|
+
module-reload watcher off. Extend the profile in
|
|
78
|
+
`$DSH_HOME/profiles/acp/cordis.patch.yml` like any other dsh profile. A global
|
|
79
|
+
`dsh-acp` installation is not required for this path.
|
|
78
80
|
|
|
79
|
-
### B ·
|
|
81
|
+
### B · Standalone server
|
|
80
82
|
|
|
81
83
|
```bash
|
|
82
|
-
npm install -g @deepseek-
|
|
83
|
-
dsh
|
|
84
|
-
dsh plugin --profile acp add -w @openma/deepseek-harness-acp
|
|
84
|
+
npm install -g @openma/deepseek-harness-acp
|
|
85
|
+
dsh-acp login # interactive; or save the key in the dsh Web UI
|
|
85
86
|
```
|
|
86
87
|
|
|
87
88
|
```jsonc
|
|
88
89
|
// Zed settings.json
|
|
89
90
|
{
|
|
90
91
|
"agent_servers": {
|
|
91
|
-
"DeepSeek Harness": { "command": "dsh
|
|
92
|
+
"DeepSeek Harness": { "command": "dsh-acp" }
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
95
|
```
|
|
95
96
|
|
|
96
|
-
|
|
97
|
-
`dsh
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
The standalone binary finds DeepSeek Harness via `--dsh-path` / `DSH_PATH`,
|
|
98
|
+
its own tree, `./node_modules`, `dsh` on PATH, or `npm root -g`. It ships an
|
|
99
|
+
npm-installed harness peer as the **last** candidate, so it still prefers the
|
|
100
|
+
dsh you installed. When a real `$DSH_HOME/profiles/acp` exists, that profile
|
|
101
|
+
owns the composition.
|
|
101
102
|
|
|
102
103
|
## Plugin and extension model
|
|
103
104
|
|
|
104
105
|
There are two independent ways to extend an ACP-backed surface.
|
|
105
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
|
+
|
|
106
129
|
### Extend the Host composition
|
|
107
130
|
|
|
108
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) {
|
|
@@ -1767,6 +1796,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1767
1796
|
const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
|
|
1768
1797
|
const SANDBOX_MODES2 = harness.sandboxModes;
|
|
1769
1798
|
const sessions = /* @__PURE__ */ new Map();
|
|
1799
|
+
const commandPublications = new LatestPublication();
|
|
1770
1800
|
const subagentByChild = /* @__PURE__ */ new Map();
|
|
1771
1801
|
const subagentByRun = /* @__PURE__ */ new Map();
|
|
1772
1802
|
const watchedSubagentParents = /* @__PURE__ */ new WeakSet();
|
|
@@ -1775,6 +1805,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1775
1805
|
let clientTerminalOutput = false;
|
|
1776
1806
|
let clientSubagentTranscript = false;
|
|
1777
1807
|
let clientElicitationForm = false;
|
|
1808
|
+
let clientInteractionMode;
|
|
1778
1809
|
const tuiClient = { advertised: false };
|
|
1779
1810
|
const rpc = new AcpRpc();
|
|
1780
1811
|
const findAgent = (agentId) => {
|
|
@@ -2003,11 +2034,11 @@ async function apply3(ctx, config = {}) {
|
|
|
2003
2034
|
'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
2035
|
);
|
|
2005
2036
|
};
|
|
2006
|
-
const agentOptionsFor = (model, provider) => ({
|
|
2037
|
+
const agentOptionsFor = (model, provider) => withInteractionMode({
|
|
2007
2038
|
...provider !== void 0 ? { provider } : config.provider !== void 0 ? { provider: config.provider } : {},
|
|
2008
2039
|
...model !== void 0 ? { model } : {},
|
|
2009
2040
|
...config.maxTokens !== void 0 ? { maxTokens: config.maxTokens } : {}
|
|
2010
|
-
});
|
|
2041
|
+
}, clientInteractionMode);
|
|
2011
2042
|
const ownedRecord = (agent) => {
|
|
2012
2043
|
const record = sessions.get(String(agent.session.id));
|
|
2013
2044
|
return record?.agent === agent ? record : void 0;
|
|
@@ -2481,12 +2512,20 @@ async function apply3(ctx, config = {}) {
|
|
|
2481
2512
|
const publishCommands = (sessionId, record) => {
|
|
2482
2513
|
const target = record ?? sessions.get(sessionId);
|
|
2483
2514
|
if (target === void 0) return;
|
|
2484
|
-
void availableCommandsFor(target)
|
|
2515
|
+
void commandPublications.run(sessionId, () => availableCommandsFor(target), (availableCommands) => {
|
|
2516
|
+
if (sessions.get(sessionId) !== target) return;
|
|
2517
|
+
logDebug(
|
|
2518
|
+
`available commands ${sessionId}: ${availableCommands.map((command) => command.name).join(", ")}`
|
|
2519
|
+
);
|
|
2485
2520
|
notify(sessionId, { sessionUpdate: "available_commands_update", availableCommands });
|
|
2486
2521
|
}).catch((error) => {
|
|
2487
2522
|
logWarn(`publishing commands failed: ${String(error)}`);
|
|
2488
2523
|
});
|
|
2489
2524
|
};
|
|
2525
|
+
ctx.on("commands/change", () => {
|
|
2526
|
+
logDebug(`commands/change: ${sessions.size} live ACP session(s)`);
|
|
2527
|
+
for (const [sessionId, record] of sessions) publishCommands(sessionId, record);
|
|
2528
|
+
});
|
|
2490
2529
|
const publishConfigOptions = (sessionId, record) => {
|
|
2491
2530
|
void configOptions(record).then((options) => {
|
|
2492
2531
|
notify(sessionId, {
|
|
@@ -2699,6 +2738,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2699
2738
|
const capsMeta = params.clientCapabilities?.["_meta"];
|
|
2700
2739
|
clientTerminalOutput = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["terminal_output"] === true : false;
|
|
2701
2740
|
clientSubagentTranscript = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["subagent-transcript"] === true : false;
|
|
2741
|
+
clientInteractionMode = interactionModeFromClientMeta(capsMeta);
|
|
2702
2742
|
clientElicitationForm = params.clientCapabilities?.elicitation?.form !== void 0 && params.clientCapabilities.elicitation.form !== null;
|
|
2703
2743
|
tuiClient.advertised = advertisesCordis(capsMeta);
|
|
2704
2744
|
const providers = await listProviderRoutes();
|
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) {
|
|
@@ -1768,6 +1797,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1768
1797
|
const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
|
|
1769
1798
|
const SANDBOX_MODES2 = harness.sandboxModes;
|
|
1770
1799
|
const sessions = /* @__PURE__ */ new Map();
|
|
1800
|
+
const commandPublications = new LatestPublication();
|
|
1771
1801
|
const subagentByChild = /* @__PURE__ */ new Map();
|
|
1772
1802
|
const subagentByRun = /* @__PURE__ */ new Map();
|
|
1773
1803
|
const watchedSubagentParents = /* @__PURE__ */ new WeakSet();
|
|
@@ -1776,6 +1806,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1776
1806
|
let clientTerminalOutput = false;
|
|
1777
1807
|
let clientSubagentTranscript = false;
|
|
1778
1808
|
let clientElicitationForm = false;
|
|
1809
|
+
let clientInteractionMode;
|
|
1779
1810
|
const tuiClient = { advertised: false };
|
|
1780
1811
|
const rpc = new AcpRpc();
|
|
1781
1812
|
const findAgent = (agentId) => {
|
|
@@ -2004,11 +2035,11 @@ async function apply3(ctx, config = {}) {
|
|
|
2004
2035
|
'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
2036
|
);
|
|
2006
2037
|
};
|
|
2007
|
-
const agentOptionsFor = (model, provider) => ({
|
|
2038
|
+
const agentOptionsFor = (model, provider) => withInteractionMode({
|
|
2008
2039
|
...provider !== void 0 ? { provider } : config.provider !== void 0 ? { provider: config.provider } : {},
|
|
2009
2040
|
...model !== void 0 ? { model } : {},
|
|
2010
2041
|
...config.maxTokens !== void 0 ? { maxTokens: config.maxTokens } : {}
|
|
2011
|
-
});
|
|
2042
|
+
}, clientInteractionMode);
|
|
2012
2043
|
const ownedRecord = (agent) => {
|
|
2013
2044
|
const record = sessions.get(String(agent.session.id));
|
|
2014
2045
|
return record?.agent === agent ? record : void 0;
|
|
@@ -2482,12 +2513,20 @@ async function apply3(ctx, config = {}) {
|
|
|
2482
2513
|
const publishCommands = (sessionId, record) => {
|
|
2483
2514
|
const target = record ?? sessions.get(sessionId);
|
|
2484
2515
|
if (target === void 0) return;
|
|
2485
|
-
void availableCommandsFor(target)
|
|
2516
|
+
void commandPublications.run(sessionId, () => availableCommandsFor(target), (availableCommands) => {
|
|
2517
|
+
if (sessions.get(sessionId) !== target) return;
|
|
2518
|
+
logDebug(
|
|
2519
|
+
`available commands ${sessionId}: ${availableCommands.map((command) => command.name).join(", ")}`
|
|
2520
|
+
);
|
|
2486
2521
|
notify(sessionId, { sessionUpdate: "available_commands_update", availableCommands });
|
|
2487
2522
|
}).catch((error) => {
|
|
2488
2523
|
logWarn(`publishing commands failed: ${String(error)}`);
|
|
2489
2524
|
});
|
|
2490
2525
|
};
|
|
2526
|
+
ctx.on("commands/change", () => {
|
|
2527
|
+
logDebug(`commands/change: ${sessions.size} live ACP session(s)`);
|
|
2528
|
+
for (const [sessionId, record] of sessions) publishCommands(sessionId, record);
|
|
2529
|
+
});
|
|
2491
2530
|
const publishConfigOptions = (sessionId, record) => {
|
|
2492
2531
|
void configOptions(record).then((options) => {
|
|
2493
2532
|
notify(sessionId, {
|
|
@@ -2700,6 +2739,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2700
2739
|
const capsMeta = params.clientCapabilities?.["_meta"];
|
|
2701
2740
|
clientTerminalOutput = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["terminal_output"] === true : false;
|
|
2702
2741
|
clientSubagentTranscript = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["subagent-transcript"] === true : false;
|
|
2742
|
+
clientInteractionMode = interactionModeFromClientMeta(capsMeta);
|
|
2703
2743
|
clientElicitationForm = params.clientCapabilities?.elicitation?.form !== void 0 && params.clientCapabilities.elicitation.form !== null;
|
|
2704
2744
|
tuiClient.advertised = advertisesCordis(capsMeta);
|
|
2705
2745
|
const providers = await listProviderRoutes();
|
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) {
|
|
@@ -1763,6 +1792,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1763
1792
|
const { createUserMessage: createUserMessage2, errorChain: errorChain2, sessionId: SessionId2, foldSessionTitle: foldSessionTitle2, setSandboxMode: setSandboxMode2 } = harness;
|
|
1764
1793
|
const SANDBOX_MODES2 = harness.sandboxModes;
|
|
1765
1794
|
const sessions = /* @__PURE__ */ new Map();
|
|
1795
|
+
const commandPublications = new LatestPublication();
|
|
1766
1796
|
const subagentByChild = /* @__PURE__ */ new Map();
|
|
1767
1797
|
const subagentByRun = /* @__PURE__ */ new Map();
|
|
1768
1798
|
const watchedSubagentParents = /* @__PURE__ */ new WeakSet();
|
|
@@ -1771,6 +1801,7 @@ async function apply3(ctx, config = {}) {
|
|
|
1771
1801
|
let clientTerminalOutput = false;
|
|
1772
1802
|
let clientSubagentTranscript = false;
|
|
1773
1803
|
let clientElicitationForm = false;
|
|
1804
|
+
let clientInteractionMode;
|
|
1774
1805
|
const tuiClient = { advertised: false };
|
|
1775
1806
|
const rpc = new AcpRpc();
|
|
1776
1807
|
const findAgent = (agentId) => {
|
|
@@ -1999,11 +2030,11 @@ async function apply3(ctx, config = {}) {
|
|
|
1999
2030
|
'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
2031
|
);
|
|
2001
2032
|
};
|
|
2002
|
-
const agentOptionsFor = (model, provider) => ({
|
|
2033
|
+
const agentOptionsFor = (model, provider) => withInteractionMode({
|
|
2003
2034
|
...provider !== void 0 ? { provider } : config.provider !== void 0 ? { provider: config.provider } : {},
|
|
2004
2035
|
...model !== void 0 ? { model } : {},
|
|
2005
2036
|
...config.maxTokens !== void 0 ? { maxTokens: config.maxTokens } : {}
|
|
2006
|
-
});
|
|
2037
|
+
}, clientInteractionMode);
|
|
2007
2038
|
const ownedRecord = (agent) => {
|
|
2008
2039
|
const record = sessions.get(String(agent.session.id));
|
|
2009
2040
|
return record?.agent === agent ? record : void 0;
|
|
@@ -2477,12 +2508,20 @@ async function apply3(ctx, config = {}) {
|
|
|
2477
2508
|
const publishCommands = (sessionId, record) => {
|
|
2478
2509
|
const target = record ?? sessions.get(sessionId);
|
|
2479
2510
|
if (target === void 0) return;
|
|
2480
|
-
void availableCommandsFor(target)
|
|
2511
|
+
void commandPublications.run(sessionId, () => availableCommandsFor(target), (availableCommands) => {
|
|
2512
|
+
if (sessions.get(sessionId) !== target) return;
|
|
2513
|
+
logDebug(
|
|
2514
|
+
`available commands ${sessionId}: ${availableCommands.map((command) => command.name).join(", ")}`
|
|
2515
|
+
);
|
|
2481
2516
|
notify(sessionId, { sessionUpdate: "available_commands_update", availableCommands });
|
|
2482
2517
|
}).catch((error) => {
|
|
2483
2518
|
logWarn(`publishing commands failed: ${String(error)}`);
|
|
2484
2519
|
});
|
|
2485
2520
|
};
|
|
2521
|
+
ctx.on("commands/change", () => {
|
|
2522
|
+
logDebug(`commands/change: ${sessions.size} live ACP session(s)`);
|
|
2523
|
+
for (const [sessionId, record] of sessions) publishCommands(sessionId, record);
|
|
2524
|
+
});
|
|
2486
2525
|
const publishConfigOptions = (sessionId, record) => {
|
|
2487
2526
|
void configOptions(record).then((options) => {
|
|
2488
2527
|
notify(sessionId, {
|
|
@@ -2695,6 +2734,7 @@ async function apply3(ctx, config = {}) {
|
|
|
2695
2734
|
const capsMeta = params.clientCapabilities?.["_meta"];
|
|
2696
2735
|
clientTerminalOutput = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["terminal_output"] === true : false;
|
|
2697
2736
|
clientSubagentTranscript = capsMeta !== null && typeof capsMeta === "object" ? capsMeta["subagent-transcript"] === true : false;
|
|
2737
|
+
clientInteractionMode = interactionModeFromClientMeta(capsMeta);
|
|
2698
2738
|
clientElicitationForm = params.clientCapabilities?.elicitation?.form !== void 0 && params.clientCapabilities.elicitation.form !== null;
|
|
2699
2739
|
tuiClient.advertised = advertisesCordis(capsMeta);
|
|
2700
2740
|
const providers = await listProviderRoutes();
|
package/package.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.4.
|
|
6
|
+
"version": "0.4.15",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/openma-ai/deepseek-harness-acp.git"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://
|
|
11
|
+
"homepage": "https://dshsuite.dev/#other-products",
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/openma-ai/deepseek-harness-acp/issues"
|
|
14
14
|
},
|
|
@@ -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",
|