@openma/deepseek-harness-acp 0.2.0 → 0.3.0
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 +27 -0
- package/cordis.patch.yml +84 -0
- package/dist/bridge.js +162 -47
- package/dist/index.js +162 -47
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -161,6 +161,33 @@ npm install --prefix /tmp/dsh-host @deepseek-ai/dsh
|
|
|
161
161
|
DSH_ACP_TEST_HOST=/tmp/dsh-host npm test
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
+
### Live iteration: paired profiles
|
|
165
|
+
|
|
166
|
+
Keep the profile you use in your editor on the published package, and point a
|
|
167
|
+
second profile at this worktree via a pnpm symlink:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# stable — what Zed uses day to day
|
|
171
|
+
dsh plugin --profile acp add -w @openma/deepseek-harness-acp
|
|
172
|
+
|
|
173
|
+
# dev — a symlink to this checkout; no packing, no version bumps
|
|
174
|
+
dsh plugin --profile acp-test add -w "link:$PWD"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The dev loop is then just `npm run build` and a process restart (`dist/` and
|
|
178
|
+
`cordis.patch.yml` are read through the link). Note pnpm treats `file:` as a
|
|
179
|
+
copy install and caches same-version tarballs — `link:` avoids both. In Zed,
|
|
180
|
+
register both entries:
|
|
181
|
+
|
|
182
|
+
```jsonc
|
|
183
|
+
{
|
|
184
|
+
"agent_servers": {
|
|
185
|
+
"DeepSeek Harness": { "command": "dsh", "args": ["--profile", "acp"] },
|
|
186
|
+
"DeepSeek Harness (dev)": { "command": "dsh", "args": ["--profile", "acp-test"] }
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
164
191
|
## License
|
|
165
192
|
|
|
166
193
|
Apache-2.0.
|
package/cordis.patch.yml
CHANGED
|
@@ -20,7 +20,91 @@
|
|
|
20
20
|
- id: hmr
|
|
21
21
|
disabled: true
|
|
22
22
|
|
|
23
|
+
# Model-facing tool rows move off the host plane and into each agent preset's
|
|
24
|
+
# own composition (standard/code/minimal/cordis ship complete agent.cordis.yml
|
|
25
|
+
# files) — the same split the web-app bundle makes, and what gives "minimal"
|
|
26
|
+
# its two-tool surface. Host-plane services (job/skill/goal registries,
|
|
27
|
+
# shell-env, sandbox, approval) stay in dsh-base and serve every preset.
|
|
28
|
+
|
|
29
|
+
- id: tool-bash
|
|
30
|
+
disabled: true
|
|
31
|
+
|
|
32
|
+
- id: tool-pwsh
|
|
33
|
+
disabled: true
|
|
34
|
+
|
|
35
|
+
- id: tool-jobs
|
|
36
|
+
disabled: true
|
|
37
|
+
|
|
38
|
+
- id: tool-fs
|
|
39
|
+
disabled: true
|
|
40
|
+
|
|
41
|
+
- id: tool-fs-search
|
|
42
|
+
disabled: true
|
|
43
|
+
|
|
44
|
+
- id: tool-str-replace-editor
|
|
45
|
+
disabled: true
|
|
46
|
+
|
|
47
|
+
- id: skill-filesystem
|
|
48
|
+
disabled: true
|
|
49
|
+
|
|
50
|
+
- id: tool-skill
|
|
51
|
+
disabled: true
|
|
52
|
+
|
|
53
|
+
- id: tool-goal
|
|
54
|
+
disabled: true
|
|
55
|
+
|
|
56
|
+
- id: plan-mode
|
|
57
|
+
disabled: true
|
|
58
|
+
|
|
59
|
+
- id: compaction-basic
|
|
60
|
+
disabled: true
|
|
61
|
+
|
|
62
|
+
- id: command-compact
|
|
63
|
+
disabled: true
|
|
64
|
+
|
|
65
|
+
- id: tool-result-pruner
|
|
66
|
+
disabled: true
|
|
67
|
+
|
|
68
|
+
- id: tool-subagent-control
|
|
69
|
+
disabled: true
|
|
70
|
+
|
|
71
|
+
- id: tool-subagent-list-agents
|
|
72
|
+
disabled: true
|
|
73
|
+
|
|
74
|
+
- id: tool-subagent
|
|
75
|
+
disabled: true
|
|
76
|
+
|
|
77
|
+
- id: tool-subagent-fork
|
|
78
|
+
disabled: true
|
|
79
|
+
|
|
80
|
+
- id: workflow-worker-thread
|
|
81
|
+
disabled: true
|
|
82
|
+
|
|
83
|
+
- id: tool-workflow
|
|
84
|
+
disabled: true
|
|
85
|
+
|
|
86
|
+
- id: tool-ralph
|
|
87
|
+
disabled: true
|
|
88
|
+
|
|
89
|
+
- id: agent-instructions
|
|
90
|
+
disabled: true
|
|
91
|
+
|
|
92
|
+
- id: tool-todo
|
|
93
|
+
disabled: true
|
|
94
|
+
|
|
95
|
+
- id: tool-web
|
|
96
|
+
disabled: true
|
|
97
|
+
|
|
23
98
|
- insert:
|
|
99
|
+
# Agent presets: per-session model-facing compositions (persona, tools,
|
|
100
|
+
# compaction). The dsh CLI injects its shipped root into any row with this
|
|
101
|
+
# id, so standard/code/minimal/creator are available and ACP session modes
|
|
102
|
+
# surface them (~/.dsh/agent-presets adds user-authored ones).
|
|
103
|
+
- id: agent-presets
|
|
104
|
+
name: '@deepseek-ai/dsh-agent-presets'
|
|
105
|
+
config:
|
|
106
|
+
default: standard
|
|
107
|
+
|
|
24
108
|
- id: acp-bridge
|
|
25
109
|
name: '@openma/deepseek-harness-acp/bridge'
|
|
26
110
|
config:
|
package/dist/bridge.js
CHANGED
|
@@ -58,7 +58,8 @@ import {
|
|
|
58
58
|
} from "@agentclientprotocol/sdk";
|
|
59
59
|
|
|
60
60
|
// src/version.ts
|
|
61
|
-
|
|
61
|
+
import { createRequire } from "node:module";
|
|
62
|
+
var VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
62
63
|
|
|
63
64
|
// src/log.ts
|
|
64
65
|
var PREFIX = "[dsh-acp]";
|
|
@@ -706,7 +707,9 @@ async function apply(ctx, config = {}) {
|
|
|
706
707
|
if (logged !== void 0) return logged;
|
|
707
708
|
const { provider, model } = routeOf(record);
|
|
708
709
|
if (provider === void 0 || model === void 0) return void 0;
|
|
709
|
-
|
|
710
|
+
const defaults = defaultSelection();
|
|
711
|
+
const effort = defaults.model === void 0 || defaults.model === model ? defaults.reasoningEffort : void 0;
|
|
712
|
+
return { provider, model, ...effort !== void 0 ? { reasoningEffort: effort } : {} };
|
|
710
713
|
},
|
|
711
714
|
set current(next) {
|
|
712
715
|
picked = next;
|
|
@@ -740,9 +743,11 @@ async function apply(ctx, config = {}) {
|
|
|
740
743
|
});
|
|
741
744
|
let handle;
|
|
742
745
|
try {
|
|
746
|
+
const presets = presetsService();
|
|
743
747
|
handle = await agents.resume({
|
|
744
748
|
resumeSessionId: sessionId,
|
|
745
|
-
agentOptions: agentOptionsFor(choice.model, choice.provider)
|
|
749
|
+
agentOptions: agentOptionsFor(choice.model, choice.provider),
|
|
750
|
+
...presetSetup(presets, record.preset) !== void 0 ? { setup: presetSetup(presets, record.preset) } : {}
|
|
746
751
|
});
|
|
747
752
|
} catch (error) {
|
|
748
753
|
sessions.delete(acpSessionId);
|
|
@@ -757,6 +762,7 @@ async function apply(ctx, config = {}) {
|
|
|
757
762
|
delete record.provider;
|
|
758
763
|
}
|
|
759
764
|
delete record.selection;
|
|
765
|
+
ensureSelection(record);
|
|
760
766
|
if (record.effort !== void 0) {
|
|
761
767
|
const route = routeOf(record);
|
|
762
768
|
const catalog = await effortCatalog(route.provider, route.model);
|
|
@@ -825,13 +831,84 @@ async function apply(ctx, config = {}) {
|
|
|
825
831
|
record.inflight = void 0;
|
|
826
832
|
inflight.resolve(reason);
|
|
827
833
|
};
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
834
|
+
const presetsService = () => ctx.get("agentPresets");
|
|
835
|
+
const presetSetup = (presets, presetId) => {
|
|
836
|
+
if (presets === void 0 || presetId === void 0) return void 0;
|
|
837
|
+
return async (agentCtx) => {
|
|
838
|
+
logDebug(`preset setup: mounting "${presetId}"`);
|
|
839
|
+
await presets.mount(agentCtx, presetId);
|
|
840
|
+
logDebug(`preset setup: mounted "${presetId}"`);
|
|
841
|
+
};
|
|
842
|
+
};
|
|
843
|
+
const presetFromLog = (header, events) => {
|
|
844
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
845
|
+
const event = events[index];
|
|
846
|
+
if (event?.type === "agent-preset/selected") {
|
|
847
|
+
return event.data?.agentPreset;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return header?.agentPreset;
|
|
851
|
+
};
|
|
852
|
+
const presetLabel = (id) => id.charAt(0).toUpperCase() + id.slice(1);
|
|
853
|
+
const modeState = (record) => {
|
|
854
|
+
const permission = permissionService();
|
|
855
|
+
if (permission !== void 0 && permission.names.length > 0) {
|
|
856
|
+
return {
|
|
857
|
+
currentModeId: record.modeId,
|
|
858
|
+
availableModes: permission.names.map((name3) => {
|
|
859
|
+
const spec = permission.resolve(name3);
|
|
860
|
+
return { id: name3, name: spec.name, description: spec.description };
|
|
861
|
+
})
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
return {
|
|
865
|
+
currentModeId: record.modeId,
|
|
866
|
+
availableModes: SANDBOX_MODES2.map((mode) => {
|
|
867
|
+
const label = MODE_LABELS[mode] ?? { name: mode, description: "" };
|
|
868
|
+
return { id: mode, name: label.name, description: label.description };
|
|
869
|
+
})
|
|
870
|
+
};
|
|
871
|
+
};
|
|
872
|
+
const switchPreset = async (record, acpSessionId, presetId) => {
|
|
873
|
+
if (record.inflight !== void 0) {
|
|
874
|
+
throw invalidParams("cannot switch presets while a prompt is running");
|
|
875
|
+
}
|
|
876
|
+
const presets = presetsService();
|
|
877
|
+
if (presets === void 0) throw invalidParams(`unknown mode: ${presetId}`);
|
|
878
|
+
let resolved;
|
|
879
|
+
try {
|
|
880
|
+
resolved = (await presets.resolve(presetId)).id;
|
|
881
|
+
} catch (error) {
|
|
882
|
+
throw invalidParams(`unknown preset: ${presetId} (${errorChain2(error)})`);
|
|
883
|
+
}
|
|
884
|
+
if (resolved === record.preset) return;
|
|
885
|
+
try {
|
|
886
|
+
record.agent.session.append("agent-preset/selected", { agentPreset: resolved });
|
|
887
|
+
} catch (error) {
|
|
888
|
+
logWarn(`recording preset selection failed: ${String(error)}`);
|
|
889
|
+
}
|
|
890
|
+
const sessionId = record.agent.session.id;
|
|
891
|
+
await record.dispose().catch((error) => {
|
|
892
|
+
logWarn(`dispose during preset switch failed: ${String(error)}`);
|
|
893
|
+
});
|
|
894
|
+
let handle;
|
|
895
|
+
try {
|
|
896
|
+
handle = await agents.resume({
|
|
897
|
+
resumeSessionId: sessionId,
|
|
898
|
+
agentOptions: agentOptionsFor(record.model ?? config.model, record.provider),
|
|
899
|
+
setup: presetSetup(presets, resolved)
|
|
900
|
+
});
|
|
901
|
+
} catch (error) {
|
|
902
|
+
sessions.delete(acpSessionId);
|
|
903
|
+
throw internalError(`preset switch failed: ${errorChain2(error)}`);
|
|
904
|
+
}
|
|
905
|
+
record.agent = handle.agent;
|
|
906
|
+
record.dispose = () => handle.dispose();
|
|
907
|
+
record.preset = resolved;
|
|
908
|
+
delete record.selection;
|
|
909
|
+
ensureSelection(record);
|
|
910
|
+
setApprovalPolicy(record, record.approvals);
|
|
911
|
+
};
|
|
835
912
|
const setApprovalPolicy = (record, policy) => {
|
|
836
913
|
try {
|
|
837
914
|
ctx.get("approval")?.setPolicy?.(record.agent, policy);
|
|
@@ -840,7 +917,19 @@ async function apply(ctx, config = {}) {
|
|
|
840
917
|
}
|
|
841
918
|
record.approvals = policy;
|
|
842
919
|
};
|
|
920
|
+
const permissionService = () => ctx.get("permission");
|
|
843
921
|
const applyMode = (record, sessionId, modeId) => {
|
|
922
|
+
const permission = permissionService();
|
|
923
|
+
if (permission !== void 0 && permission.names.includes(modeId)) {
|
|
924
|
+
let bundledApproval = record.approvals;
|
|
925
|
+
permission.apply(record.agent.session, modeId, (policy) => {
|
|
926
|
+
bundledApproval = policy;
|
|
927
|
+
});
|
|
928
|
+
setApprovalPolicy(record, bundledApproval);
|
|
929
|
+
record.modeId = permission.resolve(modeId).sandbox;
|
|
930
|
+
notify(sessionId, { sessionUpdate: "current_mode_update", currentModeId: modeId });
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
844
933
|
const mode = SANDBOX_MODES2.find((candidate) => candidate === modeId);
|
|
845
934
|
if (mode === void 0) throw invalidParams(`unknown mode: ${modeId}`);
|
|
846
935
|
setSandboxMode2(record.agent.session, mode);
|
|
@@ -871,21 +960,6 @@ async function apply(ctx, config = {}) {
|
|
|
871
960
|
};
|
|
872
961
|
const configOptions = async (record) => {
|
|
873
962
|
const result = [];
|
|
874
|
-
result.push({
|
|
875
|
-
type: "select",
|
|
876
|
-
id: "mode",
|
|
877
|
-
name: "Mode",
|
|
878
|
-
category: "mode",
|
|
879
|
-
currentValue: record.modeId,
|
|
880
|
-
options: SANDBOX_MODES2.map((mode) => {
|
|
881
|
-
const label = MODE_LABELS[mode] ?? { name: mode, description: "" };
|
|
882
|
-
return {
|
|
883
|
-
value: mode,
|
|
884
|
-
name: label.name,
|
|
885
|
-
...label.description.length > 0 ? { description: label.description } : {}
|
|
886
|
-
};
|
|
887
|
-
})
|
|
888
|
-
});
|
|
889
963
|
const models = await modelChoices(record);
|
|
890
964
|
if (models.length >= 2) {
|
|
891
965
|
result.push({
|
|
@@ -901,7 +975,14 @@ async function apply(ctx, config = {}) {
|
|
|
901
975
|
const efforts = await effortCatalog(route.provider, route.model);
|
|
902
976
|
if (efforts !== void 0 && efforts.efforts.length >= 2) {
|
|
903
977
|
const known = new Set(efforts.efforts.map((effort) => effort.id));
|
|
904
|
-
const preferred = [
|
|
978
|
+
const preferred = [
|
|
979
|
+
record.effort,
|
|
980
|
+
loggedConfig(record)?.reasoningEffort,
|
|
981
|
+
// The user's saved product default (Web UI → settings.yaml),
|
|
982
|
+
// e.g. reasoningEffort: max, outranks the adapter's default.
|
|
983
|
+
defaultSelection().reasoningEffort,
|
|
984
|
+
efforts.defaultEffort
|
|
985
|
+
].find(
|
|
905
986
|
(candidate) => candidate !== void 0 && known.has(candidate)
|
|
906
987
|
);
|
|
907
988
|
result.push({
|
|
@@ -917,16 +998,27 @@ async function apply(ctx, config = {}) {
|
|
|
917
998
|
}))
|
|
918
999
|
});
|
|
919
1000
|
}
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1001
|
+
const presets = presetsService();
|
|
1002
|
+
if (presets !== void 0 && record.preset !== void 0) {
|
|
1003
|
+
try {
|
|
1004
|
+
const roster = await presets.list();
|
|
1005
|
+
if (roster.length >= 2) {
|
|
1006
|
+
result.push({
|
|
1007
|
+
type: "select",
|
|
1008
|
+
id: "preset",
|
|
1009
|
+
name: "Preset",
|
|
1010
|
+
currentValue: record.preset,
|
|
1011
|
+
options: roster.map((preset) => ({
|
|
1012
|
+
value: preset.id,
|
|
1013
|
+
name: presetLabel(preset.id),
|
|
1014
|
+
description: `Agent preset \u201C${preset.id}\u201D`
|
|
1015
|
+
}))
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
logWarn(`preset roster unavailable: ${String(error)}`);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
930
1022
|
return result;
|
|
931
1023
|
};
|
|
932
1024
|
const publishCommands = (sessionId) => {
|
|
@@ -1020,6 +1112,7 @@ async function apply(ctx, config = {}) {
|
|
|
1020
1112
|
`| Model | ${route.model ?? "(composition default)"} |`,
|
|
1021
1113
|
`| Reasoning | ${effort ?? "(adapter default)"} |`,
|
|
1022
1114
|
`| Credential | ${await describeCredential()} |`,
|
|
1115
|
+
...record.preset !== void 0 ? [`| Preset | ${record.preset} |`] : [],
|
|
1023
1116
|
`| Permission mode | ${record.modeId} |`,
|
|
1024
1117
|
`| Approvals | ${record.approvals} |`,
|
|
1025
1118
|
`| Workspace | ${record.agent.session.header.cwd ?? process.cwd()} |`,
|
|
@@ -1128,10 +1221,13 @@ async function apply(ctx, config = {}) {
|
|
|
1128
1221
|
validateCwd(params.cwd);
|
|
1129
1222
|
syncMcpServers(params.mcpServers, params.cwd);
|
|
1130
1223
|
const sessionId = SessionId2(randomUUID());
|
|
1224
|
+
const presets = presetsService();
|
|
1225
|
+
const presetId = presets === void 0 ? void 0 : (await presets.resolve(void 0)).id;
|
|
1131
1226
|
const handle = await agents.create({
|
|
1132
1227
|
sessionId,
|
|
1133
|
-
meta: { cwd: params.cwd },
|
|
1134
|
-
agentOptions: agentOptionsFor(config.model)
|
|
1228
|
+
meta: { cwd: params.cwd, ...presetId !== void 0 ? { agentPreset: presetId } : {} },
|
|
1229
|
+
agentOptions: agentOptionsFor(config.model),
|
|
1230
|
+
...presetSetup(presets, presetId) !== void 0 ? { setup: presetSetup(presets, presetId) } : {}
|
|
1135
1231
|
});
|
|
1136
1232
|
if (closed) {
|
|
1137
1233
|
await handle.dispose();
|
|
@@ -1144,6 +1240,8 @@ async function apply(ctx, config = {}) {
|
|
|
1144
1240
|
config.model,
|
|
1145
1241
|
config.permissionMode ?? "workspace-write"
|
|
1146
1242
|
);
|
|
1243
|
+
if (presetId !== void 0) record.preset = presetId;
|
|
1244
|
+
ensureSelection(record);
|
|
1147
1245
|
queueMicrotask(() => publishCommands(String(sessionId)));
|
|
1148
1246
|
const options = await configOptions(record);
|
|
1149
1247
|
return {
|
|
@@ -1168,8 +1266,11 @@ async function apply(ctx, config = {}) {
|
|
|
1168
1266
|
});
|
|
1169
1267
|
}
|
|
1170
1268
|
let events;
|
|
1269
|
+
let storedHeader;
|
|
1171
1270
|
try {
|
|
1172
|
-
|
|
1271
|
+
const inspected = await persistence.inspect(SessionId2(sessionId));
|
|
1272
|
+
events = inspected.events;
|
|
1273
|
+
storedHeader = inspected.header;
|
|
1173
1274
|
} catch (error) {
|
|
1174
1275
|
throw invalidParams(`session not found: ${sessionId} (${errorChain2(error)})`);
|
|
1175
1276
|
}
|
|
@@ -1181,9 +1282,13 @@ async function apply(ctx, config = {}) {
|
|
|
1181
1282
|
title: replay.title
|
|
1182
1283
|
});
|
|
1183
1284
|
}
|
|
1285
|
+
const presets = presetsService();
|
|
1286
|
+
const storedPreset = presetFromLog(storedHeader, events);
|
|
1287
|
+
const presetId = presets === void 0 ? void 0 : (await presets.resolve(storedPreset)).id;
|
|
1184
1288
|
const handle = await agents.resume({
|
|
1185
1289
|
resumeSessionId: SessionId2(sessionId),
|
|
1186
|
-
agentOptions: agentOptionsFor(config.model)
|
|
1290
|
+
agentOptions: agentOptionsFor(config.model),
|
|
1291
|
+
...presetSetup(presets, presetId) !== void 0 ? { setup: presetSetup(presets, presetId) } : {}
|
|
1187
1292
|
});
|
|
1188
1293
|
const projection = new SessionProjection(replay.contextWindow);
|
|
1189
1294
|
projection.title = replay.title;
|
|
@@ -1195,6 +1300,21 @@ async function apply(ctx, config = {}) {
|
|
|
1195
1300
|
config.permissionMode ?? "workspace-write",
|
|
1196
1301
|
projection
|
|
1197
1302
|
);
|
|
1303
|
+
if (presetId !== void 0) record.preset = presetId;
|
|
1304
|
+
{
|
|
1305
|
+
const permission = permissionService();
|
|
1306
|
+
const storedMode = permission?.current(events);
|
|
1307
|
+
if (storedMode !== void 0) record.modeId = storedMode;
|
|
1308
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
1309
|
+
const event = events[index];
|
|
1310
|
+
if (event?.type === "approval/policy") {
|
|
1311
|
+
const policy = event.data?.policy;
|
|
1312
|
+
if (policy === "ask" || policy === "never") record.approvals = policy;
|
|
1313
|
+
break;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
ensureSelection(record);
|
|
1198
1318
|
queueMicrotask(() => publishCommands(sessionId));
|
|
1199
1319
|
const options = await configOptions(record);
|
|
1200
1320
|
return {
|
|
@@ -1314,13 +1434,8 @@ async function apply(ctx, config = {}) {
|
|
|
1314
1434
|
const value = typeof params.value === "string" ? params.value : void 0;
|
|
1315
1435
|
if (value === void 0) throw invalidParams(`invalid value: ${String(params.value)}`);
|
|
1316
1436
|
switch (params.configId) {
|
|
1317
|
-
case "
|
|
1318
|
-
|
|
1319
|
-
break;
|
|
1320
|
-
}
|
|
1321
|
-
case "approvals": {
|
|
1322
|
-
if (value !== "ask" && value !== "never") throw invalidParams(`unknown approvals: ${value}`);
|
|
1323
|
-
setApprovalPolicy(record, value);
|
|
1437
|
+
case "preset": {
|
|
1438
|
+
await switchPreset(record, params.sessionId, value);
|
|
1324
1439
|
break;
|
|
1325
1440
|
}
|
|
1326
1441
|
case "effort": {
|
package/dist/index.js
CHANGED
|
@@ -72,7 +72,8 @@ import {
|
|
|
72
72
|
} from "@agentclientprotocol/sdk";
|
|
73
73
|
|
|
74
74
|
// src/version.ts
|
|
75
|
-
|
|
75
|
+
import { createRequire } from "node:module";
|
|
76
|
+
var VERSION = createRequire(import.meta.url)("../package.json").version;
|
|
76
77
|
|
|
77
78
|
// src/log.ts
|
|
78
79
|
var PREFIX = "[dsh-acp]";
|
|
@@ -724,7 +725,9 @@ async function apply(ctx, config = {}) {
|
|
|
724
725
|
if (logged !== void 0) return logged;
|
|
725
726
|
const { provider, model } = routeOf(record);
|
|
726
727
|
if (provider === void 0 || model === void 0) return void 0;
|
|
727
|
-
|
|
728
|
+
const defaults = defaultSelection();
|
|
729
|
+
const effort = defaults.model === void 0 || defaults.model === model ? defaults.reasoningEffort : void 0;
|
|
730
|
+
return { provider, model, ...effort !== void 0 ? { reasoningEffort: effort } : {} };
|
|
728
731
|
},
|
|
729
732
|
set current(next) {
|
|
730
733
|
picked = next;
|
|
@@ -758,9 +761,11 @@ async function apply(ctx, config = {}) {
|
|
|
758
761
|
});
|
|
759
762
|
let handle;
|
|
760
763
|
try {
|
|
764
|
+
const presets = presetsService();
|
|
761
765
|
handle = await agents.resume({
|
|
762
766
|
resumeSessionId: sessionId,
|
|
763
|
-
agentOptions: agentOptionsFor(choice.model, choice.provider)
|
|
767
|
+
agentOptions: agentOptionsFor(choice.model, choice.provider),
|
|
768
|
+
...presetSetup(presets, record.preset) !== void 0 ? { setup: presetSetup(presets, record.preset) } : {}
|
|
764
769
|
});
|
|
765
770
|
} catch (error) {
|
|
766
771
|
sessions.delete(acpSessionId);
|
|
@@ -775,6 +780,7 @@ async function apply(ctx, config = {}) {
|
|
|
775
780
|
delete record.provider;
|
|
776
781
|
}
|
|
777
782
|
delete record.selection;
|
|
783
|
+
ensureSelection(record);
|
|
778
784
|
if (record.effort !== void 0) {
|
|
779
785
|
const route = routeOf(record);
|
|
780
786
|
const catalog = await effortCatalog(route.provider, route.model);
|
|
@@ -843,13 +849,84 @@ async function apply(ctx, config = {}) {
|
|
|
843
849
|
record.inflight = void 0;
|
|
844
850
|
inflight.resolve(reason);
|
|
845
851
|
};
|
|
846
|
-
const
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
852
|
+
const presetsService = () => ctx.get("agentPresets");
|
|
853
|
+
const presetSetup = (presets, presetId) => {
|
|
854
|
+
if (presets === void 0 || presetId === void 0) return void 0;
|
|
855
|
+
return async (agentCtx) => {
|
|
856
|
+
logDebug(`preset setup: mounting "${presetId}"`);
|
|
857
|
+
await presets.mount(agentCtx, presetId);
|
|
858
|
+
logDebug(`preset setup: mounted "${presetId}"`);
|
|
859
|
+
};
|
|
860
|
+
};
|
|
861
|
+
const presetFromLog = (header, events) => {
|
|
862
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
863
|
+
const event = events[index];
|
|
864
|
+
if (event?.type === "agent-preset/selected") {
|
|
865
|
+
return event.data?.agentPreset;
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
return header?.agentPreset;
|
|
869
|
+
};
|
|
870
|
+
const presetLabel = (id) => id.charAt(0).toUpperCase() + id.slice(1);
|
|
871
|
+
const modeState = (record) => {
|
|
872
|
+
const permission = permissionService();
|
|
873
|
+
if (permission !== void 0 && permission.names.length > 0) {
|
|
874
|
+
return {
|
|
875
|
+
currentModeId: record.modeId,
|
|
876
|
+
availableModes: permission.names.map((name3) => {
|
|
877
|
+
const spec = permission.resolve(name3);
|
|
878
|
+
return { id: name3, name: spec.name, description: spec.description };
|
|
879
|
+
})
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
return {
|
|
883
|
+
currentModeId: record.modeId,
|
|
884
|
+
availableModes: SANDBOX_MODES2.map((mode) => {
|
|
885
|
+
const label = MODE_LABELS[mode] ?? { name: mode, description: "" };
|
|
886
|
+
return { id: mode, name: label.name, description: label.description };
|
|
887
|
+
})
|
|
888
|
+
};
|
|
889
|
+
};
|
|
890
|
+
const switchPreset = async (record, acpSessionId, presetId) => {
|
|
891
|
+
if (record.inflight !== void 0) {
|
|
892
|
+
throw invalidParams("cannot switch presets while a prompt is running");
|
|
893
|
+
}
|
|
894
|
+
const presets = presetsService();
|
|
895
|
+
if (presets === void 0) throw invalidParams(`unknown mode: ${presetId}`);
|
|
896
|
+
let resolved;
|
|
897
|
+
try {
|
|
898
|
+
resolved = (await presets.resolve(presetId)).id;
|
|
899
|
+
} catch (error) {
|
|
900
|
+
throw invalidParams(`unknown preset: ${presetId} (${errorChain2(error)})`);
|
|
901
|
+
}
|
|
902
|
+
if (resolved === record.preset) return;
|
|
903
|
+
try {
|
|
904
|
+
record.agent.session.append("agent-preset/selected", { agentPreset: resolved });
|
|
905
|
+
} catch (error) {
|
|
906
|
+
logWarn(`recording preset selection failed: ${String(error)}`);
|
|
907
|
+
}
|
|
908
|
+
const sessionId = record.agent.session.id;
|
|
909
|
+
await record.dispose().catch((error) => {
|
|
910
|
+
logWarn(`dispose during preset switch failed: ${String(error)}`);
|
|
911
|
+
});
|
|
912
|
+
let handle;
|
|
913
|
+
try {
|
|
914
|
+
handle = await agents.resume({
|
|
915
|
+
resumeSessionId: sessionId,
|
|
916
|
+
agentOptions: agentOptionsFor(record.model ?? config.model, record.provider),
|
|
917
|
+
setup: presetSetup(presets, resolved)
|
|
918
|
+
});
|
|
919
|
+
} catch (error) {
|
|
920
|
+
sessions.delete(acpSessionId);
|
|
921
|
+
throw internalError(`preset switch failed: ${errorChain2(error)}`);
|
|
922
|
+
}
|
|
923
|
+
record.agent = handle.agent;
|
|
924
|
+
record.dispose = () => handle.dispose();
|
|
925
|
+
record.preset = resolved;
|
|
926
|
+
delete record.selection;
|
|
927
|
+
ensureSelection(record);
|
|
928
|
+
setApprovalPolicy(record, record.approvals);
|
|
929
|
+
};
|
|
853
930
|
const setApprovalPolicy = (record, policy) => {
|
|
854
931
|
try {
|
|
855
932
|
ctx.get("approval")?.setPolicy?.(record.agent, policy);
|
|
@@ -858,7 +935,19 @@ async function apply(ctx, config = {}) {
|
|
|
858
935
|
}
|
|
859
936
|
record.approvals = policy;
|
|
860
937
|
};
|
|
938
|
+
const permissionService = () => ctx.get("permission");
|
|
861
939
|
const applyMode = (record, sessionId, modeId) => {
|
|
940
|
+
const permission = permissionService();
|
|
941
|
+
if (permission !== void 0 && permission.names.includes(modeId)) {
|
|
942
|
+
let bundledApproval = record.approvals;
|
|
943
|
+
permission.apply(record.agent.session, modeId, (policy) => {
|
|
944
|
+
bundledApproval = policy;
|
|
945
|
+
});
|
|
946
|
+
setApprovalPolicy(record, bundledApproval);
|
|
947
|
+
record.modeId = permission.resolve(modeId).sandbox;
|
|
948
|
+
notify(sessionId, { sessionUpdate: "current_mode_update", currentModeId: modeId });
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
862
951
|
const mode = SANDBOX_MODES2.find((candidate) => candidate === modeId);
|
|
863
952
|
if (mode === void 0) throw invalidParams(`unknown mode: ${modeId}`);
|
|
864
953
|
setSandboxMode2(record.agent.session, mode);
|
|
@@ -889,21 +978,6 @@ async function apply(ctx, config = {}) {
|
|
|
889
978
|
};
|
|
890
979
|
const configOptions = async (record) => {
|
|
891
980
|
const result = [];
|
|
892
|
-
result.push({
|
|
893
|
-
type: "select",
|
|
894
|
-
id: "mode",
|
|
895
|
-
name: "Mode",
|
|
896
|
-
category: "mode",
|
|
897
|
-
currentValue: record.modeId,
|
|
898
|
-
options: SANDBOX_MODES2.map((mode) => {
|
|
899
|
-
const label = MODE_LABELS[mode] ?? { name: mode, description: "" };
|
|
900
|
-
return {
|
|
901
|
-
value: mode,
|
|
902
|
-
name: label.name,
|
|
903
|
-
...label.description.length > 0 ? { description: label.description } : {}
|
|
904
|
-
};
|
|
905
|
-
})
|
|
906
|
-
});
|
|
907
981
|
const models = await modelChoices(record);
|
|
908
982
|
if (models.length >= 2) {
|
|
909
983
|
result.push({
|
|
@@ -919,7 +993,14 @@ async function apply(ctx, config = {}) {
|
|
|
919
993
|
const efforts = await effortCatalog(route.provider, route.model);
|
|
920
994
|
if (efforts !== void 0 && efforts.efforts.length >= 2) {
|
|
921
995
|
const known = new Set(efforts.efforts.map((effort) => effort.id));
|
|
922
|
-
const preferred = [
|
|
996
|
+
const preferred = [
|
|
997
|
+
record.effort,
|
|
998
|
+
loggedConfig(record)?.reasoningEffort,
|
|
999
|
+
// The user's saved product default (Web UI → settings.yaml),
|
|
1000
|
+
// e.g. reasoningEffort: max, outranks the adapter's default.
|
|
1001
|
+
defaultSelection().reasoningEffort,
|
|
1002
|
+
efforts.defaultEffort
|
|
1003
|
+
].find(
|
|
923
1004
|
(candidate) => candidate !== void 0 && known.has(candidate)
|
|
924
1005
|
);
|
|
925
1006
|
result.push({
|
|
@@ -935,16 +1016,27 @@ async function apply(ctx, config = {}) {
|
|
|
935
1016
|
}))
|
|
936
1017
|
});
|
|
937
1018
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1019
|
+
const presets = presetsService();
|
|
1020
|
+
if (presets !== void 0 && record.preset !== void 0) {
|
|
1021
|
+
try {
|
|
1022
|
+
const roster = await presets.list();
|
|
1023
|
+
if (roster.length >= 2) {
|
|
1024
|
+
result.push({
|
|
1025
|
+
type: "select",
|
|
1026
|
+
id: "preset",
|
|
1027
|
+
name: "Preset",
|
|
1028
|
+
currentValue: record.preset,
|
|
1029
|
+
options: roster.map((preset) => ({
|
|
1030
|
+
value: preset.id,
|
|
1031
|
+
name: presetLabel(preset.id),
|
|
1032
|
+
description: `Agent preset \u201C${preset.id}\u201D`
|
|
1033
|
+
}))
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
} catch (error) {
|
|
1037
|
+
logWarn(`preset roster unavailable: ${String(error)}`);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
948
1040
|
return result;
|
|
949
1041
|
};
|
|
950
1042
|
const publishCommands = (sessionId) => {
|
|
@@ -1038,6 +1130,7 @@ async function apply(ctx, config = {}) {
|
|
|
1038
1130
|
`| Model | ${route.model ?? "(composition default)"} |`,
|
|
1039
1131
|
`| Reasoning | ${effort ?? "(adapter default)"} |`,
|
|
1040
1132
|
`| Credential | ${await describeCredential()} |`,
|
|
1133
|
+
...record.preset !== void 0 ? [`| Preset | ${record.preset} |`] : [],
|
|
1041
1134
|
`| Permission mode | ${record.modeId} |`,
|
|
1042
1135
|
`| Approvals | ${record.approvals} |`,
|
|
1043
1136
|
`| Workspace | ${record.agent.session.header.cwd ?? process.cwd()} |`,
|
|
@@ -1146,10 +1239,13 @@ async function apply(ctx, config = {}) {
|
|
|
1146
1239
|
validateCwd(params.cwd);
|
|
1147
1240
|
syncMcpServers(params.mcpServers, params.cwd);
|
|
1148
1241
|
const sessionId = SessionId2(randomUUID());
|
|
1242
|
+
const presets = presetsService();
|
|
1243
|
+
const presetId = presets === void 0 ? void 0 : (await presets.resolve(void 0)).id;
|
|
1149
1244
|
const handle = await agents.create({
|
|
1150
1245
|
sessionId,
|
|
1151
|
-
meta: { cwd: params.cwd },
|
|
1152
|
-
agentOptions: agentOptionsFor(config.model)
|
|
1246
|
+
meta: { cwd: params.cwd, ...presetId !== void 0 ? { agentPreset: presetId } : {} },
|
|
1247
|
+
agentOptions: agentOptionsFor(config.model),
|
|
1248
|
+
...presetSetup(presets, presetId) !== void 0 ? { setup: presetSetup(presets, presetId) } : {}
|
|
1153
1249
|
});
|
|
1154
1250
|
if (closed) {
|
|
1155
1251
|
await handle.dispose();
|
|
@@ -1162,6 +1258,8 @@ async function apply(ctx, config = {}) {
|
|
|
1162
1258
|
config.model,
|
|
1163
1259
|
config.permissionMode ?? "workspace-write"
|
|
1164
1260
|
);
|
|
1261
|
+
if (presetId !== void 0) record.preset = presetId;
|
|
1262
|
+
ensureSelection(record);
|
|
1165
1263
|
queueMicrotask(() => publishCommands(String(sessionId)));
|
|
1166
1264
|
const options = await configOptions(record);
|
|
1167
1265
|
return {
|
|
@@ -1186,8 +1284,11 @@ async function apply(ctx, config = {}) {
|
|
|
1186
1284
|
});
|
|
1187
1285
|
}
|
|
1188
1286
|
let events;
|
|
1287
|
+
let storedHeader;
|
|
1189
1288
|
try {
|
|
1190
|
-
|
|
1289
|
+
const inspected = await persistence.inspect(SessionId2(sessionId));
|
|
1290
|
+
events = inspected.events;
|
|
1291
|
+
storedHeader = inspected.header;
|
|
1191
1292
|
} catch (error) {
|
|
1192
1293
|
throw invalidParams(`session not found: ${sessionId} (${errorChain2(error)})`);
|
|
1193
1294
|
}
|
|
@@ -1199,9 +1300,13 @@ async function apply(ctx, config = {}) {
|
|
|
1199
1300
|
title: replay.title
|
|
1200
1301
|
});
|
|
1201
1302
|
}
|
|
1303
|
+
const presets = presetsService();
|
|
1304
|
+
const storedPreset = presetFromLog(storedHeader, events);
|
|
1305
|
+
const presetId = presets === void 0 ? void 0 : (await presets.resolve(storedPreset)).id;
|
|
1202
1306
|
const handle = await agents.resume({
|
|
1203
1307
|
resumeSessionId: SessionId2(sessionId),
|
|
1204
|
-
agentOptions: agentOptionsFor(config.model)
|
|
1308
|
+
agentOptions: agentOptionsFor(config.model),
|
|
1309
|
+
...presetSetup(presets, presetId) !== void 0 ? { setup: presetSetup(presets, presetId) } : {}
|
|
1205
1310
|
});
|
|
1206
1311
|
const projection = new SessionProjection(replay.contextWindow);
|
|
1207
1312
|
projection.title = replay.title;
|
|
@@ -1213,6 +1318,21 @@ async function apply(ctx, config = {}) {
|
|
|
1213
1318
|
config.permissionMode ?? "workspace-write",
|
|
1214
1319
|
projection
|
|
1215
1320
|
);
|
|
1321
|
+
if (presetId !== void 0) record.preset = presetId;
|
|
1322
|
+
{
|
|
1323
|
+
const permission = permissionService();
|
|
1324
|
+
const storedMode = permission?.current(events);
|
|
1325
|
+
if (storedMode !== void 0) record.modeId = storedMode;
|
|
1326
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
1327
|
+
const event = events[index];
|
|
1328
|
+
if (event?.type === "approval/policy") {
|
|
1329
|
+
const policy = event.data?.policy;
|
|
1330
|
+
if (policy === "ask" || policy === "never") record.approvals = policy;
|
|
1331
|
+
break;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
ensureSelection(record);
|
|
1216
1336
|
queueMicrotask(() => publishCommands(sessionId));
|
|
1217
1337
|
const options = await configOptions(record);
|
|
1218
1338
|
return {
|
|
@@ -1332,13 +1452,8 @@ async function apply(ctx, config = {}) {
|
|
|
1332
1452
|
const value = typeof params.value === "string" ? params.value : void 0;
|
|
1333
1453
|
if (value === void 0) throw invalidParams(`invalid value: ${String(params.value)}`);
|
|
1334
1454
|
switch (params.configId) {
|
|
1335
|
-
case "
|
|
1336
|
-
|
|
1337
|
-
break;
|
|
1338
|
-
}
|
|
1339
|
-
case "approvals": {
|
|
1340
|
-
if (value !== "ask" && value !== "never") throw invalidParams(`unknown approvals: ${value}`);
|
|
1341
|
-
setApprovalPolicy(record, value);
|
|
1455
|
+
case "preset": {
|
|
1456
|
+
await switchPreset(record, params.sessionId, value);
|
|
1342
1457
|
break;
|
|
1343
1458
|
}
|
|
1344
1459
|
case "effort": {
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.3.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/openma-ai/deepseek-harness-acp.git"
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"bugs": {
|
|
13
13
|
"url": "https://github.com/openma-ai/deepseek-harness-acp/issues"
|
|
14
14
|
},
|
|
15
|
-
"description": "Agent Client Protocol (ACP) adapter for DeepSeek Harness
|
|
15
|
+
"description": "Agent Client Protocol (ACP) adapter for DeepSeek Harness \u2014 use DeepSeek Harness from ACP clients such as Zed.",
|
|
16
16
|
"main": "dist/index.js",
|
|
17
17
|
"bin": {
|
|
18
18
|
"dsh-acp": "dist/index.js"
|
|
@@ -123,4 +123,4 @@
|
|
|
123
123
|
"patch": "./cordis.patch.yml"
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
}
|
|
126
|
+
}
|