pi-openai-toolkit 0.23.1 → 0.23.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 (42) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +83 -83
  3. package/README.md +6 -2
  4. package/README.zh.md +6 -2
  5. package/config.schema.json +278 -278
  6. package/docs/configuration.md +306 -298
  7. package/docs/internals.md +184 -181
  8. package/package.json +136 -135
  9. package/src/compact-client.ts +412 -412
  10. package/src/compaction-projection.ts +35 -35
  11. package/src/config/migration.ts +103 -103
  12. package/src/config.ts +310 -310
  13. package/src/context-management/codex-provider.ts +270 -270
  14. package/src/context-management/history-notes.ts +357 -357
  15. package/src/context-management/manual-compact.ts +247 -599
  16. package/src/context-management/scoped-compaction.ts +89 -0
  17. package/src/context-management/tools.ts +371 -371
  18. package/src/context-management/types.ts +168 -168
  19. package/src/context-management/window-manager.ts +912 -905
  20. package/src/debug.ts +238 -238
  21. package/src/deferred-tool-carryover.ts +282 -282
  22. package/src/details-store.ts +151 -151
  23. package/src/extension-runtime.ts +1919 -1986
  24. package/src/image-generation/extension.ts +189 -189
  25. package/src/image-generation/protocol.ts +579 -579
  26. package/src/image-generation/types.ts +300 -300
  27. package/src/native-fallback.ts +32 -29
  28. package/src/payload-rewrite.ts +515 -515
  29. package/src/pi-context-hook.ts +117 -117
  30. package/src/remote-v2-client.ts +811 -811
  31. package/src/request-context-cache.ts +155 -155
  32. package/src/responses-headers.ts +180 -180
  33. package/src/runtime.ts +865 -865
  34. package/src/serializer.ts +882 -882
  35. package/src/supported-environment.ts +27 -27
  36. package/src/types.ts +565 -565
  37. package/src/web-search/alpha-client.ts +876 -876
  38. package/src/web-search/extension.ts +530 -530
  39. package/src/web-search/payload.ts +299 -299
  40. package/src/web-search/prompt.ts +60 -60
  41. package/src/web-search/types.ts +166 -166
  42. package/tsconfig.check.json +50 -50
@@ -0,0 +1,89 @@
1
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
+ import {
3
+ estimateTokens,
4
+ findCutPoint,
5
+ type FileOperations,
6
+ type SessionBeforeCompactEvent,
7
+ type SessionEntry,
8
+ } from "@earendil-works/pi-coding-agent";
9
+ import { isRecord } from "./types";
10
+ import type { RemoteWindowCompactionInput } from "./window-manager";
11
+
12
+ function addFileOperation(name: string, args: unknown, files: FileOperations): void {
13
+ if (!isRecord(args) || typeof args.path !== "string") return;
14
+ if (name === "read") files.read.add(args.path);
15
+ else if (name === "write") files.written.add(args.path);
16
+ else if (name === "edit") files.edited.add(args.path);
17
+ }
18
+
19
+ /** Only canonical, current-window operations may contribute summary file metadata. */
20
+ function collectFileOperations(messages: readonly AgentMessage[], scope: RemoteWindowCompactionInput): FileOperations {
21
+ const files: FileOperations = { read: new Set(), written: new Set(), edited: new Set() };
22
+ const previous = scope.owningCompaction;
23
+ if (previous && isRecord(previous.details)) {
24
+ for (const path of Array.isArray(previous.details.readFiles) ? previous.details.readFiles : []) {
25
+ if (typeof path === "string") files.read.add(path);
26
+ }
27
+ for (const path of Array.isArray(previous.details.modifiedFiles) ? previous.details.modifiedFiles : []) {
28
+ if (typeof path === "string") files.edited.add(path);
29
+ }
30
+ }
31
+ for (const message of messages) {
32
+ if (message.role === "assistant") {
33
+ for (const block of message.content) if (block.type === "toolCall") addFileOperation(block.name, block.arguments, files);
34
+ } else if (message.role === "toolResult") {
35
+ for (const call of message.nestedCalls?.calls ?? []) addFileOperation(call.name, call.arguments, files);
36
+ }
37
+ }
38
+ return files;
39
+ }
40
+
41
+ /**
42
+ * Adapt canonical contributions to the public cut-point primitive. These are
43
+ * detached in-memory views with REAL source IDs, never entries to persist.
44
+ * Omitted entries contribute nothing; edited messages replace their raw values.
45
+ */
46
+ export function prepareScopedNativeCompaction(
47
+ event: SessionBeforeCompactEvent,
48
+ scope: RemoteWindowCompactionInput,
49
+ ): SessionBeforeCompactEvent {
50
+ const entries: SessionEntry[] = [];
51
+ for (const projected of scope.entries) {
52
+ if (projected.sourceEntry.type === "compaction") continue;
53
+ const messages = projected.messages.filter((message) => message.role !== "system");
54
+ if (!messages.length) continue;
55
+ // A single retained ID cannot safely identify a split within one source.
56
+ if (messages.length !== 1) throw new Error("compaction-source-projection-unavailable");
57
+ entries.push({ type: "message", id: projected.sourceEntry.id, parentId: projected.sourceEntry.parentId,
58
+ timestamp: projected.sourceEntry.timestamp, message: structuredClone(messages[0]!) });
59
+ }
60
+ if (!entries.length) throw new Error("unsafe-compaction-retained-start");
61
+ const settings = event.preparation.settings;
62
+ if (!settings || !Number.isFinite(settings.keepRecentTokens) || !Number.isFinite(settings.reserveTokens)) {
63
+ throw new Error("compaction-settings-unavailable");
64
+ }
65
+ const owner = scope.owningCompaction;
66
+ const ownerIndex = owner ? event.branchEntries.findIndex((entry) => entry.id === owner.id) : -1;
67
+ if (owner && ownerIndex < scope.windowBoundaryIndex) throw new Error("compaction-owner-mismatch");
68
+ const lowerIndex = Math.max(scope.windowBoundaryIndex, ownerIndex);
69
+ const minimumKeptIndex = entries.findIndex((entry) => event.branchEntries.findIndex((raw) => raw.id === entry.id) >= lowerIndex);
70
+ if (minimumKeptIndex < 0) throw new Error("compaction-current-window-too-small");
71
+ const cut = findCutPoint(entries, minimumKeptIndex, entries.length, settings.keepRecentTokens);
72
+ const kept = entries[cut.firstKeptEntryIndex];
73
+ if (kept?.type !== "message" || kept.message.role === "toolResult") throw new Error("unsafe-compaction-retained-start");
74
+ const firstKeptEntryId = kept.id;
75
+ if (!firstKeptEntryId) throw new Error("unsafe-compaction-retained-start");
76
+ const messages = (start: number, end: number) => entries.slice(start, end).flatMap((entry) => entry.type === "message" ? [entry.message] : []);
77
+ const messagesToSummarize = messages(0, cut.isSplitTurn ? cut.turnStartIndex : cut.firstKeptEntryIndex);
78
+ const turnPrefixMessages = cut.isSplitTurn ? messages(cut.turnStartIndex, cut.firstKeptEntryIndex) : [];
79
+ return {
80
+ ...event,
81
+ preparation: {
82
+ firstKeptEntryId, messagesToSummarize, turnPrefixMessages, isSplitTurn: cut.isSplitTurn,
83
+ tokensBefore: scope.messages.reduce((tokens, message) => tokens + estimateTokens(message), 0),
84
+ previousSummary: scope.owningCompaction?.summary,
85
+ fileOps: collectFileOperations([...messagesToSummarize, ...turnPrefixMessages], scope),
86
+ settings: { ...settings },
87
+ },
88
+ };
89
+ }