@ch4acko3/dsh-turn-fold 0.3.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/LICENSE +21 -0
- package/README.md +59 -0
- package/README.zh-CN.md +35 -0
- package/harmony.patch.yml +4 -0
- package/index.cjs +13 -0
- package/inline-source.cjs +885 -0
- package/locales/en.json +43 -0
- package/locales/zh.json +43 -0
- package/locales.cjs +21 -0
- package/package.json +60 -0
- package/patch.cjs +67 -0
- package/settings.cjs +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ch4acko3
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# dsh-turn-fold
|
|
2
|
+
|
|
3
|
+
English | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
A [dsh-harmony](https://github.com/memorax-ai/dsh-harmony) provider that adds
|
|
6
|
+
Codex-Desktop-style turn folding to the DSH WebUI conversation.
|
|
7
|
+
|
|
8
|
+
During a turn, the summary bar remains visible while native thinking, notes,
|
|
9
|
+
commands, and tool calls keep streaming. Consecutive reasoning and tool activity
|
|
10
|
+
share one compact group from the second item onward. When a turn settles, known
|
|
11
|
+
Agent activity, including context injection, moves into one disclosure
|
|
12
|
+
immediately before the final answer. Its configurable metrics default to wall
|
|
13
|
+
time, tool-call count, and input/output tokens, and appear only when the loaded
|
|
14
|
+
turn contains enough data to calculate them without guessing.
|
|
15
|
+
|
|
16
|
+
The final answer is located through `turn-tail.closing.finalNode`, not
|
|
17
|
+
`finish_reason` or DOM position. Completed, stopped, and interrupted turns fold,
|
|
18
|
+
with distinct status labels for the latter two. A turn remains expanded when
|
|
19
|
+
DSH marks its closing branch unavailable, when any later node follows the
|
|
20
|
+
closing answer, or while the user has keyboard focus or an active text selection
|
|
21
|
+
inside its activity. Failed, max-token, closing-less, and open turns also stay
|
|
22
|
+
expanded so errors and unfinished work are never hidden.
|
|
23
|
+
|
|
24
|
+
Expanding reuses the original native node renderers, so tool details, copy, and
|
|
25
|
+
file links keep working. Open turns are remembered per session and turn while
|
|
26
|
+
the WebUI remains loaded. The disclosure has keyboard-visible focus, accessible
|
|
27
|
+
state and action labels, responsive wrapping, reduced-motion handling, and a
|
|
28
|
+
short open/close transition that unmounts the activity after it closes.
|
|
29
|
+
|
|
30
|
+
## How it works
|
|
31
|
+
|
|
32
|
+
Two pinned Source Patches run in memory against the compiled browser bundle of
|
|
33
|
+
`@deepseek-ai/dsh-client-ui-conversation` (`lib/client.js`); installed DSH files
|
|
34
|
+
are never modified.
|
|
35
|
+
|
|
36
|
+
| Patch | Selector (expect 1) | Effect |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `inject-turn-fold-runtime` | `FunctionDeclaration[name.name="ChatView"], VariableStatement:has(VariableDeclaration[name.name="ChatView"])` | Injects the fold renderer + disclosure UI into either native or decorated `ChatView` |
|
|
39
|
+
| `rewrite-node-render-loop` | `CallExpression[expression.name.name="map"][expression.expression.name="order"]` | Replaces the `order.map(...)` node loop with the per-turn renderer |
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
dsh plugin --profile web add github:CH4ACKO3/dsh-turn-fold
|
|
45
|
+
dsh harmony status --profile web # both patches must be `bound`
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Test
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
node test/run.cjs
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`npm install` installs test-only copies of the pinned DSH conversation package,
|
|
55
|
+
TypeScript, and TSQuery. The test suite applies both patches in memory, parses
|
|
56
|
+
the final browser bundle, and covers completed, split-activity, post-closing,
|
|
57
|
+
partial-history, failed, interrupted, open, accessibility, and state-retention
|
|
58
|
+
behavior. A missing target or selector mismatch fails the test; it is never
|
|
59
|
+
reported as a skipped pass.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# dsh-turn-fold
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 简体中文
|
|
4
|
+
|
|
5
|
+
一个基于 [dsh-harmony](https://github.com/memorax-ai/dsh-harmony) 的 Provider,为 DSH WebUI 对话添加 Codex Desktop 风格的回合折叠。
|
|
6
|
+
|
|
7
|
+
回合进行期间,摘要栏保持可见,原生思考、说明、命令和工具调用继续流式输出。从第二项开始,连续的推理和工具活动会合并为一个紧凑分组。回合结束后,包括上下文注入在内的已知 Agent 活动会收进最终答复前方的折叠栏。摘要指标可以配置,默认显示耗时、工具调用次数以及输入/输出 token;只有当已加载的回合包含足够数据、无需猜测即可计算时才会展示对应指标。
|
|
8
|
+
|
|
9
|
+
最终答复通过 `turn-tail.closing.finalNode` 定位,不依赖 `finish_reason` 或 DOM 位置。正常完成、已停止和已中断的回合都会折叠,后两者显示不同的状态标签。当 DSH 将结束分支标记为不可用、结束答复之后仍有节点,或者用户的键盘焦点或文本选择位于活动内容中时,回合会保持展开。失败、达到最大 token、缺少结束节点以及仍在进行的回合也会保持展开,避免隐藏错误或未完成的工作。
|
|
10
|
+
|
|
11
|
+
展开后仍然使用原生节点渲染器,因此工具详情、复制功能和文件链接都能继续工作。WebUI 保持加载期间,每个会话和回合的展开状态都会被记住。折叠控件提供键盘可见焦点、无障碍状态与操作标签、响应式换行、减少动态效果支持,以及关闭后再卸载活动内容的短暂开合动画。
|
|
12
|
+
|
|
13
|
+
## 工作原理
|
|
14
|
+
|
|
15
|
+
两个固定目标的 Source Patch 会在内存中修改 `@deepseek-ai/dsh-client-ui-conversation` 的编译后浏览器包(`lib/client.js`),不会修改已安装的 DSH 文件。
|
|
16
|
+
|
|
17
|
+
| Patch | 选择器(预期命中 1 次) | 作用 |
|
|
18
|
+
| --- | --- | --- |
|
|
19
|
+
| `inject-turn-fold-runtime` | `FunctionDeclaration[name.name="ChatView"], VariableStatement:has(VariableDeclaration[name.name="ChatView"])` | 向原生或已装饰的 `ChatView` 注入折叠渲染器和折叠 UI |
|
|
20
|
+
| `rewrite-node-render-loop` | `CallExpression[expression.name.name="map"][expression.expression.name="order"]` | 将 `order.map(...)` 节点循环替换为按回合渲染器 |
|
|
21
|
+
|
|
22
|
+
## 安装
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
dsh plugin --profile web add github:CH4ACKO3/dsh-turn-fold
|
|
26
|
+
dsh harmony status --profile web # 两个 Patch 都必须为 `bound`
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 测试
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
node test/run.cjs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`npm install` 会安装仅用于测试的固定版本 DSH 对话包、TypeScript 和 TSQuery。测试套件会在内存中应用两个 Patch、解析最终浏览器包,并覆盖已完成回合、分段活动、结束后活动、部分历史、失败、中断、进行中、无障碍和状态保留等行为。目标缺失或选择器不匹配会使测试失败,不会被报告为跳过后通过。
|
package/index.cjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Host entry for the @ch4acko3/dsh-turn-fold Harmony provider.
|
|
4
|
+
const { settingsNamespace } = require('@deepseek-ai/dsh-settings')
|
|
5
|
+
const { Config, SETTINGS_NAMESPACE } = require('./settings.cjs')
|
|
6
|
+
|
|
7
|
+
exports.Config = Config
|
|
8
|
+
exports.inject = ['harmony']
|
|
9
|
+
exports.apply = (ctx, config) => {
|
|
10
|
+
ctx.inject(['settings'], (settingsCtx) => {
|
|
11
|
+
settingsCtx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), Config, { base: config })
|
|
12
|
+
})
|
|
13
|
+
}
|
|
@@ -0,0 +1,885 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Runtime injected into @deepseek-ai/dsh-client-ui-conversation/lib/client.js.
|
|
4
|
+
// It executes inside the target module factory, where react,
|
|
5
|
+
// react_jsx_runtime, formatRunDuration, and formatTokens are already in scope.
|
|
6
|
+
const dictionaries = require('./locales.cjs')
|
|
7
|
+
const { DEFAULT_SUMMARY_FIELDS, SETTINGS_NAMESPACE, SUMMARY_FIELDS } = require('./settings.cjs')
|
|
8
|
+
|
|
9
|
+
module.exports = String.raw`/* @ch4acko3/dsh-turn-fold runtime (injected) */
|
|
10
|
+
var __ch4acko3DshTurnFoldLocaleNamespace = "@ch4acko3/dsh-turn-fold";
|
|
11
|
+
var __ch4acko3DshTurnFoldDictionaries = ${JSON.stringify(dictionaries)};
|
|
12
|
+
var __ch4acko3DshTurnFoldSettingsNamespace = ${JSON.stringify(SETTINGS_NAMESPACE)};
|
|
13
|
+
var __ch4acko3DshTurnFoldKnownFields = ${JSON.stringify(SUMMARY_FIELDS)};
|
|
14
|
+
var __ch4acko3DshTurnFoldDefaultFields = ${JSON.stringify(DEFAULT_SUMMARY_FIELDS)};
|
|
15
|
+
var __ch4acko3DshTurnFoldTranslate = null;
|
|
16
|
+
var __ch4acko3DshTurnFoldSettingsScope = null;
|
|
17
|
+
var __ch4acko3DshTurnFoldSummaryFields = __ch4acko3DshTurnFoldDefaultFields.slice();
|
|
18
|
+
var __ch4acko3DshTurnFoldSettingsListeners = new Set();
|
|
19
|
+
var __ch4acko3DshTurnFoldCss = [
|
|
20
|
+
".__ch4acko3-dsh-turn-fold{min-width:0;margin:1px 0 2px;animation:__ch4acko3-dsh-turn-fold-enter .18s cubic-bezier(.33,1,.68,1)}",
|
|
21
|
+
".__ch4acko3-dsh-turn-fold__header{display:block;width:100%;min-height:28px;box-sizing:border-box;margin:0;padding:3px 4px;color:var(--dsw-alias-label-secondary);text-align:left;font:var(--dsw-font-xs-13)}",
|
|
22
|
+
"button.__ch4acko3-dsh-turn-fold__header{appearance:none;-webkit-tap-highlight-color:transparent;border:0;border-radius:0;background:transparent;cursor:pointer}",
|
|
23
|
+
"button.__ch4acko3-dsh-turn-fold__header:focus-visible{outline:2px solid var(--dsw-static-deepseek-500);outline-offset:1px}",
|
|
24
|
+
".__ch4acko3-dsh-turn-fold__label{display:inline;max-width:100%;font:var(--dsw-font-xs-13);font-variant-numeric:tabular-nums;color:inherit}",
|
|
25
|
+
".__ch4acko3-dsh-turn-fold__metric{white-space:nowrap}",
|
|
26
|
+
".__ch4acko3-dsh-turn-fold__separator{display:inline-block;width:1px;height:10px;margin:0 7px;background:var(--dsw-alias-border-l2);vertical-align:-1px}",
|
|
27
|
+
".__ch4acko3-dsh-turn-fold__metricWindow{display:inline-block;overflow:hidden;vertical-align:bottom}",
|
|
28
|
+
".__ch4acko3-dsh-turn-fold__metricValue{display:inline-block;animation:__ch4acko3-dsh-turn-fold-metric-roll .2s cubic-bezier(.33,1,.68,1)}",
|
|
29
|
+
".__ch4acko3-dsh-turn-fold__rule{width:100%;height:1px;background:var(--dsw-alias-border-l3)}",
|
|
30
|
+
".__ch4acko3-dsh-turn-fold__chevron{display:inline-block;margin-left:5px;color:var(--dsw-alias-label-caption);vertical-align:-2px;transform:rotate(-90deg);transition:transform .16s cubic-bezier(.33,1,.68,1)}",
|
|
31
|
+
".__ch4acko3-dsh-turn-fold--open .__ch4acko3-dsh-turn-fold__chevron{transform:rotate(0deg)}",
|
|
32
|
+
".__ch4acko3-dsh-turn-fold__clip{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows .18s cubic-bezier(.33,1,.68,1),opacity .14s ease}",
|
|
33
|
+
".__ch4acko3-dsh-turn-fold--open .__ch4acko3-dsh-turn-fold__clip{grid-template-rows:1fr;opacity:1}",
|
|
34
|
+
".__ch4acko3-dsh-turn-fold__bodyWrap{min-height:0;overflow:hidden}",
|
|
35
|
+
".__ch4acko3-dsh-turn-fold__body{display:flex;flex-direction:column;gap:16px;margin-top:12px}",
|
|
36
|
+
".__ch4acko3-dsh-turn-fold__closing{display:contents}",
|
|
37
|
+
".__ch4acko3-dsh-turn-fold__closing [data-variant=think]{display:none}",
|
|
38
|
+
".__ch4acko3-dsh-turn-fold__activityText{display:contents}",
|
|
39
|
+
".__ch4acko3-dsh-turn-fold__activityText [data-variant=think]{display:none}",
|
|
40
|
+
".__ch4acko3-dsh-turn-fold-activity{min-width:0}",
|
|
41
|
+
".__ch4acko3-dsh-turn-fold-activity__row{position:relative;overflow:hidden}",
|
|
42
|
+
".__ch4acko3-dsh-turn-fold-activity[data-state=running] .__ch4acko3-dsh-turn-fold-activity__row:after{content:\"\";position:absolute;inset-block:0;left:-300px;width:300px;pointer-events:none;background:linear-gradient(90deg,transparent 0%,color-mix(in srgb,var(--dsw-alias-bg-base) 60%,transparent) 55%,transparent 100%);animation:2.6s ease-out infinite __ch4acko3-dsh-turn-fold-activity-sweep}",
|
|
43
|
+
".__ch4acko3-dsh-turn-fold-activity__leading{flex-shrink:0}",
|
|
44
|
+
".__ch4acko3-dsh-turn-fold-activity__title{font-weight:400}",
|
|
45
|
+
".__ch4acko3-dsh-turn-fold-activity__chevron{color:var(--dsw-alias-label-secondary)}",
|
|
46
|
+
".__ch4acko3-dsh-turn-fold-activity__separator{width:2px;height:2px;margin:0 8px;flex:none;border-radius:1px;background:var(--dsw-alias-label-caption)}",
|
|
47
|
+
".__ch4acko3-dsh-turn-fold-activity__failure{min-width:0;color:var(--dsw-alias-state-error-primary);font-size:14px;line-height:24px}",
|
|
48
|
+
".__ch4acko3-dsh-turn-fold-activity__clip{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows .18s cubic-bezier(.16,1,.3,1),opacity .12s ease-out}",
|
|
49
|
+
".__ch4acko3-dsh-turn-fold-activity--open .__ch4acko3-dsh-turn-fold-activity__clip{grid-template-rows:1fr;opacity:1}",
|
|
50
|
+
".__ch4acko3-dsh-turn-fold-activity__bodyWrap{min-height:0;overflow:hidden}",
|
|
51
|
+
".__ch4acko3-dsh-turn-fold-activity__body{display:flex;flex-direction:column;gap:8px;margin:4px 0 4px 22px}",
|
|
52
|
+
".__ch4acko3-dsh-turn-fold-settings{list-style:none;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px}",
|
|
53
|
+
".__ch4acko3-dsh-turn-fold-settings__header{appearance:none;width:100%;display:flex;align-items:center;gap:12px;padding:14px 16px;border:0;border-radius:12px;background:transparent;color:inherit;text-align:left;font:inherit;cursor:pointer}",
|
|
54
|
+
".__ch4acko3-dsh-turn-fold-settings__header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}",
|
|
55
|
+
".__ch4acko3-dsh-turn-fold-settings__headText{display:flex;flex:1;min-width:0;flex-direction:column;gap:4px}",
|
|
56
|
+
".__ch4acko3-dsh-turn-fold-settings__title{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}",
|
|
57
|
+
".__ch4acko3-dsh-turn-fold-settings__description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}",
|
|
58
|
+
".__ch4acko3-dsh-turn-fold-settings__chevron{flex:none;transform:rotate(-90deg);transition:transform .16s}",
|
|
59
|
+
".__ch4acko3-dsh-turn-fold-settings--open .__ch4acko3-dsh-turn-fold-settings__chevron{transform:rotate(0deg)}",
|
|
60
|
+
".__ch4acko3-dsh-turn-fold-settings__body{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px 16px;margin:0 16px;padding:12px 0 14px;border-top:1px solid var(--dsw-alias-border-l2)}",
|
|
61
|
+
".__ch4acko3-dsh-turn-fold-settings__field{display:flex;align-items:center;gap:8px;min-width:0;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}",
|
|
62
|
+
".__ch4acko3-dsh-turn-fold-settings__field input{accent-color:var(--dsw-alias-brand-primary)}",
|
|
63
|
+
".__ch4acko3-dsh-turn-fold-settings__readOnly{grid-column:1/-1;margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px}",
|
|
64
|
+
"@keyframes __ch4acko3-dsh-turn-fold-enter{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}",
|
|
65
|
+
"@keyframes __ch4acko3-dsh-turn-fold-metric-roll{from{opacity:.15;transform:translateY(65%)}to{opacity:1;transform:translateY(0)}}",
|
|
66
|
+
"@keyframes __ch4acko3-dsh-turn-fold-activity-sweep{0%{left:-300px}90%,to{left:100%}}",
|
|
67
|
+
"@media(max-width:520px){.__ch4acko3-dsh-turn-fold__label{line-height:18px}.__ch4acko3-dsh-turn-fold-settings__body{grid-template-columns:1fr}}",
|
|
68
|
+
"@media(prefers-reduced-motion:reduce){.__ch4acko3-dsh-turn-fold,.__ch4acko3-dsh-turn-fold__metricValue,.__ch4acko3-dsh-turn-fold-activity[data-state=running] .__ch4acko3-dsh-turn-fold-activity__row:after{animation:none}.__ch4acko3-dsh-turn-fold__chevron,.__ch4acko3-dsh-turn-fold__clip,.__ch4acko3-dsh-turn-fold-activity__clip,.__ch4acko3-dsh-turn-fold-settings__chevron{transition:none}}"
|
|
69
|
+
].join("");
|
|
70
|
+
if (typeof document !== "undefined") {
|
|
71
|
+
var __ch4acko3DshTurnFoldStyle = document.getElementById("ch4acko3-dsh-turn-fold-style");
|
|
72
|
+
if (__ch4acko3DshTurnFoldStyle === null) {
|
|
73
|
+
__ch4acko3DshTurnFoldStyle = document.createElement("style");
|
|
74
|
+
__ch4acko3DshTurnFoldStyle.id = "ch4acko3-dsh-turn-fold-style";
|
|
75
|
+
__ch4acko3DshTurnFoldStyle.setAttribute("data-plugin", "@ch4acko3/dsh-turn-fold");
|
|
76
|
+
document.head.appendChild(__ch4acko3DshTurnFoldStyle);
|
|
77
|
+
}
|
|
78
|
+
__ch4acko3DshTurnFoldStyle.textContent = __ch4acko3DshTurnFoldCss;
|
|
79
|
+
}
|
|
80
|
+
var __ch4acko3DshTurnFoldOpenKeys = new Set();
|
|
81
|
+
var __ch4acko3DshTurnFoldBodyId = 0;
|
|
82
|
+
function __ch4acko3DshTurnFoldText(key, params) {
|
|
83
|
+
if (__ch4acko3DshTurnFoldTranslate === null) throw new Error("@ch4acko3/dsh-turn-fold: locale service was not installed");
|
|
84
|
+
return __ch4acko3DshTurnFoldTranslate(key, params);
|
|
85
|
+
}
|
|
86
|
+
function __ch4acko3DshTurnFoldDecodeSettings(section) {
|
|
87
|
+
if (typeof section !== "object" || section === null || !Array.isArray(section.summaryFields)) return void 0;
|
|
88
|
+
var seen = new Set();
|
|
89
|
+
var fields = [];
|
|
90
|
+
for (var i = 0; i < section.summaryFields.length; i++) {
|
|
91
|
+
var field = section.summaryFields[i];
|
|
92
|
+
if (typeof field !== "string" || __ch4acko3DshTurnFoldKnownFields.indexOf(field) < 0) return void 0;
|
|
93
|
+
if (!seen.has(field)) {
|
|
94
|
+
seen.add(field);
|
|
95
|
+
fields.push(field);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return { summaryFields: fields };
|
|
99
|
+
}
|
|
100
|
+
function __ch4acko3DshTurnFoldPublishSettings(fields) {
|
|
101
|
+
if (__ch4acko3DshTurnFoldSummaryFields.length === fields.length && __ch4acko3DshTurnFoldSummaryFields.every(function (field, index) { return field === fields[index]; })) return;
|
|
102
|
+
__ch4acko3DshTurnFoldSummaryFields = fields.slice();
|
|
103
|
+
__ch4acko3DshTurnFoldSettingsListeners.forEach(function (listener) { listener(); });
|
|
104
|
+
}
|
|
105
|
+
function __ch4acko3DshTurnFoldInstall(ctx) {
|
|
106
|
+
ctx.effect(function () { return ctx.locale.register(__ch4acko3DshTurnFoldLocaleNamespace, __ch4acko3DshTurnFoldDictionaries); }, "@ch4acko3/dsh-turn-fold: dictionaries");
|
|
107
|
+
__ch4acko3DshTurnFoldTranslate = ctx.locale.bind(__ch4acko3DshTurnFoldLocaleNamespace);
|
|
108
|
+
var scope = ctx.settingsScope.bind({ namespace: __ch4acko3DshTurnFoldSettingsNamespace, decode: __ch4acko3DshTurnFoldDecodeSettings });
|
|
109
|
+
__ch4acko3DshTurnFoldSettingsScope = scope;
|
|
110
|
+
function publish() {
|
|
111
|
+
var snapshot = scope.getSnapshot();
|
|
112
|
+
if (snapshot.status === "ready" && snapshot.value !== void 0) __ch4acko3DshTurnFoldPublishSettings(snapshot.value.summaryFields);
|
|
113
|
+
}
|
|
114
|
+
ctx.effect(function () { return scope.subscribe(publish); }, "@ch4acko3/dsh-turn-fold: settings");
|
|
115
|
+
publish();
|
|
116
|
+
ctx.slots.inject("settings.plugin.item", function () {
|
|
117
|
+
return ctx.slots.register({
|
|
118
|
+
name: "settings.plugin.item",
|
|
119
|
+
key: __ch4acko3DshTurnFoldSettingsNamespace
|
|
120
|
+
}, __ch4acko3DshTurnFoldSettingsCard);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function __ch4acko3DshTurnFoldSubscribeSettings(listener) {
|
|
124
|
+
__ch4acko3DshTurnFoldSettingsListeners.add(listener);
|
|
125
|
+
return function () { __ch4acko3DshTurnFoldSettingsListeners.delete(listener); };
|
|
126
|
+
}
|
|
127
|
+
function __ch4acko3DshTurnFoldGetSettingsSnapshot() {
|
|
128
|
+
return __ch4acko3DshTurnFoldSummaryFields;
|
|
129
|
+
}
|
|
130
|
+
function __ch4acko3DshTurnFoldNumber(value) {
|
|
131
|
+
return typeof value === "number" && isFinite(value) && value >= 0 ? value : null;
|
|
132
|
+
}
|
|
133
|
+
function __ch4acko3DshTurnFoldUsage(usage) {
|
|
134
|
+
if (typeof usage !== "object" || usage === null) return null;
|
|
135
|
+
var uncached = __ch4acko3DshTurnFoldNumber(usage.inputTokens);
|
|
136
|
+
var output = __ch4acko3DshTurnFoldNumber(usage.outputTokens);
|
|
137
|
+
if (uncached === null || output === null) return null;
|
|
138
|
+
var cacheRead = usage.cacheReadTokens === void 0 ? 0 : __ch4acko3DshTurnFoldNumber(usage.cacheReadTokens);
|
|
139
|
+
var cacheWrite = usage.cacheWriteTokens === void 0 ? 0 : __ch4acko3DshTurnFoldNumber(usage.cacheWriteTokens);
|
|
140
|
+
var reasoning = usage.reasoningTokens === void 0 ? 0 : __ch4acko3DshTurnFoldNumber(usage.reasoningTokens);
|
|
141
|
+
if (cacheRead === null || cacheWrite === null || reasoning === null) return null;
|
|
142
|
+
return {
|
|
143
|
+
inputTokens: uncached + cacheRead + cacheWrite,
|
|
144
|
+
outputTokens: output,
|
|
145
|
+
cacheReadTokens: cacheRead,
|
|
146
|
+
cacheWriteTokens: cacheWrite,
|
|
147
|
+
reasoningTokens: reasoning
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function __ch4acko3DshTurnFoldReasoningTexts(node) {
|
|
151
|
+
var blocks = node !== void 0 && node.data !== void 0 ? node.data.blocks : void 0;
|
|
152
|
+
if (!Array.isArray(blocks)) return [];
|
|
153
|
+
return blocks.filter(function (block) {
|
|
154
|
+
return block !== void 0 && block.kind === "reasoning" && typeof block.text === "string" && block.text.length > 0;
|
|
155
|
+
}).map(function (block) { return block.text; });
|
|
156
|
+
}
|
|
157
|
+
function __ch4acko3DshTurnFoldMotionMs() {
|
|
158
|
+
if (typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches) return 0;
|
|
159
|
+
return 180;
|
|
160
|
+
}
|
|
161
|
+
function __ch4acko3DshTurnFoldInteractionKeys() {
|
|
162
|
+
var keys = new Set();
|
|
163
|
+
if (typeof document === "undefined") return keys;
|
|
164
|
+
var active = document.activeElement;
|
|
165
|
+
var activeRow = active instanceof Element ? active.closest("[data-chat-anchor-key]") : null;
|
|
166
|
+
if (activeRow !== null && activeRow.dataset.chatAnchorKey) keys.add(activeRow.dataset.chatAnchorKey);
|
|
167
|
+
if (typeof window === "undefined" || typeof window.getSelection !== "function") return keys;
|
|
168
|
+
var selection = window.getSelection();
|
|
169
|
+
if (selection === null || selection.isCollapsed || selection.rangeCount === 0) return keys;
|
|
170
|
+
var range = selection.getRangeAt(0);
|
|
171
|
+
var rows = document.querySelectorAll("[data-chat-anchor-key]");
|
|
172
|
+
for (var i = 0; i < rows.length; i++) {
|
|
173
|
+
if (range.intersectsNode(rows[i]) && rows[i].dataset.chatAnchorKey) keys.add(rows[i].dataset.chatAnchorKey);
|
|
174
|
+
}
|
|
175
|
+
return keys;
|
|
176
|
+
}
|
|
177
|
+
function __ch4acko3DshTurnFoldChevron() {
|
|
178
|
+
return react_jsx_runtime.jsx("svg", {
|
|
179
|
+
className: "__ch4acko3-dsh-turn-fold__chevron",
|
|
180
|
+
width: 12,
|
|
181
|
+
height: 12,
|
|
182
|
+
viewBox: "0 0 12 12",
|
|
183
|
+
"aria-hidden": true,
|
|
184
|
+
children: react_jsx_runtime.jsx("path", {
|
|
185
|
+
d: "M3.5 4.5 6 7l2.5-2.5",
|
|
186
|
+
fill: "none",
|
|
187
|
+
stroke: "currentColor",
|
|
188
|
+
strokeWidth: 1.5,
|
|
189
|
+
strokeLinecap: "round",
|
|
190
|
+
strokeLinejoin: "round"
|
|
191
|
+
})
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function __ch4acko3DshTurnFoldToolFacts(toolKeys, nodeStore) {
|
|
195
|
+
var failed = 0;
|
|
196
|
+
var running = false;
|
|
197
|
+
for (var i = 0; i < toolKeys.length; i++) {
|
|
198
|
+
var node = nodeStore.get(toolKeys[i]);
|
|
199
|
+
var root = node === void 0 || node.data === void 0 ? void 0 : node.data.root;
|
|
200
|
+
if (root !== void 0 && root.kind === "tool-result") {
|
|
201
|
+
if (root.isError === true) failed++;
|
|
202
|
+
} else {
|
|
203
|
+
running = true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { failed: failed, running: running };
|
|
207
|
+
}
|
|
208
|
+
function __ch4acko3DshTurnFoldActivityGroup(props) {
|
|
209
|
+
var foldKey = props.foldKey;
|
|
210
|
+
var toolCount = 0;
|
|
211
|
+
var hasThink = false;
|
|
212
|
+
for (var itemIndex = 0; itemIndex < props.items.length; itemIndex++) {
|
|
213
|
+
if (props.items[itemIndex].kind === "tool") toolCount++;
|
|
214
|
+
else hasThink = true;
|
|
215
|
+
}
|
|
216
|
+
var initialOpen = __ch4acko3DshTurnFoldOpenKeys.has(foldKey);
|
|
217
|
+
var openState = react.useState(initialOpen);
|
|
218
|
+
var open = openState[0];
|
|
219
|
+
var setOpen = openState[1];
|
|
220
|
+
var renderedState = react.useState(initialOpen);
|
|
221
|
+
var bodyRendered = renderedState[0];
|
|
222
|
+
var setBodyRendered = renderedState[1];
|
|
223
|
+
var frameRef = react.useRef(null);
|
|
224
|
+
var timerRef = react.useRef(null);
|
|
225
|
+
react.useEffect(function () {
|
|
226
|
+
return function () {
|
|
227
|
+
if (frameRef.current !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frameRef.current);
|
|
228
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
229
|
+
};
|
|
230
|
+
}, []);
|
|
231
|
+
var title = hasThink && toolCount === 0
|
|
232
|
+
? __ch4acko3DshTurnFoldText("activityGroup.think")
|
|
233
|
+
: __ch4acko3DshTurnFoldText((hasThink ? "activityGroup.thinkAndTools." : "activityGroup.tools.") + (toolCount === 1 ? "one" : "many"), { count: toolCount });
|
|
234
|
+
var failure = props.failed === 0 ? null : __ch4acko3DshTurnFoldText("activityGroup.failures." + (props.failed === 1 ? "one" : "many"), { count: props.failed });
|
|
235
|
+
var state = props.running ? "running" : props.failed > 0 ? "error" : "ok";
|
|
236
|
+
function toggle() {
|
|
237
|
+
if (frameRef.current !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frameRef.current);
|
|
238
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
239
|
+
frameRef.current = null;
|
|
240
|
+
timerRef.current = null;
|
|
241
|
+
if (open) {
|
|
242
|
+
__ch4acko3DshTurnFoldOpenKeys.delete(foldKey);
|
|
243
|
+
setOpen(false);
|
|
244
|
+
var delay = __ch4acko3DshTurnFoldMotionMs();
|
|
245
|
+
if (delay === 0) setBodyRendered(false);
|
|
246
|
+
else timerRef.current = setTimeout(function () {
|
|
247
|
+
timerRef.current = null;
|
|
248
|
+
setBodyRendered(false);
|
|
249
|
+
}, delay);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
__ch4acko3DshTurnFoldOpenKeys.add(foldKey);
|
|
253
|
+
setBodyRendered(true);
|
|
254
|
+
if (__ch4acko3DshTurnFoldMotionMs() === 0 || typeof requestAnimationFrame !== "function") {
|
|
255
|
+
setOpen(true);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
frameRef.current = requestAnimationFrame(function () {
|
|
259
|
+
frameRef.current = null;
|
|
260
|
+
setOpen(true);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return react_jsx_runtime.jsxs("div", {
|
|
264
|
+
className: "__ch4acko3-dsh-turn-fold-activity" + (open ? " __ch4acko3-dsh-turn-fold-activity--open" : ""),
|
|
265
|
+
"data-ch4acko3-dsh-turn-fold-activity": "",
|
|
266
|
+
"data-ch4acko3-dsh-turn-fold-activity-open": open ? "true" : "false",
|
|
267
|
+
"data-dsh-fold-owner": "@ch4acko3/dsh-turn-fold",
|
|
268
|
+
"data-dsh-fold-scope": "activity-run",
|
|
269
|
+
"data-state": state,
|
|
270
|
+
children: [
|
|
271
|
+
react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
|
|
272
|
+
rowClassName: "__ch4acko3-dsh-turn-fold-activity__row",
|
|
273
|
+
leadingClassName: "__ch4acko3-dsh-turn-fold-activity__leading",
|
|
274
|
+
titleClassName: "__ch4acko3-dsh-turn-fold-activity__title",
|
|
275
|
+
chevronClassName: "__ch4acko3-dsh-turn-fold-activity__chevron",
|
|
276
|
+
icon: props.failed > 0 ? react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }) : react_jsx_runtime.jsx(_deepseek_ai_dsh_client_ui_primitives.IconApiOutline14, { size: 14 }),
|
|
277
|
+
title: title,
|
|
278
|
+
open: open,
|
|
279
|
+
expandable: true,
|
|
280
|
+
expandOnRowClick: true,
|
|
281
|
+
onToggle: toggle,
|
|
282
|
+
collapsedContent: failure === null ? void 0 : react_jsx_runtime.jsxs(react_jsx_runtime.Fragment, { children: [
|
|
283
|
+
react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold-activity__separator", "aria-hidden": true }),
|
|
284
|
+
react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold-activity__failure", children: failure })
|
|
285
|
+
] })
|
|
286
|
+
}),
|
|
287
|
+
react_jsx_runtime.jsx("div", {
|
|
288
|
+
className: "__ch4acko3-dsh-turn-fold-activity__clip",
|
|
289
|
+
"aria-hidden": !open,
|
|
290
|
+
inert: !open,
|
|
291
|
+
children: bodyRendered ? react_jsx_runtime.jsx("div", {
|
|
292
|
+
className: "__ch4acko3-dsh-turn-fold-activity__bodyWrap",
|
|
293
|
+
children: react_jsx_runtime.jsx("div", {
|
|
294
|
+
className: "__ch4acko3-dsh-turn-fold-activity__body",
|
|
295
|
+
children: props.items.map(function (item) {
|
|
296
|
+
return item.kind === "reasoning"
|
|
297
|
+
? react_jsx_runtime.jsx(ReasoningRow, { text: item.text, running: false, t: props.t }, item.key)
|
|
298
|
+
: props.renderNode(item.key);
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
}) : null
|
|
302
|
+
})
|
|
303
|
+
]
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
function __ch4acko3DshTurnFoldSettingsCard() {
|
|
307
|
+
var openState = react.useState(false);
|
|
308
|
+
var open = openState[0];
|
|
309
|
+
var setOpen = openState[1];
|
|
310
|
+
var pendingState = react.useState(false);
|
|
311
|
+
var pending = pendingState[0];
|
|
312
|
+
var setPending = pendingState[1];
|
|
313
|
+
var failedState = react.useState(false);
|
|
314
|
+
var failed = failedState[0];
|
|
315
|
+
var setFailed = failedState[1];
|
|
316
|
+
var scope = __ch4acko3DshTurnFoldSettingsScope;
|
|
317
|
+
if (scope === null) return null;
|
|
318
|
+
var snapshot = react.useSyncExternalStore(function (listener) { return scope.subscribe(listener); }, function () { return scope.getSnapshot(); }, function () { return scope.getSnapshot(); });
|
|
319
|
+
if (snapshot.status !== "ready" || snapshot.value === void 0) return null;
|
|
320
|
+
var fields = snapshot.value.summaryFields;
|
|
321
|
+
var title = __ch4acko3DshTurnFoldText("settings.title");
|
|
322
|
+
function toggleField(field, checked) {
|
|
323
|
+
if (!snapshot.writable || pending) return;
|
|
324
|
+
var next = __ch4acko3DshTurnFoldKnownFields.filter(function (candidate) {
|
|
325
|
+
return candidate === field ? checked : fields.indexOf(candidate) >= 0;
|
|
326
|
+
});
|
|
327
|
+
setPending(true);
|
|
328
|
+
setFailed(false);
|
|
329
|
+
scope.set("summaryFields", next).then(function () {
|
|
330
|
+
setPending(false);
|
|
331
|
+
}, function () {
|
|
332
|
+
setPending(false);
|
|
333
|
+
setFailed(true);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return react_jsx_runtime.jsxs("li", {
|
|
337
|
+
className: "__ch4acko3-dsh-turn-fold-settings" + (open ? " __ch4acko3-dsh-turn-fold-settings--open" : ""),
|
|
338
|
+
"data-ch4acko3-dsh-turn-fold-settings": "",
|
|
339
|
+
children: [
|
|
340
|
+
react_jsx_runtime.jsxs("button", {
|
|
341
|
+
type: "button",
|
|
342
|
+
className: "__ch4acko3-dsh-turn-fold-settings__header",
|
|
343
|
+
"aria-expanded": open,
|
|
344
|
+
"aria-label": __ch4acko3DshTurnFoldText(open ? "settings.collapse" : "settings.expand", { title: title }),
|
|
345
|
+
onClick: function () { setOpen(!open); },
|
|
346
|
+
children: [
|
|
347
|
+
react_jsx_runtime.jsxs("span", {
|
|
348
|
+
className: "__ch4acko3-dsh-turn-fold-settings__headText",
|
|
349
|
+
children: [
|
|
350
|
+
react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold-settings__title", children: title }),
|
|
351
|
+
react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold-settings__description", children: __ch4acko3DshTurnFoldText("settings.description") })
|
|
352
|
+
]
|
|
353
|
+
}),
|
|
354
|
+
react_jsx_runtime.jsx(__ch4acko3DshTurnFoldChevron, {})
|
|
355
|
+
]
|
|
356
|
+
}),
|
|
357
|
+
open ? react_jsx_runtime.jsxs("div", {
|
|
358
|
+
className: "__ch4acko3-dsh-turn-fold-settings__body",
|
|
359
|
+
children: [
|
|
360
|
+
!snapshot.writable ? react_jsx_runtime.jsx("p", { className: "__ch4acko3-dsh-turn-fold-settings__readOnly", role: "status", children: __ch4acko3DshTurnFoldText("settings.readOnly") }) : null,
|
|
361
|
+
failed ? react_jsx_runtime.jsx("p", { className: "__ch4acko3-dsh-turn-fold-settings__readOnly", role: "alert", children: __ch4acko3DshTurnFoldText("settings.writeFailed") }) : null,
|
|
362
|
+
__ch4acko3DshTurnFoldKnownFields.map(function (field) {
|
|
363
|
+
return react_jsx_runtime.jsxs("label", {
|
|
364
|
+
className: "__ch4acko3-dsh-turn-fold-settings__field",
|
|
365
|
+
children: [
|
|
366
|
+
react_jsx_runtime.jsx("input", {
|
|
367
|
+
type: "checkbox",
|
|
368
|
+
checked: fields.indexOf(field) >= 0,
|
|
369
|
+
disabled: !snapshot.writable || pending,
|
|
370
|
+
onChange: function (event) { toggleField(field, event.currentTarget.checked); }
|
|
371
|
+
}),
|
|
372
|
+
react_jsx_runtime.jsx("span", { children: __ch4acko3DshTurnFoldText("settings." + field) })
|
|
373
|
+
]
|
|
374
|
+
}, field);
|
|
375
|
+
})
|
|
376
|
+
]
|
|
377
|
+
}) : null
|
|
378
|
+
]
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
function __ch4acko3DshTurnFoldLiveDuration(metrics, running) {
|
|
382
|
+
var nowState = react.useState(function () { return Date.now(); });
|
|
383
|
+
var now = nowState[0];
|
|
384
|
+
var setNow = nowState[1];
|
|
385
|
+
react.useEffect(function () {
|
|
386
|
+
if (!running || typeof metrics.startTime !== "number") return;
|
|
387
|
+
var timer = setInterval(function () { setNow(Date.now()); }, 1000);
|
|
388
|
+
return function () { clearInterval(timer); };
|
|
389
|
+
}, [running, metrics.startTime]);
|
|
390
|
+
if (running && typeof metrics.startTime === "number") return Math.max(0, now - metrics.startTime);
|
|
391
|
+
return metrics.durationMs;
|
|
392
|
+
}
|
|
393
|
+
function __ch4acko3DshTurnFoldSpacedDuration(value) {
|
|
394
|
+
return value.replace(/(\d)(?=(?:小时|分钟|秒|分|时))/g, "$1 ").replace(/(小时|分钟|秒|分|时)(?=\d)/g, "$1 ");
|
|
395
|
+
}
|
|
396
|
+
function __ch4acko3DshTurnFoldAnimatedPart(field, key, parameter, display, animationKey, qualifier) {
|
|
397
|
+
var marker = "__ch4acko3_dsh_turn_fold_value__";
|
|
398
|
+
var params = {};
|
|
399
|
+
params[parameter] = marker;
|
|
400
|
+
var template = __ch4acko3DshTurnFoldText(key, params);
|
|
401
|
+
var position = template.indexOf(marker);
|
|
402
|
+
if (position < 0) throw new Error("@ch4acko3/dsh-turn-fold: summary locale omitted {" + parameter + "} for " + key);
|
|
403
|
+
qualifier = qualifier || "";
|
|
404
|
+
return {
|
|
405
|
+
field: field,
|
|
406
|
+
text: template.slice(0, position) + qualifier + display + template.slice(position + marker.length),
|
|
407
|
+
prefix: template.slice(0, position) + qualifier,
|
|
408
|
+
value: display,
|
|
409
|
+
suffix: template.slice(position + marker.length),
|
|
410
|
+
rolling: true,
|
|
411
|
+
animationKey: String(animationKey)
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function __ch4acko3DshTurnFoldCountPart(field, key, count, display, qualifier) {
|
|
415
|
+
return __ch4acko3DshTurnFoldAnimatedPart(field, key, "count", display, count, qualifier);
|
|
416
|
+
}
|
|
417
|
+
function __ch4acko3DshTurnFoldDurationPart(field, key, duration) {
|
|
418
|
+
var part = __ch4acko3DshTurnFoldAnimatedPart(field, key, "duration", duration, duration);
|
|
419
|
+
part.segments = duration.split(/(\d+)/).filter(function (segment) { return segment.length > 0; });
|
|
420
|
+
return part;
|
|
421
|
+
}
|
|
422
|
+
function __ch4acko3DshTurnFoldSummaryParts(metrics, running, settled, completed, durationT) {
|
|
423
|
+
var fields = react.useSyncExternalStore(__ch4acko3DshTurnFoldSubscribeSettings, __ch4acko3DshTurnFoldGetSettingsSnapshot, __ch4acko3DshTurnFoldGetSettingsSnapshot);
|
|
424
|
+
var durationMs = __ch4acko3DshTurnFoldLiveDuration(metrics, running);
|
|
425
|
+
var parts = [];
|
|
426
|
+
for (var i = 0; i < fields.length; i++) {
|
|
427
|
+
var field = fields[i];
|
|
428
|
+
var value = metrics[field];
|
|
429
|
+
if (field === "duration") {
|
|
430
|
+
if (typeof durationMs === "number" && isFinite(durationMs) && durationMs >= 0) {
|
|
431
|
+
var duration = __ch4acko3DshTurnFoldSpacedDuration(formatRunDuration(durationMs, durationT));
|
|
432
|
+
parts.push(__ch4acko3DshTurnFoldDurationPart(field, completed ? "summary.elapsed" : "summary.duration", duration));
|
|
433
|
+
}
|
|
434
|
+
} else if (field === "toolCalls" || field === "modelCalls") {
|
|
435
|
+
if (typeof value === "number") parts.push(__ch4acko3DshTurnFoldCountPart(field, "summary." + field + (value === 1 ? ".one" : ".many"), value, String(value)));
|
|
436
|
+
} else if (field === "timeToFirstToken") {
|
|
437
|
+
if (typeof value === "number") parts.push({ field: field, text: __ch4acko3DshTurnFoldText("summary.timeToFirstToken", { seconds: value < 10000 ? Math.round(value / 100) / 10 : Math.round(value / 1000) }) });
|
|
438
|
+
} else if (field === "tokensPerSecond") {
|
|
439
|
+
if (typeof value === "number") parts.push({ field: field, text: __ch4acko3DshTurnFoldText("summary.tokensPerSecond", { count: value >= 10 ? Math.round(value) : Math.round(value * 10) / 10 }) });
|
|
440
|
+
} else if (typeof value === "number") {
|
|
441
|
+
parts.push(__ch4acko3DshTurnFoldCountPart(field, "summary." + field, value, formatTokens(value), metrics.tokenUsagePartial && settled ? "≥ " : ""));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
return parts.length === 0 ? [{ field: "activity", text: __ch4acko3DshTurnFoldText("summary.activity") }] : parts;
|
|
445
|
+
}
|
|
446
|
+
function __ch4acko3DshTurnFoldSummaryLabel(parts) {
|
|
447
|
+
return parts.map(function (part) { return part.text; }).join(" | ");
|
|
448
|
+
}
|
|
449
|
+
function __ch4acko3DshTurnFoldStatusSuffix(termination) {
|
|
450
|
+
if (termination === "aborted") return __ch4acko3DshTurnFoldText("summary.stoppedSuffix");
|
|
451
|
+
if (termination === "interrupted") return __ch4acko3DshTurnFoldText("summary.interruptedSuffix");
|
|
452
|
+
return "";
|
|
453
|
+
}
|
|
454
|
+
function __ch4acko3DshTurnFoldSummaryChildren(parts, disclosure, statusSuffix) {
|
|
455
|
+
var children = [];
|
|
456
|
+
for (var i = 0; i < parts.length; i++) {
|
|
457
|
+
var part = parts[i];
|
|
458
|
+
if (i > 0) children.push(react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold__separator", "aria-hidden": true }, "separator-" + i));
|
|
459
|
+
var animatedValue = part.segments === void 0
|
|
460
|
+
? react_jsx_runtime.jsx("span", {
|
|
461
|
+
className: "__ch4acko3-dsh-turn-fold__metricWindow",
|
|
462
|
+
children: react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold__metricValue", children: part.value }, part.field + "-" + part.animationKey)
|
|
463
|
+
}, "value")
|
|
464
|
+
: part.segments.map(function (segment, segmentIndex) {
|
|
465
|
+
return /^\d+$/.test(segment) ? react_jsx_runtime.jsx("span", {
|
|
466
|
+
className: "__ch4acko3-dsh-turn-fold__metricWindow",
|
|
467
|
+
children: react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold__metricValue", children: segment }, part.field + "-" + segmentIndex + "-" + segment)
|
|
468
|
+
}, "segment-" + segmentIndex) : segment;
|
|
469
|
+
});
|
|
470
|
+
var content = part.rolling ? [part.prefix, animatedValue, part.suffix] : part.text;
|
|
471
|
+
children.push((part.rolling ? react_jsx_runtime.jsxs : react_jsx_runtime.jsx)("span", { className: "__ch4acko3-dsh-turn-fold__metric", children: content }, part.field));
|
|
472
|
+
}
|
|
473
|
+
if (statusSuffix) children.push(react_jsx_runtime.jsx("span", { className: "__ch4acko3-dsh-turn-fold__metric", children: statusSuffix }, "status"));
|
|
474
|
+
if (disclosure) children.push(react_jsx_runtime.jsx(__ch4acko3DshTurnFoldChevron, {}, "chevron"));
|
|
475
|
+
return children;
|
|
476
|
+
}
|
|
477
|
+
function __ch4acko3DshTurnFoldSummary(props) {
|
|
478
|
+
var parts = __ch4acko3DshTurnFoldSummaryParts(props.metrics, props.running, props.settled, props.completed, props.t);
|
|
479
|
+
var statusSuffix = __ch4acko3DshTurnFoldStatusSuffix(props.termination);
|
|
480
|
+
var label = __ch4acko3DshTurnFoldSummaryLabel(parts) + statusSuffix;
|
|
481
|
+
return react_jsx_runtime.jsxs("div", {
|
|
482
|
+
className: "__ch4acko3-dsh-turn-fold",
|
|
483
|
+
"data-ch4acko3-dsh-turn-fold-summary": props.running ? "running" : "complete",
|
|
484
|
+
"data-dsh-summary-owner": "@ch4acko3/dsh-turn-fold",
|
|
485
|
+
children: [
|
|
486
|
+
react_jsx_runtime.jsx("div", {
|
|
487
|
+
className: "__ch4acko3-dsh-turn-fold__header",
|
|
488
|
+
role: props.running ? "status" : void 0,
|
|
489
|
+
"aria-label": props.running ? label : void 0,
|
|
490
|
+
children: react_jsx_runtime.jsxs("span", { className: "__ch4acko3-dsh-turn-fold__label", "aria-hidden": props.running ? true : void 0, children: __ch4acko3DshTurnFoldSummaryChildren(parts, false, statusSuffix) })
|
|
491
|
+
}),
|
|
492
|
+
react_jsx_runtime.jsx("div", { className: "__ch4acko3-dsh-turn-fold__rule", "aria-hidden": true })
|
|
493
|
+
]
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
function __ch4acko3DshTurnFoldNodeTurn(node) {
|
|
497
|
+
var location = node === void 0 ? void 0 : node.location;
|
|
498
|
+
return location !== void 0 && (location.kind === "turn" || location.kind === "step") ? location.turn.turn : null;
|
|
499
|
+
}
|
|
500
|
+
function __ch4acko3DshTurnFoldHasVisibleNonReasoning(node) {
|
|
501
|
+
var blocks = node.data === void 0 ? void 0 : node.data.blocks;
|
|
502
|
+
if (!Array.isArray(blocks)) return false;
|
|
503
|
+
for (var i = 0; i < blocks.length; i++) {
|
|
504
|
+
var block = blocks[i];
|
|
505
|
+
if (block === void 0 || block.kind === "reasoning" || block.kind === "tool-call") continue;
|
|
506
|
+
if (block.kind !== "text" || typeof block.text !== "string" || block.text.trim() !== "") return true;
|
|
507
|
+
}
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
function __ch4acko3DshTurnFoldHasToolCallBlock(node) {
|
|
511
|
+
var blocks = node.data === void 0 ? void 0 : node.data.blocks;
|
|
512
|
+
return Array.isArray(blocks) && blocks.some(function (block) { return block !== void 0 && block.kind === "tool-call"; });
|
|
513
|
+
}
|
|
514
|
+
function __ch4acko3DshTurnFoldIsActivityNode(node) {
|
|
515
|
+
if (node.kind === "tool-call") return true;
|
|
516
|
+
if (node.kind !== "assistant-step" || __ch4acko3DshTurnFoldReasoningTexts(node).length === 0) return false;
|
|
517
|
+
return __ch4acko3DshTurnFoldHasToolCallBlock(node) || !__ch4acko3DshTurnFoldHasVisibleNonReasoning(node);
|
|
518
|
+
}
|
|
519
|
+
function __ch4acko3DshTurnFoldRenderNativeEntry(entry, renderNode, hideReasoning) {
|
|
520
|
+
var rendered = renderNode(entry.key);
|
|
521
|
+
if (hideReasoning) rendered = react_jsx_runtime.jsx("div", {
|
|
522
|
+
className: "__ch4acko3-dsh-turn-fold__activityText",
|
|
523
|
+
children: rendered
|
|
524
|
+
}, "activity-text:" + String(entry.key));
|
|
525
|
+
return entry.closingKey === void 0 ? rendered : react_jsx_runtime.jsx("div", {
|
|
526
|
+
className: "__ch4acko3-dsh-turn-fold__closing",
|
|
527
|
+
children: rendered
|
|
528
|
+
}, entry.closingKey);
|
|
529
|
+
}
|
|
530
|
+
function __ch4acko3DshTurnFoldRenderEntries(entries, nodeStore, renderNode, sessionId, interactionKeys, t) {
|
|
531
|
+
var out = [];
|
|
532
|
+
for (var i = 0; i < entries.length; i++) {
|
|
533
|
+
var entry = entries[i];
|
|
534
|
+
if (entry.type === "element") {
|
|
535
|
+
out.push(entry.element);
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
var turn = __ch4acko3DshTurnFoldNodeTurn(entry.node);
|
|
539
|
+
if (!__ch4acko3DshTurnFoldIsActivityNode(entry.node)) {
|
|
540
|
+
out.push(__ch4acko3DshTurnFoldRenderNativeEntry(entry, renderNode, false));
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
var activityEntries = [entry];
|
|
544
|
+
var j = i + 1;
|
|
545
|
+
while (j < entries.length) {
|
|
546
|
+
var next = entries[j];
|
|
547
|
+
if (next.type !== "node" || !__ch4acko3DshTurnFoldIsActivityNode(next.node) || next.order !== activityEntries[activityEntries.length - 1].order + 1 || __ch4acko3DshTurnFoldNodeTurn(next.node) !== turn) break;
|
|
548
|
+
if (__ch4acko3DshTurnFoldHasVisibleNonReasoning(next.node)) break;
|
|
549
|
+
activityEntries.push(next);
|
|
550
|
+
j++;
|
|
551
|
+
}
|
|
552
|
+
var selected = activityEntries.some(function (activityEntry) { return interactionKeys.has(activityEntry.key); });
|
|
553
|
+
if (turn === null || activityEntries.length < 2 || selected) {
|
|
554
|
+
for (var k = 0; k < activityEntries.length; k++) out.push(__ch4acko3DshTurnFoldRenderNativeEntry(activityEntries[k], renderNode, false));
|
|
555
|
+
} else {
|
|
556
|
+
var items = [];
|
|
557
|
+
var toolKeys = [];
|
|
558
|
+
for (var activityIndex = 0; activityIndex < activityEntries.length; activityIndex++) {
|
|
559
|
+
var activityEntry = activityEntries[activityIndex];
|
|
560
|
+
if (activityEntry.node.kind === "tool-call") {
|
|
561
|
+
toolKeys.push(activityEntry.key);
|
|
562
|
+
items.push({ kind: "tool", key: activityEntry.key });
|
|
563
|
+
} else {
|
|
564
|
+
var texts = __ch4acko3DshTurnFoldReasoningTexts(activityEntry.node);
|
|
565
|
+
for (var textIndex = 0; textIndex < texts.length; textIndex++) items.push({ kind: "reasoning", key: String(activityEntry.key) + ":" + String(textIndex), text: texts[textIndex] });
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (__ch4acko3DshTurnFoldHasVisibleNonReasoning(entry.node)) out.push(__ch4acko3DshTurnFoldRenderNativeEntry(entry, renderNode, true));
|
|
569
|
+
var facts = __ch4acko3DshTurnFoldToolFacts(toolKeys, nodeStore);
|
|
570
|
+
var foldKey = "activity:" + String(sessionId) + ":" + String(turn) + ":" + String(entry.key);
|
|
571
|
+
out.push(react_jsx_runtime.jsx(__ch4acko3DshTurnFoldActivityGroup, {
|
|
572
|
+
failed: facts.failed,
|
|
573
|
+
foldKey: foldKey,
|
|
574
|
+
items: items,
|
|
575
|
+
renderNode: renderNode,
|
|
576
|
+
running: facts.running,
|
|
577
|
+
t: t
|
|
578
|
+
}, foldKey));
|
|
579
|
+
}
|
|
580
|
+
i = j - 1;
|
|
581
|
+
}
|
|
582
|
+
return out;
|
|
583
|
+
}
|
|
584
|
+
function __ch4acko3DshTurnFoldRenderKeys(keys, orderPositions, nodeStore, renderNode, sessionId, t) {
|
|
585
|
+
var entries = [];
|
|
586
|
+
for (var i = 0; i < keys.length; i++) {
|
|
587
|
+
var key = keys[i];
|
|
588
|
+
var node = nodeStore.get(key);
|
|
589
|
+
if (node !== void 0) entries.push({ type: "node", key: key, node: node, order: orderPositions.get(key) });
|
|
590
|
+
}
|
|
591
|
+
return __ch4acko3DshTurnFoldRenderEntries(entries, nodeStore, renderNode, sessionId, new Set(), t);
|
|
592
|
+
}
|
|
593
|
+
function __ch4acko3DshTurnFoldDisclosure(props) {
|
|
594
|
+
var activity = props.activity;
|
|
595
|
+
var foldKey = props.foldKey;
|
|
596
|
+
var renderNode = props.renderNode;
|
|
597
|
+
var initialOpen = __ch4acko3DshTurnFoldOpenKeys.has(foldKey);
|
|
598
|
+
var expandedState = react.useState(initialOpen);
|
|
599
|
+
var expanded = expandedState[0];
|
|
600
|
+
var setExpanded = expandedState[1];
|
|
601
|
+
var renderedState = react.useState(initialOpen);
|
|
602
|
+
var bodyRendered = renderedState[0];
|
|
603
|
+
var setBodyRendered = renderedState[1];
|
|
604
|
+
var frameRef = react.useRef(null);
|
|
605
|
+
var timerRef = react.useRef(null);
|
|
606
|
+
var bodyIdState = react.useState(function () { return "ch4acko3-dsh-turn-fold-body-" + (++__ch4acko3DshTurnFoldBodyId); });
|
|
607
|
+
var bodyId = bodyIdState[0];
|
|
608
|
+
react.useEffect(function () {
|
|
609
|
+
return function () {
|
|
610
|
+
if (frameRef.current !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frameRef.current);
|
|
611
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
612
|
+
};
|
|
613
|
+
}, []);
|
|
614
|
+
var parts = __ch4acko3DshTurnFoldSummaryParts(props.metrics, false, true, props.completed, props.t);
|
|
615
|
+
var statusSuffix = __ch4acko3DshTurnFoldStatusSuffix(props.termination);
|
|
616
|
+
var label = __ch4acko3DshTurnFoldSummaryLabel(parts) + statusSuffix;
|
|
617
|
+
var actionLabel = __ch4acko3DshTurnFoldText(expanded ? "action.collapse" : "action.expand", { summary: label });
|
|
618
|
+
function toggle() {
|
|
619
|
+
if (frameRef.current !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frameRef.current);
|
|
620
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
621
|
+
frameRef.current = null;
|
|
622
|
+
timerRef.current = null;
|
|
623
|
+
if (expanded) {
|
|
624
|
+
__ch4acko3DshTurnFoldOpenKeys.delete(foldKey);
|
|
625
|
+
setExpanded(false);
|
|
626
|
+
var delay = __ch4acko3DshTurnFoldMotionMs();
|
|
627
|
+
if (delay === 0) setBodyRendered(false);
|
|
628
|
+
else timerRef.current = setTimeout(function () {
|
|
629
|
+
timerRef.current = null;
|
|
630
|
+
setBodyRendered(false);
|
|
631
|
+
}, delay);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
__ch4acko3DshTurnFoldOpenKeys.add(foldKey);
|
|
635
|
+
setBodyRendered(true);
|
|
636
|
+
if (__ch4acko3DshTurnFoldMotionMs() === 0 || typeof requestAnimationFrame !== "function") {
|
|
637
|
+
setExpanded(true);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
frameRef.current = requestAnimationFrame(function () {
|
|
641
|
+
frameRef.current = null;
|
|
642
|
+
setExpanded(true);
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
return react_jsx_runtime.jsxs("div", {
|
|
646
|
+
className: "__ch4acko3-dsh-turn-fold" + (expanded ? " __ch4acko3-dsh-turn-fold--open" : ""),
|
|
647
|
+
"data-ch4acko3-dsh-turn-fold": "",
|
|
648
|
+
"data-ch4acko3-dsh-turn-fold-open": expanded ? "true" : "false",
|
|
649
|
+
"data-dsh-fold-owner": "@ch4acko3/dsh-turn-fold",
|
|
650
|
+
"data-dsh-fold-scope": "turn",
|
|
651
|
+
children: [
|
|
652
|
+
react_jsx_runtime.jsx("button", {
|
|
653
|
+
type: "button",
|
|
654
|
+
className: "__ch4acko3-dsh-turn-fold__header",
|
|
655
|
+
"aria-expanded": expanded,
|
|
656
|
+
"aria-controls": bodyId,
|
|
657
|
+
"aria-label": actionLabel,
|
|
658
|
+
title: actionLabel,
|
|
659
|
+
onClick: toggle,
|
|
660
|
+
children: react_jsx_runtime.jsxs("span", { className: "__ch4acko3-dsh-turn-fold__label", "aria-hidden": true, children: __ch4acko3DshTurnFoldSummaryChildren(parts, true, statusSuffix) })
|
|
661
|
+
}),
|
|
662
|
+
react_jsx_runtime.jsx("div", { className: "__ch4acko3-dsh-turn-fold__rule", "aria-hidden": true }),
|
|
663
|
+
react_jsx_runtime.jsx("div", {
|
|
664
|
+
id: bodyId,
|
|
665
|
+
className: "__ch4acko3-dsh-turn-fold__clip",
|
|
666
|
+
"aria-hidden": !expanded,
|
|
667
|
+
inert: !expanded,
|
|
668
|
+
children: bodyRendered ? react_jsx_runtime.jsx("div", {
|
|
669
|
+
className: "__ch4acko3-dsh-turn-fold__bodyWrap",
|
|
670
|
+
children: react_jsx_runtime.jsxs("div", {
|
|
671
|
+
className: "__ch4acko3-dsh-turn-fold__body",
|
|
672
|
+
children: [
|
|
673
|
+
__ch4acko3DshTurnFoldRenderKeys(activity, props.orderPositions, props.nodeStore, renderNode, props.sessionId, props.t),
|
|
674
|
+
(props.closingReasoning || []).map(function (text, index) {
|
|
675
|
+
return react_jsx_runtime.jsx(ReasoningRow, { text: text, running: false, t: props.t }, "closing-reasoning-" + index);
|
|
676
|
+
})
|
|
677
|
+
]
|
|
678
|
+
})
|
|
679
|
+
}) : null
|
|
680
|
+
})
|
|
681
|
+
]
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
function __ch4acko3DshTurnFoldPlaybackTime(timeline) {
|
|
685
|
+
var clock = timeline.playbackClock;
|
|
686
|
+
return clock !== void 0 && clock.kind === "historical" && typeof clock.time === "number" && isFinite(clock.time)
|
|
687
|
+
? clock.time
|
|
688
|
+
: null;
|
|
689
|
+
}
|
|
690
|
+
function __ch4acko3DshTurnFoldPlanMetrics(plan, nodeStore, timeline) {
|
|
691
|
+
var turnLoc = timeline.turns.get(plan.turn);
|
|
692
|
+
var startEv = turnLoc === void 0 ? void 0 : turnLoc.start;
|
|
693
|
+
var endEv = turnLoc === void 0 ? void 0 : turnLoc.end;
|
|
694
|
+
var startTime = startEv !== void 0 && typeof startEv.time === "number" ? startEv.time : null;
|
|
695
|
+
var complete = startTime !== null && endEv !== void 0 && typeof endEv.time === "number";
|
|
696
|
+
var playbackTime = __ch4acko3DshTurnFoldPlaybackTime(timeline);
|
|
697
|
+
var durationMs = complete && endEv.time >= startTime
|
|
698
|
+
? endEv.time - startTime
|
|
699
|
+
: startTime !== null && playbackTime !== null
|
|
700
|
+
? Math.max(0, playbackTime - startTime)
|
|
701
|
+
: null;
|
|
702
|
+
var metrics = {
|
|
703
|
+
startTime: startTime,
|
|
704
|
+
durationMs: durationMs,
|
|
705
|
+
toolCalls: 0,
|
|
706
|
+
modelCalls: 0,
|
|
707
|
+
inputTokens: 0,
|
|
708
|
+
outputTokens: 0,
|
|
709
|
+
cacheReadTokens: 0,
|
|
710
|
+
cacheWriteTokens: 0,
|
|
711
|
+
reasoningTokens: 0,
|
|
712
|
+
tokenUsagePartial: false,
|
|
713
|
+
timeToFirstToken: null,
|
|
714
|
+
tokensPerSecond: null
|
|
715
|
+
};
|
|
716
|
+
var usageReliable = true;
|
|
717
|
+
var usageSamples = 0;
|
|
718
|
+
var decodeMs = 0;
|
|
719
|
+
var decodeTokens = 0;
|
|
720
|
+
var sampledDecode = false;
|
|
721
|
+
var firstStep = null;
|
|
722
|
+
var keys = plan.activity.slice();
|
|
723
|
+
if (plan.closingKey !== void 0 && keys.indexOf(plan.closingKey) < 0) keys.push(plan.closingKey);
|
|
724
|
+
for (var i = 0; i < keys.length; i++) {
|
|
725
|
+
var node = nodeStore.get(keys[i]);
|
|
726
|
+
if (node === void 0) continue;
|
|
727
|
+
if (node.kind === "tool-call") metrics.toolCalls++;
|
|
728
|
+
if (node.kind !== "assistant-step") continue;
|
|
729
|
+
metrics.modelCalls++;
|
|
730
|
+
var data = node.data === void 0 ? {} : node.data;
|
|
731
|
+
var usage = __ch4acko3DshTurnFoldUsage(data.usage);
|
|
732
|
+
if (usage === null) usageReliable = false;
|
|
733
|
+
else {
|
|
734
|
+
usageSamples++;
|
|
735
|
+
metrics.inputTokens += usage.inputTokens;
|
|
736
|
+
metrics.outputTokens += usage.outputTokens;
|
|
737
|
+
metrics.cacheReadTokens += usage.cacheReadTokens;
|
|
738
|
+
metrics.cacheWriteTokens += usage.cacheWriteTokens;
|
|
739
|
+
metrics.reasoningTokens += usage.reasoningTokens;
|
|
740
|
+
}
|
|
741
|
+
var finalNode = data.finalNode;
|
|
742
|
+
var timing = finalNode === void 0 ? void 0 : finalNode.timing;
|
|
743
|
+
var step = typeof data.step === "number" ? data.step : i;
|
|
744
|
+
if (timing !== void 0 && timing.stepStartTime !== null && timing.firstTokenTime !== null && (firstStep === null || step < firstStep)) {
|
|
745
|
+
firstStep = step;
|
|
746
|
+
metrics.timeToFirstToken = Math.max(0, timing.firstTokenTime - timing.stepStartTime);
|
|
747
|
+
}
|
|
748
|
+
if (timing !== void 0 && timing.firstTokenTime !== null && typeof timing.completedTime === "number" && usage !== null) {
|
|
749
|
+
decodeMs += Math.max(0, timing.completedTime - timing.firstTokenTime);
|
|
750
|
+
decodeTokens += usage.outputTokens;
|
|
751
|
+
sampledDecode = true;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
if (sampledDecode && decodeMs > 0) metrics.tokensPerSecond = decodeTokens / (decodeMs / 1000);
|
|
755
|
+
if (!usageReliable) {
|
|
756
|
+
metrics.tokenUsagePartial = usageSamples > 0;
|
|
757
|
+
if (usageSamples === 0) {
|
|
758
|
+
metrics.inputTokens = null;
|
|
759
|
+
metrics.outputTokens = null;
|
|
760
|
+
metrics.cacheReadTokens = null;
|
|
761
|
+
metrics.cacheWriteTokens = null;
|
|
762
|
+
metrics.reasoningTokens = null;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return metrics;
|
|
766
|
+
}
|
|
767
|
+
function __ch4acko3DshTurnFoldRender(props) {
|
|
768
|
+
var order = props.order;
|
|
769
|
+
var nodeStore = props.nodeStore;
|
|
770
|
+
var timeline = props.timeline;
|
|
771
|
+
var playbackTime = __ch4acko3DshTurnFoldPlaybackTime(timeline);
|
|
772
|
+
var renderNode = props.renderNode;
|
|
773
|
+
var sessionId = props.sessionId;
|
|
774
|
+
var orderPositions = new Map();
|
|
775
|
+
var FOLD_KINDS = {
|
|
776
|
+
"assistant-step": true,
|
|
777
|
+
"context": true,
|
|
778
|
+
"tool-call": true,
|
|
779
|
+
"command": true,
|
|
780
|
+
"manual-compaction": true,
|
|
781
|
+
"compaction": true,
|
|
782
|
+
"model-retry": true
|
|
783
|
+
};
|
|
784
|
+
var plans = new Map();
|
|
785
|
+
var i, key, node, loc, turnNum, plan;
|
|
786
|
+
for (i = 0; i < order.length; i++) {
|
|
787
|
+
key = order[i];
|
|
788
|
+
orderPositions.set(key, i);
|
|
789
|
+
node = nodeStore.get(key);
|
|
790
|
+
if (node === void 0) continue;
|
|
791
|
+
loc = node.location;
|
|
792
|
+
if (loc === void 0 || (loc.kind !== "turn" && loc.kind !== "step")) continue;
|
|
793
|
+
turnNum = loc.turn.turn;
|
|
794
|
+
plan = plans.get(turnNum);
|
|
795
|
+
if (plan === void 0) {
|
|
796
|
+
plan = { turn: turnNum, status: loc.turn.status, endReason: void 0, closingSeq: void 0, closingKey: void 0, closingOrder: -1, closingReasoning: [], tailKey: void 0, branchUnavailable: false, hasAfterClosing: false, hasError: false, activity: [], firstActivityOrder: -1 };
|
|
797
|
+
plans.set(turnNum, plan);
|
|
798
|
+
}
|
|
799
|
+
var endEvent = loc.turn.end;
|
|
800
|
+
if (endEvent !== void 0 && endEvent.data !== void 0 && endEvent.data.reason !== void 0) plan.endReason = endEvent.data.reason.kind;
|
|
801
|
+
if (node.kind === "turn-tail") {
|
|
802
|
+
plan.tailKey = key;
|
|
803
|
+
var closing = node.data === void 0 ? void 0 : node.data.closing;
|
|
804
|
+
if (closing !== null && closing !== void 0 && closing.finalNode !== void 0) plan.closingSeq = closing.finalNode.seq;
|
|
805
|
+
plan.branchUnavailable = node.data !== void 0 && node.data.branchUnavailable === true;
|
|
806
|
+
} else if (node.kind === "turn-error" || node.kind === "turn-max-tokens") {
|
|
807
|
+
plan.hasError = true;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
for (i = 0; i < order.length; i++) {
|
|
811
|
+
key = order[i];
|
|
812
|
+
node = nodeStore.get(key);
|
|
813
|
+
if (node === void 0) continue;
|
|
814
|
+
loc = node.location;
|
|
815
|
+
if (loc === void 0 || (loc.kind !== "turn" && loc.kind !== "step")) continue;
|
|
816
|
+
plan = plans.get(loc.turn.turn);
|
|
817
|
+
if (plan === void 0) continue;
|
|
818
|
+
if (plan.closingSeq !== void 0 && node.kind === "assistant-step" && node.data !== void 0 && node.data.finalNode !== void 0 && node.data.finalNode.seq === plan.closingSeq) {
|
|
819
|
+
plan.closingKey = key;
|
|
820
|
+
plan.closingOrder = i;
|
|
821
|
+
plan.closingReasoning = __ch4acko3DshTurnFoldReasoningTexts(node);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
for (i = 0; i < order.length; i++) {
|
|
825
|
+
key = order[i];
|
|
826
|
+
node = nodeStore.get(key);
|
|
827
|
+
if (node === void 0) continue;
|
|
828
|
+
loc = node.location;
|
|
829
|
+
if (loc === void 0 || (loc.kind !== "turn" && loc.kind !== "step")) continue;
|
|
830
|
+
plan = plans.get(loc.turn.turn);
|
|
831
|
+
if (plan === void 0 || key === plan.closingKey || key === plan.tailKey) continue;
|
|
832
|
+
if (plan.closingOrder >= 0 && i > plan.closingOrder) plan.hasAfterClosing = true;
|
|
833
|
+
if (FOLD_KINDS[node.kind] === true) {
|
|
834
|
+
if (plan.firstActivityOrder < 0) plan.firstActivityOrder = i;
|
|
835
|
+
plan.activity.push(key);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
var entries = [];
|
|
839
|
+
var interactionKeys = __ch4acko3DshTurnFoldInteractionKeys();
|
|
840
|
+
for (i = 0; i < order.length; i++) {
|
|
841
|
+
key = order[i];
|
|
842
|
+
node = nodeStore.get(key);
|
|
843
|
+
if (node === void 0) continue;
|
|
844
|
+
loc = node.location;
|
|
845
|
+
var isTurn = loc !== void 0 && (loc.kind === "turn" || loc.kind === "step");
|
|
846
|
+
plan = isTurn ? plans.get(loc.turn.turn) : void 0;
|
|
847
|
+
var foldable = plan !== void 0 && plan.status === "closed" && (plan.endReason === "completed" || plan.endReason === "aborted" || plan.endReason === "interrupted") && !plan.hasError && !plan.branchUnavailable && !plan.hasAfterClosing && plan.closingKey !== void 0 && (plan.activity.length > 0 || plan.closingReasoning.length > 0) && !plan.activity.some(function (activityKey) { return interactionKeys.has(activityKey); });
|
|
848
|
+
if (foldable && FOLD_KINDS[node.kind] === true && key !== plan.closingKey) continue;
|
|
849
|
+
var summaryAnchor = plan === void 0 ? void 0 : plan.closingKey !== void 0 && (plan.firstActivityOrder < 0 || plan.closingOrder < plan.firstActivityOrder) ? plan.closingKey : plan.activity[0];
|
|
850
|
+
if (plan !== void 0 && !foldable && summaryAnchor !== void 0 && key === summaryAnchor) {
|
|
851
|
+
entries.push({ type: "element", element: react_jsx_runtime.jsx(__ch4acko3DshTurnFoldSummary, {
|
|
852
|
+
completed: plan.endReason === "completed",
|
|
853
|
+
metrics: __ch4acko3DshTurnFoldPlanMetrics(plan, nodeStore, timeline),
|
|
854
|
+
termination: plan.endReason === "aborted" || plan.endReason === "interrupted" ? plan.endReason : void 0,
|
|
855
|
+
running: plan.status !== "closed" && playbackTime === null,
|
|
856
|
+
settled: plan.status === "closed",
|
|
857
|
+
t: props.t
|
|
858
|
+
}, "ch4acko3-dsh-turn-fold-summary-" + String(sessionId) + "-" + plan.turn) });
|
|
859
|
+
}
|
|
860
|
+
if (foldable && key === plan.closingKey) {
|
|
861
|
+
entries.push({ type: "element", element: react_jsx_runtime.jsx(__ch4acko3DshTurnFoldDisclosure, {
|
|
862
|
+
activity: plan.activity,
|
|
863
|
+
closingReasoning: plan.closingReasoning,
|
|
864
|
+
completed: plan.endReason === "completed",
|
|
865
|
+
metrics: __ch4acko3DshTurnFoldPlanMetrics(plan, nodeStore, timeline),
|
|
866
|
+
nodeStore: nodeStore,
|
|
867
|
+
orderPositions: orderPositions,
|
|
868
|
+
sessionId: sessionId,
|
|
869
|
+
termination: plan.endReason === "aborted" || plan.endReason === "interrupted" ? plan.endReason : void 0,
|
|
870
|
+
foldKey: String(sessionId) + ":" + plan.turn,
|
|
871
|
+
renderNode: renderNode,
|
|
872
|
+
t: props.t
|
|
873
|
+
}, "ch4acko3-dsh-turn-fold-" + String(sessionId) + "-" + plan.turn) });
|
|
874
|
+
}
|
|
875
|
+
entries.push({
|
|
876
|
+
type: "node",
|
|
877
|
+
key: key,
|
|
878
|
+
node: node,
|
|
879
|
+
order: i,
|
|
880
|
+
closingKey: foldable && key === plan.closingKey && plan.closingReasoning.length > 0 ? "ch4acko3-dsh-turn-fold-closing-" + String(sessionId) + "-" + plan.turn : void 0
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
return __ch4acko3DshTurnFoldRenderEntries(entries, nodeStore, renderNode, sessionId, interactionKeys, props.t);
|
|
884
|
+
}
|
|
885
|
+
`;
|
package/locales/en.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"summary.activity": "Agent activity",
|
|
3
|
+
"summary.duration": "Worked for {duration}",
|
|
4
|
+
"summary.elapsed": "Took {duration}",
|
|
5
|
+
"summary.toolCalls.one": "{count} tool call",
|
|
6
|
+
"summary.toolCalls.many": "{count} tool calls",
|
|
7
|
+
"summary.modelCalls.one": "{count} model call",
|
|
8
|
+
"summary.modelCalls.many": "{count} model calls",
|
|
9
|
+
"summary.inputTokens": "{count} input tokens",
|
|
10
|
+
"summary.outputTokens": "{count} output tokens",
|
|
11
|
+
"summary.cacheReadTokens": "{count} cache-read tokens",
|
|
12
|
+
"summary.cacheWriteTokens": "{count} cache-write tokens",
|
|
13
|
+
"summary.reasoningTokens": "{count} reasoning tokens",
|
|
14
|
+
"summary.timeToFirstToken": "First token in {seconds}s",
|
|
15
|
+
"summary.tokensPerSecond": "{count} tokens/s",
|
|
16
|
+
"summary.stoppedSuffix": " - Stopped",
|
|
17
|
+
"summary.interruptedSuffix": " - Interrupted",
|
|
18
|
+
"activityGroup.think": "Think",
|
|
19
|
+
"activityGroup.tools.one": "{count} tool call",
|
|
20
|
+
"activityGroup.tools.many": "{count} tool calls",
|
|
21
|
+
"activityGroup.thinkAndTools.one": "Think · {count} tool call",
|
|
22
|
+
"activityGroup.thinkAndTools.many": "Think · {count} tool calls",
|
|
23
|
+
"activityGroup.failures.one": "{count} failed",
|
|
24
|
+
"activityGroup.failures.many": "{count} failed",
|
|
25
|
+
"action.expand": "Expand agent activity: {summary}",
|
|
26
|
+
"action.collapse": "Collapse agent activity: {summary}",
|
|
27
|
+
"settings.title": "Turn Fold",
|
|
28
|
+
"settings.description": "Choose the metrics shown in the turn summary bar.",
|
|
29
|
+
"settings.expand": "Expand settings: {title}",
|
|
30
|
+
"settings.collapse": "Collapse settings: {title}",
|
|
31
|
+
"settings.readOnly": "This settings source is read-only.",
|
|
32
|
+
"settings.writeFailed": "Could not save this setting.",
|
|
33
|
+
"settings.duration": "Elapsed time",
|
|
34
|
+
"settings.toolCalls": "Tool calls",
|
|
35
|
+
"settings.modelCalls": "Model calls",
|
|
36
|
+
"settings.inputTokens": "Input tokens",
|
|
37
|
+
"settings.outputTokens": "Output tokens",
|
|
38
|
+
"settings.cacheReadTokens": "Cache-read tokens",
|
|
39
|
+
"settings.cacheWriteTokens": "Cache-write tokens",
|
|
40
|
+
"settings.reasoningTokens": "Reasoning tokens",
|
|
41
|
+
"settings.timeToFirstToken": "Time to first token",
|
|
42
|
+
"settings.tokensPerSecond": "Output speed"
|
|
43
|
+
}
|
package/locales/zh.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"summary.activity": "执行过程",
|
|
3
|
+
"summary.duration": "已工作 {duration}",
|
|
4
|
+
"summary.elapsed": "耗时 {duration}",
|
|
5
|
+
"summary.toolCalls.one": "{count} 次工具调用",
|
|
6
|
+
"summary.toolCalls.many": "{count} 次工具调用",
|
|
7
|
+
"summary.modelCalls.one": "{count} 次模型调用",
|
|
8
|
+
"summary.modelCalls.many": "{count} 次模型调用",
|
|
9
|
+
"summary.inputTokens": "{count} 输入 tokens",
|
|
10
|
+
"summary.outputTokens": "{count} 输出 tokens",
|
|
11
|
+
"summary.cacheReadTokens": "{count} 缓存读取 tokens",
|
|
12
|
+
"summary.cacheWriteTokens": "{count} 缓存写入 tokens",
|
|
13
|
+
"summary.reasoningTokens": "{count} 推理 tokens",
|
|
14
|
+
"summary.timeToFirstToken": "首 token 用时 {seconds} 秒",
|
|
15
|
+
"summary.tokensPerSecond": "{count} tokens/秒",
|
|
16
|
+
"summary.stoppedSuffix": " - 已停止",
|
|
17
|
+
"summary.interruptedSuffix": " - 已中断",
|
|
18
|
+
"activityGroup.think": "Think",
|
|
19
|
+
"activityGroup.tools.one": "{count} 次工具调用",
|
|
20
|
+
"activityGroup.tools.many": "{count} 次工具调用",
|
|
21
|
+
"activityGroup.thinkAndTools.one": "Think · {count} 次工具调用",
|
|
22
|
+
"activityGroup.thinkAndTools.many": "Think · {count} 次工具调用",
|
|
23
|
+
"activityGroup.failures.one": "{count} 个失败",
|
|
24
|
+
"activityGroup.failures.many": "{count} 个失败",
|
|
25
|
+
"action.expand": "展开执行过程:{summary}",
|
|
26
|
+
"action.collapse": "收起执行过程:{summary}",
|
|
27
|
+
"settings.title": "会话折叠",
|
|
28
|
+
"settings.description": "选择 turn 摘要栏中显示的指标。",
|
|
29
|
+
"settings.expand": "展开设置:{title}",
|
|
30
|
+
"settings.collapse": "收起设置:{title}",
|
|
31
|
+
"settings.readOnly": "当前设置来源为只读。",
|
|
32
|
+
"settings.writeFailed": "无法保存此设置。",
|
|
33
|
+
"settings.duration": "工作耗时",
|
|
34
|
+
"settings.toolCalls": "工具调用次数",
|
|
35
|
+
"settings.modelCalls": "模型调用次数",
|
|
36
|
+
"settings.inputTokens": "输入 tokens",
|
|
37
|
+
"settings.outputTokens": "输出 tokens",
|
|
38
|
+
"settings.cacheReadTokens": "缓存读取 tokens",
|
|
39
|
+
"settings.cacheWriteTokens": "缓存写入 tokens",
|
|
40
|
+
"settings.reasoningTokens": "推理 tokens",
|
|
41
|
+
"settings.timeToFirstToken": "首 token 用时",
|
|
42
|
+
"settings.tokensPerSecond": "输出速度"
|
|
43
|
+
}
|
package/locales.cjs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const dictionaries = {
|
|
4
|
+
en: require('./locales/en.json'),
|
|
5
|
+
zh: require('./locales/zh.json'),
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const expected = Object.keys(dictionaries.en).sort()
|
|
9
|
+
for (const [locale, dictionary] of Object.entries(dictionaries)) {
|
|
10
|
+
const actual = Object.keys(dictionary).sort()
|
|
11
|
+
if (JSON.stringify(actual) !== JSON.stringify(expected)) {
|
|
12
|
+
throw new Error(`@ch4acko3/dsh-turn-fold: locale ${locale} does not match the English key set`)
|
|
13
|
+
}
|
|
14
|
+
for (const [key, value] of Object.entries(dictionary)) {
|
|
15
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
16
|
+
throw new Error(`@ch4acko3/dsh-turn-fold: locale ${locale} has an invalid value for ${key}`)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = dictionaries
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ch4acko3/dsh-turn-fold",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Codex-style turn folding for the DSH WebUI conversation, implemented as a dsh-harmony provider.",
|
|
5
|
+
"main": "./index.cjs",
|
|
6
|
+
"files": [
|
|
7
|
+
"README.md",
|
|
8
|
+
"README.zh-CN.md",
|
|
9
|
+
"harmony.patch.yml",
|
|
10
|
+
"index.cjs",
|
|
11
|
+
"inline-source.cjs",
|
|
12
|
+
"locales.cjs",
|
|
13
|
+
"locales/*.json",
|
|
14
|
+
"settings.cjs",
|
|
15
|
+
"patch.cjs"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/ch4acko3/dsh-turn-fold.git"
|
|
24
|
+
},
|
|
25
|
+
"dsh": {
|
|
26
|
+
"bundle": {
|
|
27
|
+
"patch": "./harmony.patch.yml"
|
|
28
|
+
},
|
|
29
|
+
"harmony": {
|
|
30
|
+
"patches": ["./patch.cjs"]
|
|
31
|
+
},
|
|
32
|
+
"plugin": {
|
|
33
|
+
"schemaVersion": 1,
|
|
34
|
+
"displayName": {
|
|
35
|
+
"en": "Turn Fold",
|
|
36
|
+
"zh-CN": "Turn Fold"
|
|
37
|
+
},
|
|
38
|
+
"summary": {
|
|
39
|
+
"en": "Collapse each completed turn's agent activity into a summary bar; keep the final answer visible.",
|
|
40
|
+
"zh-CN": "将每个已完成 turn 的 Agent activity 折叠成摘要栏,最终答复保持可见。"
|
|
41
|
+
},
|
|
42
|
+
"category": "ui"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"test": "node test/run.cjs",
|
|
47
|
+
"check": "node test/run.cjs"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@deepseek-ai/dsh-settings": "0.1.0-rc.8",
|
|
51
|
+
"@deepseek-ai/schemastery": "^3.18.1"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.8",
|
|
55
|
+
"@phenomnomnominal/tsquery": "^6.2.0",
|
|
56
|
+
"react": "18.3.1",
|
|
57
|
+
"react-test-renderer": "18.3.1",
|
|
58
|
+
"typescript": "^6.0.3"
|
|
59
|
+
}
|
|
60
|
+
}
|
package/patch.cjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// @ch4acko3/dsh-turn-fold — Harmony Source Patches for the DSH conversation chat flow.
|
|
2
|
+
//
|
|
3
|
+
// These three patches run in order, in memory only, against the compiled browser
|
|
4
|
+
// bundle of @deepseek-ai/dsh-client-ui-conversation (lib/client.js). They never
|
|
5
|
+
// modify the installed package.
|
|
6
|
+
//
|
|
7
|
+
// 1. inject-turn-fold-runtime — injects the fold renderer + disclosure UI
|
|
8
|
+
// into the module factory, immediately before the ChatView component.
|
|
9
|
+
// 2. rewrite-node-render-loop — replaces the `order.map(...)` node render
|
|
10
|
+
// loop with a call to the injected renderer, which groups a completed
|
|
11
|
+
// turn's agent activity into a collapsible disclosure while keeping the
|
|
12
|
+
// final answer (turn-tail.closing.finalNode) and the turn tail visible.
|
|
13
|
+
// 3. install-turn-fold-services — registers the plugin's native DSH locale
|
|
14
|
+
// namespace and binds its native settings scope during conversation boot.
|
|
15
|
+
//
|
|
16
|
+
// Both selectors are pinned with an exact `expect: 1` and a target version so
|
|
17
|
+
// a compiled-shape drift fails loudly in `dsh harmony status`.
|
|
18
|
+
|
|
19
|
+
const INLINE = require('./inline-source.cjs')
|
|
20
|
+
|
|
21
|
+
const TARGET = {
|
|
22
|
+
package: '@deepseek-ai/dsh-client-ui-conversation',
|
|
23
|
+
version: '0.1.0-rc.8',
|
|
24
|
+
files: ['lib/client.js'],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = [
|
|
28
|
+
{
|
|
29
|
+
id: 'inject-turn-fold-runtime',
|
|
30
|
+
target: TARGET,
|
|
31
|
+
select: 'FunctionDeclaration[name.name="ChatView"], VariableStatement:has(VariableDeclaration[name.name="ChatView"])',
|
|
32
|
+
expect: 1,
|
|
33
|
+
apply({ node, sourceFile, edit }) {
|
|
34
|
+
edit.prependLeft(node.getStart(sourceFile), INLINE + '\n\n')
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'rewrite-node-render-loop',
|
|
39
|
+
target: TARGET,
|
|
40
|
+
select: 'CallExpression[expression.name.name="map"][expression.expression.name="order"]',
|
|
41
|
+
expect: 1,
|
|
42
|
+
apply({ node, sourceFile, edit }) {
|
|
43
|
+
const callback = node.arguments[0]
|
|
44
|
+
if (callback === undefined) throw new Error('@ch4acko3/dsh-turn-fold: order.map callback is missing')
|
|
45
|
+
const renderNode = sourceFile.text.slice(callback.getStart(sourceFile), callback.getEnd())
|
|
46
|
+
edit.overwrite(
|
|
47
|
+
node.getStart(sourceFile),
|
|
48
|
+
node.getEnd(),
|
|
49
|
+
`__ch4acko3DshTurnFoldRender({ order, nodeStore, timeline, sessionId, renderNode: ${renderNode}, t })`
|
|
50
|
+
)
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'install-turn-fold-services',
|
|
55
|
+
target: TARGET,
|
|
56
|
+
select: 'VariableStatement:has(VariableDeclaration[name.name="t"][initializer.expression.name.name="bind"])',
|
|
57
|
+
expect: 1,
|
|
58
|
+
apply({ node, sourceFile, edit }) {
|
|
59
|
+
const statement = sourceFile.text.slice(node.getStart(sourceFile), node.getEnd())
|
|
60
|
+
edit.overwrite(
|
|
61
|
+
node.getStart(sourceFile),
|
|
62
|
+
node.getEnd(),
|
|
63
|
+
`${statement}\n\t\t\t__ch4acko3DshTurnFoldInstall(ctx);`
|
|
64
|
+
)
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
]
|
package/settings.cjs
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const z = require('@deepseek-ai/schemastery')
|
|
4
|
+
|
|
5
|
+
const SETTINGS_NAMESPACE = 'dsh-turn-fold'
|
|
6
|
+
|
|
7
|
+
const SUMMARY_FIELDS = [
|
|
8
|
+
'duration',
|
|
9
|
+
'toolCalls',
|
|
10
|
+
'modelCalls',
|
|
11
|
+
'inputTokens',
|
|
12
|
+
'outputTokens',
|
|
13
|
+
'cacheReadTokens',
|
|
14
|
+
'cacheWriteTokens',
|
|
15
|
+
'reasoningTokens',
|
|
16
|
+
'timeToFirstToken',
|
|
17
|
+
'tokensPerSecond',
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
const DEFAULT_SUMMARY_FIELDS = [
|
|
21
|
+
'duration',
|
|
22
|
+
'toolCalls',
|
|
23
|
+
'inputTokens',
|
|
24
|
+
'outputTokens',
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
const Config = z.object({
|
|
28
|
+
summaryFields: z.array(z.union(SUMMARY_FIELDS)).default(DEFAULT_SUMMARY_FIELDS),
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
Config,
|
|
33
|
+
DEFAULT_SUMMARY_FIELDS,
|
|
34
|
+
SETTINGS_NAMESPACE,
|
|
35
|
+
SUMMARY_FIELDS,
|
|
36
|
+
}
|