pi-optchat 0.11.0 → 0.11.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.
- package/dist/core/cache.d.ts +14 -0
- package/dist/core/cache.js +96 -0
- package/dist/core/compactor.d.ts +28 -0
- package/dist/core/compactor.js +123 -0
- package/dist/core/images.d.ts +7 -0
- package/dist/core/images.js +19 -0
- package/dist/core/import.d.ts +40 -0
- package/dist/core/import.js +90 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +12 -0
- package/dist/core/memory.d.ts +196 -0
- package/dist/core/memory.js +573 -0
- package/dist/core/messages.d.ts +42 -0
- package/dist/core/messages.js +122 -0
- package/dist/core/prompts.d.ts +22 -0
- package/dist/core/prompts.js +146 -0
- package/dist/core/store.d.ts +57 -0
- package/dist/core/store.js +3 -0
- package/dist/core/tools.d.ts +76 -0
- package/dist/core/tools.js +64 -0
- package/dist/durable/import.d.ts +64 -0
- package/dist/durable/import.js +109 -0
- package/dist/durable/index.d.ts +5 -0
- package/dist/durable/index.js +5 -0
- package/dist/durable/optchat.d.ts +42 -0
- package/dist/durable/optchat.js +262 -0
- package/dist/durable/store.d.ts +65 -0
- package/dist/durable/store.js +167 -0
- package/docs/core.md +1 -1
- package/docs/durable.md +2 -2
- package/package.json +13 -3
- package/src/durable/import.ts +1 -1
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { Saved, Store } from './store.ts';
|
|
2
|
+
export declare const NODE = 512;
|
|
3
|
+
export declare const VIEW = 128000;
|
|
4
|
+
export declare const CAP = 30000;
|
|
5
|
+
/** The most characters of one message a leaf sends the compactor, so a huge paste can't overflow it; zoom still pages through all of it. */
|
|
6
|
+
export declare const SOURCE = 100000;
|
|
7
|
+
/** The most characters one zoom into a message returns, so a page stays under the tool output CAP instead of losing its middle. */
|
|
8
|
+
export declare const PAGE = 25000;
|
|
9
|
+
export declare const KINDS: readonly ['user', 'talk', 'tool', 'echo', 'note', 'work'];
|
|
10
|
+
export type Kind = typeof KINDS[number];
|
|
11
|
+
/** Marks an entry as imported history: the summarizer treats it as historical, not as a new request. `source` is a label the host
|
|
12
|
+
* chooses, such as "claude" or "email". */
|
|
13
|
+
export interface Origin {
|
|
14
|
+
source: string;
|
|
15
|
+
conversation: string;
|
|
16
|
+
message: string;
|
|
17
|
+
title: string;
|
|
18
|
+
project?: string;
|
|
19
|
+
}
|
|
20
|
+
/** A message as stores save it. */
|
|
21
|
+
export interface Entry {
|
|
22
|
+
i: number;
|
|
23
|
+
kind: Kind;
|
|
24
|
+
text: string;
|
|
25
|
+
date: string;
|
|
26
|
+
receipt?: string;
|
|
27
|
+
origin?: Origin;
|
|
28
|
+
}
|
|
29
|
+
/** A message as memory keeps it in RAM: its text stays in the store, and `Memory.text(i)` reads it. */
|
|
30
|
+
export type Message = Omit<Entry, 'text'>;
|
|
31
|
+
export interface Part {
|
|
32
|
+
l: number;
|
|
33
|
+
i: number;
|
|
34
|
+
}
|
|
35
|
+
/** A summary node as stores save it. `size` is its line's bytes in a view. */
|
|
36
|
+
export interface Summary extends Part {
|
|
37
|
+
text: string;
|
|
38
|
+
size: number;
|
|
39
|
+
}
|
|
40
|
+
/** A summary node as memory keeps it in RAM: `Memory.summary(part)` reads its text from the store. */
|
|
41
|
+
export type Node = Omit<Summary, 'text'>;
|
|
42
|
+
/** `part` is the node to build: a message's leaf, or the merge of its two halves. `call` is the tool call a tool result's leaf
|
|
43
|
+
* answers, raw, since its own line is often not built yet (#153). */
|
|
44
|
+
export interface Compression {
|
|
45
|
+
context: string;
|
|
46
|
+
source: string;
|
|
47
|
+
part: Part;
|
|
48
|
+
historical?: boolean;
|
|
49
|
+
call?: {
|
|
50
|
+
i: number;
|
|
51
|
+
text: string;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export type Compressor = (input: Compression, signal: AbortSignal) => Promise<string>;
|
|
55
|
+
/** A compressor throws this when the model itself gives no line for an input (a refusal, an empty reply, 5 cut-off replies):
|
|
56
|
+
* asked again it fails alike, so the node keeps the start of its source instead of being retried forever (#193). */
|
|
57
|
+
export declare class Refused extends Error {
|
|
58
|
+
}
|
|
59
|
+
export declare const start: ({ l, i }: Part) => number;
|
|
60
|
+
export declare const end: (part: Part) => number;
|
|
61
|
+
export declare const bytes: (s: string) => number;
|
|
62
|
+
export declare const flat: (s: string) => string;
|
|
63
|
+
/** The first NODE bytes, without a split character at the end. */
|
|
64
|
+
export declare const cut: (s: string) => string;
|
|
65
|
+
export declare const isView: (text: string) => boolean;
|
|
66
|
+
export declare function cap(text: string, limit?: number): string;
|
|
67
|
+
/** The index of the view's most due pair of sibling lines whose parent is built, or -1 (recipe §3.2). A pair is as due as
|
|
68
|
+
* long ago it ended, in its own line size; equal pairs go oldest first. This is the order of Taelin's rollback push. */
|
|
69
|
+
export declare function mostDue(view: readonly Part[], total: number, built: (part: Part) => boolean): number;
|
|
70
|
+
export declare function isEntry(value: unknown): value is Entry;
|
|
71
|
+
export declare function isSummary(value: unknown): value is Summary;
|
|
72
|
+
/** The log is authoritative. The tree and the view follow the recipe: the view grows a line per message and, once it passes
|
|
73
|
+
* `budget`, merges its most due pairs in one batch down to half of it, so between batches it only grows at its end.
|
|
74
|
+
* Compactions get their own view (recipe §4): the chat's merged further, to between an eighth and a quarter of the budget,
|
|
75
|
+
* and again whenever the chat's merges, so parallel compactions read it from the cache. */
|
|
76
|
+
export declare class Memory {
|
|
77
|
+
private readonly compress;
|
|
78
|
+
private readonly warn;
|
|
79
|
+
readonly budget: number;
|
|
80
|
+
private readonly jobs;
|
|
81
|
+
private readonly retryMs;
|
|
82
|
+
readonly root: Message[];
|
|
83
|
+
readonly tree: Map<number, Node>;
|
|
84
|
+
/** Texts whose store write hasn't finished (a store that writes behind can't read them yet) or was skipped after a failed save,
|
|
85
|
+
* by message index and by node. */
|
|
86
|
+
private readonly unsaved;
|
|
87
|
+
private readonly listeners;
|
|
88
|
+
private readonly controller;
|
|
89
|
+
private readonly busy;
|
|
90
|
+
private readonly retryAt;
|
|
91
|
+
private readonly reported;
|
|
92
|
+
/** Messages without their node, and merges whose halves are built, oldest first, so the scheduler never scans the tree for work (recipe §4). */
|
|
93
|
+
private readonly unbuilt;
|
|
94
|
+
private readonly merges;
|
|
95
|
+
private retryTimer?;
|
|
96
|
+
/** The most summaries owed at once since none were last owed. */
|
|
97
|
+
private peak;
|
|
98
|
+
private scheduled;
|
|
99
|
+
private stopped;
|
|
100
|
+
private readonly chat;
|
|
101
|
+
private readonly compaction;
|
|
102
|
+
/** The last store write still running, if any. Once an append fails, later writes are skipped and appends throw, as after a failed file write. */
|
|
103
|
+
private writing?;
|
|
104
|
+
private failed?;
|
|
105
|
+
readonly store: Store;
|
|
106
|
+
/** Why a message's append failed in the store, if one did: from then on nothing more is saved, yet `settle` and `close` still
|
|
107
|
+
* resolve, so a host whose store writes behind checks this to learn its log lost its tail. */
|
|
108
|
+
get saveError(): string | undefined;
|
|
109
|
+
lastError?: string;
|
|
110
|
+
/** `saved` is what `store.load()` gave (see `openMemory`). `jobs`: summaries built at once, and how many unbuilt lines a new
|
|
111
|
+
* message's node waits behind. Pi's chat and imports pass the "Summaries at once" setting. */
|
|
112
|
+
constructor({ store, saved }: {
|
|
113
|
+
store: Store;
|
|
114
|
+
saved: Saved;
|
|
115
|
+
}, compress: Compressor, warn?: (s: string) => void, budget?: number, jobs?: number, retryMs?: number);
|
|
116
|
+
append(kind: Kind, text: string, date?: string, receipt?: string, origin?: Origin): Entry;
|
|
117
|
+
node(part: Part): Node | undefined;
|
|
118
|
+
/** Message `i`'s text, from the store. */
|
|
119
|
+
text(i: number): string;
|
|
120
|
+
/** Every message with its text, read from the store: for imports, which plan from the whole log. */
|
|
121
|
+
entries(): Entry[];
|
|
122
|
+
/** A built node's text, from the store. */
|
|
123
|
+
summary(part: Part): string | undefined;
|
|
124
|
+
private line;
|
|
125
|
+
/** `write`, with `text` kept in `unsaved` until the write has finished. */
|
|
126
|
+
private keeping;
|
|
127
|
+
/** Runs a store write at once when none is running, so a store that finishes its writes as it returns (FileStore) throws here
|
|
128
|
+
* as before; otherwise after the running ones, so writes land in the order Memory makes them. Returns the queued write, settled
|
|
129
|
+
* through `failed`, unless it finished at once. */
|
|
130
|
+
private enqueue;
|
|
131
|
+
/** Takes the saved views if they still tile the log from the start, and returns how many messages they cover. */
|
|
132
|
+
private load;
|
|
133
|
+
/** A saved view, `{ parts, merging }` or an older bare list of parts, if it tiles the log from the start. */
|
|
134
|
+
private tiling;
|
|
135
|
+
/** Saved when either view merges or changes batch state: a view that only grew is the saved one plus later messages, as `load`
|
|
136
|
+
* replays it. The log stays authoritative, so a failed save only warns. */
|
|
137
|
+
private save;
|
|
138
|
+
private push;
|
|
139
|
+
get view(): readonly Part[];
|
|
140
|
+
render(): string;
|
|
141
|
+
get ready(): boolean;
|
|
142
|
+
get pending(): number;
|
|
143
|
+
get active(): number;
|
|
144
|
+
get size(): number;
|
|
145
|
+
/** Summaries built out of the backlog since it was last empty, and when the next failed one is retried. */
|
|
146
|
+
progress(now?: number): {
|
|
147
|
+
done: number;
|
|
148
|
+
total: number;
|
|
149
|
+
retryIn: number | undefined;
|
|
150
|
+
};
|
|
151
|
+
private owed;
|
|
152
|
+
onChange(listener: () => void): () => void;
|
|
153
|
+
private emit;
|
|
154
|
+
/** The view line covering message `at`. */
|
|
155
|
+
covering(at: number): Part | undefined;
|
|
156
|
+
/** Returns whether either view, or its batch state, changed. */
|
|
157
|
+
private fit;
|
|
158
|
+
private schedule;
|
|
159
|
+
private pump;
|
|
160
|
+
/** Nothing is being built, nothing more can start, and something failed: only a retry can make progress. */
|
|
161
|
+
private get stalled();
|
|
162
|
+
private build;
|
|
163
|
+
/** The tool call a result answers: a run of calls is followed by their results in the same order. A result that doesn't
|
|
164
|
+
* start with the call's tool name (an `Agent error`, an odd import) has none. */
|
|
165
|
+
private callOf;
|
|
166
|
+
/** The compactions' view up to the node. A line still being built shows as a placeholder instead of ending the view: an A/B on
|
|
167
|
+
* real turns (#101) found that cutting there also hid the built lines after it, such as an echo's own tool call. */
|
|
168
|
+
private compactionView;
|
|
169
|
+
private queueParent;
|
|
170
|
+
/** A 'turn' waits until every part of the view is built, or until everything pending has failed: it then goes on with placeholders
|
|
171
|
+
* for the missing lines, `lastError` says why, and the failed nodes are still retried in the background. 'tree' waits for every
|
|
172
|
+
* node, through failures. As in the recipe, the view may run over budget until pending merges land.
|
|
173
|
+
* 'ahead' (imports) waits until a new message's node would start at once. Due merges count too: messages go first, so a steady
|
|
174
|
+
* stream of them would otherwise take every worker and the views could never merge. */
|
|
175
|
+
settle(signal?: AbortSignal, until?: 'turn' | 'tree' | 'ahead'): Promise<void>;
|
|
176
|
+
private expectedNodes;
|
|
177
|
+
/** n = 1 gives the message whole, or, when it is longer than `limit` or `offset` is given, the page of up to `limit` characters from `offset`.
|
|
178
|
+
* Paging a message that fits in one page is allowed, but the page says so. */
|
|
179
|
+
zoom(id: number, n: number, offset?: number, limit?: number): string;
|
|
180
|
+
/** The largest whole lines covering the chat, oldest first: one per power of two in the message count. */
|
|
181
|
+
private roots;
|
|
182
|
+
/** Original messages containing `text`, ignoring case, newest first, older than message `before`. Never summaries,
|
|
183
|
+
* nor the logged zoom/search calls and results, which only copy memory. */
|
|
184
|
+
search(text: string, before?: number): Message[];
|
|
185
|
+
date(id: number): string;
|
|
186
|
+
close(): Promise<void>;
|
|
187
|
+
}
|
|
188
|
+
/** `jobs`: summaries built at once (8). `retryMs`: how long a failed summary waits before it is tried again. */
|
|
189
|
+
export interface MemoryOptions {
|
|
190
|
+
warn?: (s: string) => void;
|
|
191
|
+
budget?: number;
|
|
192
|
+
jobs?: number;
|
|
193
|
+
retryMs?: number;
|
|
194
|
+
}
|
|
195
|
+
/** Loads a store and opens its memory. */
|
|
196
|
+
export declare function openMemory(store: Store, compress: Compressor, { warn, budget, jobs, retryMs }?: MemoryOptions): Promise<Memory>;
|