mnfst 0.5.270 → 0.5.271

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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.270';
5
+ const MANIFEST_BUILD_VERSION = '0.5.271';
6
6
 
7
7
  /* Manifest Data Sources - Appwrite Integration */
8
8
 
@@ -1009,8 +1009,8 @@
1009
1009
  /* Manifest Chat — optional LLM (Claude) adapter
1010
1010
  * By Andrew Matlock under MIT license · https://manifestx.dev
1011
1011
  *
1012
- * Reference `claude` adapter: replies stream from a relay holding the API key
1013
- * (mnfst-run's /_ai/chat locally; your own endpoint once published). $chat
1012
+ * Reference `claude` adapter: replies stream from the same-origin /_ai/chat relay,
1013
+ * served by mnfst-run locally and by Manifest hosting once published. $chat
1014
1014
  * never calls the LLM — this adapter does, behind the same contract. Optional, loaded separately from the bundle.
1015
1015
  * Attachments ride draft.body.media[] as base64 → image/document blocks.
1016
1016
  */
@@ -1030,7 +1030,7 @@
1030
1030
 
1031
1031
  function claudeAdapter(opts) {
1032
1032
  opts = opts || {};
1033
- // Same-origin relay mnfst-run serves for an `ai` block; override via
1033
+ // Same-origin relay for an `ai` block; override via
1034
1034
  // opts.endpoint / window.CHAT_LLM_ENDPOINT.
1035
1035
  const endpoint = opts.endpoint || window.CHAT_LLM_ENDPOINT || '/_ai/chat';
1036
1036
  // only when set — the relay's ai block (system + grounding) is the default
@@ -1044,7 +1044,9 @@
1044
1044
  function loadStore(cid) { try { return JSON.parse(localStorage.getItem(lsKey(cid)) || '[]'); } catch { return []; } }
1045
1045
  function saveMsg(cid, m) {
1046
1046
  const all = loadStore(cid);
1047
- all.push({ id: m.id, role: m.author.kind === 'agent' ? 'assistant' : 'user', text: m.body.text, ts: m.ts });
1047
+ const r = { id: m.id, role: m.author.kind === 'agent' ? 'assistant' : 'user', text: m.body.text, ts: m.ts };
1048
+ if (m.error) r.error = true;
1049
+ all.push(r);
1048
1050
  try { localStorage.setItem(lsKey(cid), JSON.stringify(all.slice(-200))); } catch { }
1049
1051
  }
1050
1052
  const toMsg = (r) => ({ id: r.id, conversationId: null, author: r.role === 'assistant' ? BOT : USER, body: { text: r.text }, ts: r.ts, status: 'delivered' });
@@ -1053,14 +1055,19 @@
1053
1055
  // Only what the API accepts is forwarded (images + PDFs with data);
1054
1056
  // audio/video/voice render locally but don't reach the model.
1055
1057
  function apiMessages(cid, draft) {
1056
- const hist = loadStore(cid).map(r => ({ role: r.role, content: r.text }));
1058
+ const text = (draft.body && draft.body.text) || draft.text || '';
1059
+ const stored = loadStore(cid);
1060
+ const prev = stored[stored.length - 1];
1061
+ if (prev && prev.role === 'user' && prev.text === text) stored.pop(); // send() already saved this turn
1062
+ // relays accept up to 100 messages, starting on a user turn
1063
+ const hist = stored.filter(r => !r.error && r.text && r.text.trim()).slice(-99).map(r => ({ role: r.role, content: r.text }));
1064
+ while (hist.length && hist[0].role !== 'user') hist.shift();
1057
1065
  const media = ((draft.body && draft.body.media) || []).filter(a =>
1058
1066
  a.data && (a.kind === 'image' || a.mediaType === 'application/pdf'));
1059
1067
  const blocks = media.map(a => a.kind === 'image'
1060
1068
  ? { type: 'image', source: { type: 'base64', media_type: a.mediaType, data: a.data } }
1061
1069
  : { type: 'document', source: { type: 'base64', media_type: 'application/pdf', data: a.data } });
1062
- const text = (draft.body && draft.body.text) || draft.text || '';
1063
- const last = blocks.length ? { role: 'user', content: [...blocks, { type: 'text', text }] } : { role: 'user', content: text };
1070
+ const last = blocks.length ? { role: 'user', content: text.trim() ? [...blocks, { type: 'text', text }] : blocks } : { role: 'user', content: text };
1064
1071
  return [...hist, last];
1065
1072
  }
1066
1073
 
@@ -1069,10 +1076,19 @@
1069
1076
  const messages = streamReply._pending; streamReply._pending = null;
1070
1077
  const mid = id('m');
1071
1078
  h.onMessage && h.onMessage({ id: mid, conversationId: cid, author: BOT, body: { text: '' }, ts: Date.now(), status: 'streaming', meta: { model: opts.model } });
1072
- let full = '';
1079
+ let full = '', reply = '';
1073
1080
  try {
1074
1081
  const resp = await fetch(endpoint, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ system, model: opts.model, messages }) });
1075
- if (!resp.ok) throw new Error('HTTP ' + resp.status);
1082
+ if (!resp.ok) {
1083
+ let body = '', msg = '';
1084
+ try { body = await resp.text(); } catch { }
1085
+ try { const j = JSON.parse(body); msg = (j && (j.message || j.error)) || ''; } catch { }
1086
+ if (!msg) {
1087
+ const line = body.split('\n').find(l => l.startsWith('data:'));
1088
+ try { const evt = line && JSON.parse(line.slice(5).trim()); msg = (evt && evt.error && evt.error.message) || ''; } catch { }
1089
+ }
1090
+ const err = new Error('HTTP ' + resp.status); err.relayMessage = typeof msg === 'string' ? msg : ''; throw err;
1091
+ }
1076
1092
  const reader = resp.body.getReader(); const dec = new TextDecoder(); let buf = '';
1077
1093
  for (; ;) {
1078
1094
  const { done, value } = await reader.read(); if (done) break;
@@ -1083,16 +1099,20 @@
1083
1099
  const line = frame.split('\n').find(l => l.startsWith('data:')); if (!line) continue;
1084
1100
  let evt; try { evt = JSON.parse(line.slice(5).trim()); } catch { continue; }
1085
1101
  if (evt.type === 'content_block_delta' && evt.delta && evt.delta.type === 'text_delta') {
1086
- full += evt.delta.text; h.onMessagePart && h.onMessagePart(mid, { text: evt.delta.text });
1102
+ full += evt.delta.text; reply += evt.delta.text; h.onMessagePart && h.onMessagePart(mid, { text: evt.delta.text });
1087
1103
  } else if (evt.type === 'error') { full += '\n\n_(error: ' + (evt.error && evt.error.message) + ')_'; h.onMessagePart && h.onMessagePart(mid, { text: '\n\n_(error)_' }); }
1088
1104
  }
1089
1105
  }
1090
1106
  } catch (e) {
1091
- const note = '\n\n(no AI relay at `' + endpoint + '`' + (e && /^HTTP /.test(e.message) ? ': ' + e.message : '') + ')';
1107
+ const note = e && e.relayMessage
1108
+ ? '\n\n(' + e.relayMessage + ')'
1109
+ : '\n\n(AI chat unavailable at `' + endpoint + '`' + (e && /^HTTP /.test(e.message) ? ': ' + e.message : '') + ')';
1092
1110
  h.onMessagePart && h.onMessagePart(mid, { text: note }); full += note;
1093
1111
  }
1094
1112
  h.onMessagePart && h.onMessagePart(mid, { text: '', done: true });
1095
- saveMsg(cid, { id: mid, author: BOT, body: { text: full }, ts: Date.now() });
1113
+ // error notes show in the UI but never reach the model: keep partial text, else flag the entry
1114
+ if (reply.trim()) saveMsg(cid, { id: mid, author: BOT, body: { text: reply }, ts: Date.now() });
1115
+ else saveMsg(cid, { id: mid, author: BOT, body: { text: full }, ts: Date.now(), error: true });
1096
1116
  }
1097
1117
 
1098
1118
  return {
@@ -2,7 +2,7 @@
2
2
 
3
3
  (function () {
4
4
 
5
- const MANIFEST_BUILD_VERSION = '0.5.270';
5
+ const MANIFEST_BUILD_VERSION = '0.5.271';
6
6
 
7
7
  /* Manifest Data Sources - Configuration */
8
8
 
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "manifest.appwrite.auth.js": "sha384-gWLSeVPqCLMiUZB8MU7GqMg3x2yULFUsp8nTTZrPp/9Dlkix42rBn9yIimvwrHqZ",
3
- "manifest.appwrite.data.js": "sha384-3B8BYXfmdDuSnUk17A9DL+ZLAlPab4fcSlE3or6PZU7lLsg5FAPGFnuob10+YcOk",
3
+ "manifest.appwrite.data.js": "sha384-go0Kp+qGs1e5uIrBUXfDH1J1WUegEtsf0ZVHS5wEQiJXkU2f/M8eSCPXlJtU6CJR",
4
4
  "manifest.appwrite.presences.js": "sha384-LINPhIPTCK+rA8zd+HPUzMSEgH6Sl2vQMEyItT97bnEE2FYGYKqjXX+CWdt6nl9z",
5
5
  "manifest.bindings.js": "sha384-lPtMf8Ykaic9gNVZKq8Scia1881ZeMAyxer3WCIkUNwwrgzGBWto1OXADUwjvORF",
6
6
  "manifest.charts.js": "sha384-AFbP7mQnigy7DU1s+YE30yKTeQAKfgNazhbfSNbfd9ZpLgeulZKaPi/fAq3gJHDO",
7
- "manifest.chat.js": "sha384-6dag383ZYdunerLnJfcdN1RN0D+vc7HcTnNQL57xfVOID2J8+iiVOYzXte/vLf5n",
7
+ "manifest.chat.js": "sha384-8kxS2HImRVeRiarqaGiNFlCTqB7inp/y7Hn0kIPNzADl130s4JgnmJ7uCmW0Mmvt",
8
8
  "manifest.code.js": "sha384-WGPlZE5Sp9GygUzJSmCdpLyYQTgvmEKc9BQS9Hmq1VTQwkqYJzPSWibHvPekcres",
9
9
  "manifest.color.js": "sha384-6Rv3LxyTcZNjrhtayQfqRdCx0uSZ4BiEbgEI98I62eTvp8Aw7LBIoNJ0Je1oktwL",
10
10
  "manifest.colorpicker.js": "sha384-P+Zx0QzhMGfku8s3yEskTte4/iXCGVX3zdhu42IGNfFcSmhOW+nqVK7w+uczWRGY",
11
11
  "manifest.combobox.js": "sha384-/lJo6vaxKjgnBSRs/dzkhK1dzGk3GBw8FISoNJZB70mwAVwu1k5veZyBXjOb4keS",
12
12
  "manifest.components.js": "sha384-BUFA8h+G5Plr82sV7bKzO42pPoiRZwRQcKj1lt2ROFiKjjlkayU/vmkAFqEsdBA+",
13
13
  "manifest.computed.js": "sha384-GYML/e81gQfN+iDbqhPUgny8bINCyL+SrbTofoGk4hlCnLLjv51mCv42JMqq+ku5",
14
- "manifest.data.js": "sha384-K+ZPmelLQY+iphwUQJB2xzSYmYLzZaDV5wJ0TCHlk6kOiAjQ/jtPFDjsexM89asO",
14
+ "manifest.data.js": "sha384-HNnAhuzs+a3HkWH2WgL5cE/iCTbZmMMkYH++Q9oJMhAyYGchPkwbeSnL89yF3qnT",
15
15
  "manifest.datepicker.js": "sha384-EzlMwvIxlla/0BuyhAEqxN0M8TGcWIWgEIg840V0akKQQK1uY648wPWMkobvtq/o",
16
16
  "manifest.defer.js": "sha384-PRp7+dCZHnnl55rX2xrHutLrQnszHo7o5o9Tq28M/yjLZPuXDzcwQNxCdvbtCYSz",
17
17
  "manifest.device.js": "sha384-YeQaS56L8IILqrQNBSeAOLwIh5DuAOrE60cYLK1+46qJtUrXlAvqGe2j5mbV4Vq7",
@@ -28,7 +28,7 @@
28
28
  "manifest.slides.js": "sha384-3uRTkyK9XPLmnxI2+igZlpi4EyPlU/7IHj5j3BZJJ2KN455vXyk99fiXV3feO/XY",
29
29
  "manifest.status.js": "sha384-ofu7nBnVIGZ1U1o2R9d2H3V8aEMPUCVbl5FO3gIToXqi0oa36fTviEdh5UU7Kitw",
30
30
  "manifest.svg.js": "sha384-qr/8H9+2cIhSXNbRWRtIdrDlTOxKlNJqwEefHvCYoiBNW/kKhPTFa109Orv/EBnb",
31
- "manifest.sw.js": "sha384-G6HWkuawf//LfV6UNbBQOHDwKUJmeNyP9JsO1N/YEkxuNzW3qOVAzDoY+C42Y8Eu",
31
+ "manifest.sw.js": "sha384-WjwI0K3kGBDGcQgkUTf8WQjKN2tiQxwkucPsrFWcNAMAy9IMSXFyqz43ERGIY9eO",
32
32
  "manifest.tabs.js": "sha384-otU09H7jnawVKQdLAYpMCd3jx00tgyPVr42D2hLIBzN5dG4se505YesavdnMqEi1",
33
33
  "manifest.tailwind.js": "sha384-yuP3LEvWU+QVjxjkZ0YhErtC9RrGmhOmHjjFjhS9obqZbp5/KTIEnSR0CXDvHE0B",
34
34
  "manifest.toasts.js": "sha384-UpOz9fAdGeGUhL0NamBg5iPepEfIy73p9HYdcxfOQC5b7CVsl7Our0skdZzaLNcC",
@@ -16,7 +16,7 @@
16
16
 
17
17
  // Build stamps the published version here; unstamped (dev) falls back to the
18
18
  // registration URL's `v`, then 'dev'.
19
- const BUILD_VERSION = '0.5.270';
19
+ const BUILD_VERSION = '0.5.271';
20
20
  const CACHE_PREFIX = 'mnfst-sw:';
21
21
  const META_CACHE = CACHE_PREFIX + 'meta';
22
22
  // Sized to hold a full precache.json warm-up (PRECACHE_MAX_ENTRIES server-side)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.270",
3
+ "version": "0.5.271",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter",