@bryti/agent 0.0.1 → 0.1.0
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/Dockerfile +27 -0
- package/README.md +77 -50
- package/config.example.yml +265 -0
- package/dist/active-hours.d.ts +23 -0
- package/dist/active-hours.d.ts.map +1 -0
- package/dist/active-hours.js +68 -0
- package/dist/active-hours.js.map +1 -0
- package/dist/agent.d.ts +84 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +383 -0
- package/dist/agent.js.map +1 -0
- package/dist/channels/markdown/ir.d.ts +79 -0
- package/dist/channels/markdown/ir.d.ts.map +1 -0
- package/dist/channels/markdown/ir.js +824 -0
- package/dist/channels/markdown/ir.js.map +1 -0
- package/dist/channels/markdown/render.d.ts +35 -0
- package/dist/channels/markdown/render.d.ts.map +1 -0
- package/dist/channels/markdown/render.js +178 -0
- package/dist/channels/markdown/render.js.map +1 -0
- package/dist/channels/telegram-network-errors.d.ts +27 -0
- package/dist/channels/telegram-network-errors.d.ts.map +1 -0
- package/dist/channels/telegram-network-errors.js +156 -0
- package/dist/channels/telegram-network-errors.js.map +1 -0
- package/dist/channels/telegram.d.ts +76 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js +814 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/types.d.ts +59 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +9 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/channels/whatsapp.d.ts +45 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js +310 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +635 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +35 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +113 -0
- package/dist/commands.js.map +1 -0
- package/dist/compaction/history.d.ts +17 -0
- package/dist/compaction/history.d.ts.map +1 -0
- package/dist/compaction/history.js +35 -0
- package/dist/compaction/history.js.map +1 -0
- package/dist/compaction/index.d.ts +3 -0
- package/dist/compaction/index.d.ts.map +1 -0
- package/dist/compaction/index.js +3 -0
- package/dist/compaction/index.js.map +1 -0
- package/dist/compaction/proactive.d.ts +25 -0
- package/dist/compaction/proactive.d.ts.map +1 -0
- package/dist/compaction/proactive.js +87 -0
- package/dist/compaction/proactive.js.map +1 -0
- package/dist/compaction/transcript-repair.d.ts +55 -0
- package/dist/compaction/transcript-repair.d.ts.map +1 -0
- package/dist/compaction/transcript-repair.js +215 -0
- package/dist/compaction/transcript-repair.js.map +1 -0
- package/dist/config.d.ts +128 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +317 -0
- package/dist/config.js.map +1 -0
- package/dist/crash-recovery.d.ts +23 -0
- package/dist/crash-recovery.d.ts.map +1 -0
- package/dist/crash-recovery.js +96 -0
- package/dist/crash-recovery.js.map +1 -0
- package/dist/defaults/extensions/EXTENSIONS.md +158 -0
- package/dist/defaults/extensions/documents-hedgedoc.ts +153 -0
- package/dist/history.d.ts +31 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +49 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +673 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +39 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +143 -0
- package/dist/logger.js.map +1 -0
- package/dist/memory/conversation-search.d.ts +15 -0
- package/dist/memory/conversation-search.d.ts.map +1 -0
- package/dist/memory/conversation-search.js +60 -0
- package/dist/memory/conversation-search.js.map +1 -0
- package/dist/memory/core-memory.d.ts +28 -0
- package/dist/memory/core-memory.d.ts.map +1 -0
- package/dist/memory/core-memory.js +102 -0
- package/dist/memory/core-memory.js.map +1 -0
- package/dist/memory/embeddings.d.ts +44 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +139 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/search.d.ts +49 -0
- package/dist/memory/search.d.ts.map +1 -0
- package/dist/memory/search.js +97 -0
- package/dist/memory/search.js.map +1 -0
- package/dist/memory/store.d.ts +32 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +205 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/message-queue.d.ts +73 -0
- package/dist/message-queue.d.ts.map +1 -0
- package/dist/message-queue.js +188 -0
- package/dist/message-queue.js.map +1 -0
- package/dist/model-infra.d.ts +64 -0
- package/dist/model-infra.d.ts.map +1 -0
- package/dist/model-infra.js +202 -0
- package/dist/model-infra.js.map +1 -0
- package/dist/projection/format.d.ts +10 -0
- package/dist/projection/format.d.ts.map +1 -0
- package/dist/projection/format.js +30 -0
- package/dist/projection/format.js.map +1 -0
- package/dist/projection/index.d.ts +11 -0
- package/dist/projection/index.d.ts.map +1 -0
- package/dist/projection/index.js +9 -0
- package/dist/projection/index.js.map +1 -0
- package/dist/projection/reflection.d.ts +94 -0
- package/dist/projection/reflection.d.ts.map +1 -0
- package/dist/projection/reflection.js +334 -0
- package/dist/projection/reflection.js.map +1 -0
- package/dist/projection/store.d.ts +144 -0
- package/dist/projection/store.d.ts.map +1 -0
- package/dist/projection/store.js +519 -0
- package/dist/projection/store.js.map +1 -0
- package/dist/projection/tools.d.ts +11 -0
- package/dist/projection/tools.d.ts.map +1 -0
- package/dist/projection/tools.js +237 -0
- package/dist/projection/tools.js.map +1 -0
- package/dist/scheduler.d.ts +36 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +286 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/system-prompt.d.ts +41 -0
- package/dist/system-prompt.d.ts.map +1 -0
- package/dist/system-prompt.js +162 -0
- package/dist/system-prompt.js.map +1 -0
- package/dist/time.d.ts +52 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +138 -0
- package/dist/time.js.map +1 -0
- package/dist/tools/archival-memory-tool.d.ts +8 -0
- package/dist/tools/archival-memory-tool.d.ts.map +1 -0
- package/dist/tools/archival-memory-tool.js +68 -0
- package/dist/tools/archival-memory-tool.js.map +1 -0
- package/dist/tools/conversation-search-tool.d.ts +6 -0
- package/dist/tools/conversation-search-tool.d.ts.map +1 -0
- package/dist/tools/conversation-search-tool.js +28 -0
- package/dist/tools/conversation-search-tool.js.map +1 -0
- package/dist/tools/core-memory-tool.d.ts +7 -0
- package/dist/tools/core-memory-tool.d.ts.map +1 -0
- package/dist/tools/core-memory-tool.js +59 -0
- package/dist/tools/core-memory-tool.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +15 -0
- package/dist/tools/fetch-url.d.ts.map +1 -0
- package/dist/tools/fetch-url.js +76 -0
- package/dist/tools/fetch-url.js.map +1 -0
- package/dist/tools/files.d.ts +10 -0
- package/dist/tools/files.d.ts.map +1 -0
- package/dist/tools/files.js +127 -0
- package/dist/tools/files.js.map +1 -0
- package/dist/tools/index.d.ts +17 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +118 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/result.d.ts +21 -0
- package/dist/tools/result.d.ts.map +1 -0
- package/dist/tools/result.js +36 -0
- package/dist/tools/result.js.map +1 -0
- package/dist/tools/skill-install.d.ts +17 -0
- package/dist/tools/skill-install.d.ts.map +1 -0
- package/dist/tools/skill-install.js +148 -0
- package/dist/tools/skill-install.js.map +1 -0
- package/dist/tools/web-search.d.ts +42 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +237 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/trust/guardrail.d.ts +60 -0
- package/dist/trust/guardrail.d.ts.map +1 -0
- package/dist/trust/guardrail.js +171 -0
- package/dist/trust/guardrail.js.map +1 -0
- package/dist/trust/index.d.ts +12 -0
- package/dist/trust/index.d.ts.map +1 -0
- package/dist/trust/index.js +12 -0
- package/dist/trust/index.js.map +1 -0
- package/dist/trust/store.d.ts +118 -0
- package/dist/trust/store.d.ts.map +1 -0
- package/dist/trust/store.js +209 -0
- package/dist/trust/store.js.map +1 -0
- package/dist/trust/wrapper.d.ts +36 -0
- package/dist/trust/wrapper.d.ts.map +1 -0
- package/dist/trust/wrapper.js +142 -0
- package/dist/trust/wrapper.js.map +1 -0
- package/dist/usage.d.ts +53 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +124 -0
- package/dist/usage.js.map +1 -0
- package/dist/util/math.d.ts +9 -0
- package/dist/util/math.d.ts.map +1 -0
- package/dist/util/math.js +22 -0
- package/dist/util/math.js.map +1 -0
- package/dist/util/ssrf.d.ts +21 -0
- package/dist/util/ssrf.d.ts.map +1 -0
- package/dist/util/ssrf.js +77 -0
- package/dist/util/ssrf.js.map +1 -0
- package/dist/workers/index.d.ts +8 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +7 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/registry.d.ts +53 -0
- package/dist/workers/registry.d.ts.map +1 -0
- package/dist/workers/registry.js +38 -0
- package/dist/workers/registry.js.map +1 -0
- package/dist/workers/scoped-tools.d.ts +21 -0
- package/dist/workers/scoped-tools.d.ts.map +1 -0
- package/dist/workers/scoped-tools.js +111 -0
- package/dist/workers/scoped-tools.js.map +1 -0
- package/dist/workers/spawn.d.ts +62 -0
- package/dist/workers/spawn.d.ts.map +1 -0
- package/dist/workers/spawn.js +314 -0
- package/dist/workers/spawn.js.map +1 -0
- package/dist/workers/tools.d.ts +26 -0
- package/dist/workers/tools.d.ts.map +1 -0
- package/dist/workers/tools.js +380 -0
- package/dist/workers/tools.js.map +1 -0
- package/docker-compose.yml +72 -0
- package/package.json +16 -1
- package/run.sh +27 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-channel FIFO message queue with merge and backpressure.
|
|
3
|
+
*
|
|
4
|
+
* Two core guarantees:
|
|
5
|
+
*
|
|
6
|
+
* 1. Per-channel serialization: only one message is processed at a time per
|
|
7
|
+
* channel. Subsequent messages queue up behind it rather than racing into
|
|
8
|
+
* the agent loop in parallel.
|
|
9
|
+
*
|
|
10
|
+
* 2. Burst merging: rapid-fire messages that arrive within MERGE_WINDOW_MS of
|
|
11
|
+
* each other are joined into a single prompt before being dispatched. This
|
|
12
|
+
* handles the common "user sends three quick messages" pattern without the
|
|
13
|
+
* agent seeing three separate incomplete thoughts.
|
|
14
|
+
*
|
|
15
|
+
* New messages queue up to MAX_DEPTH; beyond that the caller gets a rejection
|
|
16
|
+
* callback (backpressure signal, not silent drop).
|
|
17
|
+
*/
|
|
18
|
+
const MAX_DEPTH = 10;
|
|
19
|
+
// 2-3 seconds is the sweet spot: fast enough that the user experiences a
|
|
20
|
+
// single response (not noticeable delay), long enough to catch split messages
|
|
21
|
+
// that arrive in separate network frames. The current 5s value is conservative
|
|
22
|
+
// and can be tuned down if latency matters more.
|
|
23
|
+
const MERGE_WINDOW_MS = 5000;
|
|
24
|
+
const RATE_LIMIT_MAX = 10;
|
|
25
|
+
const RATE_LIMIT_WINDOW_MS = 60_000;
|
|
26
|
+
/**
|
|
27
|
+
* Sliding window rate limiter. Tracks timestamps of recent messages per user
|
|
28
|
+
* and rejects when the limit is exceeded.
|
|
29
|
+
*/
|
|
30
|
+
class RateLimiter {
|
|
31
|
+
maxMessages;
|
|
32
|
+
windowMs;
|
|
33
|
+
windows = new Map();
|
|
34
|
+
constructor(maxMessages, windowMs) {
|
|
35
|
+
this.maxMessages = maxMessages;
|
|
36
|
+
this.windowMs = windowMs;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if a message from this user should be allowed.
|
|
40
|
+
* Returns true if allowed, false if rate-limited.
|
|
41
|
+
*/
|
|
42
|
+
check(userId) {
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
const cutoff = now - this.windowMs;
|
|
45
|
+
let timestamps = this.windows.get(userId);
|
|
46
|
+
if (!timestamps) {
|
|
47
|
+
timestamps = [];
|
|
48
|
+
this.windows.set(userId, timestamps);
|
|
49
|
+
}
|
|
50
|
+
// Prune old entries
|
|
51
|
+
while (timestamps.length > 0 && timestamps[0] < cutoff) {
|
|
52
|
+
timestamps.shift();
|
|
53
|
+
}
|
|
54
|
+
if (timestamps.length >= this.maxMessages) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
timestamps.push(now);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Serialises processing per channel and merges rapid follow-up messages.
|
|
63
|
+
*/
|
|
64
|
+
export class MessageQueue {
|
|
65
|
+
queues = new Map();
|
|
66
|
+
processFn;
|
|
67
|
+
rejectFn;
|
|
68
|
+
maxDepth;
|
|
69
|
+
mergeWindowMs;
|
|
70
|
+
rateLimiter;
|
|
71
|
+
constructor(processFn, rejectFn, maxDepth = MAX_DEPTH, mergeWindowMs = MERGE_WINDOW_MS) {
|
|
72
|
+
this.processFn = processFn;
|
|
73
|
+
this.rejectFn = rejectFn;
|
|
74
|
+
this.maxDepth = maxDepth;
|
|
75
|
+
this.mergeWindowMs = mergeWindowMs;
|
|
76
|
+
this.rateLimiter = new RateLimiter(RATE_LIMIT_MAX, RATE_LIMIT_WINDOW_MS);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Enqueue a message. If nothing is processing for this channel, starts
|
|
80
|
+
* draining immediately. Rate-limited per user (10 messages/minute).
|
|
81
|
+
*/
|
|
82
|
+
enqueue(msg) {
|
|
83
|
+
const key = msg.channelId;
|
|
84
|
+
// Rate limiting: skip for internal messages (worker triggers, scheduler)
|
|
85
|
+
const rawObj = msg.raw;
|
|
86
|
+
const isInternal = rawObj?.type != null;
|
|
87
|
+
if (!isInternal && !this.rateLimiter.check(msg.userId)) {
|
|
88
|
+
console.warn(`[queue] Rate limit exceeded for user ${msg.userId}`);
|
|
89
|
+
this.rejectFn(msg).catch((err) => console.error("rejectFn error:", err));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let q = this.queues.get(key);
|
|
93
|
+
if (!q) {
|
|
94
|
+
q = { entries: [], processing: false };
|
|
95
|
+
this.queues.set(key, q);
|
|
96
|
+
}
|
|
97
|
+
if (q.entries.length >= this.maxDepth) {
|
|
98
|
+
// Queue full: invoke the rejection callback immediately and return without
|
|
99
|
+
// enqueuing. This is a backpressure signal to the caller — the message is
|
|
100
|
+
// not silently dropped, but it is not queued either. The caller decides
|
|
101
|
+
// how to respond (e.g., send "I'm busy" to the user).
|
|
102
|
+
this.rejectFn(msg).catch((err) => console.error("rejectFn error:", err));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
q.entries.push({ msg, arrivedAt: Date.now() });
|
|
106
|
+
if (!q.processing) {
|
|
107
|
+
this.drain(key).catch((err) => console.error("Queue drain error:", err));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Drain the queue for a channel sequentially, merging close messages.
|
|
112
|
+
*/
|
|
113
|
+
async drain(key) {
|
|
114
|
+
const q = this.queues.get(key);
|
|
115
|
+
if (!q)
|
|
116
|
+
return;
|
|
117
|
+
q.processing = true;
|
|
118
|
+
while (q.entries.length > 0) {
|
|
119
|
+
const batch = this.takeMergeBatch(q);
|
|
120
|
+
const merged = this.mergeEntries(batch);
|
|
121
|
+
try {
|
|
122
|
+
await this.processFn(merged);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
console.error("processMessage error:", err);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
q.processing = false;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Take a batch of entries that should be merged together.
|
|
132
|
+
*
|
|
133
|
+
* The first entry is always included. Additional entries are included if they
|
|
134
|
+
* arrived within mergeWindowMs of the FIRST entry in the batch. This is a
|
|
135
|
+
* fixed window anchored to the first message, not a sliding window — an
|
|
136
|
+
* entry that arrives 1ms after the previous one is still excluded if it
|
|
137
|
+
* falls outside the window from the first entry.
|
|
138
|
+
*/
|
|
139
|
+
takeMergeBatch(q) {
|
|
140
|
+
const batch = [];
|
|
141
|
+
const first = q.entries.shift();
|
|
142
|
+
batch.push(first);
|
|
143
|
+
while (q.entries.length > 0) {
|
|
144
|
+
const next = q.entries[0];
|
|
145
|
+
if (next.arrivedAt - first.arrivedAt <= this.mergeWindowMs) {
|
|
146
|
+
batch.push(q.entries.shift());
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return batch;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Merge multiple queue entries into a single IncomingMessage by joining
|
|
156
|
+
* their text with newlines. Metadata (userId, channelId, platform, etc.) is
|
|
157
|
+
* taken from the first entry.
|
|
158
|
+
*
|
|
159
|
+
* Note: images (and other non-text attachments) from subsequent burst
|
|
160
|
+
* entries are currently dropped — only their text is merged.
|
|
161
|
+
* TODO: carry images from all burst entries into the merged message.
|
|
162
|
+
*/
|
|
163
|
+
mergeEntries(entries) {
|
|
164
|
+
if (entries.length === 1) {
|
|
165
|
+
return entries[0].msg;
|
|
166
|
+
}
|
|
167
|
+
const texts = entries.map((e) => e.msg.text).filter(Boolean);
|
|
168
|
+
return {
|
|
169
|
+
...entries[0].msg,
|
|
170
|
+
text: texts.join("\n"),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Number of queued (not-yet-processing) messages for a channel.
|
|
175
|
+
* Exposed for monitoring dashboards and unit tests.
|
|
176
|
+
*/
|
|
177
|
+
queueDepth(channelId) {
|
|
178
|
+
return this.queues.get(channelId)?.entries.length ?? 0;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Whether the channel is currently mid-process (drain loop running).
|
|
182
|
+
* Exposed for monitoring dashboards and unit tests.
|
|
183
|
+
*/
|
|
184
|
+
isProcessing(channelId) {
|
|
185
|
+
return this.queues.get(channelId)?.processing ?? false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=message-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-queue.js","sourceRoot":"","sources":["../src/message-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared model infrastructure: AuthStorage, ModelRegistry, models.json
|
|
3
|
+
* generation, and model string resolution. Used by the main agent, workers,
|
|
4
|
+
* reflection, and the guardrail.
|
|
5
|
+
*
|
|
6
|
+
* This module does three things:
|
|
7
|
+
* 1. Generates models.json from bryti config so pi's ModelRegistry
|
|
8
|
+
* discovers all configured providers and models.
|
|
9
|
+
* 2. Sets up AuthStorage, bridging Claude CLI credentials and pi auth.json
|
|
10
|
+
* so every LLM caller gets tokens without extra wiring.
|
|
11
|
+
* 3. Exposes model resolution helpers (resolveModel, resolveFirstModel)
|
|
12
|
+
* that translate "provider/modelId" config strings into registry Model
|
|
13
|
+
* objects with fuzzy fallback.
|
|
14
|
+
*
|
|
15
|
+
* These three concerns live together because every LLM-calling component
|
|
16
|
+
* (agent, workers, reflection, guardrail) needs all three: without models.json
|
|
17
|
+
* the registry has nothing to load; without AuthStorage the registry cannot
|
|
18
|
+
* authenticate; without resolution helpers callers cannot turn config strings
|
|
19
|
+
* into actual Model objects.
|
|
20
|
+
*/
|
|
21
|
+
import type { Model } from "@mariozechner/pi-ai";
|
|
22
|
+
import { AuthStorage, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
23
|
+
import type { Config } from "./config.js";
|
|
24
|
+
export interface ModelInfra {
|
|
25
|
+
authStorage: AuthStorage;
|
|
26
|
+
modelRegistry: ModelRegistry;
|
|
27
|
+
agentDir: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create the auth and model registry infrastructure from config. Generates
|
|
31
|
+
* models.json, sets up AuthStorage with runtime API keys, and initializes
|
|
32
|
+
* ModelRegistry. Shared by everything that talks to an LLM.
|
|
33
|
+
*
|
|
34
|
+
* Auth priority for Anthropic:
|
|
35
|
+
* 1. Claude CLI credentials (~/.claude/.credentials.json) — primary source
|
|
36
|
+
* 2. Pi auth.json (~/.pi/agent/auth.json) — fallback for pi CLI users
|
|
37
|
+
* 3. Explicit api_key in config — always wins as a runtime override
|
|
38
|
+
*/
|
|
39
|
+
export declare function createModelInfra(config: Config): ModelInfra;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a "provider/modelId" string against the registry.
|
|
42
|
+
*
|
|
43
|
+
* Resolution order:
|
|
44
|
+
* 1. Exact match via ModelRegistry.find(provider, modelId).
|
|
45
|
+
* 2. Fuzzy match: scans all available models for one whose id contains
|
|
46
|
+
* modelId as a substring. This handles cases where model IDs in the
|
|
47
|
+
* registry include version suffixes (e.g. "claude-3-5-sonnet-20241022")
|
|
48
|
+
* that the shorter config string ("claude-3-5-sonnet") doesn't carry.
|
|
49
|
+
*
|
|
50
|
+
* Returns null if neither strategy finds a match.
|
|
51
|
+
*/
|
|
52
|
+
export declare function resolveModel(modelString: string, modelRegistry: ModelRegistry): Model<any> | null;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the first usable model from an ordered list of "provider/modelId"
|
|
55
|
+
* candidate strings.
|
|
56
|
+
*
|
|
57
|
+
* Used by the guardrail to pick a model without requiring a full config
|
|
58
|
+
* context: it passes its ordered preference list and gets back whatever is
|
|
59
|
+
* actually available in the registry. Returns the first successful resolution,
|
|
60
|
+
* not the "best" or highest-capability model. Returns null if no candidate
|
|
61
|
+
* resolves.
|
|
62
|
+
*/
|
|
63
|
+
export declare function resolveFirstModel(candidates: string[], modelRegistry: ModelRegistry): Model<any> | null;
|
|
64
|
+
//# sourceMappingURL=model-infra.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-infra.d.ts","sourceRoot":"","sources":["../src/model-infra.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EACL,WAAW,EACX,aAAa,EACd,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAM1C,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAwID;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAyB3D;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,aAAa,GAC3B,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAanB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAAE,EACpB,aAAa,EAAE,aAAa,GAC3B,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAMnB"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared model infrastructure: AuthStorage, ModelRegistry, models.json
|
|
3
|
+
* generation, and model string resolution. Used by the main agent, workers,
|
|
4
|
+
* reflection, and the guardrail.
|
|
5
|
+
*
|
|
6
|
+
* This module does three things:
|
|
7
|
+
* 1. Generates models.json from bryti config so pi's ModelRegistry
|
|
8
|
+
* discovers all configured providers and models.
|
|
9
|
+
* 2. Sets up AuthStorage, bridging Claude CLI credentials and pi auth.json
|
|
10
|
+
* so every LLM caller gets tokens without extra wiring.
|
|
11
|
+
* 3. Exposes model resolution helpers (resolveModel, resolveFirstModel)
|
|
12
|
+
* that translate "provider/modelId" config strings into registry Model
|
|
13
|
+
* objects with fuzzy fallback.
|
|
14
|
+
*
|
|
15
|
+
* These three concerns live together because every LLM-calling component
|
|
16
|
+
* (agent, workers, reflection, guardrail) needs all three: without models.json
|
|
17
|
+
* the registry has nothing to load; without AuthStorage the registry cannot
|
|
18
|
+
* authenticate; without resolution helpers callers cannot turn config strings
|
|
19
|
+
* into actual Model objects.
|
|
20
|
+
*/
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import os from "node:os";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import { AuthStorage, ModelRegistry, } from "@mariozechner/pi-coding-agent";
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// models.json generation
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Generate models.json from bryti config so pi's ModelRegistry discovers
|
|
30
|
+
* all configured providers and models.
|
|
31
|
+
*/
|
|
32
|
+
function generateModelsJson(config, agentDir) {
|
|
33
|
+
const modelsJsonPath = path.join(agentDir, "models.json");
|
|
34
|
+
const providers = {};
|
|
35
|
+
for (const provider of config.models.providers) {
|
|
36
|
+
if (provider.name === "groq") {
|
|
37
|
+
// Groq's provider format is not currently compatible with the SDK's
|
|
38
|
+
// openai-completions adapter (auth header shape differs). Skipping
|
|
39
|
+
// prevents ModelRegistry from producing broken entries.
|
|
40
|
+
// TODO: revisit once the SDK adds a native Groq adapter.
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Providers without an api_key use OAuth from ~/.pi/agent/auth.json.
|
|
44
|
+
// We still need to include them in models.json so custom model IDs
|
|
45
|
+
// (not yet in SDK built-ins) are discoverable.
|
|
46
|
+
// Use "oauth" as a placeholder apiKey: pi's auth.json holds the real token
|
|
47
|
+
// and AuthStorage resolves it at call time, but ModelRegistry requires a
|
|
48
|
+
// non-empty apiKey field to accept the entry at all.
|
|
49
|
+
const apiKey = provider.api_key || "oauth";
|
|
50
|
+
providers[provider.name] = {
|
|
51
|
+
baseUrl: provider.base_url || `https://api.${provider.name}.com`,
|
|
52
|
+
api: provider.api || "openai-completions",
|
|
53
|
+
apiKey: apiKey,
|
|
54
|
+
models: provider.models.map((m) => ({
|
|
55
|
+
id: m.id,
|
|
56
|
+
name: m.name || m.id,
|
|
57
|
+
contextWindow: m.context_window || 200000,
|
|
58
|
+
maxTokens: m.max_tokens || 32000,
|
|
59
|
+
input: m.input ?? ["text", "image"],
|
|
60
|
+
...(m.api && { api: m.api }),
|
|
61
|
+
...(m.cost && { cost: m.cost }),
|
|
62
|
+
...(m.compat && { compat: m.compat }),
|
|
63
|
+
})),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
fs.writeFileSync(modelsJsonPath, JSON.stringify({ providers }, null, 2), "utf-8");
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Seed AuthStorage with Anthropic credentials from the Claude CLI credential
|
|
70
|
+
* file (~/.claude/.credentials.json) if no Anthropic credential is already
|
|
71
|
+
* present in auth.json.
|
|
72
|
+
*
|
|
73
|
+
* Claude CLI is the primary auth source for users who have it installed.
|
|
74
|
+
* Pi auth.json is used as the fallback (for users who logged in via `pi login`).
|
|
75
|
+
*
|
|
76
|
+
* Once seeded, pi's AuthStorage manages the refresh lifecycle going forward:
|
|
77
|
+
* it will auto-refresh the token using the refresh token when it expires.
|
|
78
|
+
*
|
|
79
|
+
* Credential format conversion:
|
|
80
|
+
* Claude CLI stores { accessToken, refreshToken, expiresAt } under the
|
|
81
|
+
* "claudeAiOauth" key. Pi expects { type: "oauth", access, refresh, expires }.
|
|
82
|
+
* The field names are remapped here; the values are passed through unchanged.
|
|
83
|
+
*
|
|
84
|
+
* This function is called before runtime overrides are applied (setRuntimeApiKey),
|
|
85
|
+
* so an explicit api_key in config always wins over the seeded credential.
|
|
86
|
+
*/
|
|
87
|
+
function seedFromClaudeCliIfNeeded(authStorage) {
|
|
88
|
+
// Already have Anthropic creds — nothing to do
|
|
89
|
+
if (authStorage.has("anthropic")) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const claudeCredPath = path.join(os.homedir(), ".claude", ".credentials.json");
|
|
93
|
+
let raw;
|
|
94
|
+
try {
|
|
95
|
+
raw = fs.readFileSync(claudeCredPath, "utf-8");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// File doesn't exist or isn't readable — Claude CLI not installed
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
let parsed;
|
|
102
|
+
try {
|
|
103
|
+
parsed = JSON.parse(raw);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
console.warn("[auth] ~/.claude/.credentials.json is not valid JSON, skipping");
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const creds = parsed.claudeAiOauth;
|
|
110
|
+
if (!creds?.accessToken || !creds?.refreshToken) {
|
|
111
|
+
console.warn("[auth] ~/.claude/.credentials.json has no usable claudeAiOauth credentials, skipping");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Convert Claude CLI format → pi AuthStorage OAuthCredential format:
|
|
115
|
+
// Claude CLI: { accessToken, refreshToken, expiresAt }
|
|
116
|
+
// pi: { type: "oauth", access, refresh, expires }
|
|
117
|
+
authStorage.set("anthropic", {
|
|
118
|
+
type: "oauth",
|
|
119
|
+
access: creds.accessToken,
|
|
120
|
+
refresh: creds.refreshToken,
|
|
121
|
+
expires: creds.expiresAt ?? Date.now(),
|
|
122
|
+
});
|
|
123
|
+
console.log("[auth] Seeded Anthropic credentials from Claude CLI (~/.claude/.credentials.json)");
|
|
124
|
+
}
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
// Infrastructure creation
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
/**
|
|
129
|
+
* Create the auth and model registry infrastructure from config. Generates
|
|
130
|
+
* models.json, sets up AuthStorage with runtime API keys, and initializes
|
|
131
|
+
* ModelRegistry. Shared by everything that talks to an LLM.
|
|
132
|
+
*
|
|
133
|
+
* Auth priority for Anthropic:
|
|
134
|
+
* 1. Claude CLI credentials (~/.claude/.credentials.json) — primary source
|
|
135
|
+
* 2. Pi auth.json (~/.pi/agent/auth.json) — fallback for pi CLI users
|
|
136
|
+
* 3. Explicit api_key in config — always wins as a runtime override
|
|
137
|
+
*/
|
|
138
|
+
export function createModelInfra(config) {
|
|
139
|
+
const agentDir = path.join(config.data_dir, ".pi");
|
|
140
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
141
|
+
generateModelsJson(config, agentDir);
|
|
142
|
+
// Auth: start with ~/.pi/agent/auth.json (pi CLI OAuth creds), then
|
|
143
|
+
// seed from Claude CLI if no Anthropic credential is present there.
|
|
144
|
+
// AuthStorage uses file-level locking so concurrent token refreshes are safe.
|
|
145
|
+
const authStorage = new AuthStorage();
|
|
146
|
+
// Seed from Claude CLI before applying runtime overrides, so an explicit
|
|
147
|
+
// api_key in config still wins (setRuntimeApiKey takes precedence).
|
|
148
|
+
seedFromClaudeCliIfNeeded(authStorage);
|
|
149
|
+
for (const provider of config.models.providers) {
|
|
150
|
+
if (provider.api_key) {
|
|
151
|
+
authStorage.setRuntimeApiKey(provider.name, provider.api_key);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const modelRegistry = new ModelRegistry(authStorage, path.join(agentDir, "models.json"));
|
|
155
|
+
modelRegistry.refresh();
|
|
156
|
+
return { authStorage, modelRegistry, agentDir };
|
|
157
|
+
}
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
// Model resolution
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
/**
|
|
162
|
+
* Resolve a "provider/modelId" string against the registry.
|
|
163
|
+
*
|
|
164
|
+
* Resolution order:
|
|
165
|
+
* 1. Exact match via ModelRegistry.find(provider, modelId).
|
|
166
|
+
* 2. Fuzzy match: scans all available models for one whose id contains
|
|
167
|
+
* modelId as a substring. This handles cases where model IDs in the
|
|
168
|
+
* registry include version suffixes (e.g. "claude-3-5-sonnet-20241022")
|
|
169
|
+
* that the shorter config string ("claude-3-5-sonnet") doesn't carry.
|
|
170
|
+
*
|
|
171
|
+
* Returns null if neither strategy finds a match.
|
|
172
|
+
*/
|
|
173
|
+
export function resolveModel(modelString, modelRegistry) {
|
|
174
|
+
const [providerName, modelId] = modelString.includes("/")
|
|
175
|
+
? modelString.split("/")
|
|
176
|
+
: [modelString, modelString];
|
|
177
|
+
let model = modelRegistry.find(providerName, modelId);
|
|
178
|
+
if (!model) {
|
|
179
|
+
const available = modelRegistry.getAvailable();
|
|
180
|
+
model = available.find((m) => m.provider === providerName && m.id.includes(modelId));
|
|
181
|
+
}
|
|
182
|
+
return model ?? null;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Resolve the first usable model from an ordered list of "provider/modelId"
|
|
186
|
+
* candidate strings.
|
|
187
|
+
*
|
|
188
|
+
* Used by the guardrail to pick a model without requiring a full config
|
|
189
|
+
* context: it passes its ordered preference list and gets back whatever is
|
|
190
|
+
* actually available in the registry. Returns the first successful resolution,
|
|
191
|
+
* not the "best" or highest-capability model. Returns null if no candidate
|
|
192
|
+
* resolves.
|
|
193
|
+
*/
|
|
194
|
+
export function resolveFirstModel(candidates, modelRegistry) {
|
|
195
|
+
for (const candidate of candidates) {
|
|
196
|
+
const model = resolveModel(candidate, modelRegistry);
|
|
197
|
+
if (model)
|
|
198
|
+
return model;
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=model-infra.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-infra.js","sourceRoot":"","sources":["../src/model-infra.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format projections for system prompt injection.
|
|
3
|
+
*/
|
|
4
|
+
import type { Projection } from "./store.js";
|
|
5
|
+
/**
|
|
6
|
+
* Render a short projection list suitable for inclusion in the system prompt.
|
|
7
|
+
* Capped at maxItems to avoid crowding context.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatProjectionsForPrompt(projections: Projection[], maxItems?: number): string;
|
|
10
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/projection/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,QAAQ,SAAK,GAAG,MAAM,CAwB3F"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format projections for system prompt injection.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Render a short projection list suitable for inclusion in the system prompt.
|
|
6
|
+
* Capped at maxItems to avoid crowding context.
|
|
7
|
+
*/
|
|
8
|
+
export function formatProjectionsForPrompt(projections, maxItems = 15) {
|
|
9
|
+
if (projections.length === 0) {
|
|
10
|
+
return "No upcoming projections.";
|
|
11
|
+
}
|
|
12
|
+
const capped = projections.slice(0, maxItems);
|
|
13
|
+
const lines = capped.map((p) => {
|
|
14
|
+
const when = p.trigger_on_fact
|
|
15
|
+
? `[waiting for: "${p.trigger_on_fact}"]`
|
|
16
|
+
: p.resolved_when
|
|
17
|
+
? `[${p.resolved_when.slice(0, 16)}, ${p.resolution}]`
|
|
18
|
+
: p.raw_when
|
|
19
|
+
? `[${p.raw_when}, ${p.resolution}]`
|
|
20
|
+
: `[someday]`;
|
|
21
|
+
const recur = p.recurrence ? ` [recurring: ${p.recurrence}]` : "";
|
|
22
|
+
const ctx = p.context ? ` — ${p.context}` : "";
|
|
23
|
+
return `- ${when}${recur} ${p.summary}${ctx} (id: ${p.id})`;
|
|
24
|
+
});
|
|
25
|
+
const overflow = projections.length > maxItems
|
|
26
|
+
? `\n(${projections.length - maxItems} more — use projection_list to see all)`
|
|
27
|
+
: "";
|
|
28
|
+
return lines.join("\n") + overflow;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/projection/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,WAAyB,EAAE,QAAQ,GAAG,EAAE;IACjF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,0BAA0B,CAAC;IACpC,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,eAAe;YAC5B,CAAC,CAAC,kBAAkB,CAAC,CAAC,eAAe,IAAI;YACzC,CAAC,CAAC,CAAC,CAAC,aAAa;gBACf,CAAC,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG;gBACtD,CAAC,CAAC,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,UAAU,GAAG;oBACpC,CAAC,CAAC,WAAW,CAAC;QACpB,MAAM,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,OAAO,GAAG,GAAG,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,GAAG,QAAQ;QAC5C,CAAC,CAAC,MAAM,WAAW,CAAC,MAAM,GAAG,QAAQ,yCAAyC;QAC9E,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projection: forward-looking agent memory.
|
|
3
|
+
* Memory answers "what do I know?"; projection answers "what do I expect?"
|
|
4
|
+
*/
|
|
5
|
+
export { createProjectionStore } from "./store.js";
|
|
6
|
+
export type { Projection, ProjectionResolution, ProjectionStatus, ProjectionStore, ProjectionDependency, ProjectionDependencyInput, DependencyConditionType, } from "./store.js";
|
|
7
|
+
export { formatProjectionsForPrompt } from "./format.js";
|
|
8
|
+
export { createProjectionTools } from "./tools.js";
|
|
9
|
+
export { runReflection } from "./reflection.js";
|
|
10
|
+
export type { ReflectionResult } from "./reflection.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EACV,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projection: forward-looking agent memory.
|
|
3
|
+
* Memory answers "what do I know?"; projection answers "what do I expect?"
|
|
4
|
+
*/
|
|
5
|
+
export { createProjectionStore } from "./store.js";
|
|
6
|
+
export { formatProjectionsForPrompt } from "./format.js";
|
|
7
|
+
export { createProjectionTools } from "./tools.js";
|
|
8
|
+
export { runReflection } from "./reflection.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/projection/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAUnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Projection reflection pass.
|
|
3
|
+
*
|
|
4
|
+
* Lightweight background job that scans recent conversation history for
|
|
5
|
+
* future references the agent missed during live chat.
|
|
6
|
+
*
|
|
7
|
+
* Runs every 30 min via cron. Reads the JSONL audit log, makes a single
|
|
8
|
+
* completeSimple() call with a narrow extraction prompt (no agent loop,
|
|
9
|
+
* no tools), parses the JSON output, and writes projections directly to
|
|
10
|
+
* SQLite. Existing pending projections are included in the prompt so the
|
|
11
|
+
* model won't duplicate them. A per-user timestamp tracks the last run
|
|
12
|
+
* to skip unchanged transcripts.
|
|
13
|
+
*
|
|
14
|
+
* Why completeSimple() instead of a full agent loop?
|
|
15
|
+
* The reflection pass has no side effects and requires no tool calls. It only
|
|
16
|
+
* needs one prompt in and one JSON blob out. Using a full agent loop would add
|
|
17
|
+
* latency, cost, and the risk of unintended tool invocations. completeSimple()
|
|
18
|
+
* is cheaper, faster, and keeps the pass strictly read-only from the model's
|
|
19
|
+
* perspective.
|
|
20
|
+
*/
|
|
21
|
+
import type { Config } from "../config.js";
|
|
22
|
+
import type { ProjectionResolution, ProjectionStore } from "./store.js";
|
|
23
|
+
export interface ProjectionCandidate {
|
|
24
|
+
summary: string;
|
|
25
|
+
when?: string;
|
|
26
|
+
resolution?: ProjectionResolution;
|
|
27
|
+
context?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ArchiveCandidate {
|
|
30
|
+
content: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ReflectionOutput {
|
|
33
|
+
project: ProjectionCandidate[];
|
|
34
|
+
/**
|
|
35
|
+
* TODO: archive candidates are extracted from the LLM output but are not
|
|
36
|
+
* currently written anywhere. This field is a placeholder for a future
|
|
37
|
+
* feature that would auto-insert noteworthy facts into archival memory
|
|
38
|
+
* during the reflection pass.
|
|
39
|
+
*/
|
|
40
|
+
archive: ArchiveCandidate[];
|
|
41
|
+
}
|
|
42
|
+
export interface ReflectionResult {
|
|
43
|
+
/** Number of projections written to the store. */
|
|
44
|
+
projectionsAdded: number;
|
|
45
|
+
/** Raw candidates extracted (before dedup). */
|
|
46
|
+
candidates: ProjectionCandidate[];
|
|
47
|
+
/** Whether reflection was skipped (no new messages). */
|
|
48
|
+
skipped: boolean;
|
|
49
|
+
/** Reason for skipping, if applicable. */
|
|
50
|
+
skipReason?: string;
|
|
51
|
+
}
|
|
52
|
+
interface HistoryEntry {
|
|
53
|
+
role: "user" | "assistant" | "system" | "tool";
|
|
54
|
+
content: string;
|
|
55
|
+
timestamp: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Read user+assistant messages from the JSONL audit log for the last
|
|
59
|
+
* `windowMinutes`. Returns entries in chronological order, capped at
|
|
60
|
+
* `maxMessages`.
|
|
61
|
+
*
|
|
62
|
+
* Reads from the JSONL audit log written by src/compaction/history.ts, NOT
|
|
63
|
+
* from the pi SDK session file. The audit log is the only way to get
|
|
64
|
+
* structured turn-by-turn history outside of a live session context: the pi
|
|
65
|
+
* session file is append-only and interleaved with tool scaffolding, whereas
|
|
66
|
+
* the audit log contains clean role/content/timestamp records per message.
|
|
67
|
+
*/
|
|
68
|
+
export declare function readRecentHistory(historyDir: string, windowMinutes: number, maxMessages?: number): HistoryEntry[];
|
|
69
|
+
interface CompletionMessage {
|
|
70
|
+
role: "system" | "user";
|
|
71
|
+
content: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Single chat completion via the pi SDK provider layer. Uses reflection_model
|
|
75
|
+
* if configured, otherwise falls back to the primary model and then the
|
|
76
|
+
* fallback chain. This lets operators use a cheaper model for reflection.
|
|
77
|
+
*/
|
|
78
|
+
export declare function sdkComplete(config: Config, messages: CompletionMessage[]): Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Parse the LLM output, tolerating markdown code fences and minor formatting.
|
|
81
|
+
*
|
|
82
|
+
* Even with `temperature: 0` and an explicit "output JSON only" instruction,
|
|
83
|
+
* models occasionally wrap their response in a ```json ... ``` code fence.
|
|
84
|
+
* The stripping step removes those fences before calling JSON.parse(), so
|
|
85
|
+
* both bare JSON and fenced JSON are accepted.
|
|
86
|
+
*/
|
|
87
|
+
export declare function parseReflectionOutput(raw: string): ReflectionOutput;
|
|
88
|
+
/**
|
|
89
|
+
* Run one reflection pass for a user. Reads recent conversation, extracts
|
|
90
|
+
* future references via LLM, and writes new projections to the store.
|
|
91
|
+
*/
|
|
92
|
+
export declare function runReflection(config: Config, userId: string, windowMinutes?: number, store?: ProjectionStore, completeFn?: typeof sdkComplete): Promise<ReflectionResult>;
|
|
93
|
+
export {};
|
|
94
|
+
//# sourceMappingURL=reflection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reflection.d.ts","sourceRoot":"","sources":["../../src/projection/reflection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAUxE,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B;;;;;OAKG;IACH,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,kDAAkD;IAClD,gBAAgB,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAC;IACjB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,WAAW,SAAK,GACf,YAAY,EAAE,CAyChB;AAuCD,UAAU,iBAAiB;IACzB,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,iBAAiB,EAAE,GAC5B,OAAO,CAAC,MAAM,CAAC,CA6CjB;AA+CD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAgBnE;AAMD;;;GAGG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,aAAa,SAAK,EAClB,KAAK,CAAC,EAAE,eAAe,EACvB,UAAU,CAAC,EAAE,OAAO,WAAW,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAwH3B"}
|