dsh-better-ask-user 0.1.6 → 0.1.7
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/lib/client.js +6 -1
- package/package.json +1 -1
- package/src/ask-tool.js +47 -5
- package/src/client/AskHistoryRow.tsx +3 -3
- package/src/client/index.ts +5 -0
- package/src/settings.js +11 -9
package/lib/client.js
CHANGED
|
@@ -580,7 +580,7 @@ function AskHistoryRow({
|
|
|
580
580
|
revealPanel(callId);
|
|
581
581
|
} : void 0;
|
|
582
582
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: AskHistoryRow_default.row, children: [
|
|
583
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: AskHistoryRow_default.icon, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.
|
|
583
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: AskHistoryRow_default.icon, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconQuestionOutlineRegular, {}) }),
|
|
584
584
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: AskHistoryRow_default.title, children: t("history.title") }),
|
|
585
585
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: AskHistoryRow_default.summary, title: summary, children: summary }),
|
|
586
586
|
action !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -2017,6 +2017,11 @@ function apply(ctx) {
|
|
|
2017
2017
|
name: "tool.call.toolview",
|
|
2018
2018
|
key: "ask_user_question",
|
|
2019
2019
|
locale: NS,
|
|
2020
|
+
// The shipped `@deepseek-ai/dsh-client-ui-tool` already registers
|
|
2021
|
+
// `ask-question-toolview` for this key at priority 0, and the slot registry
|
|
2022
|
+
// rejects a second entry at the same priority (which failed the whole client
|
|
2023
|
+
// boot). A lower priority shadows it: lowest renders.
|
|
2024
|
+
priority: -1,
|
|
2020
2025
|
inject: (sessionId) => ({
|
|
2021
2026
|
revealPanel: (callId) => ctx.get("userQuestionPanels")?.reveal(sessionId, callId) ?? false,
|
|
2022
2027
|
reviewPanel: (callId, record) => ctx.get("userQuestionPanels")?.review(sessionId, callId, record) ?? false
|
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.7",
|
|
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
|
@@ -5,12 +5,16 @@ import { buildDefaultAnswer } from './default-answer.js'
|
|
|
5
5
|
/** Model-visible notice for the native pending result. */
|
|
6
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.'
|
|
7
7
|
|
|
8
|
+
/** Model-visible warning for a host auto-selected default batch. */
|
|
9
|
+
export const AUTO_SELECTED_WARNING = 'These answers were auto-selected by the host timeout behavior, not submitted by the user. Do not treat them as user confirmation.'
|
|
10
|
+
|
|
8
11
|
function questionRequest(questions, exec) {
|
|
9
12
|
return {
|
|
10
13
|
questions: questions.map(question => ({
|
|
11
14
|
id: question.id,
|
|
12
15
|
question: question.question,
|
|
13
16
|
...(question.header !== undefined ? { header: question.header } : {}),
|
|
17
|
+
...(question.detail !== undefined ? { detail: question.detail } : {}),
|
|
14
18
|
...(question.options !== undefined ? {
|
|
15
19
|
options: question.options.map(option => ({ ...option })),
|
|
16
20
|
} : {}),
|
|
@@ -36,14 +40,51 @@ function answerResult(result) {
|
|
|
36
40
|
selected: [...answer.selected],
|
|
37
41
|
...(answer.custom !== undefined ? { custom: answer.custom } : {}),
|
|
38
42
|
})),
|
|
43
|
+
...(result.autoSelected === true ? { autoSelected: true, warning: AUTO_SELECTED_WARNING } : {}),
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Add the optional detail field to the model-visible question schema. */
|
|
48
|
+
function parametersWithDetail(parameters) {
|
|
49
|
+
if (parameters === undefined) return parameters
|
|
50
|
+
const next = structuredClone(parameters)
|
|
51
|
+
const properties = next?.properties?.questions?.items?.properties
|
|
52
|
+
if (properties !== undefined && properties.detail === undefined) {
|
|
53
|
+
properties.detail = {
|
|
54
|
+
type: 'string',
|
|
55
|
+
description: 'Optional longer detail or context rendered as sanitized markdown below the question.',
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return next
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Allow the additive auto-selected warning fields on the normal answer branch. */
|
|
62
|
+
function extendAutoSelectedSchema(schema) {
|
|
63
|
+
const branches = Array.isArray(schema?.oneOf) ? schema.oneOf : [schema]
|
|
64
|
+
for (const branch of branches) {
|
|
65
|
+
const properties = branch?.properties
|
|
66
|
+
if (properties?.answers === undefined) continue
|
|
67
|
+
if (properties.autoSelected === undefined) {
|
|
68
|
+
properties.autoSelected = {
|
|
69
|
+
type: 'boolean',
|
|
70
|
+
description: 'True when the host auto-selected the default batch after the timeout; not a user answer.',
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (properties.warning === undefined) {
|
|
74
|
+
properties.warning = { type: 'string', description: 'Model-visible warning for an auto-selected batch.' }
|
|
75
|
+
}
|
|
39
76
|
}
|
|
77
|
+
return schema
|
|
40
78
|
}
|
|
41
79
|
|
|
42
80
|
/** The timed path can return the official pending shape; keep it valid. */
|
|
43
81
|
function outputWithPending(base) {
|
|
44
82
|
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))
|
|
83
|
+
const schema = extendAutoSelectedSchema(structuredClone(base.output.schema))
|
|
84
|
+
if (Array.isArray(schema?.oneOf) && schema.oneOf.some(branch => branch?.properties?.pending !== undefined)) {
|
|
85
|
+
output.schema = schema
|
|
86
|
+
return output
|
|
87
|
+
}
|
|
47
88
|
output.schema = {
|
|
48
89
|
oneOf: [
|
|
49
90
|
schema,
|
|
@@ -71,9 +112,10 @@ function outputWithPending(base) {
|
|
|
71
112
|
*/
|
|
72
113
|
export function createBetterAskTool(ctx, base, readConfig) {
|
|
73
114
|
const output = outputWithPending(base)
|
|
115
|
+
const parameters = parametersWithDetail(base.parameters)
|
|
74
116
|
|
|
75
117
|
const execute = async (args, exec) => {
|
|
76
|
-
const violations = validateJsonSchemaValue(
|
|
118
|
+
const violations = validateJsonSchemaValue(parameters, args, '')
|
|
77
119
|
if (violations.length > 0) throw new ToolArgsError(violations)
|
|
78
120
|
validateQuestionIds(args.questions)
|
|
79
121
|
|
|
@@ -113,5 +155,5 @@ export function createBetterAskTool(ctx, base, readConfig) {
|
|
|
113
155
|
return answerResult(result)
|
|
114
156
|
}
|
|
115
157
|
|
|
116
|
-
return { ...base, output, execute }
|
|
117
|
-
}
|
|
158
|
+
return { ...base, parameters, output, execute }
|
|
159
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** History row for ask_user_question: compact summary plus a replay button. */
|
|
2
|
-
import {
|
|
2
|
+
import { IconQuestionOutlineRegular } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
3
3
|
import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'
|
|
4
4
|
import type { ToolCallViewProps, UserQuestionRecord } from '@deepseek-ai/dsh-client-ui-tool/client'
|
|
5
5
|
import type { AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions/types'
|
|
@@ -116,7 +116,7 @@ export function AskHistoryRow({
|
|
|
116
116
|
|
|
117
117
|
return (
|
|
118
118
|
<div className={css.row}>
|
|
119
|
-
<span className={css.icon} aria-hidden="true"><
|
|
119
|
+
<span className={css.icon} aria-hidden="true"><IconQuestionOutlineRegular /></span>
|
|
120
120
|
<span className={css.title}>{t('history.title')}</span>
|
|
121
121
|
<span className={css.summary} title={summary}>{summary}</span>
|
|
122
122
|
{action !== undefined && (
|
|
@@ -131,4 +131,4 @@ export function AskHistoryRow({
|
|
|
131
131
|
)}
|
|
132
132
|
</div>
|
|
133
133
|
)
|
|
134
|
-
}
|
|
134
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -419,6 +419,11 @@ export function apply(ctx: ClientContext): void {
|
|
|
419
419
|
name: 'tool.call.toolview',
|
|
420
420
|
key: 'ask_user_question',
|
|
421
421
|
locale: NS,
|
|
422
|
+
// The shipped `@deepseek-ai/dsh-client-ui-tool` already registers
|
|
423
|
+
// `ask-question-toolview` for this key at priority 0, and the slot registry
|
|
424
|
+
// rejects a second entry at the same priority (which failed the whole client
|
|
425
|
+
// boot). A lower priority shadows it: lowest renders.
|
|
426
|
+
priority: -1,
|
|
422
427
|
inject: (sessionId: SessionId) => ({
|
|
423
428
|
revealPanel: (callId: string) => ctx.get('userQuestionPanels')?.reveal(sessionId, callId) ?? false,
|
|
424
429
|
reviewPanel: (callId: string, record: UserQuestionRecord) => ctx.get('userQuestionPanels')?.review(sessionId, callId, record) ?? false,
|
package/src/settings.js
CHANGED
|
@@ -12,9 +12,11 @@ function hasOwn(value, key) {
|
|
|
12
12
|
return value !== null && typeof value === 'object' && Object.hasOwn(value, key)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
function descriptor(service, ns) {
|
|
15
|
+
async function descriptor(service, ns) {
|
|
16
16
|
try {
|
|
17
|
-
|
|
17
|
+
const rows = await service.describe()
|
|
18
|
+
if (!Array.isArray(rows)) return undefined
|
|
19
|
+
return rows.find(row => row?.ns === ns)
|
|
18
20
|
} catch {
|
|
19
21
|
return undefined
|
|
20
22
|
}
|
|
@@ -36,25 +38,25 @@ export async function migrateLegacyQuestionTimeout(service) {
|
|
|
36
38
|
return { status: 'unavailable' }
|
|
37
39
|
}
|
|
38
40
|
const deadline = Date.now() + WAIT_MS
|
|
39
|
-
let source = descriptor(service, LEGACY_GOAL_NS)
|
|
40
|
-
let target = descriptor(service, ASK_NS)
|
|
41
|
+
let source = await descriptor(service, LEGACY_GOAL_NS)
|
|
42
|
+
let target = await descriptor(service, ASK_NS)
|
|
41
43
|
while ((source === undefined || target === undefined) && Date.now() < deadline) {
|
|
42
44
|
await sleep(WAIT_INTERVAL_MS)
|
|
43
|
-
source = descriptor(service, LEGACY_GOAL_NS)
|
|
44
|
-
target = descriptor(service, ASK_NS)
|
|
45
|
+
source = await descriptor(service, LEGACY_GOAL_NS)
|
|
46
|
+
target = await descriptor(service, ASK_NS)
|
|
45
47
|
}
|
|
46
48
|
if (source === undefined || target === undefined) return { status: 'pending' }
|
|
47
49
|
if (!hasOwn(source.user, 'questionTimeoutSeconds')) return { status: 'no-change' }
|
|
48
50
|
if (hasOwn(target.user, 'questionTimeoutSeconds')) return { status: 'no-change' }
|
|
49
51
|
const value = source.value?.questionTimeoutSeconds
|
|
50
52
|
if (!validSeconds(value)) return { status: 'no-change' }
|
|
51
|
-
if (
|
|
53
|
+
if (service.writable === false) return { status: 'pending' }
|
|
52
54
|
try {
|
|
53
55
|
await service.update(ASK_NS, { questionTimeoutSeconds: value }, target.revision)
|
|
54
56
|
} catch (error) {
|
|
55
57
|
return { status: 'error', error: error instanceof Error ? error.message : String(error) }
|
|
56
58
|
}
|
|
57
|
-
const after = descriptor(service, ASK_NS)
|
|
59
|
+
const after = await descriptor(service, ASK_NS)
|
|
58
60
|
return after?.user?.questionTimeoutSeconds === value
|
|
59
61
|
? { status: 'complete', value }
|
|
60
62
|
: { status: 'pending', value }
|
|
@@ -76,4 +78,4 @@ export function mountLegacyMigration(ctx) {
|
|
|
76
78
|
inner.logger?.warn?.('better-ask-user: legacy question wait migration failed: ' + String(error))
|
|
77
79
|
})
|
|
78
80
|
})
|
|
79
|
-
}
|
|
81
|
+
}
|