@zihanw/pi-forge 0.5.0 → 0.5.2

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.
Files changed (129) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +6 -2
  3. package/README.zh-CN.md +5 -2
  4. package/dist/codecs/prompt-stack.d.ts.map +1 -1
  5. package/dist/codecs/prompt-stack.js +17 -0
  6. package/dist/codecs/prompt-stack.js.map +1 -1
  7. package/dist/compiler.d.ts.map +1 -1
  8. package/dist/compiler.js +81 -0
  9. package/dist/compiler.js.map +1 -1
  10. package/dist/context-diff-history.d.ts +61 -0
  11. package/dist/context-diff-history.d.ts.map +1 -0
  12. package/dist/context-diff-history.js +84 -0
  13. package/dist/context-diff-history.js.map +1 -0
  14. package/dist/context-diff-snapshot.d.ts +19 -0
  15. package/dist/context-diff-snapshot.d.ts.map +1 -0
  16. package/dist/context-diff-snapshot.js +146 -0
  17. package/dist/context-diff-snapshot.js.map +1 -0
  18. package/dist/context-diff.d.ts +70 -0
  19. package/dist/context-diff.d.ts.map +1 -0
  20. package/dist/context-diff.js +259 -0
  21. package/dist/context-diff.js.map +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +5 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/lifecycle.d.ts +2 -0
  26. package/dist/lifecycle.d.ts.map +1 -1
  27. package/dist/lifecycle.js +19 -2
  28. package/dist/lifecycle.js.map +1 -1
  29. package/dist/payload-capture.d.ts +10 -0
  30. package/dist/payload-capture.d.ts.map +1 -1
  31. package/dist/payload-capture.js +39 -9
  32. package/dist/payload-capture.js.map +1 -1
  33. package/dist/payload-command.d.ts +2 -0
  34. package/dist/payload-command.d.ts.map +1 -1
  35. package/dist/payload-command.js +36 -6
  36. package/dist/payload-command.js.map +1 -1
  37. package/dist/payload-state.d.ts +3 -0
  38. package/dist/payload-state.d.ts.map +1 -1
  39. package/dist/payload-state.js +5 -0
  40. package/dist/payload-state.js.map +1 -1
  41. package/dist/preview.d.ts.map +1 -1
  42. package/dist/preview.js +43 -9
  43. package/dist/preview.js.map +1 -1
  44. package/dist/regex.d.ts +12 -0
  45. package/dist/regex.d.ts.map +1 -1
  46. package/dist/regex.js +81 -5
  47. package/dist/regex.js.map +1 -1
  48. package/dist/runtime/tool-policy-runtime.d.ts.map +1 -1
  49. package/dist/runtime/tool-policy-runtime.js +13 -3
  50. package/dist/runtime/tool-policy-runtime.js.map +1 -1
  51. package/dist/runtime/web-editor-runtime.d.ts +2 -1
  52. package/dist/runtime/web-editor-runtime.d.ts.map +1 -1
  53. package/dist/runtime/web-editor-runtime.js +8 -3
  54. package/dist/runtime/web-editor-runtime.js.map +1 -1
  55. package/dist/types.d.ts +17 -0
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/types.js.map +1 -1
  58. package/dist/ui-contribution/contrib-port.d.ts +170 -0
  59. package/dist/ui-contribution/contrib-port.d.ts.map +1 -0
  60. package/dist/ui-contribution/contrib-port.js +640 -0
  61. package/dist/ui-contribution/contrib-port.js.map +1 -0
  62. package/dist/ui-contribution/index.d.ts +3 -0
  63. package/dist/ui-contribution/index.d.ts.map +1 -0
  64. package/dist/ui-contribution/index.js +2 -0
  65. package/dist/ui-contribution/index.js.map +1 -0
  66. package/dist/web-editor/client-script.generated.d.ts.map +1 -1
  67. package/dist/web-editor/client-script.generated.js +1 -1
  68. package/dist/web-editor/client-script.generated.js.map +1 -1
  69. package/dist/web-editor/client-styles.generated.d.ts.map +1 -1
  70. package/dist/web-editor/client-styles.generated.js +1 -1
  71. package/dist/web-editor/client-styles.generated.js.map +1 -1
  72. package/dist/web-editor/contrib-service.d.ts +41 -0
  73. package/dist/web-editor/contrib-service.d.ts.map +1 -0
  74. package/dist/web-editor/contrib-service.js +174 -0
  75. package/dist/web-editor/contrib-service.js.map +1 -0
  76. package/dist/web-editor/line-diff.d.ts +28 -0
  77. package/dist/web-editor/line-diff.d.ts.map +1 -0
  78. package/dist/web-editor/line-diff.js +216 -0
  79. package/dist/web-editor/line-diff.js.map +1 -0
  80. package/dist/web-editor/page.d.ts +1 -1
  81. package/dist/web-editor/page.d.ts.map +1 -1
  82. package/dist/web-editor/page.js +2 -2
  83. package/dist/web-editor/page.js.map +1 -1
  84. package/dist/web-editor/schema-form.d.ts +63 -0
  85. package/dist/web-editor/schema-form.d.ts.map +1 -0
  86. package/dist/web-editor/schema-form.js +213 -0
  87. package/dist/web-editor/schema-form.js.map +1 -0
  88. package/dist/web-editor/server.d.ts.map +1 -1
  89. package/dist/web-editor/server.js +125 -7
  90. package/dist/web-editor/server.js.map +1 -1
  91. package/dist/web-editor/styles.d.ts.map +1 -1
  92. package/dist/web-editor/styles.js +188 -21
  93. package/dist/web-editor/styles.js.map +1 -1
  94. package/dist/web-editor/types.d.ts +19 -0
  95. package/dist/web-editor/types.d.ts.map +1 -1
  96. package/dist/web-host.d.ts +7 -3
  97. package/dist/web-host.d.ts.map +1 -1
  98. package/dist/web-host.js +85 -12
  99. package/dist/web-host.js.map +1 -1
  100. package/docs/README.md +1 -0
  101. package/docs/concepts/agent-profiles.md +1 -1
  102. package/docs/concepts/prompt-stacks.md +4 -0
  103. package/docs/design/0.5.1-plan.md +237 -0
  104. package/docs/design/architecture-0.5.md +22 -1
  105. package/docs/design/context-diff-plan.md +8 -2
  106. package/docs/development/release.md +7 -1
  107. package/docs/development/roadmap.md +14 -0
  108. package/docs/getting-started.md +1 -1
  109. package/docs/guides/delegation.md +3 -3
  110. package/docs/guides/use-cases.md +4 -2
  111. package/docs/guides/web-editor.md +5 -1
  112. package/docs/reference/commands.md +1 -1
  113. package/docs/reference/configuration.md +6 -3
  114. package/docs/reference/features.md +5 -0
  115. package/docs/reference/public-api.md +14 -2
  116. package/docs/reference/stack-schema.md +59 -2
  117. package/docs/reference/ui-contribution-port.md +51 -0
  118. package/docs/zh-CN/concepts/agent-profiles.md +1 -1
  119. package/docs/zh-CN/concepts/prompt-stacks.md +10 -4
  120. package/docs/zh-CN/guides/delegation.md +2 -2
  121. package/docs/zh-CN/guides/web-editor.md +4 -0
  122. package/docs/zh-CN/reference/commands.md +1 -1
  123. package/examples/custom-system-status-extension/README.md +4 -3
  124. package/examples/custom-system-status-extension/index.ts +8 -6
  125. package/examples/hack-prompt-stack.json +118 -0
  126. package/examples/minimal-prompt-stack.json +36 -0
  127. package/package.json +6 -1
  128. package/examples/image-reader-prompt-stack.json +0 -114
  129. package/examples/reviewer-prompt-stack.json +0 -104
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Host-neutral rolling context-diff history.
3
+ *
4
+ * Keeps the last N turn snapshots captured from provider payloads and exposes
5
+ * the latest engine-computed diff plus compact summaries for recent turns.
6
+ */
7
+ import { diffTurns, turnApproxTokens } from "./context-diff.js";
8
+ import { extractTurnSnapshot } from "./context-diff-snapshot.js";
9
+ export const CONTEXT_DIFF_HISTORY_LIMIT = 20;
10
+ export function createContextDiffHistory() {
11
+ return {
12
+ turns: [],
13
+ nextTurnNumber: 1,
14
+ usageByTurnId: new Map(),
15
+ cacheReportingModels: new Set(),
16
+ };
17
+ }
18
+ /** Append a captured payload, evict old turns past the limit, and compute the latest diff. */
19
+ export function appendContextDiffCapture(history, capture) {
20
+ const nextTurnNumber = history.nextTurnNumber ?? 1;
21
+ const turnId = capture.turnId ?? `turn-${nextTurnNumber}`;
22
+ history.nextTurnNumber = nextTurnNumber + 1;
23
+ const snapshot = extractTurnSnapshot({
24
+ ...capture,
25
+ turnId,
26
+ });
27
+ const previous = history.turns.at(-1);
28
+ history.turns.push(snapshot);
29
+ if (history.turns.length > CONTEXT_DIFF_HISTORY_LIMIT) {
30
+ const evicted = history.turns.shift();
31
+ if (evicted)
32
+ history.usageByTurnId.delete(evicted.turnId);
33
+ }
34
+ const diff = diffTurns(previous, snapshot);
35
+ history.latestDiff = diff;
36
+ return diff;
37
+ }
38
+ /** Attach the authoritative usage returned on the assistant message for one captured provider request. */
39
+ export function attachContextDiffUsage(history, turnId, usage) {
40
+ if (!history.turns.some((turn) => turn.turnId === turnId))
41
+ return false;
42
+ const modelKey = `${usage.provider}/${usage.model}`;
43
+ const currentReportsCache = usage.cacheRead > 0 || usage.cacheWrite > 0;
44
+ const cacheReported = currentReportsCache || history.cacheReportingModels.has(modelKey);
45
+ if (currentReportsCache)
46
+ history.cacheReportingModels.add(modelKey);
47
+ const promptTokens = usage.input + usage.cacheRead + usage.cacheWrite;
48
+ history.usageByTurnId.set(turnId, {
49
+ ...usage,
50
+ promptTokens,
51
+ cacheHitRatio: cacheReported && promptTokens > 0 ? usage.cacheRead / promptTokens : null,
52
+ cacheStatus: cacheReported ? "reported" : "not-reported",
53
+ });
54
+ return true;
55
+ }
56
+ /** Build the response-shaped view: compact summaries for recent turns + latest full diff. */
57
+ export function getContextDiffView(history) {
58
+ const turns = history.turns.map((turn, index) => {
59
+ const previous = index > 0 ? history.turns[index - 1] : undefined;
60
+ const diff = diffTurns(previous, turn);
61
+ return {
62
+ turnId: turn.turnId,
63
+ capturedAt: turn.capturedAt,
64
+ stackId: turn.stackId,
65
+ approxTokens: turnApproxTokens(turn),
66
+ blockCount: turn.blocks.length,
67
+ chars: turn.blocks.reduce((sum, block) => sum + block.chars, 0),
68
+ deltaTokens: diff.deltaTokens,
69
+ prefixTokens: diff.prefixTokens,
70
+ prefixRatio: diff.prefixRatio,
71
+ changedBlocks: diff.summary.changedBlocks,
72
+ usage: history.usageByTurnId.get(turn.turnId),
73
+ };
74
+ });
75
+ const latest = history.turns.length > 0 && history.latestDiff
76
+ ? {
77
+ turn: history.turns[history.turns.length - 1],
78
+ diff: history.latestDiff,
79
+ usage: history.usageByTurnId.get(history.turns[history.turns.length - 1].turnId),
80
+ }
81
+ : null;
82
+ return { turns, latest, latestDiff: history.latestDiff ?? null };
83
+ }
84
+ //# sourceMappingURL=context-diff-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-diff-history.js","sourceRoot":"","sources":["../src/context-diff-history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Host-neutral snapshot extraction from captured provider payloads.
3
+ *
4
+ * This module stays free of Node/DOM/Vue APIs so the same extraction logic can
5
+ * be reused by the web host and future non-web surfaces.
6
+ */
7
+ import { type TurnSnapshot } from "./context-diff.ts";
8
+ export interface ContextDiffCapture {
9
+ turnId?: string;
10
+ capturedAt: string;
11
+ stackId?: string;
12
+ payload?: unknown;
13
+ /** Secret-redacted, complete provider-request JSON used for diff identity. */
14
+ serializedPayload?: string;
15
+ text: string;
16
+ }
17
+ /** Convert a captured provider payload into an ordered TurnSnapshot of Blocks. */
18
+ export declare function extractTurnSnapshot(capture: ContextDiffCapture): TurnSnapshot;
19
+ //# sourceMappingURL=context-diff-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-diff-snapshot.d.ts","sourceRoot":"","sources":["../src/context-diff-snapshot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAyD,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE7G,MAAM,WAAW,kBAAkB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACb;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,YAAY,CAO7E"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Host-neutral snapshot extraction from captured provider payloads.
3
+ *
4
+ * This module stays free of Node/DOM/Vue APIs so the same extraction logic can
5
+ * be reused by the web host and future non-web surfaces.
6
+ */
7
+ import { createBlock, createTurnSnapshot, hashText } from "./context-diff.js";
8
+ /** Convert a captured provider payload into an ordered TurnSnapshot of Blocks. */
9
+ export function extractTurnSnapshot(capture) {
10
+ return createTurnSnapshot({
11
+ turnId: capture.turnId ?? capture.capturedAt,
12
+ capturedAt: capture.capturedAt,
13
+ stackId: capture.stackId ?? "",
14
+ blocks: extractBlocks(capture),
15
+ });
16
+ }
17
+ function extractBlocks(capture) {
18
+ const serializedPayload = parseSerializedPayload(capture.serializedPayload);
19
+ const payload = serializedPayload === undefined ? capture.payload : serializedPayload;
20
+ if (!isPlainObject(payload)) {
21
+ return [createBlock("payload-text", "payload", capture.text, capture.serializedPayload === undefined ? undefined : {
22
+ section: "payload",
23
+ serializedPayload: capture.serializedPayload,
24
+ })];
25
+ }
26
+ const blocks = [];
27
+ const messageKeyCounts = new Map();
28
+ for (const [key, value] of Object.entries(payload)) {
29
+ if (key === "system") {
30
+ blocks.push(createSystemBlock(value));
31
+ continue;
32
+ }
33
+ if (key === "messages" && Array.isArray(value) && value.length > 0) {
34
+ for (const message of value) {
35
+ const text = messageToText(message);
36
+ const role = messageRole(message);
37
+ const baseKey = `message-${keyPart(role)}-${hashText(`${role}\u0000${text}`).slice(0, 8)}`;
38
+ const occurrence = messageKeyCounts.get(baseKey) ?? 0;
39
+ messageKeyCounts.set(baseKey, occurrence + 1);
40
+ const messageKey = occurrence === 0 ? baseKey : `${baseKey}-${occurrence + 1}`;
41
+ blocks.push(createBlock(messageKey, role, text, {
42
+ section: "messages",
43
+ value: message,
44
+ }));
45
+ }
46
+ continue;
47
+ }
48
+ blocks.push(createRequestFieldBlock(key, value));
49
+ }
50
+ if (blocks.length > 0)
51
+ return blocks;
52
+ return [createBlock("payload", "payload", stringify(payload), {
53
+ section: "payload",
54
+ value: payload,
55
+ })];
56
+ }
57
+ function createRequestFieldBlock(key, value) {
58
+ return createBlock(`request-${key}`, "request", stringify({ [key]: value }, 2), {
59
+ section: "request",
60
+ field: key,
61
+ value,
62
+ });
63
+ }
64
+ function createSystemBlock(value) {
65
+ if (typeof value === "string") {
66
+ return createBlock("system", "system", value, {
67
+ section: "system",
68
+ value,
69
+ });
70
+ }
71
+ if (Array.isArray(value)) {
72
+ const systemText = contentBlocksToText(value);
73
+ return createBlock("system", "system", systemText || stringify(value), {
74
+ section: "system",
75
+ value,
76
+ });
77
+ }
78
+ return createBlock("system", "system", stringify(value), {
79
+ section: "system",
80
+ value,
81
+ });
82
+ }
83
+ function messageRole(message) {
84
+ return isPlainObject(message) && typeof message.role === "string" && message.role.length > 0
85
+ ? message.role
86
+ : "message";
87
+ }
88
+ function keyPart(value) {
89
+ const part = value.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "");
90
+ return part || "message";
91
+ }
92
+ function parseSerializedPayload(serializedPayload) {
93
+ if (serializedPayload === undefined)
94
+ return undefined;
95
+ try {
96
+ return JSON.parse(serializedPayload);
97
+ }
98
+ catch {
99
+ return undefined;
100
+ }
101
+ }
102
+ function stringify(value, space = 0) {
103
+ try {
104
+ const result = JSON.stringify(value, null, space);
105
+ return result === undefined ? String(value) : result;
106
+ }
107
+ catch {
108
+ return String(value);
109
+ }
110
+ }
111
+ function messageToText(message) {
112
+ if (typeof message === "string")
113
+ return message;
114
+ if (!isPlainObject(message))
115
+ return stringify(message);
116
+ const content = message.content;
117
+ if (typeof content === "string")
118
+ return content;
119
+ if (Array.isArray(content))
120
+ return contentBlocksToText(content);
121
+ return stringify(message);
122
+ }
123
+ function contentBlocksToText(content) {
124
+ if (!Array.isArray(content))
125
+ return typeof content === "string" ? content : "";
126
+ const parts = [];
127
+ for (const part of content) {
128
+ if (isPlainObject(part) && typeof part.text === "string") {
129
+ parts.push(part.text);
130
+ }
131
+ else if (isPlainObject(part) && part.type === "image") {
132
+ parts.push("[image content]");
133
+ }
134
+ else if (typeof part === "string") {
135
+ parts.push(part);
136
+ }
137
+ else if (part !== undefined && part !== null) {
138
+ parts.push(stringify(part));
139
+ }
140
+ }
141
+ return parts.join("\n").trim();
142
+ }
143
+ function isPlainObject(value) {
144
+ return !!value && typeof value === "object" && !Array.isArray(value);
145
+ }
146
+ //# sourceMappingURL=context-diff-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-diff-snapshot.js","sourceRoot":"","sources":["../src/context-diff-snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Host-neutral context diff engine.
3
+ *
4
+ * Pure functions only: no DOM, no Vue, no Node APIs. Consecutive turn
5
+ * snapshots are compared with a simple prefix-walk that models KV-cache
6
+ * reuse without attempting a full Myers diff.
7
+ */
8
+ export interface Block {
9
+ key: string;
10
+ role: string;
11
+ text: string;
12
+ chars: number;
13
+ approxTokens: number;
14
+ hash: string;
15
+ }
16
+ export interface TurnSnapshot {
17
+ turnId: string;
18
+ capturedAt: string;
19
+ stackId: string;
20
+ blocks: Block[];
21
+ }
22
+ export type DiffBlockStatus = "same" | "added" | "removed" | "modified";
23
+ export interface DiffBlock {
24
+ status: DiffBlockStatus;
25
+ before?: Block;
26
+ after?: Block;
27
+ tokenDelta: number;
28
+ }
29
+ export interface TurnDiffSummary {
30
+ sameBlocks: number;
31
+ addedBlocks: number;
32
+ removedBlocks: number;
33
+ modifiedBlocks: number;
34
+ changedBlocks: number;
35
+ /** Net tokens introduced by added or lengthened modified blocks. */
36
+ addedTokens: number;
37
+ /** Net tokens removed by removed or shortened modified blocks. */
38
+ removedTokens: number;
39
+ /** Net total token change (`addedTokens - removedTokens`). */
40
+ netTokens: number;
41
+ }
42
+ export interface TurnDiff {
43
+ blocks: DiffBlock[];
44
+ prefixTokens: number;
45
+ prefixRatio: number;
46
+ deltaTokens: number;
47
+ summary: TurnDiffSummary;
48
+ }
49
+ /** Estimate tokens from characters using the same chars/4 approximation as payload capture. */
50
+ export declare function estimateApproxTokens(text: string): number;
51
+ /** Pure string hash used as the block identity shortcut. */
52
+ export declare function hashText(text: string): string;
53
+ export declare function createBlock(key: string, role: string, text: string, serialized?: unknown): Block;
54
+ export declare function createTurnSnapshot(input: {
55
+ turnId: string;
56
+ capturedAt?: string;
57
+ stackId?: string;
58
+ blocks?: Block[];
59
+ }): TurnSnapshot;
60
+ export declare function turnApproxTokens(turn: TurnSnapshot): number;
61
+ /**
62
+ * Diff two consecutive turn snapshots.
63
+ *
64
+ * The cache-boundary walk compares block arrays positionally while hashes
65
+ * match. This preserves the serialized-prefix meaning even when a later
66
+ * block is moved. Classification uses stable block keys after the boundary so
67
+ * a middle insertion does not make every following block look modified.
68
+ */
69
+ export declare function diffTurns(previous: TurnSnapshot | null | undefined, current: TurnSnapshot): TurnDiff;
70
+ //# sourceMappingURL=context-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-diff.d.ts","sourceRoot":"","sources":["../src/context-diff.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,KAAK;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,EAAE,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAExE,MAAM,WAAW,SAAS;IACzB,MAAM,EAAE,eAAe,CAAC;IACxB,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACxB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,eAAe,CAAC;CACzB;AAED,+FAA+F;AAC/F,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,4DAA4D;AAC5D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO7C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,KAAK,CAahG;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB,GAAG,YAAY,CAOf;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAG3D;AA+KD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACxB,QAAQ,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,EACzC,OAAO,EAAE,YAAY,GACnB,QAAQ,CAwCV"}
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Host-neutral context diff engine.
3
+ *
4
+ * Pure functions only: no DOM, no Vue, no Node APIs. Consecutive turn
5
+ * snapshots are compared with a simple prefix-walk that models KV-cache
6
+ * reuse without attempting a full Myers diff.
7
+ */
8
+ /** Estimate tokens from characters using the same chars/4 approximation as payload capture. */
9
+ export function estimateApproxTokens(text) {
10
+ return Math.max(1, Math.ceil(text.length / 4));
11
+ }
12
+ /** Pure string hash used as the block identity shortcut. */
13
+ export function hashText(text) {
14
+ let hash = 0x811c9dc5;
15
+ for (let i = 0; i < text.length; i++) {
16
+ hash ^= text.charCodeAt(i);
17
+ hash = Math.imul(hash, 0x01000193);
18
+ }
19
+ return (hash >>> 0).toString(16).padStart(8, "0");
20
+ }
21
+ export function createBlock(key, role, text, serialized) {
22
+ const hashInput = serialized === undefined
23
+ ? { role, text }
24
+ : { role, text, serialized };
25
+ const serializedHashInput = stringifyHashInput(hashInput);
26
+ return {
27
+ key,
28
+ role,
29
+ text,
30
+ chars: text.length,
31
+ approxTokens: estimateApproxTokens(text),
32
+ hash: hashText(serializedHashInput),
33
+ };
34
+ }
35
+ export function createTurnSnapshot(input) {
36
+ return {
37
+ turnId: input.turnId,
38
+ capturedAt: input.capturedAt ?? "",
39
+ stackId: input.stackId ?? "",
40
+ blocks: input.blocks ?? [],
41
+ };
42
+ }
43
+ export function turnApproxTokens(turn) {
44
+ const chars = turn.blocks.reduce((sum, block) => sum + block.chars, 0);
45
+ return chars === 0 ? 0 : Math.ceil(chars / 4);
46
+ }
47
+ function commonPrefixLength(a, b) {
48
+ const max = Math.min(a.length, b.length);
49
+ let index = 0;
50
+ while (index < max && a.charCodeAt(index) === b.charCodeAt(index)) {
51
+ index++;
52
+ }
53
+ return index;
54
+ }
55
+ function stringifyHashInput(value) {
56
+ try {
57
+ const serialized = JSON.stringify(value);
58
+ return serialized === undefined ? String(value) : serialized;
59
+ }
60
+ catch {
61
+ return String(value);
62
+ }
63
+ }
64
+ /**
65
+ * A block hash includes fields that affect the provider wire request, while
66
+ * the visible block text remains the useful prompt excerpt. When a hash
67
+ * differs because metadata changed without changing the excerpt, no part of
68
+ * that excerpt is safe to count as a reusable prefix.
69
+ */
70
+ function safeCommonPrefixLength(before, after) {
71
+ if (before.role !== after.role || before.text === after.text)
72
+ return 0;
73
+ return commonPrefixLength(before.text, after.text);
74
+ }
75
+ function classify(before, after) {
76
+ if (before && after) {
77
+ if (before.hash === after.hash) {
78
+ return { status: "same", before, after, tokenDelta: 0 };
79
+ }
80
+ return {
81
+ status: "modified",
82
+ before,
83
+ after,
84
+ tokenDelta: 0,
85
+ };
86
+ }
87
+ if (before) {
88
+ return { status: "removed", before, tokenDelta: 0 };
89
+ }
90
+ return { status: "added", after, tokenDelta: 0 };
91
+ }
92
+ /**
93
+ * Allocate the request-level chars/4 delta across changed blocks. Per-block
94
+ * token deltas are deliberately based on character deltas, with the single
95
+ * request-level rounding remainder distributed across blocks so the chips and
96
+ * summary describe the same integer total.
97
+ */
98
+ function assignTokenDeltas(blocks, deltaTokens) {
99
+ const candidates = blocks
100
+ .map((block) => ({
101
+ block,
102
+ charDelta: (block.after?.chars ?? 0) - (block.before?.chars ?? 0),
103
+ }))
104
+ .filter(({ block, charDelta }) => block.status !== "same" && charDelta !== 0);
105
+ if (candidates.length === 0)
106
+ return;
107
+ let allocated = 0;
108
+ for (const candidate of candidates) {
109
+ candidate.block.tokenDelta = Math.trunc(candidate.charDelta / 4);
110
+ allocated += candidate.block.tokenDelta;
111
+ }
112
+ let remainder = deltaTokens - allocated;
113
+ if (remainder === 0)
114
+ return;
115
+ const direction = remainder > 0 ? 1 : -1;
116
+ const preferred = candidates.filter(({ charDelta }) => direction > 0 ? charDelta > 0 : charDelta < 0);
117
+ const targets = preferred.length > 0 ? preferred : candidates;
118
+ const wholeShare = Math.trunc(Math.abs(remainder) / targets.length);
119
+ if (wholeShare > 0) {
120
+ for (const target of targets)
121
+ target.block.tokenDelta += direction * wholeShare;
122
+ remainder -= direction * wholeShare * targets.length;
123
+ }
124
+ for (let index = 0; remainder !== 0; index++) {
125
+ targets[index % targets.length].block.tokenDelta += direction;
126
+ remainder -= direction;
127
+ }
128
+ }
129
+ function summarize(blocks, netTokens) {
130
+ let sameBlocks = 0;
131
+ let addedBlocks = 0;
132
+ let removedBlocks = 0;
133
+ let modifiedBlocks = 0;
134
+ let addedTokens = 0;
135
+ let removedTokens = 0;
136
+ for (const block of blocks) {
137
+ switch (block.status) {
138
+ case "same":
139
+ sameBlocks++;
140
+ break;
141
+ case "added":
142
+ addedBlocks++;
143
+ if (block.tokenDelta > 0)
144
+ addedTokens += block.tokenDelta;
145
+ if (block.tokenDelta < 0)
146
+ removedTokens += -block.tokenDelta;
147
+ break;
148
+ case "removed":
149
+ removedBlocks++;
150
+ if (block.tokenDelta > 0)
151
+ addedTokens += block.tokenDelta;
152
+ if (block.tokenDelta < 0)
153
+ removedTokens += -block.tokenDelta;
154
+ break;
155
+ case "modified":
156
+ modifiedBlocks++;
157
+ if (block.tokenDelta > 0) {
158
+ addedTokens += block.tokenDelta;
159
+ }
160
+ else {
161
+ removedTokens += -block.tokenDelta;
162
+ }
163
+ break;
164
+ }
165
+ }
166
+ return {
167
+ sameBlocks,
168
+ addedBlocks,
169
+ removedBlocks,
170
+ modifiedBlocks,
171
+ changedBlocks: addedBlocks + removedBlocks + modifiedBlocks,
172
+ addedTokens,
173
+ removedTokens,
174
+ netTokens,
175
+ };
176
+ }
177
+ function hasUniqueStableKeys(blocks) {
178
+ const keys = blocks.map((block) => block.key);
179
+ return keys.every((key) => key.length > 0) && new Set(keys).size === keys.length;
180
+ }
181
+ function alignBlocks(beforeBlocks, afterBlocks) {
182
+ const afterKeys = new Set(afterBlocks.map((block) => block.key));
183
+ const useKeys = hasUniqueStableKeys(beforeBlocks)
184
+ && hasUniqueStableKeys(afterBlocks)
185
+ && beforeBlocks.some((block) => afterKeys.has(block.key));
186
+ if (!useKeys) {
187
+ return alignPositional(beforeBlocks, afterBlocks);
188
+ }
189
+ const beforeByKey = new Map(beforeBlocks.map((block) => [block.key, block]));
190
+ const beforeIndexByKey = new Map(beforeBlocks.map((block, index) => [block.key, index]));
191
+ const aligned = [];
192
+ let beforeCursor = 0;
193
+ let afterCursor = 0;
194
+ for (let afterIndex = 0; afterIndex < afterBlocks.length; afterIndex++) {
195
+ const after = afterBlocks[afterIndex];
196
+ const beforeIndex = beforeIndexByKey.get(after.key);
197
+ if (beforeIndex === undefined || beforeIndex < beforeCursor)
198
+ continue;
199
+ aligned.push(...alignPositional(beforeBlocks.slice(beforeCursor, beforeIndex), afterBlocks.slice(afterCursor, afterIndex)));
200
+ aligned.push({ before: beforeByKey.get(after.key), after });
201
+ beforeCursor = beforeIndex + 1;
202
+ afterCursor = afterIndex + 1;
203
+ }
204
+ aligned.push(...alignPositional(beforeBlocks.slice(beforeCursor), afterBlocks.slice(afterCursor)));
205
+ return aligned;
206
+ }
207
+ function alignPositional(beforeBlocks, afterBlocks) {
208
+ const maxLength = Math.max(beforeBlocks.length, afterBlocks.length);
209
+ return Array.from({ length: maxLength }, (_, index) => ({
210
+ before: beforeBlocks[index],
211
+ after: afterBlocks[index],
212
+ }));
213
+ }
214
+ /**
215
+ * Diff two consecutive turn snapshots.
216
+ *
217
+ * The cache-boundary walk compares block arrays positionally while hashes
218
+ * match. This preserves the serialized-prefix meaning even when a later
219
+ * block is moved. Classification uses stable block keys after the boundary so
220
+ * a middle insertion does not make every following block look modified.
221
+ */
222
+ export function diffTurns(previous, current) {
223
+ const beforeBlocks = previous?.blocks ?? [];
224
+ const afterBlocks = current.blocks;
225
+ const diffBlocks = alignBlocks(beforeBlocks, afterBlocks).map(({ before, after }) => classify(before, after));
226
+ let prefixChars = 0;
227
+ let boundaryCrossed = false;
228
+ for (let index = 0; index < Math.max(beforeBlocks.length, afterBlocks.length); index++) {
229
+ const before = beforeBlocks[index];
230
+ const after = afterBlocks[index];
231
+ if (!boundaryCrossed) {
232
+ if (before && after && before.hash === after.hash) {
233
+ prefixChars += after.chars;
234
+ continue;
235
+ }
236
+ if (before && after) {
237
+ prefixChars += safeCommonPrefixLength(before, after);
238
+ }
239
+ boundaryCrossed = true;
240
+ }
241
+ }
242
+ const currentTokens = turnApproxTokens(current);
243
+ const previousTokens = previous ? turnApproxTokens(previous) : 0;
244
+ const currentChars = afterBlocks.reduce((sum, block) => sum + block.chars, 0);
245
+ const prefixTokens = !boundaryCrossed || prefixChars >= currentChars
246
+ ? currentTokens
247
+ : Math.min(currentTokens, Math.floor(prefixChars / 4));
248
+ const deltaTokens = currentTokens - previousTokens;
249
+ assignTokenDeltas(diffBlocks, deltaTokens);
250
+ const prefixRatio = currentTokens === 0 ? 0 : prefixTokens / currentTokens;
251
+ return {
252
+ blocks: diffBlocks,
253
+ prefixTokens,
254
+ prefixRatio,
255
+ deltaTokens,
256
+ summary: summarize(diffBlocks, deltaTokens),
257
+ };
258
+ }
259
+ //# sourceMappingURL=context-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-diff.js","sourceRoot":"","sources":["../src/context-diff.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,YAAY,EAAoB,MAAM,iCAAiC,CAAC;AAgBhH;;;;;GAKG;AACH,OAAO,EACN,aAAa,EACb,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACX,iCAAiC,EACjC,+BAA+B,EAC/B,4BAA4B,EAC5B,yBAAyB,EACzB,mBAAmB,GACnB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACX,iBAAiB,EACjB,sBAAsB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACX,mBAAmB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACX,iBAAiB,EACjB,sBAAsB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,EAAE,YAAY,QAwF/C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA4B,YAAY,EAAoB,MAAM,iCAAiC,CAAC;AAiBhH;;;;;GAKG;AACH,OAAO,EACN,aAAa,EACb,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACvB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACX,iCAAiC,EACjC,+BAA+B,EAC/B,4BAA4B,EAC5B,yBAAyB,EACzB,mBAAmB,GACnB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACX,iBAAiB,EACjB,sBAAsB,GACtB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACX,mBAAmB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACX,iBAAiB,EACjB,sBAAsB,GACtB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,EAAE,EAAE,YAAY,QA0F/C"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { registerLifecycleHandlers } from "./lifecycle.js";
2
- import { registerPayloadCommands, registerPayloadRequestHandler, armPayloadIntercept, clearPayloadCapture, webPayloadSnapshot } from "./payload-command.js";
2
+ import { registerPayloadCommands, registerPayloadRequestHandler, armPayloadIntercept, clearPayloadCapture, recordProviderResponseUsage, webPayloadSnapshot } from "./payload-command.js";
3
3
  import { buildPreview } from "./preview.js";
4
4
  import { registerPresetCommand } from "./preset-command.js";
5
5
  import { registerProfileCommand } from "./profile-command.js";
@@ -11,6 +11,7 @@ import { ForgeWorkspace } from "./workspace.js";
11
11
  import { createToolPolicyRuntime } from "./runtime/tool-policy-runtime.js";
12
12
  import { createWebEditorRuntime } from "./runtime/web-editor-runtime.js";
13
13
  import { createCompileCycleState } from "./compile-cycle.js";
14
+ import { getContextDiffView } from "./context-diff-history.js";
14
15
  import { createPayloadState } from "./payload-state.js";
15
16
  /**
16
17
  * Intentional public surface (0.5.0): the default Pi extension factory plus
@@ -68,7 +69,8 @@ export default function piForge(pi) {
68
69
  clearPayloadCapture(payloadState, ctx);
69
70
  return { ok: true, ...webPayloadSnapshot(payloadState) };
70
71
  },
71
- }));
72
+ getContextDiff: () => ({ ok: true, ...getContextDiffView(payloadState.contextDiffHistory) }),
73
+ }), () => pi.events);
72
74
  registerLifecycleHandlers(pi, workspace, compileCycle, {
73
75
  reloadStacks: stackRuntime.reloadStacks,
74
76
  disposePromptStackRuntime: stackRuntime.dispose,
@@ -85,6 +87,7 @@ export default function piForge(pi) {
85
87
  workspace.startHostPort(pi.events);
86
88
  },
87
89
  disposeForgeWorkspace: () => workspace.dispose(),
90
+ recordProviderResponseUsage: (message) => recordProviderResponseUsage(payloadState, message),
88
91
  });
89
92
  registerPayloadRequestHandler(pi, payloadState, () => currentActive());
90
93
  registerPayloadCommands(pi, payloadState);