dsh-nextsteps 1.3.3 → 1.3.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/client.js +6 -3
- package/index.js +40 -9
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -9,7 +9,7 @@ window.__ModuleLoader__.load({
|
|
|
9
9
|
const TOOL_NAME = 'suggest_followups';
|
|
10
10
|
const MAX_FOLLOWUPS = 6;
|
|
11
11
|
const PROMPT_TRUNCATE = 60;
|
|
12
|
-
const CLICKED_KEY = 'dsh
|
|
12
|
+
const CLICKED_KEY = 'dsh-nextsteps.clicked';
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
const CSS = `
|
|
@@ -226,9 +226,12 @@ window.__ModuleLoader__.load({
|
|
|
226
226
|
function captureForTurn(sessionId, turn) {
|
|
227
227
|
const entries = captures.get(sessionId);
|
|
228
228
|
if (entries === undefined) return null;
|
|
229
|
+
const external = typeof pluginSettings.model === 'string' && pluginSettings.model !== '';
|
|
229
230
|
let best = null;
|
|
230
|
-
for (const entry of entries.
|
|
231
|
-
if (entry.turn
|
|
231
|
+
for (const [callId, entry] of entries.entries()) {
|
|
232
|
+
if (entry.turn !== turn) continue;
|
|
233
|
+
if (external && !callId.startsWith('generated-')) continue;
|
|
234
|
+
best = entry;
|
|
232
235
|
}
|
|
233
236
|
return best;
|
|
234
237
|
}
|
package/index.js
CHANGED
|
@@ -124,7 +124,13 @@ const PARAMETER_SCHEMA = {
|
|
|
124
124
|
required: ['followups']
|
|
125
125
|
};
|
|
126
126
|
|
|
127
|
-
function toolDescription() {
|
|
127
|
+
function toolDescription(external = false) {
|
|
128
|
+
if (external) {
|
|
129
|
+
return [
|
|
130
|
+
'This tool is not used any more: the host generates the followup suggestions after your turn with a separate model.',
|
|
131
|
+
'Do not call it. Just finish your answer as usual.'
|
|
132
|
+
].join('\n');
|
|
133
|
+
}
|
|
128
134
|
return [
|
|
129
135
|
'MANDATORY in every turn: once all real work and other tool calls are done, call this tool BEFORE writing your final answer — the answer must come after this tool returns, so the turn ends cleanly right after it. Never write your final answer before calling it.',
|
|
130
136
|
'Suggest exactly the number of followup prompts stated in the nextsteps section of the system prompt.',
|
|
@@ -140,6 +146,11 @@ function toolDescription() {
|
|
|
140
146
|
|
|
141
147
|
function nextstepsSectionText() {
|
|
142
148
|
const settings = settingsLoad();
|
|
149
|
+
if (typeof settings.model === 'string' && settings.model !== '') {
|
|
150
|
+
return [
|
|
151
|
+
'nextsteps (the followup suggestion cards): the host generates them after your turn with a separate model, so you must not call any followup tool. Just finish your answer as usual.'
|
|
152
|
+
].join('\n');
|
|
153
|
+
}
|
|
143
154
|
const language = LANGUAGE_NAMES[settings.lang] ?? LANGUAGE_NAMES.auto;
|
|
144
155
|
const languageRule = settings.lang === 'auto'
|
|
145
156
|
? `Write every prompt and label in the same language the conversation has been using.`
|
|
@@ -153,10 +164,11 @@ function nextstepsSectionText() {
|
|
|
153
164
|
|
|
154
165
|
const PLUGIN_REV = 'sf-2';
|
|
155
166
|
|
|
156
|
-
function toolSpec() {
|
|
167
|
+
function toolSpec(settings = { lang: 'auto', maxFollowups: 3, model: '' }) {
|
|
168
|
+
const external = typeof settings.model === 'string' && settings.model !== '';
|
|
157
169
|
return {
|
|
158
170
|
name: TOOL_NAME,
|
|
159
|
-
description: toolDescription(),
|
|
171
|
+
description: toolDescription(external),
|
|
160
172
|
parameters: PARAMETER_SCHEMA,
|
|
161
173
|
output: {
|
|
162
174
|
schema: { type: 'string' },
|
|
@@ -166,6 +178,7 @@ function toolSpec() {
|
|
|
166
178
|
]
|
|
167
179
|
},
|
|
168
180
|
async execute(args) {
|
|
181
|
+
if (external) return 'The host generates the followup suggestions after this turn. Do not call this tool again.';
|
|
169
182
|
const followups = coerceFollowups(args.followups);
|
|
170
183
|
const problem = validationProblem(followups);
|
|
171
184
|
if (problem !== null) return problem;
|
|
@@ -202,15 +215,33 @@ async function modelCatalog(ctx) {
|
|
|
202
215
|
return out;
|
|
203
216
|
}
|
|
204
217
|
|
|
218
|
+
function textOf(content) {
|
|
219
|
+
if (typeof content === 'string') return content;
|
|
220
|
+
if (!Array.isArray(content)) return '';
|
|
221
|
+
const parts = [];
|
|
222
|
+
for (const part of content) {
|
|
223
|
+
if (part === null || typeof part !== 'object') continue;
|
|
224
|
+
if (part.type === 'text' && typeof part.text === 'string') parts.push(part.text);
|
|
225
|
+
else if (part.type === 'reasoning' && typeof part.text === 'string') parts.push(part.text);
|
|
226
|
+
}
|
|
227
|
+
return parts.join('\n');
|
|
228
|
+
}
|
|
229
|
+
|
|
205
230
|
function turnTranscript(events, afterSeq) {
|
|
206
231
|
const lines = [];
|
|
207
232
|
for (const entry of events) {
|
|
208
233
|
const event = entry?.event ?? entry;
|
|
209
234
|
if (event === null || typeof event !== 'object') continue;
|
|
210
235
|
if (Number.isSafeInteger(afterSeq) && Number.isSafeInteger(event.seq) && event.seq > afterSeq) break;
|
|
211
|
-
if (event.type === 'user/message'
|
|
212
|
-
|
|
213
|
-
|
|
236
|
+
if (event.type === 'user/message') {
|
|
237
|
+
const text = textOf(event.data?.content);
|
|
238
|
+
if (text !== '' && event.data?.source?.kind === 'user') lines.push(`User: ${text.slice(0, 2000)}`);
|
|
239
|
+
} else if (event.type === 'assistant/message') {
|
|
240
|
+
const text = textOf(event.data?.message?.content);
|
|
241
|
+
if (text !== '') lines.push(`Assistant: ${text.slice(0, 2000)}`);
|
|
242
|
+
} else if (event.type === 'tool/call' && typeof event.data?.name === 'string') {
|
|
243
|
+
lines.push(`Tool call: ${event.data.name}`);
|
|
244
|
+
}
|
|
214
245
|
}
|
|
215
246
|
return lines.join('\n\n');
|
|
216
247
|
}
|
|
@@ -321,13 +352,13 @@ async function apply(ctx) {
|
|
|
321
352
|
settings = next;
|
|
322
353
|
try {
|
|
323
354
|
try { ctx.tools.unregister(TOOL_NAME); } catch { /* not registered yet */ }
|
|
324
|
-
|
|
355
|
+
ctx.tools.register(toolSpec(next));
|
|
325
356
|
} catch (error) {
|
|
326
357
|
console.error('dsh-nextsteps: tool re-registration failed:', error);
|
|
327
358
|
}
|
|
328
359
|
};
|
|
329
360
|
try {
|
|
330
|
-
|
|
361
|
+
ctx.tools.register(toolSpec(settings));
|
|
331
362
|
} catch (error) {
|
|
332
363
|
console.error('dsh-nextsteps: tool registration failed:', error);
|
|
333
364
|
}
|
|
@@ -335,7 +366,7 @@ async function apply(ctx) {
|
|
|
335
366
|
ctx.inject(['tools', 'systemPrompt'], (sub) => {
|
|
336
367
|
try {
|
|
337
368
|
try { sub.tools.unregister(TOOL_NAME); } catch { /* not registered yet */ }
|
|
338
|
-
|
|
369
|
+
sub.tools.register(toolSpec(settings));
|
|
339
370
|
} catch (error) {
|
|
340
371
|
console.error('dsh-nextsteps: tool registration via inject failed:', error);
|
|
341
372
|
}
|