@evandu/super-pi 0.1.140 → 0.1.142
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/.super-pi-check-inputs.json +2 -2
- package/dist/client/.super-pi-client-sources.json +6 -6
- package/dist/client/assets/{CodeMirrorEditor-DvZeOLny.js → CodeMirrorEditor-iLUdQy9q.js} +2 -2
- package/dist/client/assets/{dist-C_VuSpx8.js → dist-0dCNvYEE.js} +1 -1
- package/dist/client/assets/{dist-gyzurUDR.js → dist-B4JqBNQI.js} +1 -1
- package/dist/client/assets/{dist-BCUfH4nP.js → dist-B8FbKhnf.js} +1 -1
- package/dist/client/assets/{dist-CTkzLBdb.js → dist-BA6EsWzo.js} +1 -1
- package/dist/client/assets/{dist-Cb1gxS57.js → dist-Bj2C-QqM.js} +1 -1
- package/dist/client/assets/{dist-gBAr9yXF.js → dist-Bt8G7e7e.js} +1 -1
- package/dist/client/assets/{dist-DAcS4Kj8.js → dist-CWBm3q4a.js} +1 -1
- package/dist/client/assets/{dist-qG53hT1b.js → dist-Cfa_e2VZ.js} +1 -1
- package/dist/client/assets/{dist-D7yfnKNC.js → dist-CoTJns5x.js} +1 -1
- package/dist/client/assets/{dist-CaUsvSz1.js → dist-CtCiGxne.js} +1 -1
- package/dist/client/assets/{dist-DdfW8Gjv.js → dist-DBAoCOnn.js} +1 -1
- package/dist/client/assets/{dist-DA8yW4lK.js → dist-DEUl3Yqk.js} +1 -1
- package/dist/client/assets/{dist-r4Kq1ABA.js → dist-DHyWJ9kA.js} +1 -1
- package/dist/client/assets/{dist-DRgWZqFH.js → dist-DbLEngKN.js} +1 -1
- package/dist/client/assets/{dist-C-QmRwbd.js → dist-Df9zcCXs.js} +1 -1
- package/dist/client/assets/{dist-CqDSeoUk.js → dist-Dq6y_nK3.js} +1 -1
- package/dist/client/assets/{dist-DlQ8PMvv.js → dist-Dxq1s4j3.js} +1 -1
- package/dist/client/assets/{dist-3BuyVG3H.js → dist-F634gv7V.js} +1 -1
- package/dist/client/assets/{dist-BIIMtU9W.js → dist-JuLMNOUt.js} +1 -1
- package/dist/client/assets/{dist-DN0M4DAX.js → dist-Nt-BWmBB.js} +1 -1
- package/dist/client/assets/{dist-HJdP1yxN.js → dist-ic-MopV2.js} +1 -1
- package/dist/client/assets/{dist-Dvca0LeR.js → dist-rIYPNzbY.js} +1 -1
- package/dist/client/assets/{index-CNbh1fL2.js → index-CX5gWDve.js} +13 -13
- package/dist/client/assets/{index-DCSFD4VV.css → index-DMhigTiY.css} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/agents.d.ts +2 -0
- package/dist/server/agents.js +10 -3
- package/dist/server/application/conversation-service.d.ts +17 -2
- package/dist/server/application/conversation-service.js +42 -8
- package/dist/server/application/run-service.d.ts +1 -0
- package/dist/server/application/run-service.js +121 -20
- package/dist/server/application/session-orchestrator-service.js +8 -1
- package/dist/server/command-handler.js +4 -0
- package/dist/server/store.d.ts +22 -1
- package/dist/server/store.js +108 -3
- package/dist/server/types.d.ts +36 -1
- package/package.json +325 -315
package/dist/server/store.js
CHANGED
|
@@ -1060,7 +1060,7 @@ export class Store {
|
|
|
1060
1060
|
// here and never consulted again: the session picker edits the conversation's own fields, so an
|
|
1061
1061
|
// existing conversation is untouched by later workspace settings, and a workspace edit never
|
|
1062
1062
|
// rewrites history. Field by field, never a spread, for the same reason setConversationModel
|
|
1063
|
-
// narrows:
|
|
1063
|
+
// narrows: every inherited field has an explicit birth override, including null for Pi's default.
|
|
1064
1064
|
if (workspace.defaultModel)
|
|
1065
1065
|
conversation.model = { provider: workspace.defaultModel.provider, modelId: workspace.defaultModel.modelId, label: workspace.defaultModel.label };
|
|
1066
1066
|
if (workspace.defaultThinkingLevel)
|
|
@@ -1072,6 +1072,8 @@ export class Store {
|
|
|
1072
1072
|
// rewritten: it describes how this conversation came to be, not what is true right now.
|
|
1073
1073
|
if (configuration.modelNotice !== undefined)
|
|
1074
1074
|
conversation.modelNotice = configuration.modelNotice;
|
|
1075
|
+
if (configuration.agentNotice !== undefined)
|
|
1076
|
+
conversation.agentNotice = configuration.agentNotice;
|
|
1075
1077
|
if (configuration.model !== undefined) {
|
|
1076
1078
|
if (configuration.model)
|
|
1077
1079
|
conversation.model = { ...configuration.model };
|
|
@@ -1084,13 +1086,55 @@ export class Store {
|
|
|
1084
1086
|
else
|
|
1085
1087
|
delete conversation.thinkingLevel;
|
|
1086
1088
|
}
|
|
1087
|
-
if (configuration.agentId)
|
|
1088
|
-
|
|
1089
|
+
if (configuration.agentId !== undefined) {
|
|
1090
|
+
if (configuration.agentId)
|
|
1091
|
+
conversation.agentId = configuration.agentId;
|
|
1092
|
+
else
|
|
1093
|
+
delete conversation.agentId;
|
|
1094
|
+
}
|
|
1095
|
+
// THE SESSION TREE'S EDGE, WRITTEN AT BIRTH. Both fields describe how this conversation CAME TO
|
|
1096
|
+
// BE, exactly like modelNotice above, so they are set once here and never rewritten: the tree
|
|
1097
|
+
// the sidebar draws after a restart is the tree that was true when each session was opened.
|
|
1098
|
+
// Written only when present, so a conversation created without them (the user's own "+") reads
|
|
1099
|
+
// as a top-level one on every code path, including every state.json from before this field.
|
|
1100
|
+
if (configuration.parentConversationId)
|
|
1101
|
+
conversation.parentConversationId = configuration.parentConversationId;
|
|
1102
|
+
if (configuration.origin)
|
|
1103
|
+
conversation.origin = configuration.origin;
|
|
1089
1104
|
}
|
|
1090
1105
|
this.state.conversations.unshift(conversation);
|
|
1091
1106
|
await this.persist();
|
|
1092
1107
|
return structuredClone(conversation);
|
|
1093
1108
|
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Records (or clears) one conversation as collapsed in the sidebar's session tree. The list is a
|
|
1111
|
+
* SET in array clothing - order means nothing, duplicates must not accumulate - and it follows the
|
|
1112
|
+
* assign -> persist -> rollback pattern `setTerminalShell` established: the in-memory value is the
|
|
1113
|
+
* previous value again the moment persistence fails, so a rejected write can never leave the
|
|
1114
|
+
* screen and the disk disagreeing.
|
|
1115
|
+
*/
|
|
1116
|
+
async setConversationCollapsed(conversationId, collapsed) {
|
|
1117
|
+
const previous = this.state.collapsedConversationIds;
|
|
1118
|
+
const next = new Set(previous ?? []);
|
|
1119
|
+
if (collapsed)
|
|
1120
|
+
next.add(conversationId);
|
|
1121
|
+
else
|
|
1122
|
+
next.delete(conversationId);
|
|
1123
|
+
if (next.size === 0)
|
|
1124
|
+
delete this.state.collapsedConversationIds;
|
|
1125
|
+
else
|
|
1126
|
+
this.state.collapsedConversationIds = [...next];
|
|
1127
|
+
try {
|
|
1128
|
+
await this.persist();
|
|
1129
|
+
}
|
|
1130
|
+
catch (error) {
|
|
1131
|
+
if (previous === undefined)
|
|
1132
|
+
delete this.state.collapsedConversationIds;
|
|
1133
|
+
else
|
|
1134
|
+
this.state.collapsedConversationIds = previous;
|
|
1135
|
+
throw error;
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1094
1138
|
/**
|
|
1095
1139
|
* Copies a conversation into a NEW one, under an id the caller has already minted.
|
|
1096
1140
|
*
|
|
@@ -1194,6 +1238,67 @@ export class Store {
|
|
|
1194
1238
|
delete conversation.archivedAt;
|
|
1195
1239
|
await this.persistMetadata(conversationId);
|
|
1196
1240
|
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Archives one whole tree as one state write. Only a conversation with no existing parent may
|
|
1243
|
+
* start it; an archived parent is still a parent, so its active descendants cannot be archived
|
|
1244
|
+
* independently. All running checks happen before the first mutation, making rejection all-or-none.
|
|
1245
|
+
*/
|
|
1246
|
+
async archiveConversationTree(conversationId) {
|
|
1247
|
+
const root = this.requireConversation(conversationId);
|
|
1248
|
+
if (root.parentConversationId && this.state.conversations.some(item => item.id === root.parentConversationId)) {
|
|
1249
|
+
throw new Error("子会话不能独立归档,请从根会话归档整棵树");
|
|
1250
|
+
}
|
|
1251
|
+
if (root.archivedAt)
|
|
1252
|
+
return;
|
|
1253
|
+
const active = this.conversationSubtree(root).filter(item => !item.archivedAt);
|
|
1254
|
+
const running = active.find(item => item.status === "running");
|
|
1255
|
+
if (running)
|
|
1256
|
+
throw new Error(`会话「${running.title}」正在运行,无法归档整棵树,请先停止运行`);
|
|
1257
|
+
const archivedAt = now();
|
|
1258
|
+
for (const conversation of active)
|
|
1259
|
+
conversation.archivedAt = archivedAt;
|
|
1260
|
+
await this.persist();
|
|
1261
|
+
}
|
|
1262
|
+
/** Restores one archived tree in one write; active descendants are already restored by definition. */
|
|
1263
|
+
async unarchiveConversationTree(conversationId) {
|
|
1264
|
+
const root = this.requireConversation(conversationId);
|
|
1265
|
+
const parent = root.parentConversationId
|
|
1266
|
+
? this.state.conversations.find(item => item.id === root.parentConversationId)
|
|
1267
|
+
: undefined;
|
|
1268
|
+
if (parent?.archivedAt)
|
|
1269
|
+
throw new Error("归档树中的子会话不能独立恢复,请从归档树的根会话恢复整棵树");
|
|
1270
|
+
if (!root.archivedAt)
|
|
1271
|
+
return;
|
|
1272
|
+
const archived = this.conversationSubtree(root).filter(item => item.archivedAt);
|
|
1273
|
+
for (const conversation of archived)
|
|
1274
|
+
delete conversation.archivedAt;
|
|
1275
|
+
await this.persist();
|
|
1276
|
+
}
|
|
1277
|
+
/** Pre-order traversal with cycle protection; archived nodes are traversed, not treated as leaves. */
|
|
1278
|
+
conversationSubtree(root) {
|
|
1279
|
+
const byParent = new Map();
|
|
1280
|
+
for (const conversation of this.state.conversations) {
|
|
1281
|
+
if (conversation.workspaceId !== root.workspaceId || !conversation.parentConversationId)
|
|
1282
|
+
continue;
|
|
1283
|
+
const siblings = byParent.get(conversation.parentConversationId);
|
|
1284
|
+
if (siblings)
|
|
1285
|
+
siblings.push(conversation);
|
|
1286
|
+
else
|
|
1287
|
+
byParent.set(conversation.parentConversationId, [conversation]);
|
|
1288
|
+
}
|
|
1289
|
+
const result = [];
|
|
1290
|
+
const visited = new Set();
|
|
1291
|
+
const walk = (conversation) => {
|
|
1292
|
+
if (visited.has(conversation.id))
|
|
1293
|
+
return;
|
|
1294
|
+
visited.add(conversation.id);
|
|
1295
|
+
result.push(conversation);
|
|
1296
|
+
for (const child of byParent.get(conversation.id) ?? [])
|
|
1297
|
+
walk(child);
|
|
1298
|
+
};
|
|
1299
|
+
walk(root);
|
|
1300
|
+
return result;
|
|
1301
|
+
}
|
|
1197
1302
|
/**
|
|
1198
1303
|
* Rename edits the title and NOTHING else. In particular `updatedAt` is deliberately not touched,
|
|
1199
1304
|
* for exactly the reason archive is: `updatedAt` is the sidebar's recency key, so bumping it would
|
package/dist/server/types.d.ts
CHANGED
|
@@ -503,6 +503,9 @@ export type Conversation = {
|
|
|
503
503
|
* not what is true right now.
|
|
504
504
|
*/
|
|
505
505
|
modelNotice?: string;
|
|
506
|
+
/** Why this conversation started on Pi's default agent instead of the workspace's deleted default.
|
|
507
|
+
* Written once at birth, like modelNotice, and rendered verbatim. */
|
|
508
|
+
agentNotice?: string;
|
|
506
509
|
/** Absent means "Pi's own default", which is why a conversation created before the picker existed still works. */
|
|
507
510
|
model?: ModelSelection;
|
|
508
511
|
thinkingLevel?: string;
|
|
@@ -516,6 +519,21 @@ export type Conversation = {
|
|
|
516
519
|
* deleted agent degrades to "no role" instead of leaving a stale snapshot in state.json.
|
|
517
520
|
*/
|
|
518
521
|
agentId?: string;
|
|
522
|
+
/**
|
|
523
|
+
* The conversation that opened this one, when an orchestrator agent created it. Absent for a
|
|
524
|
+
* conversation the user started. This is the session tree's edge, and it PERSISTS: the sidebar
|
|
525
|
+
* draws the hierarchy from it after a restart, which a server-side in-memory ledger cannot do.
|
|
526
|
+
* Absence also reads correctly on every state.json written before this field existed - no parent
|
|
527
|
+
* recorded simply means "top level", which is what those conversations genuinely are.
|
|
528
|
+
*/
|
|
529
|
+
parentConversationId?: string;
|
|
530
|
+
/**
|
|
531
|
+
* Who opened this conversation. "user" for one the user started, "orchestrator" for one an agent
|
|
532
|
+
* created. Kept beside the parent id because a conversation can be an orchestrator's without
|
|
533
|
+
* having a parent (the top-level orchestrator), and because the context menu's "stop the session
|
|
534
|
+
* AND its queue" needs to know a queue exists without polling the orchestrator's ledger.
|
|
535
|
+
*/
|
|
536
|
+
origin?: "user" | "orchestrator";
|
|
519
537
|
};
|
|
520
538
|
/**
|
|
521
539
|
* One parsed agent definition, as read from an `agents/*.md` file. `prompt` is the file body and is the
|
|
@@ -863,7 +881,13 @@ export type AppState = {
|
|
|
863
881
|
todosByConversation?: Record<string, TodoItem[]>;
|
|
864
882
|
workflows?: WorkflowRun[];
|
|
865
883
|
scheduledTasks?: ScheduledTask[];
|
|
866
|
-
customAgentDirs?: string[];
|
|
884
|
+
customAgentDirs?: string[]; /**
|
|
885
|
+
* Which conversations the reader has collapsed in the sidebar's session tree, by conversation id.
|
|
886
|
+
* Server-side so the tree looks the same after a restart and on another machine - the sidebar is a
|
|
887
|
+
* view of the PRODUCT's state, not of one browser's session. Absent (older state.json) means
|
|
888
|
+
* "nothing collapsed", which is the correct reading of a preference that did not exist yet.
|
|
889
|
+
*/
|
|
890
|
+
collapsedConversationIds?: string[];
|
|
867
891
|
};
|
|
868
892
|
export type TodoItem = {
|
|
869
893
|
id?: string;
|
|
@@ -1158,6 +1182,17 @@ export type ClientCommandBody =
|
|
|
1158
1182
|
} | {
|
|
1159
1183
|
type: "conversation.unarchive";
|
|
1160
1184
|
conversationId: string;
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Collapses or expands one conversation's whole subtree in the sidebar's session tree. The state
|
|
1188
|
+
* lives SERVER-SIDE (`AppState.collapsedConversationIds`), not in the browser: the tree must look
|
|
1189
|
+
* the same after a restart and on another machine, and a bare WS client must not be able to leave
|
|
1190
|
+
* the server's truth and the screen's truth disagreeing about a preference the product owns.
|
|
1191
|
+
*/
|
|
1192
|
+
| {
|
|
1193
|
+
type: "conversation.collapse";
|
|
1194
|
+
conversationId: string;
|
|
1195
|
+
collapsed: boolean;
|
|
1161
1196
|
} | {
|
|
1162
1197
|
type: "conversation.rename";
|
|
1163
1198
|
conversationId: string;
|