@timurproko/a1 0.1.8-dev.0b6d8cc → 0.1.8-dev.21b95d6
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/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/src/foundation/pi-engine-adapter/adapter.js +54 -10
- package/dist/src/foundation/pi-owned-ui-integration/session-shell.d.ts +6 -0
- package/dist/src/foundation/pi-owned-ui-integration/session-shell.js +37 -3
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "darwin",
|
|
6
6
|
"architecture": "arm64",
|
|
7
7
|
"capability": "unsupported",
|
|
8
|
-
"builtAt": "2026-08-25T08:
|
|
8
|
+
"builtAt": "2026-08-25T08:21:01.149Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "7524bf568992517f50ed53196c861c5edeba0d7275633bb4735ab45bd5963a28",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "linux",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-08-25T08:
|
|
8
|
+
"builtAt": "2026-08-25T08:20:57.618Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "29e22fe29de2828982bc67ef418c4adcaab1490281477b7bea592ec6fe621bcd",
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
"platform": "win32",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-08-25T08:
|
|
8
|
+
"builtAt": "2026-08-25T08:21:59.118Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian.exe",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "82d4ad108c0e73f59b8bca207c751a7822e21045895c1453296fff6b649042ea",
|
|
12
12
|
"size": 172544
|
|
13
13
|
},
|
|
14
14
|
"provenance": {
|
|
Binary file
|
|
@@ -1476,14 +1476,16 @@ export class PiEngineAdapter {
|
|
|
1476
1476
|
this.#upsertMessageBlock(event.message, "live");
|
|
1477
1477
|
return;
|
|
1478
1478
|
case "message_update": {
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1479
|
+
const delta = isRecord(event.assistantMessageEvent) && typeof event.assistantMessageEvent.delta === "string"
|
|
1480
|
+
? event.assistantMessageEvent.delta
|
|
1481
|
+
: undefined;
|
|
1482
|
+
// The delta is folded in before the block is stored, so a chunk is one update to
|
|
1483
|
+
// one block rather than a store without the delta followed by a store with it.
|
|
1484
|
+
const blocks = this.#messageBlocks(event.message, "live", this.#transcript.length);
|
|
1485
|
+
for (const [index, block] of blocks.entries()) {
|
|
1486
|
+
this.#upsertTranscriptBlock(index === 0 && delta !== undefined && !block.text.endsWith(delta)
|
|
1487
|
+
? { ...block, text: `${block.text}${delta}` }
|
|
1488
|
+
: block);
|
|
1487
1489
|
}
|
|
1488
1490
|
return;
|
|
1489
1491
|
}
|
|
@@ -1638,7 +1640,13 @@ export class PiEngineAdapter {
|
|
|
1638
1640
|
}
|
|
1639
1641
|
}
|
|
1640
1642
|
}
|
|
1641
|
-
|
|
1643
|
+
// An authoritative rebuild restates most of what is already there. Reusing the block
|
|
1644
|
+
// that already says it keeps its revision, and with it the rows the shell rendered for
|
|
1645
|
+
// it — otherwise every turn that ends re-renders the whole session.
|
|
1646
|
+
this.#setTranscript(blocks.map(block => {
|
|
1647
|
+
const existing = this.#transcriptBlock(block.id);
|
|
1648
|
+
return existing !== undefined && sameBlockContent(existing, block) ? existing : block;
|
|
1649
|
+
}));
|
|
1642
1650
|
}
|
|
1643
1651
|
#upsertMessageBlock(message, status) {
|
|
1644
1652
|
const blocks = this.#messageBlocks(message, status, this.#transcript.length);
|
|
@@ -1815,8 +1823,14 @@ export class PiEngineAdapter {
|
|
|
1815
1823
|
}
|
|
1816
1824
|
#upsertTranscriptBlock(block) {
|
|
1817
1825
|
const index = this.#transcriptIndex.get(block.id);
|
|
1818
|
-
if (index !== undefined)
|
|
1826
|
+
if (index !== undefined) {
|
|
1827
|
+
const existing = this.#transcript[index];
|
|
1828
|
+
// Nothing to tell the shell about a block that repeats itself, and keeping the
|
|
1829
|
+
// revision keeps the rows it already rendered.
|
|
1830
|
+
if (existing !== undefined && sameBlockContent(existing, block))
|
|
1831
|
+
return;
|
|
1819
1832
|
this.#transcript[index] = block;
|
|
1833
|
+
}
|
|
1820
1834
|
else {
|
|
1821
1835
|
this.#transcriptIndex.set(block.id, this.#transcript.length);
|
|
1822
1836
|
this.#transcript.push(block);
|
|
@@ -2388,6 +2402,36 @@ function compactResourceLabel(path) {
|
|
|
2388
2402
|
const segments = path.replaceAll("\\", "/").split("/").filter(Boolean);
|
|
2389
2403
|
return segments.at(-1) ?? path;
|
|
2390
2404
|
}
|
|
2405
|
+
/**
|
|
2406
|
+
* Whether two blocks say the same thing. A block that says what it already said is not a
|
|
2407
|
+
* new revision: the shell renders a block once per revision, so bumping one it did not
|
|
2408
|
+
* need re-renders it for nothing.
|
|
2409
|
+
*/
|
|
2410
|
+
function sameBlockContent(left, right) {
|
|
2411
|
+
return left.kind === right.kind
|
|
2412
|
+
&& left.status === right.status
|
|
2413
|
+
&& left.title === right.title
|
|
2414
|
+
&& left.text === right.text
|
|
2415
|
+
&& sameValue(left.payload, right.payload);
|
|
2416
|
+
}
|
|
2417
|
+
function sameValue(left, right) {
|
|
2418
|
+
if (left === right)
|
|
2419
|
+
return true;
|
|
2420
|
+
if (typeof left !== typeof right || left === null || right === null)
|
|
2421
|
+
return false;
|
|
2422
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
2423
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length)
|
|
2424
|
+
return false;
|
|
2425
|
+
return left.every((value, index) => sameValue(value, right[index]));
|
|
2426
|
+
}
|
|
2427
|
+
if (typeof left !== "object")
|
|
2428
|
+
return false;
|
|
2429
|
+
const leftKeys = Object.keys(left);
|
|
2430
|
+
const rightRecord = right;
|
|
2431
|
+
if (leftKeys.length !== Object.keys(rightRecord).length)
|
|
2432
|
+
return false;
|
|
2433
|
+
return leftKeys.every(key => Object.hasOwn(rightRecord, key) && sameValue(left[key], rightRecord[key]));
|
|
2434
|
+
}
|
|
2391
2435
|
function textFromContent(content) {
|
|
2392
2436
|
if (typeof content === "string")
|
|
2393
2437
|
return content;
|
|
@@ -39,6 +39,12 @@ export declare class OwnedUiSessionShellRoot implements PiTuiComponentPort {
|
|
|
39
39
|
readonly onDequeue?: () => void;
|
|
40
40
|
}, startup?: PiShellHeaderOptions, agentDir?: string, extensionRenderers?: PiShellExtensionRendererResolver);
|
|
41
41
|
update(view: OwnedUiSessionViewModel): void;
|
|
42
|
+
/**
|
|
43
|
+
* Applies one block: its component is created or updated in place and the order grows
|
|
44
|
+
* only when the block is new. A streamed chunk costs one component update rather than a
|
|
45
|
+
* walk of the whole transcript.
|
|
46
|
+
*/
|
|
47
|
+
applyTranscriptBlock(block: OwnedUiSessionViewModel["transcript"][number]): void;
|
|
42
48
|
render(width: number): readonly string[];
|
|
43
49
|
layoutRoot(): PiTuiLayoutNode;
|
|
44
50
|
transcriptComponent(id: string): PiShellTranscriptComponentPort | undefined;
|
|
@@ -71,6 +71,25 @@ export class OwnedUiSessionShellRoot {
|
|
|
71
71
|
this.editor.setThinkingLevel(view.thinkingLevel);
|
|
72
72
|
this.invalidate();
|
|
73
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Applies one block: its component is created or updated in place and the order grows
|
|
76
|
+
* only when the block is new. A streamed chunk costs one component update rather than a
|
|
77
|
+
* walk of the whole transcript.
|
|
78
|
+
*/
|
|
79
|
+
applyTranscriptBlock(block) {
|
|
80
|
+
this.#blocksById.set(block.id, block);
|
|
81
|
+
const component = this.#transcript.get(block.id);
|
|
82
|
+
if (component === undefined) {
|
|
83
|
+
const created = createPiShellTranscriptComponent(block, this.#cwd, this.#extensionRenderers);
|
|
84
|
+
created.setExpanded(this.#toolsExpanded);
|
|
85
|
+
this.#transcript.set(block.id, created);
|
|
86
|
+
this.#transcriptOrder.push(block.id);
|
|
87
|
+
}
|
|
88
|
+
else if (component.revision !== block.revision) {
|
|
89
|
+
component.update(block);
|
|
90
|
+
}
|
|
91
|
+
this.invalidate();
|
|
92
|
+
}
|
|
74
93
|
render(width) {
|
|
75
94
|
const queued = this.#view.editor.queuedSubmissions.length === 0 ? [] : this.#queued.render(width);
|
|
76
95
|
return [
|
|
@@ -794,9 +813,12 @@ export class OwnedUiSessionShell {
|
|
|
794
813
|
});
|
|
795
814
|
this.root.editor.setAutocompleteCommands(this.backend.workflowAutocompleteCommands());
|
|
796
815
|
this.#unsubscribe = this.backend.onEvent(event => {
|
|
797
|
-
//
|
|
798
|
-
//
|
|
799
|
-
|
|
816
|
+
// A streamed chunk names one block, and touching only that block is what keeps the
|
|
817
|
+
// cost of a chunk the same in a long session as in a new one. Everything else
|
|
818
|
+
// resynchronizes the view, which is cheap next to re-reading the transcript.
|
|
819
|
+
const view = event.type === "transcript-block" && this.#sessionGeneration === this.backend.sessionGeneration
|
|
820
|
+
? this.#syncBlock(event.block)
|
|
821
|
+
: this.#syncView();
|
|
800
822
|
if (view.lifecycle === "ready" && this.#compactionQueue.length > 0)
|
|
801
823
|
void this.#flushCompactionQueue();
|
|
802
824
|
if (event.type === "session-lifecycle" && event.lifecycle === "stopped")
|
|
@@ -1415,6 +1437,18 @@ export class OwnedUiSessionShell {
|
|
|
1415
1437
|
this.#extensionBridge.dispose();
|
|
1416
1438
|
await this.runtime.dispose();
|
|
1417
1439
|
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Applies one transcript block without re-reading the session. The listeners still hear
|
|
1442
|
+
* the view they would have heard, so nothing downstream can tell the difference.
|
|
1443
|
+
*/
|
|
1444
|
+
#syncBlock(block) {
|
|
1445
|
+
this.root.applyTranscriptBlock(block);
|
|
1446
|
+
this.runtime.requestRender();
|
|
1447
|
+
const view = this.view();
|
|
1448
|
+
for (const listener of this.#listeners)
|
|
1449
|
+
listener(view);
|
|
1450
|
+
return view;
|
|
1451
|
+
}
|
|
1418
1452
|
#syncView() {
|
|
1419
1453
|
const view = this.view();
|
|
1420
1454
|
if (this.backend.sessionGeneration !== this.#sessionGeneration) {
|
package/package.json
CHANGED