From 008489a91b0dd52039a4df76d1e1ba329232ab8e Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Fri, 17 Jul 2026 11:11:21 -0400 Subject: [PATCH] fix: pass parent modelRuntime so extension providers work in ralpi sessions ralpi's runAgentSession was letting createAgentSession create a fresh ModelRuntime from models.json only. This excluded extension-registered providers like neuralwatt, whose streamSimple wrapper handles: - 429 rate-limit header parsing (concurrent/TPM/admission/RPM) - Rate-limit error normalization for Pi's retry logic - Context-overflow error normalization Without the wrapper, neuralwatt rate-limit and context-overflow errors surfaced as raw unrecoverable errors instead of being retried by Pi's built-in retry. Now passes ctx.modelRegistry.runtime (the underlying ModelRuntime) through to createAgentSession. --- src/executor.ts | 9 ++++++++- src/utils.ts | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/executor.ts b/src/executor.ts index 654ac79..419e00d 100644 --- a/src/executor.ts +++ b/src/executor.ts @@ -3,7 +3,10 @@ import * as path from "node:path"; import type { Task, Project, Reflection, ToolUsage } from "./types"; import type { RalpiConfig } from "./types"; import type { ProgressTracker } from "./progress"; -import type { ExtensionContext } from "@earendil-works/pi-coding-agent"; +import type { + ExtensionContext, + ModelRuntime, +} from "@earendil-works/pi-coding-agent"; import { buildTaskPrompt, buildReviewPrompt, MAX_DIFF_BYTES } from "./prompts"; import { extractReflection } from "./reflection"; import { @@ -291,6 +294,8 @@ export async function runTask( undefined, // no abort signal assignedModel ?? config.model, config.thinkingLevel, + false, // noSkills — task sessions need skills + (ctx.modelRegistry as any).runtime as ModelRuntime, ); const durationMs = Date.now() - startMs; @@ -713,6 +718,7 @@ async function executeTask( "", "Stage only the files relevant to this task with `git add `, then create a meaningful git commit.", "Use a descriptive commit message and follow conventional commits format.", + "Do NOT include the task number, task ID, or any ralpi task reference in the commit message. The commit message must describe only the work done — never mention the task ID (e.g. `task 03`, `#3`, etc.).", "", "### Current Changes (git status --porcelain)", "```text", @@ -1061,6 +1067,7 @@ async function runFollowUpSession( model, config.thinkingLevel, true, // noSkills — follow-up sessions don't need the skills catalog + (ctx.modelRegistry as any).runtime as ModelRuntime, ); if (result.success) break; diff --git a/src/utils.ts b/src/utils.ts index 1b6ac23..00c8afb 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -14,6 +14,7 @@ import { getAgentDir, SessionManager, SettingsManager, + type ModelRuntime, } from "@earendil-works/pi-coding-agent"; // ─── Directory Helpers ─────────────────────────────────────────────────────── @@ -512,6 +513,11 @@ export async function runAgentSession( * focused follow-up sessions (commit/review) that don't need skills — * keeps the context lean and avoids dragging in unrelated overhead. */ noSkills = false, + /** Parent session's model runtime. Must be passed so extension-registered + * providers (e.g., neuralwatt with its streamSimple wrapper for 429 + * rate-limit normalization) are available. When omitted, the SDK creates + * a fresh runtime from models.json only — extension providers are lost. */ + modelRuntime?: ModelRuntime, ): Promise<{ success: boolean; text: string; @@ -556,6 +562,7 @@ export async function runAgentSession( sessionManager: SessionManager.inMemory(), resourceLoader: loader, settingsManager: SettingsManager.create(cwd, getAgentDir()), + modelRuntime, tools: ["read", "bash", "edit", "write", "grep", "find", "ls"], model: model as any, thinkingLevel: thinkingLevel as any,