summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-11 22:23:43 +0300
committerPaul Buetow <paul@buetow.org>2026-04-11 22:23:43 +0300
commite7fa3d644d388db2891d2ec1d3f432e29579a641 (patch)
treec3734b3a6ab819acdef831d2d909ce952b448d85
parent5f63e9139ec0b4a4ae30651f5a7a2f77c66a689c (diff)
update
-rw-r--r--Gemfile.lock48
-rw-r--r--pi/agent/extensions/loop-scheduler/README.md6
-rw-r--r--pi/agent/extensions/loop-scheduler/index.ts14
-rw-r--r--pi/agent/extensions/loop-scheduler/loop-presets.md4
-rw-r--r--pi/agent/models.json27
-rw-r--r--pi/agent/settings.json2
6 files changed, 94 insertions, 7 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 80e05d4..e1e1ddc 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,54 @@
GEM
remote: https://rubygems.org/
specs:
+ atk (4.3.5)
+ glib2 (= 4.3.5)
+ rake
+ cairo (1.18.4)
+ native-package-installer (>= 1.0.3)
+ pkg-config (>= 1.2.2)
+ red-colors
+ cairo-gobject (4.3.5)
+ cairo (>= 1.16.2)
+ glib2 (= 4.3.5)
citrus (3.0.2)
+ fiddle (1.1.8)
+ gdk4 (4.3.5)
+ cairo-gobject (= 4.3.5)
+ gdk_pixbuf2 (= 4.3.5)
+ pango (= 4.3.5)
+ rake
+ gdk_pixbuf2 (4.3.5)
+ gio2 (= 4.3.5)
+ rake
+ gio2 (4.3.5)
+ fiddle
+ gobject-introspection (= 4.3.5)
+ glib2 (4.3.5)
+ native-package-installer (>= 1.0.3)
+ pkg-config (>= 1.3.5)
+ gobject-introspection (4.3.5)
+ glib2 (= 4.3.5)
+ graphene1 (4.3.5)
+ gobject-introspection (= 4.3.5)
+ gsk4 (4.3.5)
+ gdk4 (= 4.3.5)
+ graphene1 (= 4.3.5)
+ gtk4 (4.3.5)
+ atk (= 4.3.5)
+ gdk4 (= 4.3.5)
+ gsk4 (= 4.3.5)
+ json (2.19.2)
+ matrix (0.4.3)
+ native-package-installer (1.1.9)
+ pango (4.3.5)
+ cairo-gobject (= 4.3.5)
+ gobject-introspection (= 4.3.5)
+ pkg-config (1.6.5)
+ rake (13.3.1)
+ red-colors (0.4.0)
+ json
+ matrix
toml-rb (2.2.0)
citrus (~> 3.0, > 3.0)
@@ -10,6 +57,7 @@ PLATFORMS
x86_64-linux
DEPENDENCIES
+ gtk4
toml-rb (~> 2.2)
BUNDLED WITH
diff --git a/pi/agent/extensions/loop-scheduler/README.md b/pi/agent/extensions/loop-scheduler/README.md
index 2f7a7cc..3e7ef37 100644
--- a/pi/agent/extensions/loop-scheduler/README.md
+++ b/pi/agent/extensions/loop-scheduler/README.md
@@ -5,6 +5,7 @@ Session-scoped recurring and reactive prompts for Pi.
This extension adds two commands for interactive Pi sessions:
- `/loop` re-sends a prompt on an interval while the current Pi process stays open.
+ The first run fires right after you create the loop; later runs use the interval.
- `/watch` posts a predefined prompt when the agent becomes idle or when an assistant response contains a substring.
## Commands
@@ -66,8 +67,8 @@ Start Pi in the repo, then run:
/loop 10m check whether the deployment finished and summarize what changed
```
-Pi will keep re-injecting that prompt every 10 minutes while the session stays
-open.
+The first run happens almost immediately (then every 10 minutes) while the
+session stays open.
### Flow 2: Loop another command
@@ -140,6 +141,7 @@ Preset lines use:
Loop jobs do not spam turns while Pi is busy.
+- for **Gemma 4** models, loop/watch prompts use `deliverAs: "followUp"` so Pi queues them if the runtime is still finishing a turn (avoids “Agent is already processing” after long streams)
- if a job becomes due while the agent is running, it is marked pending
- when the current work finishes, the next pending loop fires once
- missed intervals do not stack into a catch-up storm
diff --git a/pi/agent/extensions/loop-scheduler/index.ts b/pi/agent/extensions/loop-scheduler/index.ts
index b6ed621..af6b003 100644
--- a/pi/agent/extensions/loop-scheduler/index.ts
+++ b/pi/agent/extensions/loop-scheduler/index.ts
@@ -377,6 +377,13 @@ export default function loopSchedulerExtension(pi: ExtensionAPI): void {
lastCtx = ctx;
}
+ /** Gemma 4 sessions often hit a short "still processing" window after a turn; Pi requires deliverAs then. */
+ function sendScheduledUserMessage(prompt: string): void {
+ const id = lastCtx?.model?.id ?? "";
+ const gemma4 = /gemma[-_]?4|gemma4/i.test(id);
+ pi.sendUserMessage(prompt, gemma4 ? { deliverAs: "followUp" } : undefined);
+ }
+
async function openPresetFile(ctx: ExtensionContext, filePath: string, template: string, errorPrefix: string): Promise<void> {
if (!existsSync(filePath)) {
try {
@@ -537,7 +544,7 @@ export default function loopSchedulerExtension(pi: ExtensionAPI): void {
updateUi();
try {
- pi.sendUserMessage(job.prompt);
+ sendScheduledUserMessage(job.prompt);
notify(`Loop ${job.id} fired (${reason}).`, "info");
} catch (error) {
agentBusy = false;
@@ -600,7 +607,7 @@ export default function loopSchedulerExtension(pi: ExtensionAPI): void {
updateUi();
try {
- pi.sendUserMessage(job.prompt);
+ sendScheduledUserMessage(job.prompt);
notify(`Watch ${job.id} fired (${reason}).`, "info");
} catch (error) {
agentBusy = false;
@@ -656,7 +663,8 @@ export default function loopSchedulerExtension(pi: ExtensionAPI): void {
intervalMs,
intervalLabel,
createdAt: Date.now(),
- nextRunAt: Date.now() + intervalMs,
+ // First fire is ASAP; handleJobDue then sets nextRunAt to now + intervalMs for the repeating cadence.
+ nextRunAt: Date.now(),
pending: false,
paused: allPaused, // inherit the current global pause state so new jobs added while paused start paused
runs: 0,
diff --git a/pi/agent/extensions/loop-scheduler/loop-presets.md b/pi/agent/extensions/loop-scheduler/loop-presets.md
index 8d141fe..f90cad3 100644
--- a/pi/agent/extensions/loop-scheduler/loop-presets.md
+++ b/pi/agent/extensions/loop-scheduler/loop-presets.md
@@ -8,4 +8,6 @@
# * monitor: 10m check if there are any errors in the logs
* tasks: 1m automatically start with the next task with fresh context if the current task completed following the agent-task-management skill.
-* proceed: 1m proceed
+* proceed: 1m proceed with the next task following agent-task-management if the previous or currently tasks being worked on is completed and committed to git.
+* review: 1m review all code changes since the last review and add code review comments using agent-task-management skill. use go-bestpractices and SOLID skills.
+* scifi: 1m write a scifi story about the current project or continue writing the story into STORY.md.
diff --git a/pi/agent/models.json b/pi/agent/models.json
index c8f08c1..cd55155 100644
--- a/pi/agent/models.json
+++ b/pi/agent/models.json
@@ -39,6 +39,15 @@
"compat": { "thinkingFormat": "qwen-chat-template" }
},
{
+ "id": "cyankiwi/gemma-4-31B-it-AWQ-4bit",
+ "name": "Gemma 4 31B IT [vm]",
+ "reasoning": false,
+ "input": ["text"],
+ "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
+ "contextWindow": 131072,
+ "maxTokens": 8192
+ },
+ {
"id": "cyankiwi/NVIDIA-Nemotron-3-Super-120B-A12B-AWQ-4bit",
"name": "Nemotron 3 Super 120B [vm]",
"reasoning": false,
@@ -107,6 +116,15 @@
},
"models": [
{
+ "id": "cyankiwi/gemma-4-31B-it-AWQ-4bit",
+ "name": "Gemma 4 31B IT [vm1]",
+ "reasoning": false,
+ "input": ["text"],
+ "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
+ "contextWindow": 131072,
+ "maxTokens": 8192
+ },
+ {
"id": "cyankiwi/NVIDIA-Nemotron-3-Super-120B-A12B-AWQ-4bit",
"name": "Nemotron 3 Super 120B 1M [vm1]",
"reasoning": false,
@@ -203,6 +221,15 @@
},
"models": [
{
+ "id": "cyankiwi/gemma-4-31B-it-AWQ-4bit",
+ "name": "Gemma 4 31B IT [vm2]",
+ "reasoning": false,
+ "input": ["text"],
+ "cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
+ "contextWindow": 131072,
+ "maxTokens": 8192
+ },
+ {
"id": "bullpoint/Qwen3-Coder-Next-AWQ-4bit",
"name": "Qwen3 Coder Next [vm2]",
"reasoning": true,
diff --git a/pi/agent/settings.json b/pi/agent/settings.json
index d8ea9a3..2e03dc3 100644
--- a/pi/agent/settings.json
+++ b/pi/agent/settings.json
@@ -1,5 +1,5 @@
{
- "lastChangelogVersion": "0.62.0",
+ "lastChangelogVersion": "0.66.1",
"defaultProvider": "openai",
"defaultModel": "gpt-4.1",
"defaultThinkingLevel": "high"