dsh-plugin-subagent-bridge 0.14.1 → 0.15.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 +18 -0
- package/index.js +31 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,24 @@ dsh_task({ prompt: "…", cwd: "/repo/clawer" })
|
|
|
56
56
|
- 返回结果里带上 `workspace: { id, title, path }`,方便确认落在哪个项目;
|
|
57
57
|
- 项目操作失败不影响派发本身(分组是外观,不因此让任务失败)。
|
|
58
58
|
|
|
59
|
+
## 没人值守:让它自己拿主意(`assumeDefaults`)
|
|
60
|
+
|
|
61
|
+
worker 卡在 `ask_user_question` 上时,需要有人在界面上点一下;但调用方是另一个 agent 时,那个人往往不在。
|
|
62
|
+
|
|
63
|
+
所以桥在派发时会**自动追加一条常驻指令**:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
(如果缺少必要信息或需要在多个方案里选择,直接采用最合理的默认做法继续做完,
|
|
67
|
+
不要把选择权抛回给用户、不要调用 ask_user_question 等回答;
|
|
68
|
+
在结果里用一行说明你假设了什么。)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- 默认开启,配置项 `assumeDefaults: false` 可关掉;
|
|
72
|
+
- `dsh_task`、`dsh_spawn`、`dsh_followup` 三条路径都会加;
|
|
73
|
+
- prompt 里本来就提到 `ask_user_question` 时不追加,避免和调用方的明确意图打架。
|
|
74
|
+
|
|
75
|
+
效果:worker 不会停下来等人,而是选一个合理默认做法做完,并在结果里交代假设,调用方据此复核。
|
|
76
|
+
|
|
59
77
|
## 回答 worker 的问题(`dsh_answer`)
|
|
60
78
|
|
|
61
79
|
worker 需要用户拍板时会调用 `ask_user_question`,然后**卡在那里等**。如果人不在,任务就停住了。
|
package/index.js
CHANGED
|
@@ -75,6 +75,7 @@ const DEFAULTS = {
|
|
|
75
75
|
codexBin: 'codex',
|
|
76
76
|
codexSandbox: 'workspace-write',
|
|
77
77
|
codexTimeoutMs: 300000,
|
|
78
|
+
assumeDefaults: true,
|
|
78
79
|
claudeBin: 'claude',
|
|
79
80
|
claudeModel: '',
|
|
80
81
|
claudeTimeoutMs: 300000,
|
|
@@ -309,6 +310,28 @@ const TOOLS = [
|
|
|
309
310
|
},
|
|
310
311
|
]
|
|
311
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Standing instruction appended to a delegated task.
|
|
315
|
+
*
|
|
316
|
+
* A worker that stops to ask a question needs somebody at the UI; when the caller is
|
|
317
|
+
* another agent, nobody is. The caller would rather have a reasonable assumption and a
|
|
318
|
+
* finished result, so the worker is told to make one and report it.
|
|
319
|
+
*/
|
|
320
|
+
const ASSUMPTION_POLICY =
|
|
321
|
+
'如果缺少必要信息或需要在多个方案里选择,直接采用最合理的默认做法继续做完,不要把选择权抛回给用户、不要调用 ask_user_question 等回答;在结果里用一行说明你假设了什么。'
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Attach the standing instruction when the deployment wants it.
|
|
325
|
+
* @param settings - resolved settings.
|
|
326
|
+
* @param message - caller-supplied text.
|
|
327
|
+
* @returns the text to deliver.
|
|
328
|
+
*/
|
|
329
|
+
function withAssumptionPolicy(settings, message) {
|
|
330
|
+
if (settings.assumeDefaults !== true) return message
|
|
331
|
+
if (message.includes('ask_user_question')) return message
|
|
332
|
+
return `${message}\n\n(${ASSUMPTION_POLICY})`
|
|
333
|
+
}
|
|
334
|
+
|
|
312
335
|
/**
|
|
313
336
|
* Take over the questions a worker asks, so the calling agent can answer them.
|
|
314
337
|
*
|
|
@@ -965,7 +988,7 @@ export function createApi(ctx, state, settings) {
|
|
|
965
988
|
const before = Number(sessions()?.get?.(sessionId)?.seq ?? 0)
|
|
966
989
|
const requestId = randomUUID()
|
|
967
990
|
const accepted = await service.prompt(
|
|
968
|
-
{ sessionId, requestId, mode: mode === 'steer' ? 'steer' : 'queue', content: [{ type: 'text', text: message }] },
|
|
991
|
+
{ sessionId, requestId, mode: mode === 'steer' ? 'steer' : 'queue', content: [{ type: 'text', text: withAssumptionPolicy(settings, message) }] },
|
|
969
992
|
AbortSignal.timeout(30000),
|
|
970
993
|
)
|
|
971
994
|
state.dispatched.add(sessionId)
|
|
@@ -1000,7 +1023,7 @@ export function createApi(ctx, state, settings) {
|
|
|
1000
1023
|
const before = Number(sessions()?.get?.(target.sessionId)?.seq ?? 0)
|
|
1001
1024
|
const requestId = randomUUID()
|
|
1002
1025
|
const accepted = await service.prompt(
|
|
1003
|
-
{ sessionId: target.sessionId, requestId, mode: mode === 'steer' ? 'steer' : 'queue', content: [{ type: 'text', text: message }] },
|
|
1026
|
+
{ sessionId: target.sessionId, requestId, mode: mode === 'steer' ? 'steer' : 'queue', content: [{ type: 'text', text: withAssumptionPolicy(settings, message) }] },
|
|
1004
1027
|
AbortSignal.timeout(30000),
|
|
1005
1028
|
)
|
|
1006
1029
|
state.baseline.set(target.sessionId, before)
|
|
@@ -1079,7 +1102,7 @@ export function createApi(ctx, state, settings) {
|
|
|
1079
1102
|
const finished = waitForTurnEnd(ctx, targetId, waitAfter, seconds * 1000)
|
|
1080
1103
|
const requestId = randomUUID()
|
|
1081
1104
|
const accepted = await service.prompt(
|
|
1082
|
-
{ sessionId: targetId, requestId, mode: deliveryMode, content: [{ type: 'text', text: prompt }] },
|
|
1105
|
+
{ sessionId: targetId, requestId, mode: deliveryMode, content: [{ type: 'text', text: withAssumptionPolicy(settings, prompt) }] },
|
|
1083
1106
|
AbortSignal.timeout(30000),
|
|
1084
1107
|
)
|
|
1085
1108
|
state.dispatched.add(targetId)
|
|
@@ -1141,6 +1164,7 @@ export function createApi(ctx, state, settings) {
|
|
|
1141
1164
|
let settled = false
|
|
1142
1165
|
for (const target of targets) {
|
|
1143
1166
|
const resolved = resolveWorker(state, target)
|
|
1167
|
+
if (resolved !== undefined) attachQuestionAnswerer(state, ctx.get('agents')?.get?.(resolved.sessionId))
|
|
1144
1168
|
const sessionId = resolved === undefined ? target : resolved.sessionId
|
|
1145
1169
|
const value = resolved === undefined ? 'not_found' : workerStatus(ctx, sessionId, state, settings)
|
|
1146
1170
|
if (resolved !== undefined) await rememberOutcome(settings, state, sessionId, value)
|
|
@@ -2308,6 +2332,10 @@ function resolveSettings(config) {
|
|
|
2308
2332
|
}
|
|
2309
2333
|
if (key === 'codexBin' && typeof value === 'string' && value !== '') merged.codexBin = value
|
|
2310
2334
|
if (key === 'codexSandbox' && typeof value === 'string' && value !== '') merged.codexSandbox = value
|
|
2335
|
+
if (key === 'assumeDefaults') {
|
|
2336
|
+
merged.assumeDefaults = value === true || value === 'true'
|
|
2337
|
+
continue
|
|
2338
|
+
}
|
|
2311
2339
|
if (key === 'claudeBin' && typeof value === 'string' && value !== '') merged.claudeBin = value
|
|
2312
2340
|
if (key === 'claudeModel' && typeof value === 'string') merged.claudeModel = value
|
|
2313
2341
|
if (key === 'workersFile' && typeof value === 'string' && value !== '') merged.workersFile = expandHome(value)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-subagent-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Subagent bridge: lets Codex delegate a task to DeepSeek Harness the way it would spawn a subagent (one call, waits for the answer), plus a codex_dispatch tool for the reverse direction.",
|
|
6
6
|
"keywords": [
|