anentrypoint-design 0.0.193 → 0.0.194
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anentrypoint-design",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.194",
|
|
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",
|
|
@@ -46,7 +46,27 @@ export function makeChatPage(ctx) {
|
|
|
46
46
|
return async function chat(h0) {
|
|
47
47
|
const root = ctx.root;
|
|
48
48
|
const skills = [...h0.pi.skills.values()];
|
|
49
|
-
|
|
49
|
+
let providers = await fetch('/api/providers').then(r => r.json()).catch(() => []);
|
|
50
|
+
if (!Array.isArray(providers)) providers = [];
|
|
51
|
+
// Static deploy (no freddie-server, so /api/providers 404s): probe the
|
|
52
|
+
// acptoapi gateway directly and, when it answers, surface it as a real
|
|
53
|
+
// configured provider with its model list. Without this the dashboard
|
|
54
|
+
// tells the user to "run a gateway" even though one is live and chat works.
|
|
55
|
+
if (!providers.some(p => p.configured)) {
|
|
56
|
+
try {
|
|
57
|
+
const cfg = (window.__debug?.instances?.i1?.host?.fs?.readJson?.('/etc/freddie/freddie.json', null)) || {};
|
|
58
|
+
const baseUrl = (cfg?.providers?.openai?.baseUrl || 'http://localhost:4800').replace(/\/+$/, '');
|
|
59
|
+
const ac = new AbortController();
|
|
60
|
+
const t = setTimeout(() => ac.abort(), 4000);
|
|
61
|
+
const r = await fetch(baseUrl + '/v1/models', { signal: ac.signal }).catch(() => null);
|
|
62
|
+
clearTimeout(t);
|
|
63
|
+
if (r && r.ok) {
|
|
64
|
+
const j = await r.json().catch(() => null);
|
|
65
|
+
const models = Array.isArray(j?.data) ? j.data.map(m => m.id) : [];
|
|
66
|
+
providers = [{ id: 'acptoapi', name: 'acptoapi gateway (' + baseUrl + ')', configured: true, models: ['auto', ...models] }, ...providers];
|
|
67
|
+
}
|
|
68
|
+
} catch {}
|
|
69
|
+
}
|
|
50
70
|
const configuredProviders = providers.filter(p => p.configured);
|
|
51
71
|
|
|
52
72
|
const chatState = window.__fd_chatState = window.__fd_chatState || {
|
|
@@ -81,15 +101,98 @@ export function makeChatPage(ctx) {
|
|
|
81
101
|
if (!trimmed) return;
|
|
82
102
|
chatState.messages.push({ role: 'user', content: trimmed });
|
|
83
103
|
chatState.busy = true;
|
|
104
|
+
chatState.progress = 'agent thinking…';
|
|
84
105
|
chatState.abort = new AbortController();
|
|
85
106
|
saveRecentPath(chatState.cwd);
|
|
86
107
|
syncMessages();
|
|
87
108
|
renderPage();
|
|
88
109
|
try {
|
|
89
110
|
const body = { prompt: trimmed, cwd: chatState.cwd || undefined, skill: chatState.skill || undefined, provider: chatState.provider || undefined, model: chatState.model || undefined, sessionId: chatState.sessionId || undefined };
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
let resp;
|
|
112
|
+
try {
|
|
113
|
+
resp = await fetch('/api/chat', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body), signal: chatState.abort.signal });
|
|
114
|
+
} catch (fetchErr) {
|
|
115
|
+
resp = null;
|
|
116
|
+
}
|
|
117
|
+
let text = '';
|
|
118
|
+
let events = [];
|
|
119
|
+
if (resp && resp.ok) {
|
|
120
|
+
text = await resp.text();
|
|
121
|
+
events = parseSseEvents(text);
|
|
122
|
+
} else if (typeof window !== 'undefined' && typeof window.__thebirdRunAgent === 'function') {
|
|
123
|
+
// Static deploy with an in-page agent runtime (e.g. thebird): drive
|
|
124
|
+
// the REAL multi-step agent loop (host tools + acptoapi gateway +
|
|
125
|
+
// tool execution) instead of a single bare completion, so the model
|
|
126
|
+
// emits tool_calls, the loop executes them, feeds results back, and
|
|
127
|
+
// iterates. We synthesize the same {event:'message'} stream the
|
|
128
|
+
// server path produces so the render loop below is unchanged. The
|
|
129
|
+
// window global is the opt-in: hosts without it keep single-shot.
|
|
130
|
+
try {
|
|
131
|
+
let stepN = 0;
|
|
132
|
+
const onUpdate = (snap) => {
|
|
133
|
+
try {
|
|
134
|
+
const msgs = (snap && snap.context && snap.context.messages) || [];
|
|
135
|
+
const toolMsgs = msgs.filter(m => m.role === 'tool');
|
|
136
|
+
const lastAssist = [...msgs].reverse().find(m => m.role === 'assistant' && Array.isArray(m.tool_calls) && m.tool_calls.length);
|
|
137
|
+
const running = lastAssist && lastAssist.tool_calls[0] && (lastAssist.tool_calls[0].function?.name || lastAssist.tool_calls[0].name);
|
|
138
|
+
stepN = toolMsgs.length;
|
|
139
|
+
chatState.progress = running
|
|
140
|
+
? ('agent: ' + running + ' (step ' + (stepN + 1) + ')…')
|
|
141
|
+
: ('agent thinking' + (stepN ? ' (step ' + stepN + ')' : '') + '…');
|
|
142
|
+
renderPage();
|
|
143
|
+
} catch {}
|
|
144
|
+
};
|
|
145
|
+
const out = await window.__thebirdRunAgent({ prompt: trimmed, onUpdate });
|
|
146
|
+
const turnMsgs = (out && Array.isArray(out.messages)) ? out.messages : [];
|
|
147
|
+
for (const m of turnMsgs) {
|
|
148
|
+
if (m.role === 'assistant' && Array.isArray(m.tool_calls) && m.tool_calls.length) {
|
|
149
|
+
const parts = [];
|
|
150
|
+
if (m.content) parts.push({ type: 'text', text: String(m.content) });
|
|
151
|
+
for (const tc of m.tool_calls) {
|
|
152
|
+
const rawArgs = tc.function?.arguments ?? tc.arguments;
|
|
153
|
+
let input = {};
|
|
154
|
+
if (rawArgs && typeof rawArgs === 'object') input = rawArgs;
|
|
155
|
+
else if (typeof rawArgs === 'string') { try { input = JSON.parse(rawArgs || '{}'); } catch { input = {}; } }
|
|
156
|
+
parts.push({ type: 'tool_use', name: tc.function?.name || tc.name, input });
|
|
157
|
+
}
|
|
158
|
+
events.push({ event: 'message', data: { role: 'assistant', content: parts } });
|
|
159
|
+
} else if (m.role === 'tool') {
|
|
160
|
+
events.push({ event: 'message', data: { role: 'tool', content: [{ content: String(m.content ?? '') }] } });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const finalText = (out && out.result) || (out && out.error ? 'error: ' + out.error : '');
|
|
164
|
+
if (finalText) events.push({ event: 'message', data: { role: 'assistant', content: [{ type: 'text', text: String(finalText) }] } });
|
|
165
|
+
if (!events.length) events.push({ event: 'message', data: { role: 'assistant', content: [{ type: 'text', text: '' }] } });
|
|
166
|
+
} catch (e) {
|
|
167
|
+
events = [{ event: 'error', data: { error: e?.message || String(e) } }];
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
// Static deploy without an in-page agent runtime: single direct
|
|
171
|
+
// acptoapi /v1/chat/completions call (no tool loop — one shot).
|
|
172
|
+
const cfg = (window.__debug?.instances?.i1?.host?.fs?.readJson?.('/etc/freddie/freddie.json', null)) || {};
|
|
173
|
+
const baseUrl = cfg?.providers?.openai?.baseUrl || 'http://localhost:4800';
|
|
174
|
+
try {
|
|
175
|
+
const url = baseUrl.replace(/\/+$/, '') + '/v1/chat/completions';
|
|
176
|
+
const reqBody = { model: chatState.model || cfg?.providers?.openai?.model || 'auto', messages: [{ role: 'user', content: trimmed }] };
|
|
177
|
+
const r2 = await fetch(url, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(reqBody), signal: chatState.abort.signal });
|
|
178
|
+
if (!r2.ok) {
|
|
179
|
+
const errText = await r2.text().catch(() => '');
|
|
180
|
+
events = [{ event: 'error', data: { error: 'acptoapi ' + r2.status + ': ' + errText.slice(0, 200) } }];
|
|
181
|
+
} else {
|
|
182
|
+
const j = await r2.json();
|
|
183
|
+
const content = j?.choices?.[0]?.message?.content || '';
|
|
184
|
+
const tool_calls = j?.choices?.[0]?.message?.tool_calls;
|
|
185
|
+
const parts = [];
|
|
186
|
+
if (content) parts.push({ type: 'text', text: content });
|
|
187
|
+
if (Array.isArray(tool_calls)) {
|
|
188
|
+
for (const tc of tool_calls) parts.push({ type: 'tool_use', name: tc.function?.name, input: (() => { try { return JSON.parse(tc.function?.arguments || '{}'); } catch { return {}; } })() });
|
|
189
|
+
}
|
|
190
|
+
events = [{ event: 'message', data: { role: 'assistant', content: parts.length ? parts : [{ type: 'text', text: '' }] } }];
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
events = [{ event: 'error', data: { error: e?.message || String(e) } }];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
93
196
|
let assistantContent = '';
|
|
94
197
|
for (const { event, data } of events) {
|
|
95
198
|
if (event === 'start' && data.sessionId) chatState.sessionId = data.sessionId;
|
|
@@ -140,6 +243,7 @@ export function makeChatPage(ctx) {
|
|
|
140
243
|
}
|
|
141
244
|
chatState.abort = null;
|
|
142
245
|
chatState.busy = false;
|
|
246
|
+
chatState.progress = '';
|
|
143
247
|
syncMessages();
|
|
144
248
|
renderPage();
|
|
145
249
|
};
|
|
@@ -152,7 +256,9 @@ export function makeChatPage(ctx) {
|
|
|
152
256
|
const host = getChatHost();
|
|
153
257
|
if (host) {
|
|
154
258
|
host.busy = chatState.busy;
|
|
155
|
-
host.placeholder = chatState.busy
|
|
259
|
+
host.placeholder = chatState.busy
|
|
260
|
+
? (chatState.progress || 'agent working…')
|
|
261
|
+
: 'describe what you want to do in the working directory…';
|
|
156
262
|
}
|
|
157
263
|
// Refresh disabled state on header buttons.
|
|
158
264
|
const newBtn = root.querySelector('.fd-chat-new');
|