dsh-better-ask-user 0.1.2 → 0.1.4
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/package.json +1 -1
- package/src/ask-tool.js +27 -54
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-better-ask-user",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Independent ask_user_question plugin: configurable wait, input-extended countdown, markdown/mobile card, native or default timeout behavior, and PTC deadline exemption.",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"repository": {
|
package/src/ask-tool.js
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
/** ask_user_question scope shadow:
|
|
1
|
+
/** ask_user_question scope shadow: official contract plus the plugin-managed wait. */
|
|
2
2
|
import { ToolArgsError, validateJsonSchemaValue } from '@deepseek-ai/dsh-tools'
|
|
3
|
-
import { TIMED_WAIT_PARAMETER } from '@deepseek-ai/dsh-user-questions'
|
|
4
3
|
import { buildDefaultAnswer } from './default-answer.js'
|
|
5
4
|
|
|
6
5
|
/** Model-visible notice for the native pending result. */
|
|
7
6
|
export const PENDING_QUESTION_NOTICE = 'No answer batch arrived before the timeout. This is pending, not a skipped answer. Continue useful independent work. The user can still answer; their reply will be a user message identified as answer_to_pending_question with this callId and the original questions. Do not treat this as permission.'
|
|
8
7
|
|
|
9
|
-
/** Compatibility wait field description; the host owns the real wait. */
|
|
10
|
-
const COMPATIBILITY_TIMEOUT = {
|
|
11
|
-
type: 'integer',
|
|
12
|
-
description: 'Compatibility wait field. The host controls the wait duration and timeout behavior; any value supplied here is ignored.',
|
|
13
|
-
}
|
|
14
|
-
|
|
15
8
|
function questionRequest(questions, exec) {
|
|
16
9
|
return {
|
|
17
10
|
questions: questions.map(question => ({
|
|
@@ -22,7 +15,6 @@ function questionRequest(questions, exec) {
|
|
|
22
15
|
options: question.options.map(option => ({ ...option })),
|
|
23
16
|
} : {}),
|
|
24
17
|
...(question.multi_select !== undefined ? { multiSelect: question.multi_select } : {}),
|
|
25
|
-
...(question.detail !== undefined ? { detail: question.detail } : {}),
|
|
26
18
|
})),
|
|
27
19
|
...(exec.agent !== undefined ? { agent: exec.agent } : {}),
|
|
28
20
|
signal: exec.signal,
|
|
@@ -44,33 +36,30 @@ function answerResult(result) {
|
|
|
44
36
|
selected: [...answer.selected],
|
|
45
37
|
...(answer.custom !== undefined ? { custom: answer.custom } : {}),
|
|
46
38
|
})),
|
|
47
|
-
...(result.autoSelected === true ? { autoSelected: true } : {}),
|
|
48
39
|
}
|
|
49
40
|
}
|
|
50
41
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
42
|
+
/** The timed path can return the official pending shape; keep it valid. */
|
|
43
|
+
function outputWithPending(base) {
|
|
44
|
+
const output = { ...base.output }
|
|
45
|
+
const schema = structuredClone(base.output.schema)
|
|
46
|
+
if (Array.isArray(schema?.oneOf) && schema.oneOf.some(branch => branch?.properties?.pending !== undefined)) return output
|
|
47
|
+
output.schema = {
|
|
48
|
+
oneOf: [
|
|
49
|
+
schema,
|
|
50
|
+
{
|
|
51
|
+
type: 'object',
|
|
52
|
+
additionalProperties: false,
|
|
53
|
+
properties: {
|
|
54
|
+
pending: { type: 'boolean' },
|
|
55
|
+
callId: { type: 'string' },
|
|
56
|
+
message: { type: 'string' },
|
|
57
|
+
},
|
|
58
|
+
required: ['pending', 'callId', 'message'],
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
61
|
}
|
|
62
|
-
return
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function timeoutParameters(parameters) {
|
|
66
|
-
const next = structuredClone(parameters)
|
|
67
|
-
if (next?.properties === undefined) next.properties = {}
|
|
68
|
-
if (next.properties[TIMED_WAIT_PARAMETER] === undefined) {
|
|
69
|
-
next.properties[TIMED_WAIT_PARAMETER] = COMPATIBILITY_TIMEOUT
|
|
70
|
-
} else {
|
|
71
|
-
next.properties[TIMED_WAIT_PARAMETER] = { ...next.properties[TIMED_WAIT_PARAMETER], ...COMPATIBILITY_TIMEOUT }
|
|
72
|
-
}
|
|
73
|
-
return next
|
|
62
|
+
return output
|
|
74
63
|
}
|
|
75
64
|
|
|
76
65
|
/**
|
|
@@ -78,23 +67,13 @@ function timeoutParameters(parameters) {
|
|
|
78
67
|
* @param ctx - root host context with userQuestions and optional goals.
|
|
79
68
|
* @param base - existing official ask_user_question definition.
|
|
80
69
|
* @param readConfig - live config reader.
|
|
81
|
-
* @returns a ToolDefinition
|
|
70
|
+
* @returns a ToolDefinition with the official contract and the plugin wait.
|
|
82
71
|
*/
|
|
83
72
|
export function createBetterAskTool(ctx, base, readConfig) {
|
|
84
|
-
const
|
|
85
|
-
const output = {
|
|
86
|
-
...base.output,
|
|
87
|
-
schema: answersOutputSchema(base.output.schema),
|
|
88
|
-
render: (_args, value) => [{
|
|
89
|
-
type: 'text',
|
|
90
|
-
text: value?.autoSelected === true
|
|
91
|
-
? 'auto-selected default answer after the question wait expired; this is not a user answer. Verify before relying on it.\n' + JSON.stringify(value)
|
|
92
|
-
: JSON.stringify(value),
|
|
93
|
-
}],
|
|
94
|
-
}
|
|
73
|
+
const output = outputWithPending(base)
|
|
95
74
|
|
|
96
75
|
const execute = async (args, exec) => {
|
|
97
|
-
const violations = validateJsonSchemaValue(parameters, args, '')
|
|
76
|
+
const violations = validateJsonSchemaValue(base.parameters, args, '')
|
|
98
77
|
if (violations.length > 0) throw new ToolArgsError(violations)
|
|
99
78
|
validateQuestionIds(args.questions)
|
|
100
79
|
|
|
@@ -108,7 +87,7 @@ export function createBetterAskTool(ctx, base, readConfig) {
|
|
|
108
87
|
const seconds = config.questionTimeoutSeconds
|
|
109
88
|
const questions = questionRequest(args.questions, exec)
|
|
110
89
|
const defaultAnswer = mode === 'default' && seconds !== -1
|
|
111
|
-
? buildDefaultAnswer(args.questions)
|
|
90
|
+
? answerResult(buildDefaultAnswer(args.questions))
|
|
112
91
|
: undefined
|
|
113
92
|
|
|
114
93
|
if (seconds === -1) {
|
|
@@ -124,17 +103,11 @@ export function createBetterAskTool(ctx, base, readConfig) {
|
|
|
124
103
|
better: { waitMs, timeoutMode: mode, defaultAnswer },
|
|
125
104
|
}, exec.callId, waitMs)
|
|
126
105
|
if ('pending' in result) {
|
|
127
|
-
if (mode === 'default' && defaultAnswer !== undefined) return defaultAnswer
|
|
106
|
+
if (mode === 'default' && defaultAnswer !== undefined) return answerResult(defaultAnswer)
|
|
128
107
|
return { ...result, message: PENDING_QUESTION_NOTICE }
|
|
129
108
|
}
|
|
130
109
|
return answerResult(result)
|
|
131
110
|
}
|
|
132
111
|
|
|
133
|
-
return {
|
|
134
|
-
...base,
|
|
135
|
-
description: base.description + ' The host controls the wait duration and timeout behavior; the timeout argument is a compatibility field and is ignored.',
|
|
136
|
-
parameters,
|
|
137
|
-
output,
|
|
138
|
-
execute,
|
|
139
|
-
}
|
|
112
|
+
return { ...base, output, execute }
|
|
140
113
|
}
|