Skip to content

[AI-Assisted] Fix ExtensionRunner initialization in embedded mode#2027

Closed
ArtemHorik wants to merge 1 commit intoopenclaw:mainfrom
ArtemHorik:fix/embedded-extensionrunner-init
Closed

[AI-Assisted] Fix ExtensionRunner initialization in embedded mode#2027
ArtemHorik wants to merge 1 commit intoopenclaw:mainfrom
ArtemHorik:fix/embedded-extensionrunner-init

Conversation

@ArtemHorik
Copy link
Copy Markdown

@ArtemHorik ArtemHorik commented Jan 26, 2026

Summary

  • Initialize extensionRunner in embedded mode to fix auto-compaction summaries
  • Without this, ctx.model remains undefined and compaction hooks fall back to "Summary unavailable..."

Why

In embedded mode (used by bots), extensionRunner.initialize() was never called, unlike interactive mode where the UI calls it. This caused compaction-safeguard to skip real summarization.

Changes

  • Call extensionRunner.initialize() after session creation in attempt.ts
  • getActiveTools returns only valid string tool names (filters undefined)
  • setModel validates API key and returns Promise<boolean>
  • compact forwards onComplete/onError callbacks properly

Testing

✅ Fully tested locally with Clawdbot instance

  • Verified compaction now produces actual summaries instead of "Summary unavailable..."

AI Disclosure

  • Code & review: Codex, Claude Code
  • ✅ Tested locally, code reviewed and understood

Greptile Overview

Greptile Summary

This PR updates the embedded Pi runner startup so the session’s extensionRunner is bound in embedded mode, enabling compaction extensions that depend on ctx.model to generate real summaries (instead of falling back to “Summary unavailable…”). It also adds stricter handling for active tool name extraction, model setting (API key presence), and forwards compaction completion/error callbacks.

Change is localized to the embedded run attempt path (src/agents/pi-embedded-runner/run/attempt.ts) and a corresponding changelog entry.

Confidence Score: 4/5

  • This PR is likely safe to merge and should improve embedded compaction behavior, with minor concerns around stubbed extension runner state methods.
  • The change is narrowly scoped and primarily wires embedded mode into an existing extension runner API. Potential issues are mostly around behavioral expectations of extensions (isIdle/hasPendingMessages) and whether compact() should be awaitable, but no obvious runtime errors are introduced in the diff shown.
  • src/agents/pi-embedded-runner/run/attempt.ts

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

Context used:

  • Context from dashboard - CLAUDE.md (source)
  • Context from dashboard - AGENTS.md (source)

@ArtemHorik ArtemHorik force-pushed the fix/embedded-extensionrunner-init branch 2 times, most recently from 37a4aa7 to 05f1b90 Compare January 26, 2026 02:24
@sebslight sebslight added gateway Gateway runtime and removed gateway Gateway runtime labels Jan 26, 2026
@openclaw-barnacle openclaw-barnacle Bot added the agents Agent runtime and tooling label Jan 30, 2026
@ArtemHorik
Copy link
Copy Markdown
Author

Guys thats crucial - compaction not working properly without this fix.. please do priority review @sebslight

@ArtemHorik ArtemHorik force-pushed the fix/embedded-extensionrunner-init branch 2 times, most recently from 902e3f5 to 557c548 Compare January 31, 2026 16:57
@ArtemHorik ArtemHorik force-pushed the fix/embedded-extensionrunner-init branch from 557c548 to 1f78e4f Compare January 31, 2026 17:16
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +515 to +518
// IMPORTANT (embedded mode): bind the pi extension runner.
//
// In pi-coding-agent, ExtensionRunner defaults `ctx.model` to `undefined` until
// `extensionRunner.bindCore(...)` is called. Moltbot uses the SDK in embedded
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Comment/PR description says "initialize" but code calls bindCore.

This is easy to miss during future maintenance/debugging: the PR text and the inline both refer to initializing the runner, but the actual change is binding core callbacks via extensionRunner.bindCore(...). If initialize() is a real API on this object, readers may assume it was invoked when it wasn’t.

Suggestion: update the inline comment (and/or PR description) to consistently describe the action as binding the core, or rename the variable/comment to reflect bindCore.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/attempt.ts
Line: 515:518

Comment:
[P1] Comment/PR description says "initialize" but code calls `bindCore`.

This is easy to miss during future maintenance/debugging: the PR text and the inline both refer to initializing the runner, but the actual change is binding core callbacks via `extensionRunner.bindCore(...)`. If `initialize()` is a real API on this object, readers may assume it was invoked when it wasn’t.

Suggestion: update the inline comment (and/or PR description) to consistently describe the action as binding the core, or rename the variable/comment to reflect `bindCore`.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +567 to +571
isIdle: () => true,
abort: () => {
void activeSession.abort();
},
hasPendingMessages: () => false,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] isIdle/hasPendingMessages are hardcoded, which can break extensions relying on them.

In embedded mode these are currently always true/false, but extensions often gate actions (including compaction) on whether the agent is streaming or has queued messages. With the current stubs, an extension could attempt compaction or other work while the agent is mid-stream and get inconsistent behavior.

If activeSession exposes state for these (e.g. activeSession.isStreaming or similar), it’d be safer to wire these through rather than returning constants.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/attempt.ts
Line: 567:571

Comment:
[P1] `isIdle`/`hasPendingMessages` are hardcoded, which can break extensions relying on them.

In embedded mode these are currently always `true`/`false`, but extensions often gate actions (including compaction) on whether the agent is streaming or has queued messages. With the current stubs, an extension could attempt compaction or other work while the agent is mid-stream and get inconsistent behavior.

If `activeSession` exposes state for these (e.g. `activeSession.isStreaming` or similar), it’d be safer to wire these through rather than returning constants.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +574 to +583
compact: (options?: CompactOptions) => {
void (async () => {
try {
const result = await activeSession.compact(options?.customInstructions);
options?.onComplete?.(result);
} catch (error) {
const err = error instanceof Error ? error : new Error(String(error));
options?.onError?.(err);
}
})();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] compact ignores returned promise and doesn’t surface completion as an async result.

compact is implemented as fire-and-forget (void (async () => { ... })()), so callers that await compact() will resolve immediately even though compaction is still running. Some extensions might reasonably expect compact to be awaitable (even if callbacks exist).

If the bindCore contract allows it, consider returning the inner promise (or making compact async) so the caller can choose between awaiting and using callbacks.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/attempt.ts
Line: 574:583

Comment:
[P2] `compact` ignores returned promise and doesn’t surface completion as an async result.

`compact` is implemented as fire-and-forget (`void (async () => { ... })()`), so callers that `await` `compact()` will resolve immediately even though compaction is still running. Some extensions might reasonably expect `compact` to be awaitable (even if callbacks exist).

If the `bindCore` contract allows it, consider returning the inner promise (or making `compact` `async`) so the caller can choose between awaiting and using callbacks.

How can I resolve this? If you propose a fix, please make it concise.

@vignesh07
Copy link
Copy Markdown
Contributor

@ArtemHorik Can you repro this in the current main?

@sebslight
Copy link
Copy Markdown
Member

Closing as duplicate of #4223. If this is incorrect, comment and we can reopen.

@sebslight sebslight closed this Feb 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants