Skip to content

feat(context-engine): pass incoming prompt to assemble#50848

Merged
jalehman merged 3 commits into
openclaw:mainfrom
danhdoan:feat/context-engine-prompt-param
Mar 21, 2026
Merged

feat(context-engine): pass incoming prompt to assemble#50848
jalehman merged 3 commits into
openclaw:mainfrom
danhdoan:feat/context-engine-prompt-param

Conversation

@danhdoan

Copy link
Copy Markdown
Contributor

Add optional prompt parameter to the ContextEngine.assemble() interface so retrieval-oriented context engines can use the user's query for relevance-based assembly.

Summary

  • Problem: The ContextEngine.assemble() interface has no access to the current user prompt, so retrieval-oriented engines cannot use it for relevance-based context assembly.
  • Why it matters: Context engines that perform semantic search (e.g. RAG-based memory plugins) need the user's query to retrieve relevant context at assembly time.
  • What changed: Added optional prompt?: string to the assemble() params in the interface and forwarded params.prompt at the call site in attempt.ts. Added 2 tests.
  • What did NOT change (scope boundary): LegacyContextEngine is untouched — it doesn't use prompt and remains a pass-through. No behavioral change for existing engines.

Change Type

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

None

User-visible / Behavior Changes

None — additive optional parameter on an internal interface.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Steps

  1. Register a custom context engine plugin that reads params.prompt in assemble()
  2. Send a message to the gateway
  3. Observe prompt is forwarded to the engine's assemble() call

Expected

  • params.prompt contains the user's message text

Actual

  • Confirmed via unit tests

Evidence

  • Failing test/log before + passing after
    • 2 new tests: forwards prompt to the underlying engine and omits prompt when not provided — both pass

Compatibility / Migration

  • Backward compatible? Yes — parameter is optional, all existing engines continue to work unchanged
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert the commit (1 commit, 3 files)
  • Known bad symptoms reviewers should watch for: None expected — the param is optional and unused by existing engines

Risks and Mitigations

None — additive optional field with no behavioral change for existing code paths.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S labels Mar 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5f8578161

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/pi-embedded-runner/run/attempt.ts Outdated
@greptile-apps

greptile-apps Bot commented Mar 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an optional prompt?: string field to the ContextEngine.assemble() interface and forwards it at the call site in attempt.ts, enabling retrieval-oriented engines to perform relevance-based context assembly using the user's current query. The change is additive, backward-compatible, and well-scoped.

Key observations:

  • Behavioral inconsistency at the call site: attempt.ts writes prompt: params.prompt unconditionally, which means when params.prompt is undefined the assembled params object will contain the key prompt with value undefined — not truly absent. The test "omits prompt when not provided" only validates the direct-call path and does not catch this. Engine authors who guard with 'prompt' in params (a natural pattern) will see the property as always-present when called through attempt.ts.
  • LegacyContextEngine signature drift: The concrete class was left with the old assemble param type (no prompt field), while the test helper class LegacySessionKeyStrictEngine was updated in this same PR. TypeScript accepts this via bivariant method checking, but the implementation diverges from the interface it declares to implement.

Confidence Score: 3/5

  • Safe to merge with minor fix — the prompt: undefined key presence at the attempt.ts call site is inconsistent with the documented and tested contract.
  • The interface update and test logic are correct. However, the call site in attempt.ts always includes prompt as a key (possibly undefined) rather than omitting it, which contradicts the "omits prompt when not provided" test contract. An engine using 'prompt' in params as a guard would behave incorrectly. The fix is a one-line conditional spread.
  • Pay close attention to src/agents/pi-embedded-runner/run/attempt.ts line 2170 and the corresponding test coverage gap.

Comments Outside Diff (1)

  1. src/context-engine/legacy.ts, line 38-43 (link)

    P2 LegacyContextEngine.assemble signature not updated to match interface

    The ContextEngine interface now includes prompt?: string in the assemble params, but LegacyContextEngine.assemble() still declares the narrower param type without prompt. TypeScript won't error here due to bivariant method checking, but the class no longer accurately reflects the interface it implements.

    This is in contrast to LegacySessionKeyStrictEngine (test helper) which was updated in this same PR to include prompt?: string. Consider adding the field here too for parity — it's a one-line no-op addition that keeps the implementation aligned with the interface:

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/context-engine/legacy.ts
    Line: 38-43
    
    Comment:
    **`LegacyContextEngine.assemble` signature not updated to match interface**
    
    The `ContextEngine` interface now includes `prompt?: string` in the `assemble` params, but `LegacyContextEngine.assemble()` still declares the narrower param type without `prompt`. TypeScript won't error here due to bivariant method checking, but the class no longer accurately reflects the interface it implements.
    
    This is in contrast to `LegacySessionKeyStrictEngine` (test helper) which was updated in this same PR to include `prompt?: string`. Consider adding the field here too for parity — it's a one-line no-op addition that keeps the implementation aligned with the interface:
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run/attempt.ts
Line: 2170

Comment:
**`prompt: undefined` key always present, contradicting test intent**

When `params.prompt` is not set, this line produces `prompt: undefined` in the object literal — the key **is** present in the params object, it just has value `undefined`. This directly contradicts the test named `"omits prompt when not provided"` which asserts `expect(calls[0]).not.toHaveProperty("prompt")`.

The test only passes because it calls `engine.assemble()` directly without `prompt`, bypassing this code path entirely. Any retrieval engine that guards with `'prompt' in params` (a reasonable pattern matching the stated contract) will incorrectly receive `true` on every call through `attempt.ts`, even when no user prompt was present.

To honour the documented intent — **truly** omit the key when no prompt is provided — use a conditional spread:

```suggestion
              ...(params.prompt !== undefined ? { prompt: params.prompt } : {}),
```

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

---

This is a comment left during a code review.
Path: src/context-engine/legacy.ts
Line: 38-43

Comment:
**`LegacyContextEngine.assemble` signature not updated to match interface**

The `ContextEngine` interface now includes `prompt?: string` in the `assemble` params, but `LegacyContextEngine.assemble()` still declares the narrower param type without `prompt`. TypeScript won't error here due to bivariant method checking, but the class no longer accurately reflects the interface it implements.

This is in contrast to `LegacySessionKeyStrictEngine` (test helper) which was updated in this same PR to include `prompt?: string`. Consider adding the field here too for parity — it's a one-line no-op addition that keeps the implementation aligned with the interface:

```suggestion
  async assemble(params: {
    sessionId: string;
    sessionKey?: string;
    messages: AgentMessage[];
    tokenBudget?: number;
    prompt?: string;
  }): Promise<AssembleResult> {
```

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

Last reviewed commit: "feat(context-engine)..."

Comment thread src/agents/pi-embedded-runner/run/attempt.ts Outdated
@danhdoan danhdoan force-pushed the feat/context-engine-prompt-param branch from f5f8578 to 7eeb826 Compare March 20, 2026 07:22

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7eeb826a5c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agents/pi-embedded-runner/run/attempt.ts
@jalehman jalehman self-assigned this Mar 20, 2026
@jalehman jalehman force-pushed the feat/context-engine-prompt-param branch from 7eeb826 to 0977e91 Compare March 20, 2026 15:17
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation size: M and removed size: S labels Mar 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0977e912c1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +275 to +279
if (
isLegacy &&
allowedKeys.some((key) => rejectedKeys.has(key) && hasOwnLegacyCompatKey(params, key))
) {
return method(withoutLegacyCompatKeys(params, rejectedKeys));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep assemble retries active after sessionKey detection

If a strict legacy engine first rejects sessionKey in bootstrap(), compact(), or another earlier method, isLegacy becomes true with rejectedKeys = {"sessionKey"}. The fast path here then strips only sessionKey and calls assemble() directly, so a legacy engine that also rejects the new prompt field never reaches invokeWithLegacyCompat() and still throws. In the normal run path, runEmbeddedAttempt() calls contextEngine.bootstrap() before assemble() for resumed sessions, so prompt compatibility is still broken on existing session files.

Useful? React with 👍 / 👎.

@jalehman jalehman force-pushed the feat/context-engine-prompt-param branch from 0977e91 to 86d6fc3 Compare March 20, 2026 15:32
@openclaw-barnacle openclaw-barnacle Bot added the channel: msteams Channel integration: msteams label Mar 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 86d6fc3e43

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

/\bmust not have additional propert(?:y|ies)\b.*['"`]prompt['"`]/i,
/\b(?:unexpected|extraneous)\s+(?:property|properties|field|fields|key|keys)\b.*['"`]prompt['"`]/i,
/\b(?:unknown|invalid)\s+(?:property|properties|field|fields|key|keys)\b.*['"`]prompt['"`]/i,
/['"`]prompt['"`].*\b(?:was|is)\s+not allowed\b/i,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restrict prompt fallback to true unknown-field validation errors

For prompt-aware engines that reject a supplied prompt for semantic reasons, this new pattern is too broad: messages like 'prompt' is not allowed when search mode is disabled also match here, so invokeWithLegacyCompat() will classify the failure as legacy-schema incompatibility, strip prompt, and silently retry without retrieval instead of surfacing the real error. Because run.ts reuses the resolved engine across retries, one misclassified failure suppresses prompt-based assembly for the rest of that run.

Useful? React with 👍 / 👎.

@jalehman jalehman force-pushed the feat/context-engine-prompt-param branch from 86d6fc3 to a551314 Compare March 20, 2026 20:45
@openclaw-barnacle openclaw-barnacle Bot removed docs Improvements or additions to documentation channel: msteams Channel integration: msteams labels Mar 20, 2026
@jalehman jalehman force-pushed the feat/context-engine-prompt-param branch 4 times, most recently from 716cda3 to b1745a1 Compare March 20, 2026 23:14
danhdoan and others added 3 commits March 20, 2026 16:42
Add optional `prompt` parameter to the ContextEngine.assemble() interface
so retrieval-oriented context engines can use the user's query for
relevance-based assembly. Uses conditional spread at the call site to
ensure the key is truly absent when no prompt is provided.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jalehman jalehman force-pushed the feat/context-engine-prompt-param branch from b1745a1 to 282dc92 Compare March 20, 2026 23:56
@jalehman jalehman merged commit e78129a into openclaw:main Mar 21, 2026
37 checks passed
frankekn pushed a commit to artwalker/openclaw that referenced this pull request Mar 23, 2026
Merged via squash.

Prepared head SHA: 282dc92
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
furaul pushed a commit to furaul/openclaw that referenced this pull request Mar 24, 2026
Merged via squash.

Prepared head SHA: 282dc92
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
Merged via squash.

Prepared head SHA: 282dc92
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
Merged via squash.

Prepared head SHA: 282dc92
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
Merged via squash.

Prepared head SHA: 282dc92
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
Merged via squash.

Prepared head SHA: 282dc92
Co-authored-by: danhdoan <12591333+danhdoan@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants