@wisdoverse/dsh-inline-media-viewer 1.0.8 → 1.0.9
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/CHANGELOG.md +9 -2
- package/client/client.js +55 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 1.0.
|
|
3
|
+
## 1.0.9
|
|
4
|
+
|
|
5
|
+
- Collect media paths from tool-call arguments as well as the assistant's final
|
|
6
|
+
text, so every image read during a turn remains available in its preview.
|
|
7
|
+
|
|
8
|
+
## 1.0.8 (deprecated)
|
|
4
9
|
|
|
5
10
|
- Preserve output-directory context across assistant steps in one turn, so a
|
|
6
11
|
later final answer containing only media filenames still renders previews.
|
|
12
|
+
- Superseded by 1.0.9 because tool-call-only media references were not retained.
|
|
7
13
|
|
|
8
|
-
## 1.0.7
|
|
14
|
+
## 1.0.7 (deprecated)
|
|
9
15
|
|
|
10
16
|
- Resolve backticked media filenames against a preceding backticked directory,
|
|
11
17
|
matching the common "output directory plus file list" response format.
|
|
18
|
+
- Superseded by 1.0.9 because it only inspected assistant text.
|
|
12
19
|
|
|
13
20
|
## 1.0.6
|
|
14
21
|
|
package/client/client.js
CHANGED
|
@@ -80,6 +80,11 @@ window.__ModuleLoader__.load({
|
|
|
80
80
|
const found = [];
|
|
81
81
|
const seen = new Set();
|
|
82
82
|
let directory = "";
|
|
83
|
+
const ext = Array.from(MEDIA_EXTENSIONS).join("|");
|
|
84
|
+
const directories = new Set(Array.from(text.matchAll(
|
|
85
|
+
/[`'"]((?:\/|\.\.?\/|[\w.-]+\/)[^`'"\n]*[\/\\])[`'"]/g,
|
|
86
|
+
), (match) => cleanCandidate(match[1])));
|
|
87
|
+
const soleDirectory = directories.size === 1 ? directories.values().next().value : "";
|
|
83
88
|
const add = (raw) => {
|
|
84
89
|
const source = cleanCandidate(raw);
|
|
85
90
|
const kind = mediaKind(source);
|
|
@@ -95,7 +100,10 @@ window.__ModuleLoader__.load({
|
|
|
95
100
|
plain = plain.replace(/`([^`\n]+)`/g, (match, source) => {
|
|
96
101
|
const value = cleanCandidate(source);
|
|
97
102
|
if (/[/\\]$/.test(value)) directory = value;
|
|
98
|
-
else
|
|
103
|
+
else {
|
|
104
|
+
const base = directory || soleDirectory;
|
|
105
|
+
add(base && !/[/\\]/.test(value) ? `${base}${value}` : value);
|
|
106
|
+
}
|
|
99
107
|
return " ".repeat(match.length);
|
|
100
108
|
});
|
|
101
109
|
plain = plain.replace(/https?:\/\/[^\s<>"'`]+/gi, (source) => {
|
|
@@ -103,7 +111,11 @@ window.__ModuleLoader__.load({
|
|
|
103
111
|
return " ".repeat(source.length);
|
|
104
112
|
});
|
|
105
113
|
|
|
106
|
-
|
|
114
|
+
if (soleDirectory) {
|
|
115
|
+
const filenamePattern = new RegExp(String.raw`[\x60'"]([^\x60'"/\\\n]+\.(?:${ext})(?:\?[^\x60'"\s]*)?)[\x60'"]`, "gi");
|
|
116
|
+
for (const match of text.matchAll(filenamePattern)) add(`${soleDirectory}${match[1]}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
107
119
|
const pathPattern = new RegExp(
|
|
108
120
|
String.raw`(?:\/|\.\.?\/|[\w.-]+\/)[^\s<>"'\x60()\[\]{}]+?\.(?:${ext})(?:\?[^\s<>"'\x60]*)?`,
|
|
109
121
|
"gi",
|
|
@@ -112,10 +124,48 @@ window.__ModuleLoader__.load({
|
|
|
112
124
|
return found;
|
|
113
125
|
}
|
|
114
126
|
|
|
127
|
+
function toolArgumentText(raw) {
|
|
128
|
+
try {
|
|
129
|
+
const text = [];
|
|
130
|
+
const visit = (value) => {
|
|
131
|
+
if (typeof value === "string") text.push(value);
|
|
132
|
+
else if (value && typeof value === "object") Object.values(value).forEach(visit);
|
|
133
|
+
};
|
|
134
|
+
visit(JSON.parse(raw));
|
|
135
|
+
return text.join("\n");
|
|
136
|
+
} catch (_error) {
|
|
137
|
+
return raw;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const mediaMentionsDefinition = {
|
|
142
|
+
kind: "inline-media-mentions",
|
|
143
|
+
match: (event) => {
|
|
144
|
+
if (event.type === "turn/start") return { id: String(event.data.turn), role: "start" };
|
|
145
|
+
if (event.type === "tool/call") return { id: String(event.data.turn), role: "update" };
|
|
146
|
+
return null;
|
|
147
|
+
},
|
|
148
|
+
start: (_context, match) => ({ turn: match.event.data.turn, texts: [] }),
|
|
149
|
+
update: (context, match) => typeof match.event.data.arguments !== "string" ? context.state : {
|
|
150
|
+
...context.state,
|
|
151
|
+
texts: [...context.state.texts, { seq: match.event.seq, text: toolArgumentText(match.event.data.arguments) }],
|
|
152
|
+
},
|
|
153
|
+
buildLocationData: (context, scope) => scope !== "turn" || context.state === undefined ? null : {
|
|
154
|
+
kind: "turn",
|
|
155
|
+
turn: context.state.turn,
|
|
156
|
+
key: "inline-media-mentions",
|
|
157
|
+
value: { texts: context.state.texts },
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
115
161
|
function selectMedia(owner) {
|
|
116
162
|
const settings = readSettings();
|
|
117
163
|
if (!settings.autoRender) return null;
|
|
118
164
|
const text = [];
|
|
165
|
+
const mentions = owner.turn.data && owner.turn.data.get("inline-media-mentions");
|
|
166
|
+
if (mentions) {
|
|
167
|
+
text.push(...mentions.texts.filter((entry) => entry.seq <= owner.seq).map((entry) => entry.text));
|
|
168
|
+
}
|
|
119
169
|
for (const step of owner.turn.steps) {
|
|
120
170
|
const assistant = step.data.get("assistant-step");
|
|
121
171
|
if (!assistant || !assistant.finalNode || assistant.finalNode.seq > owner.seq || !Array.isArray(assistant.blocks)) continue;
|
|
@@ -492,10 +542,11 @@ window.__ModuleLoader__.load({
|
|
|
492
542
|
}
|
|
493
543
|
|
|
494
544
|
const name = "dsh-inline-media-viewer";
|
|
495
|
-
const inject = ["slots", "connection", "settingsScope", "locale"];
|
|
545
|
+
const inject = ["slots", "connection", "settingsScope", "locale", "conversationEvents"];
|
|
496
546
|
|
|
497
547
|
function apply(ctx) {
|
|
498
548
|
const connection = ctx.get("connection");
|
|
549
|
+
ctx.conversationEvents.register(mediaMentionsDefinition);
|
|
499
550
|
ctx.effect(() => ctx.locale.register(SETTINGS_NS, SETTINGS_DICT), "inline-media: dictionaries");
|
|
500
551
|
const t = ctx.locale.bind(SETTINGS_NS);
|
|
501
552
|
const scope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });
|
|
@@ -518,7 +569,7 @@ window.__ModuleLoader__.load({
|
|
|
518
569
|
exports.apply = apply;
|
|
519
570
|
exports.inject = inject;
|
|
520
571
|
exports.name = name;
|
|
521
|
-
exports.testing = Object.freeze({ extractCandidates, mediaTransport, selectMedia });
|
|
572
|
+
exports.testing = Object.freeze({ extractCandidates, mediaMentionsDefinition, mediaTransport, selectMedia, toolArgumentText });
|
|
522
573
|
return module.exports;
|
|
523
574
|
},
|
|
524
575
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wisdoverse/dsh-inline-media-viewer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "Persistent inline image, video, and audio previews for DeepSeek Harness Web conversations, with workspace-confined local reads and an optional ComfyUI proxy.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|