fraim-framework 2.0.194 → 2.0.195
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/src/ai-hub/server.js +12 -1
- package/package.json +1 -1
- package/public/ai-hub/index.html +20 -20
- package/public/ai-hub/script.js +20 -2
|
@@ -2252,9 +2252,20 @@ class AiHubServer {
|
|
|
2252
2252
|
if (!Array.isArray(body.conversations)) {
|
|
2253
2253
|
return res.status(400).json({ error: 'conversations array required' });
|
|
2254
2254
|
}
|
|
2255
|
+
// The client strips server-owned heavy fields (messages/events/artifacts/run/
|
|
2256
|
+
// delegation) from its PUT payload to stay under the body-size limit. Merge them
|
|
2257
|
+
// back from the stored record so a client-owned change (e.g. reviewApproved) never
|
|
2258
|
+
// erases run history. List membership still comes from the incoming array, so
|
|
2259
|
+
// deletes are honored (a conversation absent here is dropped).
|
|
2260
|
+
const prior = this.conversationStore.loadProject(key);
|
|
2261
|
+
const priorById = new Map(prior.conversations.map((entry) => [entry.id, entry]));
|
|
2262
|
+
const conversations = body.conversations.map((incoming) => {
|
|
2263
|
+
const existing = incoming && incoming.id ? priorById.get(incoming.id) : undefined;
|
|
2264
|
+
return existing ? { ...existing, ...incoming } : incoming;
|
|
2265
|
+
});
|
|
2255
2266
|
const saved = this.conversationStore.replaceProject(key, {
|
|
2256
2267
|
activeId: body.activeId ?? null,
|
|
2257
|
-
conversations
|
|
2268
|
+
conversations,
|
|
2258
2269
|
});
|
|
2259
2270
|
return res.json({ projectPath: key, scope: scope ?? 'project', ...saved, source: 'disk' });
|
|
2260
2271
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fraim-framework",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.195",
|
|
4
4
|
"description": "FRAIM: AI Workforce Infrastructure — the organizational capability that turns AI agents into an accountable workforce, their operators into capable AI managers, and executives into leaders with clear optics on AI proficiency.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/public/ai-hub/index.html
CHANGED
|
@@ -33,18 +33,18 @@
|
|
|
33
33
|
<div class="am-email" id="am-email"></div>
|
|
34
34
|
</div>
|
|
35
35
|
</div>
|
|
36
|
-
<button class="am-item" id="am-account" type="button">
|
|
36
|
+
<button class="am-item" id="am-account" type="button">
|
|
37
37
|
<span class="am-ico">👤</span>
|
|
38
38
|
<div><div class="am-label">Account</div><div class="am-sub">API key, sessions, billing</div></div>
|
|
39
|
-
</button>
|
|
39
|
+
</button>
|
|
40
40
|
<button class="am-item" id="am-brain" type="button">
|
|
41
41
|
<span class="am-ico">🧠</span>
|
|
42
42
|
<div><div class="am-label">Brain</div><div class="am-sub">Everything your team knows</div></div>
|
|
43
43
|
</button>
|
|
44
|
-
<button class="am-item" id="am-analytics" type="button">
|
|
44
|
+
<button class="am-item" id="am-analytics" type="button">
|
|
45
45
|
<span class="am-ico">📊</span>
|
|
46
46
|
<div><div class="am-label">Analytics</div><div class="am-sub">Usage, cost, and ROI</div></div>
|
|
47
|
-
</button>
|
|
47
|
+
</button>
|
|
48
48
|
<button class="am-item am-theme" id="am-theme-toggle" type="button" role="switch" aria-checked="false">
|
|
49
49
|
<span class="am-ico" id="am-theme-ico">🌙</span>
|
|
50
50
|
<div><div class="am-label">Dark mode</div><div class="am-sub" id="am-theme-sub">Off</div></div>
|
|
@@ -141,21 +141,21 @@
|
|
|
141
141
|
</div>
|
|
142
142
|
</section>
|
|
143
143
|
|
|
144
|
-
<section class="hub-area" id="area-connected" hidden>
|
|
145
|
-
<div class="connected-shell">
|
|
146
|
-
<div class="connected-toolbar">
|
|
147
|
-
<div class="connected-title-block">
|
|
148
|
-
<div class="connected-kicker" id="connected-kicker">Connected FRAIM</div>
|
|
149
|
-
<div class="connected-title" id="connected-title">Account</div>
|
|
150
|
-
</div>
|
|
151
|
-
<div class="connected-origin" id="connected-origin"></div>
|
|
152
|
-
<button class="connected-close" id="connected-close" type="button">Back</button>
|
|
153
|
-
</div>
|
|
154
|
-
<iframe id="connected-frame" class="connected-frame" title="FRAIM connected surface" allow="clipboard-read; clipboard-write"></iframe>
|
|
155
|
-
</div>
|
|
156
|
-
</section>
|
|
157
|
-
|
|
158
|
-
<!-- Issue #512: Projects area wraps the existing single-surface Hub. -->
|
|
144
|
+
<section class="hub-area" id="area-connected" hidden>
|
|
145
|
+
<div class="connected-shell">
|
|
146
|
+
<div class="connected-toolbar">
|
|
147
|
+
<div class="connected-title-block">
|
|
148
|
+
<div class="connected-kicker" id="connected-kicker">Connected FRAIM</div>
|
|
149
|
+
<div class="connected-title" id="connected-title">Account</div>
|
|
150
|
+
</div>
|
|
151
|
+
<div class="connected-origin" id="connected-origin"></div>
|
|
152
|
+
<button class="connected-close" id="connected-close" type="button">Back</button>
|
|
153
|
+
</div>
|
|
154
|
+
<iframe id="connected-frame" class="connected-frame" title="FRAIM connected surface" allow="clipboard-read; clipboard-write"></iframe>
|
|
155
|
+
</div>
|
|
156
|
+
</section>
|
|
157
|
+
|
|
158
|
+
<!-- Issue #512: Projects area wraps the existing single-surface Hub. -->
|
|
159
159
|
<section class="hub-area on" id="area-projects">
|
|
160
160
|
<div class="proj-tabs" id="proj-tabs">
|
|
161
161
|
<button class="ptab on" id="ptab-overview" type="button" data-view="overview">Overview</button>
|
|
@@ -868,6 +868,6 @@
|
|
|
868
868
|
</div>
|
|
869
869
|
</div>
|
|
870
870
|
|
|
871
|
-
<script src="./script.js"></script>
|
|
871
|
+
<script src="./script.js?v=conv-persist-20260705"></script>
|
|
872
872
|
</body>
|
|
873
873
|
</html>
|
package/public/ai-hub/script.js
CHANGED
|
@@ -507,11 +507,29 @@ function normalizeGeminiConversationMessages(conv) {
|
|
|
507
507
|
return changed;
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
+
// Server-owned conversation fields. The server re-derives these from the run
|
|
511
|
+
// registry and writes them to the conversation store on every run update
|
|
512
|
+
// (persistRunConversation), so the client must NOT re-upload them: a large run's
|
|
513
|
+
// messages/events/artifacts push the PUT body past the server's size limit, the
|
|
514
|
+
// request 413s, the error is swallowed, and the client-owned flags in the SAME
|
|
515
|
+
// payload (e.g. reviewApproved from "Mark complete") never persist. Strip them
|
|
516
|
+
// here; the server's PUT handler merges them back from the stored record.
|
|
517
|
+
const SERVER_OWNED_CONV_FIELDS = ['messages', 'events', 'artifacts', 'run', 'delegation'];
|
|
518
|
+
function slimConversationForPersist(conv) {
|
|
519
|
+
if (!conv || typeof conv !== 'object') return conv;
|
|
520
|
+
const slim = { ...conv };
|
|
521
|
+
for (const field of SERVER_OWNED_CONV_FIELDS) delete slim[field];
|
|
522
|
+
return slim;
|
|
523
|
+
}
|
|
524
|
+
function slimConversationsForPersist(list) {
|
|
525
|
+
return Array.isArray(list) ? list.map(slimConversationForPersist) : list;
|
|
526
|
+
}
|
|
527
|
+
|
|
510
528
|
function projectConversationPayload() {
|
|
511
529
|
return {
|
|
512
530
|
projectPath: state.projectPath || '',
|
|
513
531
|
activeId: state.activeId || null,
|
|
514
|
-
conversations: projectConversations(),
|
|
532
|
+
conversations: slimConversationsForPersist(projectConversations()),
|
|
515
533
|
};
|
|
516
534
|
}
|
|
517
535
|
|
|
@@ -537,7 +555,7 @@ function scheduleConversationDiskPersist() {
|
|
|
537
555
|
await requestJson('/api/ai-hub/conversations', {
|
|
538
556
|
method: 'PUT',
|
|
539
557
|
headers: { 'Content-Type': 'application/json' },
|
|
540
|
-
body: JSON.stringify({ scope, activeId: null, conversations: bucket }),
|
|
558
|
+
body: JSON.stringify({ scope, activeId: null, conversations: slimConversationsForPersist(bucket) }),
|
|
541
559
|
});
|
|
542
560
|
}
|
|
543
561
|
state.conversationDiskAvailable = true;
|