@trevonistrevon/pi-loop 0.1.9 → 0.2.1
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/index.js +10 -20
- package/dist/store.d.ts +1 -1
- package/dist/store.js +5 -3
- package/package.json +1 -1
- package/src/index.ts +10 -23
- package/src/store.ts +5 -3
package/dist/index.js
CHANGED
|
@@ -30,10 +30,8 @@ function debug(...args) {
|
|
|
30
30
|
function textResult(msg) {
|
|
31
31
|
return { content: [{ type: "text", text: msg }], details: undefined };
|
|
32
32
|
}
|
|
33
|
-
const LOOP_TOOL_NAMES = new Set(["LoopCreate", "LoopList", "LoopDelete", "MonitorCreate", "MonitorList", "MonitorStop"]);
|
|
34
|
-
const REMINDER_INTERVAL = 3;
|
|
35
33
|
const SYSTEM_REMINDER_TEMPLATE = `<system-reminder>
|
|
36
|
-
Scheduled loop "%
|
|
34
|
+
Scheduled loop "%prompt%" fired. Trigger: %trigger_info%.
|
|
37
35
|
[loop:%loop_id%]
|
|
38
36
|
</system-reminder>`;
|
|
39
37
|
export default function (pi) {
|
|
@@ -150,10 +148,11 @@ export default function (pi) {
|
|
|
150
148
|
if (persistedShown)
|
|
151
149
|
return;
|
|
152
150
|
persistedShown = true;
|
|
151
|
+
const sessionStartedAt = Date.now();
|
|
153
152
|
const loops = store.list();
|
|
154
153
|
if (loops.length > 0) {
|
|
155
154
|
store.clearExpired();
|
|
156
|
-
store.expireEventLoops();
|
|
155
|
+
store.expireEventLoops(sessionStartedAt);
|
|
157
156
|
triggerSystem.start();
|
|
158
157
|
widget.update();
|
|
159
158
|
}
|
|
@@ -183,11 +182,9 @@ export default function (pi) {
|
|
|
183
182
|
showPersistedLoops(isResume);
|
|
184
183
|
});
|
|
185
184
|
// ── System-reminder injection for loop fires ──
|
|
186
|
-
let
|
|
187
|
-
let lastLoopToolUseTurn = 0;
|
|
188
|
-
let reminderInjectedThisCycle = false;
|
|
185
|
+
let canInjectReminder = true;
|
|
189
186
|
const pendingReminders = [];
|
|
190
|
-
pi.on("loop:fire", (data) => {
|
|
187
|
+
pi.events.on("loop:fire", (data) => {
|
|
191
188
|
const triggerInfo = typeof data.trigger === "string"
|
|
192
189
|
? data.trigger
|
|
193
190
|
: data.trigger?.type === "cron"
|
|
@@ -201,22 +198,15 @@ export default function (pi) {
|
|
|
201
198
|
.replace("%loop_id%", data.loopId || "unknown");
|
|
202
199
|
pendingReminders.push(reminder);
|
|
203
200
|
});
|
|
201
|
+
// Allow one reminder injection per agent turn (at the first tool call),
|
|
202
|
+
// so the reminder arrives between batches of work, not mid-execution.
|
|
204
203
|
pi.on("turn_start", async () => {
|
|
205
|
-
|
|
204
|
+
canInjectReminder = true;
|
|
206
205
|
});
|
|
207
206
|
pi.on("tool_result", async (event) => {
|
|
208
|
-
if (
|
|
209
|
-
lastLoopToolUseTurn = currentTurn;
|
|
210
|
-
reminderInjectedThisCycle = false;
|
|
207
|
+
if (!canInjectReminder || pendingReminders.length === 0)
|
|
211
208
|
return {};
|
|
212
|
-
|
|
213
|
-
if (currentTurn - lastLoopToolUseTurn < REMINDER_INTERVAL || reminderInjectedThisCycle) {
|
|
214
|
-
return {};
|
|
215
|
-
}
|
|
216
|
-
if (pendingReminders.length === 0)
|
|
217
|
-
return {};
|
|
218
|
-
reminderInjectedThisCycle = true;
|
|
219
|
-
lastLoopToolUseTurn = currentTurn;
|
|
209
|
+
canInjectReminder = false;
|
|
220
210
|
const reminder = pendingReminders.shift();
|
|
221
211
|
return {
|
|
222
212
|
content: [...event.content, { type: "text", text: reminder }],
|
package/dist/store.d.ts
CHANGED
package/dist/store.js
CHANGED
|
@@ -176,15 +176,17 @@ export class LoopStore {
|
|
|
176
176
|
return count;
|
|
177
177
|
});
|
|
178
178
|
}
|
|
179
|
-
expireEventLoops() {
|
|
179
|
+
expireEventLoops(sessionStartedAt) {
|
|
180
180
|
return this.withLock(() => {
|
|
181
181
|
let count = 0;
|
|
182
182
|
for (const [_id, entry] of this.loops) {
|
|
183
183
|
if (entry.status !== "active")
|
|
184
184
|
continue;
|
|
185
185
|
if (entry.trigger.type === "event" || entry.trigger.type === "hybrid") {
|
|
186
|
-
entry.
|
|
187
|
-
|
|
186
|
+
if (entry.createdAt < sessionStartedAt) {
|
|
187
|
+
entry.status = "expired";
|
|
188
|
+
count++;
|
|
189
|
+
}
|
|
188
190
|
}
|
|
189
191
|
}
|
|
190
192
|
return count;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -35,11 +35,8 @@ function textResult(msg: string) {
|
|
|
35
35
|
return { content: [{ type: "text" as const, text: msg }], details: undefined as any };
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const LOOP_TOOL_NAMES = new Set(["LoopCreate", "LoopList", "LoopDelete", "MonitorCreate", "MonitorList", "MonitorStop"]);
|
|
39
|
-
const REMINDER_INTERVAL = 3;
|
|
40
|
-
|
|
41
38
|
const SYSTEM_REMINDER_TEMPLATE = `<system-reminder>
|
|
42
|
-
Scheduled loop "%
|
|
39
|
+
Scheduled loop "%prompt%" fired. Trigger: %trigger_info%.
|
|
43
40
|
[loop:%loop_id%]
|
|
44
41
|
</system-reminder>`;
|
|
45
42
|
|
|
@@ -156,10 +153,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
156
153
|
function showPersistedLoops(_isResume = false) {
|
|
157
154
|
if (persistedShown) return;
|
|
158
155
|
persistedShown = true;
|
|
156
|
+
const sessionStartedAt = Date.now();
|
|
159
157
|
const loops = store.list();
|
|
160
158
|
if (loops.length > 0) {
|
|
161
159
|
store.clearExpired();
|
|
162
|
-
store.expireEventLoops();
|
|
160
|
+
store.expireEventLoops(sessionStartedAt);
|
|
163
161
|
triggerSystem.start();
|
|
164
162
|
widget.update();
|
|
165
163
|
}
|
|
@@ -197,12 +195,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
197
195
|
|
|
198
196
|
// ── System-reminder injection for loop fires ──
|
|
199
197
|
|
|
200
|
-
let
|
|
201
|
-
let lastLoopToolUseTurn = 0;
|
|
202
|
-
let reminderInjectedThisCycle = false;
|
|
198
|
+
let canInjectReminder = true;
|
|
203
199
|
const pendingReminders: string[] = [];
|
|
204
200
|
|
|
205
|
-
pi.on("loop:fire"
|
|
201
|
+
pi.events.on("loop:fire", (data: any) => {
|
|
206
202
|
const triggerInfo = typeof data.trigger === "string"
|
|
207
203
|
? data.trigger
|
|
208
204
|
: data.trigger?.type === "cron"
|
|
@@ -219,25 +215,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
219
215
|
pendingReminders.push(reminder);
|
|
220
216
|
});
|
|
221
217
|
|
|
218
|
+
// Allow one reminder injection per agent turn (at the first tool call),
|
|
219
|
+
// so the reminder arrives between batches of work, not mid-execution.
|
|
222
220
|
pi.on("turn_start", async () => {
|
|
223
|
-
|
|
221
|
+
canInjectReminder = true;
|
|
224
222
|
});
|
|
225
223
|
|
|
226
224
|
pi.on("tool_result", async (event) => {
|
|
227
|
-
if (
|
|
228
|
-
lastLoopToolUseTurn = currentTurn;
|
|
229
|
-
reminderInjectedThisCycle = false;
|
|
230
|
-
return {};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (currentTurn - lastLoopToolUseTurn < REMINDER_INTERVAL || reminderInjectedThisCycle) {
|
|
234
|
-
return {};
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (pendingReminders.length === 0) return {};
|
|
225
|
+
if (!canInjectReminder || pendingReminders.length === 0) return {};
|
|
238
226
|
|
|
239
|
-
|
|
240
|
-
lastLoopToolUseTurn = currentTurn;
|
|
227
|
+
canInjectReminder = false;
|
|
241
228
|
const reminder = pendingReminders.shift()!;
|
|
242
229
|
return {
|
|
243
230
|
content: [...event.content, { type: "text" as const, text: reminder }],
|
package/src/store.ts
CHANGED
|
@@ -173,14 +173,16 @@ export class LoopStore {
|
|
|
173
173
|
});
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
expireEventLoops(): number {
|
|
176
|
+
expireEventLoops(sessionStartedAt: number): number {
|
|
177
177
|
return this.withLock(() => {
|
|
178
178
|
let count = 0;
|
|
179
179
|
for (const [_id, entry] of this.loops) {
|
|
180
180
|
if (entry.status !== "active") continue;
|
|
181
181
|
if (entry.trigger.type === "event" || entry.trigger.type === "hybrid") {
|
|
182
|
-
entry.
|
|
183
|
-
|
|
182
|
+
if (entry.createdAt < sessionStartedAt) {
|
|
183
|
+
entry.status = "expired";
|
|
184
|
+
count++;
|
|
185
|
+
}
|
|
184
186
|
}
|
|
185
187
|
}
|
|
186
188
|
return count;
|