@deepseek-ai/dsh-repeat-tool-reminder 0.1.7-rc.1 → 0.2.0-rc.1
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.i18n.yaml +84 -5
- package/lib/index.js +111 -9
- package/package.json +10 -10
package/README.i18n.yaml
CHANGED
|
@@ -1,6 +1,85 @@
|
|
|
1
|
-
# Bilingual-pair consistency record (docs/i18n/README.md):
|
|
2
|
-
#
|
|
3
|
-
#
|
|
1
|
+
# Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
|
|
2
|
+
# section, a hash of its English and Chinese blocks outside code blocks and generated regions.
|
|
3
|
+
# After editing either side, bring the other along and re-record with:
|
|
4
4
|
# pnpm run verify-translation-pairing --write packages/guard/repeat-tool-reminder/README.md
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
/:
|
|
6
|
+
en: 8eb3c6cc73da87aa
|
|
7
|
+
zh: 4059266a0486ff38
|
|
8
|
+
/deepseek-ai-dsh-repeat-tool-reminder:
|
|
9
|
+
en: add59e0d04eb964d
|
|
10
|
+
zh: d5224b61ea4e9413
|
|
11
|
+
/deepseek-ai-dsh-repeat-tool-reminder/summary:
|
|
12
|
+
en: 36ac7ba52bc4fee0
|
|
13
|
+
zh: 39894a1c067754c4
|
|
14
|
+
/deepseek-ai-dsh-repeat-tool-reminder/table-of-contents:
|
|
15
|
+
en: d152484eb41ac6b4
|
|
16
|
+
zh: 09388d293f9be9cb
|
|
17
|
+
/deepseek-ai-dsh-repeat-tool-reminder/use-this-package:
|
|
18
|
+
en: dcffe01b4cde60e0
|
|
19
|
+
zh: 9a105a1d0121b990
|
|
20
|
+
/deepseek-ai-dsh-repeat-tool-reminder/use-this-package/when-to-choose-it:
|
|
21
|
+
en: c6b47c1f0034c021
|
|
22
|
+
zh: 5a2097425754d8b0
|
|
23
|
+
/deepseek-ai-dsh-repeat-tool-reminder/use-this-package/setting-the-thresholds-and-scope:
|
|
24
|
+
en: fc64919ff223096d
|
|
25
|
+
zh: dd22a19eeffa9192
|
|
26
|
+
/deepseek-ai-dsh-repeat-tool-reminder/use-this-package/what-you-get:
|
|
27
|
+
en: 5cf91a5809d2c68a
|
|
28
|
+
zh: 8f60231436b863b8
|
|
29
|
+
/deepseek-ai-dsh-repeat-tool-reminder/understand-the-implementation:
|
|
30
|
+
en: dd6d7a1571af5a9a
|
|
31
|
+
zh: eba00095dfc1c92a
|
|
32
|
+
/deepseek-ai-dsh-repeat-tool-reminder/understand-the-implementation/design-philosophy:
|
|
33
|
+
en: 7bca56e3cba01338
|
|
34
|
+
zh: 530fda764d226f39
|
|
35
|
+
/deepseek-ai-dsh-repeat-tool-reminder/understand-the-implementation/detection-the-repeat-chain:
|
|
36
|
+
en: b76a432aad14aa90
|
|
37
|
+
zh: b0cd916f7897fb42
|
|
38
|
+
/deepseek-ai-dsh-repeat-tool-reminder/understand-the-implementation/reminder-delivery:
|
|
39
|
+
en: ebd2a7d704e0a7be
|
|
40
|
+
zh: 438213ad0412a64e
|
|
41
|
+
/deepseek-ai-dsh-repeat-tool-reminder/understand-the-implementation/source-map:
|
|
42
|
+
en: 567a964105e1340b
|
|
43
|
+
zh: 7a8b062b2d9b39d1
|
|
44
|
+
/deepseek-ai-dsh-repeat-tool-reminder/further-exploration:
|
|
45
|
+
en: 77b646e29c1aefa8
|
|
46
|
+
zh: f63b7df7412e524d
|
|
47
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience:
|
|
48
|
+
en: 215e7ba838619b7b
|
|
49
|
+
zh: a311da3843709f90
|
|
50
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/first-threshold-context-message:
|
|
51
|
+
en: 798ea2afb5efde7c
|
|
52
|
+
zh: 14fae1e31d882e8a
|
|
53
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/first-threshold-context-message/what-the-model-sees:
|
|
54
|
+
en: cf01847a41f3fe3d
|
|
55
|
+
zh: aebeb78ac617999c
|
|
56
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/first-threshold-context-message/what-the-model-sees/first-threshold-reminder:
|
|
57
|
+
en: 38c7616427fa569d
|
|
58
|
+
zh: fd443fab22a57894
|
|
59
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/first-threshold-context-message/token-effect:
|
|
60
|
+
en: 111c6d779b73194b
|
|
61
|
+
zh: 09b0e7073308ba91
|
|
62
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/first-threshold-context-message/kv-cache-effect:
|
|
63
|
+
en: f5d5f97a153f7c70
|
|
64
|
+
zh: 51155536aab03002
|
|
65
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/later-threshold-context-message:
|
|
66
|
+
en: edfa41e2478fb579
|
|
67
|
+
zh: 76b87439f3bef43c
|
|
68
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/later-threshold-context-message/what-the-model-sees:
|
|
69
|
+
en: cddb7a41c335141f
|
|
70
|
+
zh: 7ea33c6570bb2bd0
|
|
71
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/later-threshold-context-message/what-the-model-sees/later-threshold-reminder:
|
|
72
|
+
en: 341114f2e5e9c05b
|
|
73
|
+
zh: 8938e7d0f7fc150b
|
|
74
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/later-threshold-context-message/token-effect:
|
|
75
|
+
en: 2e92c0d5a90c482b
|
|
76
|
+
zh: 07ba3851b725f06d
|
|
77
|
+
/deepseek-ai-dsh-repeat-tool-reminder/model-experience/later-threshold-context-message/kv-cache-effect:
|
|
78
|
+
en: f5d5f97a153f7c70
|
|
79
|
+
zh: 51155536aab03002
|
|
80
|
+
/deepseek-ai-dsh-repeat-tool-reminder/known-limitations-and-deferred-work:
|
|
81
|
+
en: 59ffa89bf74f8da2
|
|
82
|
+
zh: 7652f49b9eac40d6
|
|
83
|
+
/deepseek-ai-dsh-repeat-tool-reminder/known-limitations-and-deferred-work/dev-note:
|
|
84
|
+
en: ef308dcf213685c7
|
|
85
|
+
zh: 5830b6bbeea9863f
|
package/lib/index.js
CHANGED
|
@@ -164,6 +164,16 @@ function validateName(subject, value) {
|
|
|
164
164
|
//#endregion
|
|
165
165
|
//#region ../../util/values/src/index.ts
|
|
166
166
|
/**
|
|
167
|
+
* Mark an unreachable closed-union branch.
|
|
168
|
+
* @param value - impossible value; an unhandled typed variant fails at the call site.
|
|
169
|
+
* @param context - optional switch-site label included in the failure message.
|
|
170
|
+
* @returns never; a runtime value that escaped its type always throws.
|
|
171
|
+
*/
|
|
172
|
+
function assertNever(value, context) {
|
|
173
|
+
const rendered = JSON.stringify(value) ?? String(value);
|
|
174
|
+
throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
167
177
|
* Deep-freeze an object graph in place while leaving live AbortSignal objects mutable.
|
|
168
178
|
* @param value - value to freeze.
|
|
169
179
|
* @returns the same value after every reachable enumerable child is frozen.
|
|
@@ -609,6 +619,89 @@ function projectImagesForTextModel(messages) {
|
|
|
609
619
|
};
|
|
610
620
|
});
|
|
611
621
|
}
|
|
622
|
+
function withoutDeveloperMessages(messages) {
|
|
623
|
+
const retained = messages.filter((message) => message.role !== "developer");
|
|
624
|
+
return retained.length === messages.length ? messages : retained;
|
|
625
|
+
}
|
|
626
|
+
function toolDeclarations(tools, mode, history) {
|
|
627
|
+
const declarations = new Map(history.tools.map((tool) => [tool.name, tool]));
|
|
628
|
+
for (const update of history.updates) for (const tool of update.additions) if (!declarations.has(tool.name)) declarations.set(tool.name, {
|
|
629
|
+
...tool,
|
|
630
|
+
deferLoading: true
|
|
631
|
+
});
|
|
632
|
+
switch (mode) {
|
|
633
|
+
case "in-history": return declarations;
|
|
634
|
+
case "addition-only": {
|
|
635
|
+
const activeNames = new Set(tools?.map((tool) => tool.name));
|
|
636
|
+
for (const name of declarations.keys()) if (!activeNames.has(name)) declarations.delete(name);
|
|
637
|
+
return declarations;
|
|
638
|
+
}
|
|
639
|
+
/* v8 ignore next 2 -- closed-union exhaustiveness guard */
|
|
640
|
+
default: return assertNever(mode);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Construct provider declarations from session-folded history without changing logged active tools.
|
|
645
|
+
* Unsupported routes and incomplete history use current declarations without developer updates.
|
|
646
|
+
* Explicitly deferred baseline tools become available only after their first retained addition.
|
|
647
|
+
* @param messages - complete request inputs, or the prefix selected for an auxiliary call.
|
|
648
|
+
* @param tools - currently active tool schemas.
|
|
649
|
+
* @param toolUpdate - the resolved route's update mode.
|
|
650
|
+
* @param history - immutable state folded from committed headers and developer messages.
|
|
651
|
+
* @returns provider declarations and the corresponding filtered history.
|
|
652
|
+
*/
|
|
653
|
+
function projectToolUpdates(messages, tools, toolUpdate, history) {
|
|
654
|
+
if (toolUpdate === void 0) {
|
|
655
|
+
let immediateTools = tools;
|
|
656
|
+
if (tools?.some((tool) => tool.deferLoading === true)) immediateTools = tools.map(({ deferLoading: _loading, ...tool }) => tool);
|
|
657
|
+
return {
|
|
658
|
+
messages: withoutDeveloperMessages(messages),
|
|
659
|
+
tools: immediateTools
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
if (history === void 0) return {
|
|
663
|
+
messages: withoutDeveloperMessages(messages),
|
|
664
|
+
tools
|
|
665
|
+
};
|
|
666
|
+
const messageIds = new Set(messages.flatMap((message) => message.role === "developer" ? [message.id] : []));
|
|
667
|
+
if (history.updates.some((update) => !messageIds.has(update.messageId))) return {
|
|
668
|
+
messages: withoutDeveloperMessages(messages),
|
|
669
|
+
tools
|
|
670
|
+
};
|
|
671
|
+
const declarations = toolDeclarations(tools, toolUpdate, history);
|
|
672
|
+
const updateIds = new Set(history.updates.map((update) => update.messageId));
|
|
673
|
+
const offered = new Set(history.tools.filter((tool) => !tool.deferLoading).map((tool) => tool.name));
|
|
674
|
+
const projectedMessages = [];
|
|
675
|
+
for (const message of messages) {
|
|
676
|
+
if (message.role !== "developer") {
|
|
677
|
+
projectedMessages.push(message);
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
if (!updateIds.has(message.id)) continue;
|
|
681
|
+
const content = message.content.filter((block) => {
|
|
682
|
+
switch (block.type) {
|
|
683
|
+
case "tool-addition":
|
|
684
|
+
if (!declarations.has(block.toolName) || offered.has(block.toolName)) return false;
|
|
685
|
+
offered.add(block.toolName);
|
|
686
|
+
return true;
|
|
687
|
+
case "tool-removal":
|
|
688
|
+
if (toolUpdate !== "in-history") return false;
|
|
689
|
+
return offered.delete(block.toolName);
|
|
690
|
+
default: return true;
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
if (content.length === 0) continue;
|
|
694
|
+
if (content.length === message.content.length) projectedMessages.push(message);
|
|
695
|
+
else projectedMessages.push({
|
|
696
|
+
...message,
|
|
697
|
+
content
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
return {
|
|
701
|
+
messages: projectedMessages.length === messages.length && projectedMessages.every((message, index) => message === messages[index]) ? messages : projectedMessages,
|
|
702
|
+
tools: [...declarations.values()]
|
|
703
|
+
};
|
|
704
|
+
}
|
|
612
705
|
//#endregion
|
|
613
706
|
//#region ../../llm/llm/src/attribution.ts
|
|
614
707
|
/**
|
|
@@ -1020,7 +1113,8 @@ var LlmError = class extends HarnessError {
|
|
|
1020
1113
|
}
|
|
1021
1114
|
/**
|
|
1022
1115
|
* Discover models advertised by one registered provider. Catalog membership
|
|
1023
|
-
*
|
|
1116
|
+
* does not constrain core routing. Catalog-driven entry points may restrict
|
|
1117
|
+
* selection and submission to the advertised models.
|
|
1024
1118
|
* @param provider - registered provider route to inspect.
|
|
1025
1119
|
* @returns detached model metadata in adapter-preferred order.
|
|
1026
1120
|
*/
|
|
@@ -1065,6 +1159,8 @@ var LlmError = class extends HarnessError {
|
|
|
1065
1159
|
const inputModalities = this.detachedModalities(resolved.inputModalities);
|
|
1066
1160
|
const systemPromptUpdate = resolved.systemPromptUpdate;
|
|
1067
1161
|
if (systemPromptUpdate !== void 0 && systemPromptUpdate !== "in-history") throw new LlmError(`adapter returned invalid system prompt update mode for provider "${provider}" model "${model}"`, "INVALID_MODEL_INFO");
|
|
1162
|
+
const toolUpdate = resolved.toolUpdate;
|
|
1163
|
+
if (toolUpdate !== void 0 && toolUpdate !== "in-history" && toolUpdate !== "addition-only") throw new LlmError(`adapter returned invalid tool update mode for provider "${provider}" model "${model}"`, "INVALID_MODEL_INFO");
|
|
1068
1164
|
const defaultMaxTokens = resolved.defaultMaxTokens;
|
|
1069
1165
|
if (defaultMaxTokens !== void 0 && (!Number.isSafeInteger(defaultMaxTokens) || defaultMaxTokens <= 0)) throw new LlmError(`adapter returned invalid default maxTokens for provider "${provider}" model "${model}"`, "INVALID_MODEL_MAX_TOKENS");
|
|
1070
1166
|
const info = {
|
|
@@ -1075,7 +1171,8 @@ var LlmError = class extends HarnessError {
|
|
|
1075
1171
|
...inputModalities === void 0 ? {} : { inputModalities },
|
|
1076
1172
|
...context === void 0 ? {} : { context: { contextWindow: context.contextWindow } },
|
|
1077
1173
|
...defaultMaxTokens === void 0 ? {} : { defaultMaxTokens },
|
|
1078
|
-
...resolved.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: resolved.systemPromptUpdate }
|
|
1174
|
+
...resolved.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: resolved.systemPromptUpdate },
|
|
1175
|
+
...resolved.toolUpdate === void 0 ? {} : { toolUpdate: resolved.toolUpdate }
|
|
1079
1176
|
};
|
|
1080
1177
|
const reasoning = resolved.reasoning;
|
|
1081
1178
|
if (reasoning === void 0) return info;
|
|
@@ -1170,6 +1267,7 @@ var LlmError = class extends HarnessError {
|
|
|
1170
1267
|
...context === void 0 ? {} : { context },
|
|
1171
1268
|
...modelInfo.inputModalities === void 0 ? {} : { inputModalities: Object.freeze([...modelInfo.inputModalities]) },
|
|
1172
1269
|
...modelInfo.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: modelInfo.systemPromptUpdate },
|
|
1270
|
+
...modelInfo.toolUpdate === void 0 ? {} : { toolUpdate: modelInfo.toolUpdate },
|
|
1173
1271
|
stream: (options) => {
|
|
1174
1272
|
if (dispatched) throw new LlmError("a prepared LLM call can only be dispatched once", "INVALID_PREPARED_CALL");
|
|
1175
1273
|
if (!callConfigEquals(options, resolvedConfig)) throw new LlmError("prepared LLM call config changed before adapter dispatch", "INVALID_PREPARED_CALL");
|
|
@@ -1259,13 +1357,17 @@ var LlmError = class extends HarnessError {
|
|
|
1259
1357
|
let projectedMessages = resolvedOptions.messages;
|
|
1260
1358
|
if (projectedMessages.some((message) => contentHasFile(message.content))) projectedMessages = projectFilesToText(projectedMessages, (ref) => this.fileReadPath(ref));
|
|
1261
1359
|
if (modelInfo.inputModalities !== void 0 && !modelInfo.inputModalities.includes("image") && projectedMessages.some((message) => contentHasImage(message.content))) projectedMessages = projectImagesForTextModel(projectedMessages);
|
|
1262
|
-
const
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1360
|
+
const projectedTools = projectToolUpdates(projectedMessages, resolvedOptions.tools, modelInfo.toolUpdate, resolvedOptions.toolHistory);
|
|
1361
|
+
projectedMessages = projectedTools.messages;
|
|
1362
|
+
let projectedOptions = resolvedOptions;
|
|
1363
|
+
if (projectedMessages !== resolvedOptions.messages || projectedTools.tools !== resolvedOptions.tools) {
|
|
1364
|
+
projectedOptions = {
|
|
1365
|
+
...resolvedOptions,
|
|
1366
|
+
messages: projectedMessages,
|
|
1367
|
+
...projectedTools.tools === void 0 ? {} : { tools: projectedTools.tools }
|
|
1368
|
+
};
|
|
1369
|
+
if (Object.isFrozen(resolvedOptions)) deepFreeze(projectedOptions);
|
|
1370
|
+
}
|
|
1269
1371
|
iterator = dispatch(this.forAdapter(projectedOptions, adapter))[Symbol.asyncIterator]();
|
|
1270
1372
|
} catch (error) {
|
|
1271
1373
|
yield adapterFailureChunk(error, options.signal);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-repeat-tool-reminder",
|
|
3
3
|
"description": "Repeat-tool-call guard plugin: advisory reminders when an agent loops on identical tool calls",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0-rc.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -30,18 +30,18 @@
|
|
|
30
30
|
"@deepseek-ai/schemastery": "~3.18.4"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@deepseek-ai/dsh-agent": "0.
|
|
34
|
-
"@deepseek-ai/dsh-tools": "0.
|
|
33
|
+
"@deepseek-ai/dsh-agent": "0.2.0-rc.1",
|
|
34
|
+
"@deepseek-ai/dsh-tools": "0.2.0-rc.1",
|
|
35
35
|
"@deepseek-ai/cordis": "~4.0.4"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@deepseek-ai/dsh-agent": "0.
|
|
39
|
-
"@deepseek-ai/dsh-agent-loop": "0.
|
|
40
|
-
"@deepseek-ai/dsh-
|
|
41
|
-
"@deepseek-ai/dsh-
|
|
42
|
-
"@deepseek-ai/dsh-session": "0.
|
|
43
|
-
"@deepseek-ai/dsh-tools": "0.
|
|
38
|
+
"@deepseek-ai/dsh-agent": "0.2.0-rc.1",
|
|
39
|
+
"@deepseek-ai/dsh-agent-loop": "0.2.0-rc.1",
|
|
40
|
+
"@deepseek-ai/dsh-agent-loop-testkit": "0.2.0-rc.1",
|
|
41
|
+
"@deepseek-ai/dsh-llm": "0.2.0-rc.1",
|
|
42
|
+
"@deepseek-ai/dsh-session": "0.2.0-rc.1",
|
|
43
|
+
"@deepseek-ai/dsh-tools": "0.2.0-rc.1",
|
|
44
44
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
45
|
-
"@deepseek-ai/dsh-session-projection": "0.
|
|
45
|
+
"@deepseek-ai/dsh-session-projection": "0.2.0-rc.1"
|
|
46
46
|
}
|
|
47
47
|
}
|