anentrypoint-design 0.0.461 → 0.0.463
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/dist/247420.js +20 -20
- package/package.json +1 -1
- package/src/components/freddie/pages-chat.js +51 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anentrypoint-design",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.463",
|
|
4
4
|
"description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/247420.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import * as webjsx from '../../../vendor/webjsx/index.js';
|
|
19
19
|
import { makePage, api, loadingState, emptyState } from './runtime.js';
|
|
20
|
-
import { Table, PageHeader } from '../content.js';
|
|
20
|
+
import { Table, PageHeader, Select } from '../content.js';
|
|
21
21
|
import { Chip } from '../shell.js';
|
|
22
22
|
import { formatTime } from '../../locale.js';
|
|
23
23
|
import { queueMessage, watchReconnect, isOnline } from '../../idb-outbox.js';
|
|
@@ -86,7 +86,37 @@ function applyEnvelope(msgs, env, sendApprove) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export const chat = makePage((ctx) => {
|
|
89
|
-
Object.assign(ctx.state, { loading: false, messages: [], draft: '', busy: false, error: null, sessionId: null, ws: null, conn: 'closed' });
|
|
89
|
+
Object.assign(ctx.state, { loading: false, messages: [], draft: '', busy: false, error: null, sessionId: null, ws: null, conn: 'closed', sessions: [], staged: [] });
|
|
90
|
+
|
|
91
|
+
// Session picker (kimi web's sessions sidebar, compact form): recent
|
|
92
|
+
// conversations from /api/sessions, needsInput badges included. Picking
|
|
93
|
+
// one reconnects the WS under that id and rebuilds from server replay.
|
|
94
|
+
api('/api/sessions').then(rows => { ctx.state.sessions = Array.isArray(rows) ? rows : []; ctx.rerender(); }).catch(() => { /* swallow: picker degrades to new-chat-only */ });
|
|
95
|
+
|
|
96
|
+
// File upload (kimi web parity): files are staged to disk via the gui-agent
|
|
97
|
+
// endpoint and ride the next prompt frame as path references — the agent
|
|
98
|
+
// reads them with its file tools, so no model-capability negotiation here.
|
|
99
|
+
async function attachFiles(fileList) {
|
|
100
|
+
const st = ctx.state;
|
|
101
|
+
if (!st.sessionId) st.sessionId = newSessionId();
|
|
102
|
+
for (const file of fileList || []) {
|
|
103
|
+
try {
|
|
104
|
+
const dataUrl = await new Promise((res, rej) => { const r = new FileReader(); r.onload = () => res(r.result); r.onerror = rej; r.readAsDataURL(file); });
|
|
105
|
+
const base64 = String(dataUrl).split(',')[1] || '';
|
|
106
|
+
const r = await api('/api/sessions/' + encodeURIComponent(st.sessionId) + '/files', { method: 'POST', body: { name: file.name, contentBase64: base64 } });
|
|
107
|
+
if (r && r.path) { st.staged = [...st.staged, { name: r.name || file.name, path: r.path }]; }
|
|
108
|
+
} catch (e) { ctx.set({ error: 'upload failed: ' + (e && e.message || e) }); }
|
|
109
|
+
}
|
|
110
|
+
ctx.rerender();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function switchSession(id) {
|
|
114
|
+
const st = ctx.state;
|
|
115
|
+
if (!id || id === st.sessionId) return;
|
|
116
|
+
try { st.ws && st.ws.close(); } catch { /* already closed */ }
|
|
117
|
+
ctx.set({ sessionId: id, messages: [], ws: null, conn: 'closed', busy: false, error: null });
|
|
118
|
+
ensureWs();
|
|
119
|
+
}
|
|
90
120
|
|
|
91
121
|
// Offline outbox: a prompt sent while genuinely offline queues to
|
|
92
122
|
// IndexedDB and auto-flushes on the real 'online' event via the legacy
|
|
@@ -144,6 +174,8 @@ export const chat = makePage((ctx) => {
|
|
|
144
174
|
if (f.error && !c.error) c.error = f.error;
|
|
145
175
|
}
|
|
146
176
|
ctx.set({ busy: false });
|
|
177
|
+
// New turns can create/rename sessions — refresh the picker.
|
|
178
|
+
api('/api/sessions').then(rows => { ctx.state.sessions = Array.isArray(rows) ? rows : []; ctx.rerender(); }).catch(() => { /* swallow: picker refresh is best-effort */ });
|
|
147
179
|
} else if (f.type === 'error') {
|
|
148
180
|
const c = cur();
|
|
149
181
|
if (c && c.role === 'assistant') c.error = f.error;
|
|
@@ -191,11 +223,13 @@ export const chat = makePage((ctx) => {
|
|
|
191
223
|
return;
|
|
192
224
|
}
|
|
193
225
|
|
|
194
|
-
if (!ensureWs() || !sendFrame({ type: 'prompt', text: t })) {
|
|
226
|
+
if (!ensureWs() || !sendFrame({ type: 'prompt', text: t, attachments: s().staged.map(f => ({ name: f.name, path: f.path })) })) {
|
|
195
227
|
curMsg.error = 'agent workspace connection unavailable';
|
|
196
228
|
delete curMsg._live;
|
|
197
229
|
ctx.set({ busy: false });
|
|
230
|
+
return;
|
|
198
231
|
}
|
|
232
|
+
ctx.set({ staged: [] });
|
|
199
233
|
}
|
|
200
234
|
|
|
201
235
|
function stop() {
|
|
@@ -208,6 +242,20 @@ export const chat = makePage((ctx) => {
|
|
|
208
242
|
return () => {
|
|
209
243
|
const st = s();
|
|
210
244
|
return h('div', { class: 'fd-chat' },
|
|
245
|
+
h('div', { class: 'fd-chat-picker' },
|
|
246
|
+
st.sessions.length ? Select({
|
|
247
|
+
value: st.sessionId || '',
|
|
248
|
+
placeholder: 'new conversation',
|
|
249
|
+
'aria-label': 'switch conversation',
|
|
250
|
+
options: st.sessions.map(row => ({ value: row.id, label: (row.title || '(untitled)').slice(0, 60) + (row.needsInput ? ' — needs input' : '') })),
|
|
251
|
+
onChange: switchSession,
|
|
252
|
+
}) : null,
|
|
253
|
+
h('label', { class: 'fd-chat-attach', title: 'attach files to the next message' },
|
|
254
|
+
'attach',
|
|
255
|
+
h('input', { type: 'file', multiple: true, style: 'display:none', onchange: (e) => { attachFiles(e.target.files); e.target.value = ''; } })),
|
|
256
|
+
...st.staged.map((f, i) => h('span', { key: 'st' + i, class: 'fd-chat-staged' },
|
|
257
|
+
f.name,
|
|
258
|
+
h('button', { type: 'button', class: 'fd-chat-staged-x', 'aria-label': 'remove ' + f.name, onclick: () => { st.staged = st.staged.filter((_, j) => j !== i); ctx.rerender(); } }, '×')))),
|
|
211
259
|
AgentChat({
|
|
212
260
|
messages: st.messages,
|
|
213
261
|
busy: st.busy,
|