pilotswarm 0.5.63 → 0.5.64
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/mcp/dist/src/server.d.ts.map +1 -1
- package/mcp/dist/src/server.js +2 -0
- package/mcp/dist/src/server.js.map +1 -1
- package/mcp/dist/src/tools/features.d.ts +4 -0
- package/mcp/dist/src/tools/features.d.ts.map +1 -0
- package/mcp/dist/src/tools/features.js +35 -0
- package/mcp/dist/src/tools/features.js.map +1 -0
- package/package.json +2 -2
- package/tui/src/node-sdk-transport.js +13 -0
- package/ui/core/src/controller.js +276 -0
- package/ui/core/src/history.js +89 -14
- package/ui/core/src/native-tasks.js +197 -0
- package/ui/core/src/question-display.js +13 -0
- package/ui/core/src/reducer.js +18 -1
- package/ui/core/src/selectors.js +46 -13
- package/ui/core/src/session-errors.js +13 -6
- package/ui/core/src/session-warning.js +14 -0
- package/ui/core/src/state.js +1 -0
- package/ui/react/src/feature-flags-panel.js +186 -0
- package/ui/react/src/native-task-card.js +59 -0
- package/ui/react/src/web-app.js +105 -15
- package/web/dist/assets/{abnfDiagram-VRR7QNED-C8iAmIqt.js → abnfDiagram-VRR7QNED-gIPHF2gV.js} +1 -1
- package/web/dist/assets/{arc-Cg8qs17j.js → arc-DMW_q5Ml.js} +1 -1
- package/web/dist/assets/{architectureDiagram-ZJ3FMSHR-fYr0dRm3.js → architectureDiagram-ZJ3FMSHR-DAKsrxcB.js} +1 -1
- package/web/dist/assets/{blockDiagram-677ZJIJ3-Bpj79Dzq.js → blockDiagram-677ZJIJ3-BUjSLpP3.js} +1 -1
- package/web/dist/assets/{c4Diagram-LMCZKHZV-b26Lsm6m.js → c4Diagram-LMCZKHZV-Dw2nPoes.js} +1 -1
- package/web/dist/assets/channel-CcOa1LtY.js +1 -0
- package/web/dist/assets/{chunk-2Q5K7J3B-VLYQfjgG.js → chunk-2Q5K7J3B-BAL28Rv0.js} +1 -1
- package/web/dist/assets/{chunk-32BRIVSS-mVx--2Hg.js → chunk-32BRIVSS-DDlt9K8s.js} +1 -1
- package/web/dist/assets/{chunk-5VM5RSS4-jwnJmked.js → chunk-5VM5RSS4-BLQGJGoP.js} +1 -1
- package/web/dist/assets/{chunk-EX3LRPZG-DdfzAT1n.js → chunk-EX3LRPZG-XFMb3HRy.js} +1 -1
- package/web/dist/assets/{chunk-JWPE2WC7-BHm6Udd8.js → chunk-JWPE2WC7-DWnKTQ72.js} +1 -1
- package/web/dist/assets/{chunk-MOJQB5TN-Dn5qSVAS.js → chunk-MOJQB5TN-MltzhnwP.js} +1 -1
- package/web/dist/assets/{chunk-RYQCIY6F-D4IKMROn.js → chunk-RYQCIY6F-Ce3q0-mJ.js} +1 -1
- package/web/dist/assets/{chunk-V7JOEXUC-BhME3pRf.js → chunk-V7JOEXUC-ThXLYY88.js} +1 -1
- package/web/dist/assets/{chunk-VR4S4FIN-CHG_NBff.js → chunk-VR4S4FIN-DbhAykiW.js} +1 -1
- package/web/dist/assets/{chunk-XXDRQBXY-yw4QCgiL.js → chunk-XXDRQBXY-BpkNB0mD.js} +1 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-B2VhHRSV.js +1 -0
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-B2VhHRSV.js +1 -0
- package/web/dist/assets/{cose-bilkent-JH36ORCC-DqwPj9Kx.js → cose-bilkent-JH36ORCC-rctqAPvj.js} +1 -1
- package/web/dist/assets/{cynefin-VYW2F7L2-CVokaaE_.js → cynefin-VYW2F7L2-Dg1cltg6.js} +1 -1
- package/web/dist/assets/{cynefinDiagram-TSTJHNR4-Bkhj9fuY.js → cynefinDiagram-TSTJHNR4-Ci23Sv4Z.js} +1 -1
- package/web/dist/assets/{dagre-VKFMJZFB-DVv-jnjb.js → dagre-VKFMJZFB-BpWTGhpv.js} +1 -1
- package/web/dist/assets/{diagram-FQU43EPY-DDlZjkrF.js → diagram-FQU43EPY-B69JpiAe.js} +1 -1
- package/web/dist/assets/{diagram-G47NLZAW-CNDUgqYa.js → diagram-G47NLZAW-BHMk1TOO.js} +1 -1
- package/web/dist/assets/{diagram-NH7WQ7WH-DywF8u8i.js → diagram-NH7WQ7WH-CtvZIIsk.js} +1 -1
- package/web/dist/assets/{diagram-OA4YK3LP-ZfN8nvLw.js → diagram-OA4YK3LP-BFvKh800.js} +1 -1
- package/web/dist/assets/{diagram-WEI45ONY-S94A6Avm.js → diagram-WEI45ONY-CgB8sWPe.js} +1 -1
- package/web/dist/assets/{ebnfDiagram-CCIWWBDH-Mpt3QUnw.js → ebnfDiagram-CCIWWBDH-DyqPNydM.js} +1 -1
- package/web/dist/assets/{erDiagram-Q63AITRT-Bh-eWbdV.js → erDiagram-Q63AITRT-CwpvZQ3Q.js} +1 -1
- package/web/dist/assets/{flowDiagram-23GEKE2U-BwRtDI6V.js → flowDiagram-23GEKE2U-EBKSKxfC.js} +1 -1
- package/web/dist/assets/{ganttDiagram-NO4QXBWP-CrZoBmcB.js → ganttDiagram-NO4QXBWP-q5tMPAuC.js} +1 -1
- package/web/dist/assets/{gitGraphDiagram-IHSO6WYX-giXv1ynk.js → gitGraphDiagram-IHSO6WYX-DCRbi4KE.js} +1 -1
- package/web/dist/assets/{index-Br-gGWmc.js → index-BfF7e08d.js} +6 -6
- package/web/dist/assets/index-uhc851H3.css +1 -0
- package/web/dist/assets/{infoDiagram-FWYZ7A6U-H_5oc4-7.js → infoDiagram-FWYZ7A6U-Bex5pSIX.js} +1 -1
- package/web/dist/assets/{ishikawaDiagram-FXEZZL3T-BydiPDX0.js → ishikawaDiagram-FXEZZL3T-Dj0li_TY.js} +1 -1
- package/web/dist/assets/{journeyDiagram-5HDEW3XC-DS1HXms0.js → journeyDiagram-5HDEW3XC-BtEGEeVr.js} +1 -1
- package/web/dist/assets/{kanban-definition-HUTT4EX6-BjY5SyYu.js → kanban-definition-HUTT4EX6-BTFfZvYt.js} +1 -1
- package/web/dist/assets/{linear-BvOotjKL.js → linear-C3SQCsip.js} +1 -1
- package/web/dist/assets/{mermaid.core-0iRu7sp-.js → mermaid.core-DALDJDu8.js} +4 -4
- package/web/dist/assets/{mindmap-definition-LN4V7U3C-DB93zsvL.js → mindmap-definition-LN4V7U3C-BZf3uw0u.js} +1 -1
- package/web/dist/assets/{papaparse.min-f5Xncedc.js → papaparse.min-Bh9MZ-fk.js} +1 -1
- package/web/dist/assets/{pegDiagram-2B236MQR-Dh_U1cFA.js → pegDiagram-2B236MQR-PuOleiMg.js} +1 -1
- package/web/dist/assets/{pieDiagram-ENE6RG2P-Csv1qxMm.js → pieDiagram-ENE6RG2P-CcFORUaW.js} +1 -1
- package/web/dist/assets/pilotswarm-B9rLtXpI.js +109 -0
- package/web/dist/assets/{quadrantDiagram-ABIIQ3AL-Bo0pcrBM.js → quadrantDiagram-ABIIQ3AL-CEm0mp4y.js} +1 -1
- package/web/dist/assets/{railroadDiagram-RFXS5EU6-CHPvHNWG.js → railroadDiagram-RFXS5EU6-DeH-uX0_.js} +1 -1
- package/web/dist/assets/{requirementDiagram-TGXJPOKE-DgX8l-6H.js → requirementDiagram-TGXJPOKE-CMbJVMc1.js} +1 -1
- package/web/dist/assets/{sankeyDiagram-HTMAVEWB-xR6MTs5a.js → sankeyDiagram-HTMAVEWB-C9gL5w_b.js} +1 -1
- package/web/dist/assets/{sequenceDiagram-DBY2YBRQ-CD_45diB.js → sequenceDiagram-DBY2YBRQ-BUo8TT74.js} +1 -1
- package/web/dist/assets/{sizeCapture-X5ZJPWSS-BJVEXU0K.js → sizeCapture-X5ZJPWSS-C5lqG0ei.js} +1 -1
- package/web/dist/assets/{stateDiagram-2N3HPSRC-Bwu6kd23.js → stateDiagram-2N3HPSRC-DyeISrEU.js} +1 -1
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-5FZbaloZ.js +1 -0
- package/web/dist/assets/{swimlanes-5IMT3BWC-BmhEzevT.js → swimlanes-5IMT3BWC-DawuBk_a.js} +2 -2
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-DL8PgtmM.js +8 -0
- package/web/dist/assets/{timeline-definition-FHXFAJF6-DFPI_uTI.js → timeline-definition-FHXFAJF6-BZJ2YJcm.js} +1 -1
- package/web/dist/assets/{vennDiagram-L72KCM5P-DDTpTkBC.js → vennDiagram-L72KCM5P-BMXBVCfe.js} +1 -1
- package/web/dist/assets/{wardleyDiagram-EHGQE667-bV2_YVIL.js → wardleyDiagram-EHGQE667-DWedKsrQ.js} +1 -1
- package/web/dist/assets/{xychartDiagram-FW5EYKEG-C7bDIXAV.js → xychartDiagram-FW5EYKEG--XdfYceC.js} +1 -1
- package/web/dist/index.html +3 -3
- package/web/runtime.js +19 -0
- package/web/server.js +2 -2
- package/web/dist/assets/channel-C-ASbcRr.js +0 -1
- package/web/dist/assets/classDiagram-OUVF2IWQ-D2vlJIb1.js +0 -1
- package/web/dist/assets/classDiagram-v2-EOCWNBFH-D2vlJIb1.js +0 -1
- package/web/dist/assets/index-DRFDn87d.css +0 -1
- package/web/dist/assets/pilotswarm-DQNSWfNK.js +0 -105
- package/web/dist/assets/stateDiagram-v2-6OUMAXLB-aypsN5jW.js +0 -1
- package/web/dist/assets/swimlanesDiagram-G3AALYLV-Duf5C4YK.js +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AA2BlD,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,CA6G7D"}
|
package/mcp/dist/src/server.js
CHANGED
|
@@ -5,6 +5,7 @@ import { registerAgentTools } from "./tools/agents.js";
|
|
|
5
5
|
import { registerFactsTools } from "./tools/facts.js";
|
|
6
6
|
import { registerModelTools } from "./tools/models.js";
|
|
7
7
|
import { registerProviderTools } from "./tools/providers.js";
|
|
8
|
+
import { registerFeatureTools } from "./tools/features.js";
|
|
8
9
|
import { registerCapabilityTools } from "./tools/capabilities.js";
|
|
9
10
|
import { registerEnhancedFactTools } from "./tools/facts-enhanced.js";
|
|
10
11
|
import { registerGraphTools } from "./tools/graph.js";
|
|
@@ -78,6 +79,7 @@ export function createMcpServer(ctx) {
|
|
|
78
79
|
registerFactsTools(server, ctx);
|
|
79
80
|
registerModelTools(server, ctx);
|
|
80
81
|
registerProviderTools(server, ctx);
|
|
82
|
+
registerFeatureTools(server, ctx);
|
|
81
83
|
registerCapabilityTools(server, ctx);
|
|
82
84
|
registerTurnControlTools(server, ctx);
|
|
83
85
|
registerGroupTools(server, ctx);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../../src/tools/features.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,QA8BzE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { FEATURE_OPERATION_SPECS, featureToolParameters } from "pilotswarm-sdk";
|
|
3
|
+
import { jsonResult, withToolErrors } from "../util/respond.js";
|
|
4
|
+
export function registerFeatureTools(server, ctx) {
|
|
5
|
+
// Web mode ignores this value and derives identity from authentication.
|
|
6
|
+
// Direct mode requires an explicitly configured identity/admin grant for
|
|
7
|
+
// feature policy; holding a catalog handle alone does not opt it in.
|
|
8
|
+
const provider = process.env.PILOTSWARM_MCP_ACTOR_PROVIDER;
|
|
9
|
+
const subject = process.env.PILOTSWARM_MCP_ACTOR_SUBJECT;
|
|
10
|
+
const viewer = {
|
|
11
|
+
principal: provider && subject ? { provider, subject } : null,
|
|
12
|
+
isAdmin: !ctx.webMode && ctx.admin && process.env.PILOTSWARM_MCP_FEATURE_ADMIN === "true",
|
|
13
|
+
};
|
|
14
|
+
for (const spec of FEATURE_OPERATION_SPECS) {
|
|
15
|
+
const schema = featureToolParameters(spec);
|
|
16
|
+
const inputSchema = {};
|
|
17
|
+
for (const [key, property] of Object.entries(schema.properties)) {
|
|
18
|
+
let field = property.type === "boolean" ? z.boolean()
|
|
19
|
+
: property.type === "integer" ? z.number().int().min(property.minimum ?? 0).max(property.maximum ?? Number.MAX_SAFE_INTEGER)
|
|
20
|
+
: z.string().min(property.minLength ?? 0).max(property.maxLength ?? 1024);
|
|
21
|
+
if (property.description)
|
|
22
|
+
field = field.describe(property.description);
|
|
23
|
+
inputSchema[key] = schema.required.includes(key) ? field : field.optional();
|
|
24
|
+
}
|
|
25
|
+
server.registerTool(spec.name, { title: spec.name.replaceAll("_", " "), description: spec.description, inputSchema }, withToolErrors(async (args) => {
|
|
26
|
+
const method = ctx.mgmt[spec.method].bind(ctx.mgmt);
|
|
27
|
+
const values = spec.kind === "audit" ? [args.limit]
|
|
28
|
+
: spec.kind === "users" ? [args.query]
|
|
29
|
+
: spec.kind === "read" ? ("targetUser" in spec ? [args.userId] : [])
|
|
30
|
+
: "targetUser" in spec ? [args.userId, args] : [args];
|
|
31
|
+
return jsonResult(await method(viewer, ...values));
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=features.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../../src/tools/features.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pilotswarm",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.64",
|
|
4
4
|
"description": "PilotSwarm application package: terminal UI, browser portal + Web API server, and MCP server — one install, three bins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"ink": "^6.8.0",
|
|
82
82
|
"jose": "^6.2.2",
|
|
83
83
|
"mermaid": "^11.16.0",
|
|
84
|
-
"pilotswarm-sdk": "0.5.
|
|
84
|
+
"pilotswarm-sdk": "0.5.64",
|
|
85
85
|
"react": "^19.2.4",
|
|
86
86
|
"react-dom": "^19.2.4",
|
|
87
87
|
"ws": "^8.18.2"
|
|
@@ -1553,6 +1553,19 @@ export class NodeSdkTransport {
|
|
|
1553
1553
|
return this.mgmt.listProviders(await this._modelProviderViewer());
|
|
1554
1554
|
}
|
|
1555
1555
|
|
|
1556
|
+
async listFeatureFlags() { return this.mgmt.listFeatureFlags(await this._modelProviderViewer()); }
|
|
1557
|
+
async getClusterFeatureFlags() { return this.mgmt.getClusterFeatureFlags(await this._modelProviderViewer()); }
|
|
1558
|
+
async getMyFeatureFlags() { return this.mgmt.getMyFeatureFlags(await this._modelProviderViewer()); }
|
|
1559
|
+
async getUserFeatureFlags(userId) { return this.mgmt.getUserFeatureFlags(await this._modelProviderViewer(), userId); }
|
|
1560
|
+
async setClusterFeatureFlag(input) { return this.mgmt.setClusterFeatureFlag(await this._modelProviderViewer(), input); }
|
|
1561
|
+
async resetClusterFeatureFlag(input) { return this.mgmt.resetClusterFeatureFlag(await this._modelProviderViewer(), input); }
|
|
1562
|
+
async setMyFeatureFlag(input) { return this.mgmt.setMyFeatureFlag(await this._modelProviderViewer(), input); }
|
|
1563
|
+
async unsetMyFeatureFlag(input) { return this.mgmt.unsetMyFeatureFlag(await this._modelProviderViewer(), input); }
|
|
1564
|
+
async setUserFeatureFlag(userId, input) { return this.mgmt.setUserFeatureFlag(await this._modelProviderViewer(), userId, input); }
|
|
1565
|
+
async unsetUserFeatureFlag(userId, input) { return this.mgmt.unsetUserFeatureFlag(await this._modelProviderViewer(), userId, input); }
|
|
1566
|
+
async listFeatureFlagChanges(limit) { return this.mgmt.listFeatureFlagChanges(await this._modelProviderViewer(), limit); }
|
|
1567
|
+
async listFeatureFlagUsers(query) { return this.mgmt.listFeatureFlagUsers(await this._modelProviderViewer(), query); }
|
|
1568
|
+
|
|
1556
1569
|
async getModelDefaults() {
|
|
1557
1570
|
return this.mgmt.getModelDefaults(await this._modelProviderViewer());
|
|
1558
1571
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { applyNativeTaskSnapshot } from "./native-tasks.js";
|
|
1
2
|
import { UI_COMMANDS, FOCUS_REGIONS, INSPECTOR_TABS, cycleValue } from "./commands.js";
|
|
2
3
|
import { BUDGET_SERIES_DAYS, BUDGET_SERIES_RANGES, canvasKey as canvasPrefKey } from "./state.js";
|
|
3
4
|
import { parseAgentSourceLink } from "./repo-links.js";
|
|
@@ -55,6 +56,23 @@ import {
|
|
|
55
56
|
import { findArtifactEntry } from "./state.js";
|
|
56
57
|
import { getTheme, listThemes } from "./themes/index.js";
|
|
57
58
|
|
|
59
|
+
function preserveNativeTaskProgress(history, current, sessionId) {
|
|
60
|
+
const retained = current?.nativeTaskSnapshot;
|
|
61
|
+
if (!retained?.ownerId) return history;
|
|
62
|
+
// Replay has reconstructed task rows from durable events. Reapply the
|
|
63
|
+
// latest live projection even when a paging rebuild carried its old
|
|
64
|
+
// metadata through; individual task revision/terminal guards still let
|
|
65
|
+
// newer durable truth win and prevent another owner from taking a row.
|
|
66
|
+
return applyNativeTaskSnapshot({ ...history, nativeTaskSnapshot: undefined }, {
|
|
67
|
+
version: 1,
|
|
68
|
+
...retained,
|
|
69
|
+
tasks: (current.chat || [])
|
|
70
|
+
.filter(item => item.kind === "native-task-group")
|
|
71
|
+
.flatMap(group => group.tasks)
|
|
72
|
+
.filter(task => task.ownerId === retained.ownerId),
|
|
73
|
+
}, { sessionId, seq: retained.liveSeq });
|
|
74
|
+
}
|
|
75
|
+
|
|
58
76
|
/**
|
|
59
77
|
* The copy selector for a package LIST row: which same-named copy it is.
|
|
60
78
|
* Scope shadowing means one name can be a shared package AND a user copy at
|
|
@@ -2523,6 +2541,8 @@ export class PilotSwarmUiController {
|
|
|
2523
2541
|
}
|
|
2524
2542
|
|
|
2525
2543
|
async stop() {
|
|
2544
|
+
this._featureRefreshSerial = (this._featureRefreshSerial || 0) + 1;
|
|
2545
|
+
this._featureUserSerial = (this._featureUserSerial || 0) + 1;
|
|
2526
2546
|
for (const timer of this._liveTurnIdleTimers?.values() || []) clearTimeout(timer);
|
|
2527
2547
|
this._liveTurnIdleTimers?.clear();
|
|
2528
2548
|
if (this.catalogTimer) clearInterval(this.catalogTimer);
|
|
@@ -2593,6 +2613,7 @@ export class PilotSwarmUiController {
|
|
|
2593
2613
|
// navigation-intent branch returns before the tail): the worker
|
|
2594
2614
|
// registry must refresh on every tick of the loop that provably runs.
|
|
2595
2615
|
this.refreshWorkerRegistryIfStale().catch(() => {});
|
|
2616
|
+
this.refreshFeatureFlagsIfStale().catch(() => {});
|
|
2596
2617
|
// Refreshes OVERLAP. The catalog loop ticks every 4s and a dozen
|
|
2597
2618
|
// actions call this directly, while one run awaits several sequential
|
|
2598
2619
|
// round-trips (N catalog pages, the folder list, up to two getSession
|
|
@@ -3003,6 +3024,7 @@ export class PilotSwarmUiController {
|
|
|
3003
3024
|
}
|
|
3004
3025
|
}
|
|
3005
3026
|
}
|
|
3027
|
+
history = preserveNativeTaskProgress(history, current, sessionId);
|
|
3006
3028
|
this.dispatch({
|
|
3007
3029
|
type: "history/set",
|
|
3008
3030
|
sessionId,
|
|
@@ -3237,6 +3259,7 @@ export class PilotSwarmUiController {
|
|
|
3237
3259
|
if (this.getState().ui?.budgetOpen) this.closeBudget();
|
|
3238
3260
|
this.dispatch({ type: "admin/visibility", visible: true });
|
|
3239
3261
|
await this.refreshAdminProfile().catch(() => {});
|
|
3262
|
+
if (this.getState().admin?.section === "features") void this.refreshFeatureFlags();
|
|
3240
3263
|
void this.refreshAdminModelProviders().catch(() => {});
|
|
3241
3264
|
void this.refreshAdminAgentPackages().catch(() => {});
|
|
3242
3265
|
}
|
|
@@ -3707,6 +3730,7 @@ export class PilotSwarmUiController {
|
|
|
3707
3730
|
|
|
3708
3731
|
setAdminSection(section) {
|
|
3709
3732
|
this.dispatch({ type: "admin/section", section });
|
|
3733
|
+
if (section === "features") void this.refreshFeatureFlags();
|
|
3710
3734
|
if (section === "providers") {
|
|
3711
3735
|
const providers = this.getState().admin?.modelProviders;
|
|
3712
3736
|
if (!providers?.fetchedAt) void this.refreshAdminModelProviders().catch(() => {});
|
|
@@ -3722,6 +3746,251 @@ export class PilotSwarmUiController {
|
|
|
3722
3746
|
}
|
|
3723
3747
|
}
|
|
3724
3748
|
|
|
3749
|
+
async selectFeatureScope(mode, userId = null) {
|
|
3750
|
+
if (!["mine", "cluster", "users"].includes(mode)) return;
|
|
3751
|
+
if (this.getState().admin?.features?.saving || mode !== "mine" && !this._featureIsAdmin()) return;
|
|
3752
|
+
if (mode === "users" && userId !== null && (!Number.isSafeInteger(userId) || userId <= 0)) return;
|
|
3753
|
+
this.dispatch({ type: "admin/features", patch: { mode, userId: mode === "users" ? userId : null,
|
|
3754
|
+
data: null, error: null, notice: null, fetchedAt: null, dirtyDrafts: {} } });
|
|
3755
|
+
await this.refreshFeatureFlags();
|
|
3756
|
+
}
|
|
3757
|
+
|
|
3758
|
+
_featureIsAdmin() {
|
|
3759
|
+
const state = this.getState();
|
|
3760
|
+
const role = state.auth?.authorization?.role;
|
|
3761
|
+
return state.admin?.profile?.isAdmin === true && (!role || role === "admin" || role === "anonymous");
|
|
3762
|
+
}
|
|
3763
|
+
|
|
3764
|
+
_featureContext() {
|
|
3765
|
+
const state = this.getState();
|
|
3766
|
+
const features = state.admin.features;
|
|
3767
|
+
return JSON.stringify([features.generation, features.mode, features.userId,
|
|
3768
|
+
state.auth?.principal?.provider, state.auth?.principal?.subject, state.auth?.authorization?.role,
|
|
3769
|
+
state.admin.profile?.provider, state.admin.profile?.subject, state.admin.profile?.isAdmin]);
|
|
3770
|
+
}
|
|
3771
|
+
|
|
3772
|
+
async _featureRequest(read) {
|
|
3773
|
+
let timeout;
|
|
3774
|
+
try {
|
|
3775
|
+
return await Promise.race([Promise.resolve().then(read), new Promise((_, reject) => {
|
|
3776
|
+
timeout = setTimeout(() => reject(new Error("Feature request timed out. Retry or refresh the settings.")), 10_000);
|
|
3777
|
+
timeout?.unref?.();
|
|
3778
|
+
})]);
|
|
3779
|
+
} finally { clearTimeout(timeout); }
|
|
3780
|
+
}
|
|
3781
|
+
|
|
3782
|
+
async refreshFeatureFlagsIfStale() {
|
|
3783
|
+
const admin = this.getState().admin;
|
|
3784
|
+
const features = admin?.features;
|
|
3785
|
+
if (!admin?.visible || admin.section !== "features" || features?.loading || features?.saving
|
|
3786
|
+
|| Object.keys(features?.dirtyDrafts || {}).length
|
|
3787
|
+
|| features?.fetchedAt && Date.now() - features.fetchedAt < 20_000) return;
|
|
3788
|
+
await this.refreshFeatureFlags({ background: true });
|
|
3789
|
+
}
|
|
3790
|
+
|
|
3791
|
+
setFeatureDraftDirty(featureKey, dirty) {
|
|
3792
|
+
const dirtyDrafts = { ...this.getState().admin.features.dirtyDrafts };
|
|
3793
|
+
if (dirty) dirtyDrafts[featureKey] = true;
|
|
3794
|
+
else delete dirtyDrafts[featureKey];
|
|
3795
|
+
this.dispatch({ type: "admin/features", patch: { dirtyDrafts } });
|
|
3796
|
+
}
|
|
3797
|
+
|
|
3798
|
+
_featureDraftKey(featureKey) {
|
|
3799
|
+
const features = this.getState().admin.features;
|
|
3800
|
+
return JSON.stringify([features.mode, features.mode === "users" ? features.userId : null, featureKey]);
|
|
3801
|
+
}
|
|
3802
|
+
|
|
3803
|
+
getFeatureDraft(featureKey) {
|
|
3804
|
+
return this.getState().admin.features.drafts?.[this._featureDraftKey(featureKey)];
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3807
|
+
getFeatureDraftCount(mode) {
|
|
3808
|
+
return Object.values(this.getState().admin.features.drafts || {}).filter(draft => draft.mode === mode).length;
|
|
3809
|
+
}
|
|
3810
|
+
|
|
3811
|
+
setFeatureDraft(featureKey, values) {
|
|
3812
|
+
const features = this.getState().admin.features;
|
|
3813
|
+
if (features.saving || features.mode !== "mine" && !this._featureIsAdmin()
|
|
3814
|
+
|| features.mode === "users" && !features.userId) return;
|
|
3815
|
+
const flag = features.data?.flags?.find(item => item.featureKey === featureKey);
|
|
3816
|
+
if (!flag?.supported) return;
|
|
3817
|
+
const key = this._featureDraftKey(featureKey);
|
|
3818
|
+
const existing = features.drafts?.[key];
|
|
3819
|
+
const stored = features.mode === "cluster" ? flag.cluster : flag.user;
|
|
3820
|
+
// Null is an operation (remove the override), not merely a pair of
|
|
3821
|
+
// values equal to today's defaults. Keep reset intent when a row exists.
|
|
3822
|
+
const equal = values === null ? !stored : features.mode === "cluster"
|
|
3823
|
+
? values.enabled === (flag.cluster?.enabled ?? flag.defaultEnabled)
|
|
3824
|
+
&& values.allowUserOverride === (flag.cluster?.allowUserOverride ?? flag.defaultAllowUserOverride)
|
|
3825
|
+
: Boolean(stored) && values.enabled === stored.enabled;
|
|
3826
|
+
const drafts = { ...features.drafts };
|
|
3827
|
+
if (equal && !existing?.uncertain && !existing?.needsReview) delete drafts[key];
|
|
3828
|
+
else drafts[key] = { featureKey, mode: features.mode, userId: features.userId,
|
|
3829
|
+
values: values === null ? null : { ...values }, expectedRevision: existing?.expectedRevision ?? flag.revision,
|
|
3830
|
+
...(existing?.uncertain ? { uncertain: true } : {}), ...(existing?.needsReview ? { needsReview: true } : {}) };
|
|
3831
|
+
this.dispatch({ type: "admin/features", patch: { drafts, error: null, notice: null } });
|
|
3832
|
+
}
|
|
3833
|
+
|
|
3834
|
+
async discardFeatureDraft(featureKey) {
|
|
3835
|
+
if (this.getState().admin.features.saving) return;
|
|
3836
|
+
const draft = this.getFeatureDraft(featureKey);
|
|
3837
|
+
const context = this._featureContext();
|
|
3838
|
+
// A lost response may hide a committed save. Reconcile it before
|
|
3839
|
+
// discarding so the old cached value cannot look authoritative.
|
|
3840
|
+
if (draft?.uncertain && !await this.refreshFeatureFlags()) return;
|
|
3841
|
+
if (context !== this._featureContext() || this.getFeatureDraft(featureKey) !== draft) return;
|
|
3842
|
+
if (draft?.uncertain) {
|
|
3843
|
+
const revision = this.getState().admin.features.data?.flags?.find(flag => flag.featureKey === featureKey)?.revision;
|
|
3844
|
+
// A GET at the old revision cannot rule out the timed-out write
|
|
3845
|
+
// committing later. A newer revision fences its compare-and-set.
|
|
3846
|
+
if (!revision || BigInt(revision) <= BigInt(draft.expectedRevision)) {
|
|
3847
|
+
this.dispatch({ type: "admin/features", patch: { error: "The earlier save is still unconfirmed. Retry Save or refresh before discarding changes." } });
|
|
3848
|
+
return;
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
const drafts = { ...this.getState().admin.features.drafts };
|
|
3852
|
+
delete drafts[this._featureDraftKey(featureKey)];
|
|
3853
|
+
this.dispatch({ type: "admin/features", patch: { drafts, error: null, notice: null } });
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3856
|
+
reviewFeatureDraft(featureKey) {
|
|
3857
|
+
const features = this.getState().admin.features;
|
|
3858
|
+
if (features.saving || features.loading || features.mode !== "mine" && !this._featureIsAdmin()) return;
|
|
3859
|
+
const key = this._featureDraftKey(featureKey);
|
|
3860
|
+
const draft = features.drafts?.[key];
|
|
3861
|
+
const flag = features.data?.flags?.find(item => item.featureKey === featureKey);
|
|
3862
|
+
if (!draft || !flag?.supported || draft.needsReview && draft.expectedRevision === flag.revision) return;
|
|
3863
|
+
this.dispatch({ type: "admin/features", patch: { drafts: { ...features.drafts,
|
|
3864
|
+
[key]: { ...draft, expectedRevision: flag.revision, needsReview: false, uncertain: false } }, error: null, notice: "Latest saved setting reviewed. Your changes are still unsaved." } });
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3867
|
+
async saveFeatureDraft(featureKey) {
|
|
3868
|
+
const draft = this.getFeatureDraft(featureKey);
|
|
3869
|
+
if (!draft) return;
|
|
3870
|
+
const flag = this.getState().admin.features.data?.flags?.find(item => item.featureKey === featureKey);
|
|
3871
|
+
if (draft.needsReview || draft.expectedRevision !== flag?.revision) {
|
|
3872
|
+
this.dispatch({ type: "admin/features", patch: { error: "Settings changed elsewhere. Review the latest saved setting before saving your changes." } });
|
|
3873
|
+
return;
|
|
3874
|
+
}
|
|
3875
|
+
await this.saveFeatureFlag(featureKey, draft.values, { draft });
|
|
3876
|
+
}
|
|
3877
|
+
|
|
3878
|
+
async searchFeatureUsers(query = "") {
|
|
3879
|
+
if (!this._featureIsAdmin()) return;
|
|
3880
|
+
const serial = this._featureUserSerial = (this._featureUserSerial || 0) + 1;
|
|
3881
|
+
const context = this._featureContext();
|
|
3882
|
+
this.dispatch({ type: "admin/features", patch: { userQuery: String(query), usersLoading: true, metadataError: null } });
|
|
3883
|
+
const current = () => this._featureUserSerial === serial && this._featureContext() === context;
|
|
3884
|
+
try {
|
|
3885
|
+
const users = await this._featureRequest(() => this.transport.listFeatureFlagUsers(String(query)));
|
|
3886
|
+
if (current()) {
|
|
3887
|
+
const features = this.getState().admin.features;
|
|
3888
|
+
const selected = features.users?.find(user => user.userId === features.userId);
|
|
3889
|
+
const selectedUserOutsideResults = Boolean(selected && !users.some(user => user.userId === selected.userId));
|
|
3890
|
+
// Searching must not remove the identity/option of the user
|
|
3891
|
+
// whose saved policy and draft remain active below the picker.
|
|
3892
|
+
this.dispatch({ type: "admin/features", patch: {
|
|
3893
|
+
users: selectedUserOutsideResults ? [selected, ...users] : users,
|
|
3894
|
+
selectedUserOutsideResults, usersLoading: false,
|
|
3895
|
+
} });
|
|
3896
|
+
}
|
|
3897
|
+
} catch (error) {
|
|
3898
|
+
if (current()) this.dispatch({ type: "admin/features", patch: { usersLoading: false,
|
|
3899
|
+
metadataError: `User directory: ${error?.message || error}` } });
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
|
|
3903
|
+
async refreshFeatureFlags({ background = false } = {}) {
|
|
3904
|
+
const serial = (this._featureRefreshSerial ?? 0) + 1;
|
|
3905
|
+
this._featureRefreshSerial = serial;
|
|
3906
|
+
const features = this.getState().admin?.features || { mode: "mine" };
|
|
3907
|
+
if (features.mode !== "mine" && !this._featureIsAdmin()) return;
|
|
3908
|
+
const context = this._featureContext();
|
|
3909
|
+
const current = () => this._featureRefreshSerial === serial && this._featureContext() === context;
|
|
3910
|
+
this.dispatch({ type: "admin/features", patch: { loading: true, ...(background ? {} : { error: null }) } });
|
|
3911
|
+
// Directory/adoption are independent diagnostics: neither may block policy.
|
|
3912
|
+
if (!background && this._featureIsAdmin()) {
|
|
3913
|
+
void this.searchFeatureUsers(features.userQuery || "");
|
|
3914
|
+
void this.refreshWorkerRegistryIfStale();
|
|
3915
|
+
}
|
|
3916
|
+
try {
|
|
3917
|
+
const data = await this._featureRequest(() => features.mode === "cluster" ? this.transport.getClusterFeatureFlags()
|
|
3918
|
+
: features.mode === "users" ? features.userId ? this.transport.getUserFeatureFlags(features.userId) : null
|
|
3919
|
+
: this.transport.getMyFeatureFlags());
|
|
3920
|
+
if (!current()) return false;
|
|
3921
|
+
this.dispatch({ type: "admin/features", patch: { data, loading: false, fetchedAt: Date.now() } });
|
|
3922
|
+
return true;
|
|
3923
|
+
} catch (error) {
|
|
3924
|
+
if (current()) this.dispatch({ type: "admin/features", patch: { loading: false, fetchedAt: Date.now(), error: String(error?.message || error) } });
|
|
3925
|
+
return false;
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3929
|
+
async saveFeatureFlag(featureKey, values, { draft } = {}) {
|
|
3930
|
+
const features = this.getState().admin?.features;
|
|
3931
|
+
if (!features || features.saving || features.loading || features.mode !== "mine" && !this._featureIsAdmin()) return;
|
|
3932
|
+
const definition = features.data?.flags?.find(flag => flag.featureKey === featureKey);
|
|
3933
|
+
if (!definition?.supported || features.mode === "users" && !features.userId) return;
|
|
3934
|
+
const target = this._featureContext();
|
|
3935
|
+
const draftKey = this._featureDraftKey(featureKey);
|
|
3936
|
+
const expectedRevision = draft?.expectedRevision ?? definition.revision;
|
|
3937
|
+
const signature = JSON.stringify([target, featureKey, expectedRevision, values]);
|
|
3938
|
+
this._featureMutationRetries ??= new Map();
|
|
3939
|
+
const requestId = this._featureMutationRetries.get(signature) ?? globalThis.crypto.randomUUID();
|
|
3940
|
+
this._featureMutationRetries.set(signature, requestId);
|
|
3941
|
+
const input = { featureKey, expectedRevision, requestId, ...(values || {}) };
|
|
3942
|
+
this.dispatch({ type: "admin/features", patch: { saving: true, error: null, notice: null } });
|
|
3943
|
+
try {
|
|
3944
|
+
const outcome = await this._featureRequest(() => {
|
|
3945
|
+
if (features.mode === "cluster") return this.transport[values ? "setClusterFeatureFlag" : "resetClusterFeatureFlag"](input);
|
|
3946
|
+
if (features.mode === "users") return this.transport[values ? "setUserFeatureFlag" : "unsetUserFeatureFlag"](features.userId, input);
|
|
3947
|
+
return this.transport[values ? "setMyFeatureFlag" : "unsetMyFeatureFlag"](input);
|
|
3948
|
+
});
|
|
3949
|
+
this._featureMutationRetries.delete(signature);
|
|
3950
|
+
if (this._featureContext() === target) {
|
|
3951
|
+
// The acknowledged mutation is authoritative even if the
|
|
3952
|
+
// following GET fails. Do not show the old value as saved.
|
|
3953
|
+
if (/^[1-9]\d*$/.test(String(outcome?.revision)) && Object.hasOwn(outcome, "setting")) {
|
|
3954
|
+
const updated = { ...definition, revision: outcome.revision,
|
|
3955
|
+
[features.mode === "cluster" ? "cluster" : "user"]: outcome.setting };
|
|
3956
|
+
const allowUser = updated.cluster?.allowUserOverride ?? updated.defaultAllowUserOverride;
|
|
3957
|
+
updated.effective = allowUser && updated.user ? updated.user.enabled
|
|
3958
|
+
: updated.cluster?.enabled ?? updated.defaultEnabled;
|
|
3959
|
+
updated.source = allowUser && updated.user ? "user" : updated.cluster ? "cluster" : "default";
|
|
3960
|
+
updated.userOverrideIgnored = Boolean(updated.user && !allowUser);
|
|
3961
|
+
const data = this.getState().admin.features.data;
|
|
3962
|
+
this.dispatch({ type: "admin/features", patch: { data: { ...data,
|
|
3963
|
+
flags: data.flags.map(flag => flag.featureKey === featureKey ? updated : flag) } } });
|
|
3964
|
+
}
|
|
3965
|
+
if (draft && this.getState().admin.features.drafts?.[draftKey] === draft) {
|
|
3966
|
+
const drafts = { ...this.getState().admin.features.drafts };
|
|
3967
|
+
delete drafts[draftKey];
|
|
3968
|
+
this.dispatch({ type: "admin/features", patch: { drafts } });
|
|
3969
|
+
}
|
|
3970
|
+
await this.refreshFeatureFlags();
|
|
3971
|
+
if (this._featureContext() === target) this.dispatch({ type: "admin/features", patch: { notice: "Setting saved." } });
|
|
3972
|
+
}
|
|
3973
|
+
} catch (error) {
|
|
3974
|
+
if (this._featureContext() === target) {
|
|
3975
|
+
if (draft && (error?.status === 409 || error?.code === "FEATURE_CONFLICT")) {
|
|
3976
|
+
this._featureMutationRetries.delete(signature);
|
|
3977
|
+
this.dispatch({ type: "admin/features", patch: { drafts: { ...this.getState().admin.features.drafts,
|
|
3978
|
+
[draftKey]: { ...draft, needsReview: true } } } });
|
|
3979
|
+
const refreshed = await this.refreshFeatureFlags({ background: true });
|
|
3980
|
+
if (this._featureContext() === target) this.dispatch({ type: "admin/features", patch: {
|
|
3981
|
+
error: refreshed ? "Settings changed elsewhere. Review the latest saved setting before saving your changes."
|
|
3982
|
+
: "Settings changed elsewhere, but the latest setting could not be loaded. Refresh settings before reviewing and saving your changes." } });
|
|
3983
|
+
return;
|
|
3984
|
+
}
|
|
3985
|
+
if (draft && !(error?.status >= 400 && error?.status < 500)) {
|
|
3986
|
+
this.dispatch({ type: "admin/features", patch: { drafts: { ...this.getState().admin.features.drafts,
|
|
3987
|
+
[draftKey]: { ...draft, uncertain: true } } } });
|
|
3988
|
+
}
|
|
3989
|
+
this.dispatch({ type: "admin/features", patch: { error: String(error?.message || error) } });
|
|
3990
|
+
}
|
|
3991
|
+
} finally { if (this._featureContext() === target) this.dispatch({ type: "admin/features", patch: { saving: false } }); }
|
|
3992
|
+
}
|
|
3993
|
+
|
|
3725
3994
|
/** Node Map: select a node (toggles off when re-selected). Scopes Activity. */
|
|
3726
3995
|
selectNodeMapNode(label) {
|
|
3727
3996
|
this.dispatch({ type: "ui/nodeMapSelect", label: label ? String(label) : null });
|
|
@@ -5784,6 +6053,12 @@ export class PilotSwarmUiController {
|
|
|
5784
6053
|
// history would corrupt the replay cursor — and they must never
|
|
5785
6054
|
// appear in the transcript.
|
|
5786
6055
|
if (event.transient === true) {
|
|
6056
|
+
if (event.eventType === "session.native_tasks_tick") {
|
|
6057
|
+
const existing = this.getState().history.bySessionId.get(sessionId);
|
|
6058
|
+
const history = applyNativeTaskSnapshot(existing, event.data, { sessionId, seq: event.liveSeq });
|
|
6059
|
+
if (history && history !== existing) this.dispatch({ type: "history/set", sessionId, history });
|
|
6060
|
+
return true;
|
|
6061
|
+
}
|
|
5787
6062
|
if (event.eventType === "assistant.live_tick") {
|
|
5788
6063
|
// A worker can die leaving a reasoning-only retained row.
|
|
5789
6064
|
// On re-entry its message ID cannot match a durable final;
|
|
@@ -9811,6 +10086,7 @@ export class PilotSwarmUiController {
|
|
|
9811
10086
|
lastSeq: events[events.length - 1]?.seq || 0,
|
|
9812
10087
|
};
|
|
9813
10088
|
}
|
|
10089
|
+
history = preserveNativeTaskProgress(history, this.getState().history.bySessionId.get(sessionId), sessionId);
|
|
9814
10090
|
this.dispatch({
|
|
9815
10091
|
type: "history/set",
|
|
9816
10092
|
sessionId,
|
package/ui/core/src/history.js
CHANGED
|
@@ -2,6 +2,8 @@ import { formatHumanDurationSeconds, formatTimestamp, shortModelName, shortSessi
|
|
|
2
2
|
import { isCanvasActionContent, parseCanvasActionContent } from "./canvas-actions.js";
|
|
3
3
|
import { formatCompactionActivityRuns } from "./context-usage.js";
|
|
4
4
|
import { canonicalSystemTitle } from "./system-titles.js";
|
|
5
|
+
import { matchesSessionError } from "./session-warning.js";
|
|
6
|
+
import { appendNativeTaskEvent } from "./native-tasks.js";
|
|
5
7
|
import { buildSessionWarning } from "./session-errors.js";
|
|
6
8
|
import { appendChatCall, CHAT_CALL_EVENT_TYPES } from "./chat-activity.js";
|
|
7
9
|
|
|
@@ -19,13 +21,20 @@ export const HISTORY_EVENT_LIMIT_STEPS = [
|
|
|
19
21
|
// load transcript pages instead of raw-stream pages.
|
|
20
22
|
export const CHAT_HISTORY_EVENT_TYPES = [
|
|
21
23
|
...CHAT_CALL_EVENT_TYPES,
|
|
22
|
-
"session.error",
|
|
23
24
|
"user.message",
|
|
24
25
|
"assistant.message",
|
|
25
26
|
// Needed to distinguish interim assistant output from the final answer
|
|
26
27
|
// when an older transcript page is loaded.
|
|
27
28
|
"session.turn_completed",
|
|
28
29
|
"session.turn_stopped",
|
|
30
|
+
// Warnings belong at the error's position in the transcript, including
|
|
31
|
+
// after recovery and when paging backward through a noisy session.
|
|
32
|
+
"session.error",
|
|
33
|
+
"subagent.started",
|
|
34
|
+
"subagent.configured",
|
|
35
|
+
"subagent.completed",
|
|
36
|
+
"subagent.failed",
|
|
37
|
+
"native.task_updated",
|
|
29
38
|
"system.message",
|
|
30
39
|
// Session regeneration boundary — rendered as an inline epoch divider in
|
|
31
40
|
// the transcript, so it must survive backward chat-history paging.
|
|
@@ -90,6 +99,63 @@ function buildRegenFailedItem(event) {
|
|
|
90
99
|
};
|
|
91
100
|
}
|
|
92
101
|
|
|
102
|
+
function buildSessionWarningItem(event) {
|
|
103
|
+
const completed = event.eventType === "session.turn_completed" && event.data?.resultType === "error";
|
|
104
|
+
if (event.eventType !== "session.error" && !completed) return null;
|
|
105
|
+
const warning = buildSessionWarning(event);
|
|
106
|
+
if (!warning) return null;
|
|
107
|
+
return {
|
|
108
|
+
...warning,
|
|
109
|
+
errorText: warning.text,
|
|
110
|
+
sourceEventType: event.eventType,
|
|
111
|
+
...(completed ? { turnCompletedSeq: event.seq } : {}),
|
|
112
|
+
time: formatTimestamp(event.createdAt),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function appendSessionWarning(chat, event) {
|
|
117
|
+
const warning = buildSessionWarningItem(event);
|
|
118
|
+
if (!warning) return;
|
|
119
|
+
if (chat.some((item) => item.id === warning.id
|
|
120
|
+
|| (item.turnCompletedSeq != null && item.turnCompletedSeq === event.seq))) return;
|
|
121
|
+
// Tool disclosures can arrive between the SDK error and the failed-turn
|
|
122
|
+
// summary. They do not start a different conversation/failure episode.
|
|
123
|
+
const previousIndex = chat.findLastIndex(item => item.kind !== "chat-call" && item.kind !== "native-task-group");
|
|
124
|
+
const previous = chat[previousIndex];
|
|
125
|
+
// A runtime error and its failed-turn summary can describe one failure.
|
|
126
|
+
// Retain the original anchor; subsequent failed turns remain distinct.
|
|
127
|
+
if (previous?.kind === "session-warning"
|
|
128
|
+
&& previous.sourceEventType === "session.error"
|
|
129
|
+
&& previous.turnCompletedSeq == null
|
|
130
|
+
&& event.eventType === "session.turn_completed"
|
|
131
|
+
&& matchesSessionError(previous.errorText, warning.errorText)) {
|
|
132
|
+
chat[previousIndex] = { ...previous, turnCompletedSeq: event.seq };
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
chat.push(warning);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const parentChatCallTypes = new Set(CHAT_CALL_EVENT_TYPES);
|
|
139
|
+
function appendParentChatCall(chat, event) {
|
|
140
|
+
if (!parentChatCallTypes.has(event?.eventType)) return;
|
|
141
|
+
const data = event?.data || {};
|
|
142
|
+
// Native tasks have their own abridged disclosure. Generic call cards
|
|
143
|
+
// would duplicate them and reveal the full native prompt/arguments.
|
|
144
|
+
const name = data.toolName || data.name;
|
|
145
|
+
const namespace = `${event.sessionId}:${data.durableSessionId || ""}`;
|
|
146
|
+
const keys = [data.toolCallId && `call:${data.toolCallId}`, data.requestId && `request:${data.requestId}`].filter(Boolean);
|
|
147
|
+
// An empty diagnostic completion has neither a call to update nor useful
|
|
148
|
+
// content. Keep it in Activity without evicting real conversation cards.
|
|
149
|
+
const hasContent = name || data.arguments != null || data.args != null || data.result != null || data.output != null
|
|
150
|
+
|| data.error || data.partialOutput || data.progressMessage || data.childSessionId || data.agentId || data.task;
|
|
151
|
+
if (!keys.length && !hasContent) return;
|
|
152
|
+
const parentCall = !name && chat.some(item => item.kind === "chat-call" && item.namespace === namespace
|
|
153
|
+
&& item.callKeys.some(key => keys.includes(key)));
|
|
154
|
+
const nativeCall = name === "task" || Boolean(!name && !parentCall && data.toolCallId && chat.some(item =>
|
|
155
|
+
item.kind === "native-task-group" && item.tasks.some(task => task.toolCallId === data.toolCallId)));
|
|
156
|
+
if (!nativeCall) appendChatCall(chat, event);
|
|
157
|
+
}
|
|
158
|
+
|
|
93
159
|
function clampHistoryItems(items, maxItems) {
|
|
94
160
|
const list = Array.isArray(items) ? items.filter(Boolean) : [];
|
|
95
161
|
const safeMax = Math.max(DEFAULT_HISTORY_EVENT_LIMIT, Number(maxItems) || DEFAULT_HISTORY_EVENT_LIMIT);
|
|
@@ -881,7 +947,21 @@ function formatActivity(event) {
|
|
|
881
947
|
const body = formatEventSnippet(event);
|
|
882
948
|
let runs = null;
|
|
883
949
|
|
|
950
|
+
// Native child transcripts remain inspectable as events, but only their
|
|
951
|
+
// lifecycle belongs in the parent's activity feed.
|
|
952
|
+
if (event.eventType?.startsWith("native.") || event.eventType === "session.background_tasks_changed") return null;
|
|
884
953
|
switch (event.eventType) {
|
|
954
|
+
case "subagent.started":
|
|
955
|
+
case "subagent.completed":
|
|
956
|
+
case "subagent.failed": {
|
|
957
|
+
const phase = event.eventType.slice("subagent.".length);
|
|
958
|
+
const name = event.data?.agentDisplayName || event.data?.agentName || "agent";
|
|
959
|
+
const duration = Number.isFinite(event.data?.durationMs)
|
|
960
|
+
? ` (${formatHumanDurationSeconds(event.data.durationMs / 1000)})` : "";
|
|
961
|
+
runs = buildLabeledActivityRuns(time, "[native agent]", "cyan", `${name} ${phase}${duration}`, phase === "failed" ? "red" : "white");
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
case "subagent.configured":
|
|
885
965
|
case "assistant.usage":
|
|
886
966
|
case "session.info":
|
|
887
967
|
case "session.idle":
|
|
@@ -1226,11 +1306,9 @@ export function buildHistoryModel(events = [], options = {}) {
|
|
|
1226
1306
|
|
|
1227
1307
|
for (const event of events) {
|
|
1228
1308
|
storedEvents.push(event);
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
if (warning) chat.push(warning);
|
|
1233
|
-
}
|
|
1309
|
+
appendNativeTaskEvent(chat, event);
|
|
1310
|
+
appendParentChatCall(chat, event);
|
|
1311
|
+
appendSessionWarning(chat, event);
|
|
1234
1312
|
if (["user.message", "session.turn_completed", "session.turn_stopped", "session.epoch_committed"].includes(event.eventType)) {
|
|
1235
1313
|
settleAssistantResponses(chat, event);
|
|
1236
1314
|
}
|
|
@@ -1309,6 +1387,7 @@ export function appendEventToHistory(history, event) {
|
|
|
1309
1387
|
? existingEvents
|
|
1310
1388
|
: [...existingEvents, event].slice(-loadedEventLimit);
|
|
1311
1389
|
const next = {
|
|
1390
|
+
nativeTaskSnapshot: history?.nativeTaskSnapshot,
|
|
1312
1391
|
closedLiveKeys: history?.closedLiveKeys || [],
|
|
1313
1392
|
closedLiveStreams: history?.closedLiveStreams || [],
|
|
1314
1393
|
chat: clampHistoryItems(history?.chat || [], loadedEventLimit),
|
|
@@ -1328,14 +1407,10 @@ export function appendEventToHistory(history, event) {
|
|
|
1328
1407
|
stoppedMessageIds: Array.isArray(history?.stoppedMessageIds) ? history.stoppedMessageIds : [],
|
|
1329
1408
|
};
|
|
1330
1409
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
appendChatCall(next.chat, event);
|
|
1410
|
+
appendNativeTaskEvent(next.chat, event);
|
|
1411
|
+
appendParentChatCall(next.chat, event);
|
|
1412
|
+
appendSessionWarning(next.chat, event);
|
|
1413
|
+
next.chat = clampHistoryItems(next.chat, loadedEventLimit);
|
|
1339
1414
|
|
|
1340
1415
|
if (["user.message", "session.turn_completed", "session.turn_stopped", "session.epoch_committed"].includes(event.eventType)) {
|
|
1341
1416
|
settleAssistantResponses(next.chat, event);
|