Skip to content

[OMEGA-179 & OMEGA-183] Context Frames - #284

Open
blackhammer116 wants to merge 136 commits into
singnet:mainfrom
iCog-Labs-Dev:main
Open

[OMEGA-179 & OMEGA-183] Context Frames#284
blackhammer116 wants to merge 136 commits into
singnet:mainfrom
iCog-Labs-Dev:main

Conversation

@blackhammer116

@blackhammer116 blackhammer116 commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR introduces Context Frames as OmegaClaw’s primary runtime working state.

User requests, autonomous tasks, goals, results, and completion state are now represented as native frames. The main loop admits new messages into frames before prompting the model, records command results back into the active frame, and schedules work according to frame priority and execution mode.

The change also adds semantic frame composition, dedicated frame-management skills, and a separate runtime prompt for frame behavior.

Motivation

Previously, the agent primarily relied on raw conversation history and a standalone human-message suffix. That made it difficult to:

  • Track the lifecycle of individual requests.
  • Prevent completed requests from being repeated.
  • Separate user-directed work from autonomous work.
  • Resume or switch between concurrent tasks.
  • Maintain compact, task-specific histories.
  • Express relationships and dependencies between tasks.
  • Maintain a context at a very low token usage.

Context Frames provide an explicit lifecycle and bounded working state for each task.

Changes

Context Frames

Added a native frame runtime supporting:

  • RootFrame, Frame, FrameRef, Goal, and SubFrame structures.
  • Active, completed, index, and relational frame spaces.
  • UserDirective and AgentDirective frame sources.
  • Fast and Slow execution modes.
  • Active, focused, suspended, blocked, completed, failed, and archived states.
  • Frame creation, loading, switching, snapshotting, indexing, and removal.
  • Priority-based frame selection.
  • Frame-specific hypotheses, methods, constraints, deliverables, results, and compact history.
  • STM and LTM completion paths.
  • Exposure of the last admitted frame ID.

New user messages are admitted as high-priority UserDirective frames in Fast mode. Autonomous work is represented by lower-priority AgentDirective frames in Slow mode.

Frame-aware main loop

The main loop now:

  • Initializes the frame runtime during startup.
  • Admits new messages into frames before constructing the LLM prompt.
  • Uses CURRENT_CONTEXT_FRAME_S_EXPR instead of raw global history as the model’s working state.
  • Emits explicit loop signals for new input, frame continuation, and idle/autonomous cycles.
  • Records each command batch and its result in the current frame.
  • Maintains or selects the next eligible frame after execution.
  • Switches between Fast and Slow modes according to available work.
  • Removes the deprecated spamShield configuration.

Conversation history is still recorded for episodes and auditing, but it is no longer injected directly into every LLM request.

Semantic frame composition

Added frame_relation.py to identify relationships between frames using:

  1. Compact frame extraction.
  2. OpenAI or local embeddings.
  3. Persistent ChromaDB collections.
  4. Top-k semantic retrieval.
  5. LLM-assisted relationship classification.

Supported relationship types include:

  • DuplicateOf
  • ContinuationOf
  • FollowUp
  • SubgoalOf
  • ParentOf
  • DependsOn
  • Blocks
  • Supersedes
  • SameProject
  • SameFailureCluster
  • RelatedButSeparate
  • Unrelated

Collections are separated by embedding provider to prevent vector-dimension conflicts. Content hashes prevent unchanged frames from being embedded again.

Runtime frame prompt

Added memory/prompt_context_frame.txt as a dedicated frame policy.

The policy tells the agent to:

  • Treat the current frame as authoritative.
  • Prioritize user-directed work over autonomous work.
  • Complete answered requests in the same command batch as the response.
  • Use LTM only for durable, reusable knowledge.
  • Avoid sending messages during idle inspection or autonomous goal creation.
  • Query historical memory only when information is not available in the frame.

The file is loaded safely at runtime and remains separate from the provider-specific base prompt.

Frame-management skills

Added commands for:

  • Creating user and autonomous frames.
  • Switching frames and execution modes.
  • Inspecting root, current, active, completed, index, and relation spaces.
  • Recording hypotheses and results.
  • Completing frames to STM or LTM.
  • Clearing transient frame data.
  • Extending Slow-mode processing with send_probe.

The command normalizer now recognizes these frame-management operations.

Helper utilities

Added helpers for:

  • Stable frame and goal ID generation.
  • Compact summaries with SHA-256 digests.
  • Balanced Frame and FrameRef parsing.
  • Filtering completed frame references by date.
  • Selecting the highest-priority eligible frame for the current root mode.

The legacy search command is also normalized to websearch.

Authentication fix

Safely normalizes GATEWAY_URL when the configuration value is missing or null.

This prevents channel authentication from failing with:

AttributeError: 'NoneType' object has no attribute 'rstrip'

How Has This Been Tested?

  • Manual testing and verification of the working state of the agent

Checklist

  • The code generated by LLM is reviewed by the PR creator
  • Self-review completed
  • Test scenarios above are passed with the version of the code from PR

surafelfikru and others added 30 commits March 27, 2026 00:36
This was implemented in main and this commit is syncing the telgram
implementations of last_message with main
Implemented telegram security/capability matrix
Also made the function configurable through CLI input
Load BOT_TOKEN/CHAT_ID from .env via dotenv instead of passing through
metta config. Refactor channel selection from case to if chains.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add prompt-configure that asks for each setting interactively with
defaults shown. CLI args (name=value) still override and skip the prompt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bereket-Eshete and others added 20 commits July 20, 2026 17:27
- replace cfv2-check-ref-id and cfv2-remove-frame-ref with a second
  cfv2-check-frame-id clause that pattern-matches FrameRef, allowing
  cfv2-remove-frame to handle both Frame and FrameRef spaces uniformly

- update cfv2-remove-frame comment to reflect it now dispatches on
  both Frame and FrameRef via cfv2-check-frame-id

- fix swapped case comments in loop.metta  block to match
  actual branch order of the if expression

- remove unnecessary comment above  binding
fix(context): frame ID normalisation, FrameRef fixes and 4-case loop signal
…ew modifications on the context frame skills description
With context frames the received message is no longer passed after the
":-:-:-:" delimiter, so the mock never found a registered answer and every
test that drives the agent failed.

- match the request against the CURRENT_CONTEXT_FRAME_S_EXPR section when
  the delimiter carries a loop signal, keeping the HUMAN-MSG path first so
  the suite still runs on core main
- serve an answer once per frame and complete the frame afterwards, so an
  unfinished frame does not keep later messages from becoming current
- let a test keep the frame open with set_answer(..., complete_frame=False)
- drop registered answers between tests
Disable Chroma's default embedding function because frame relations provide
their own embeddings, and skip similarity queries when no other frames exist.
Remove duplicate frame-completion operations from skills.metta so the canonical
implementations in context.metta are invoked only once.
Frame completion mutates memory and frame spaces but stays a
nondeterministic call, while the command dispatcher evaluates commands
under collapse. Every retry re-executed the whole chain with its side
effects, each pass produced a different result, and the agent never
returned. Wrap the three completion commands in once.

balance_parentheses split an answer by lines and then stripped the outer
parens of the whole block. An answer whose first form takes no arguments
was corrupted: the command name kept its closing paren and the remaining
form became a string, so the agent reported a syntax error and ran none
of the commands. Split a block into top-level forms first, ignoring
parens inside string literals.
[OMEGA-286] Match mock answers against the context frame
[OMEGA-286] Fix frame completion loop and multi-form answer parsing
@jazzbox35

jazzbox35 commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

@blackhammer116

I did review the code changes and tried out my own build version.

This looks like, in general, a needed useful addition to OmegaClaw. I've wondered for a while how we could streamline and refine the prompt which is kind of non filtered at the moment.

I think this is based on the spirit of Minsky's work on frames. I had to refresh my memory. But the main idea is to create conceptual chunks with slots. The slots are typically properties that can dynamically change in some cases. The frames are related in a network. It's a GOFAI structure, but that's fine so long as applicable.

So I think what this PR does is take that basic plan of Minsky's (and I remember it more like a "schema" in the literature) and use it for prompt refinement and state transition. A reasonable plan. I think relations between the frames are handled by embedding similarity. I'm not sure if there is symbolic linking of frames (is there?). The main goal is to make OmegaClaw smarter and more efficient, more able to hold to its goals. Fair enough.

That said, I do have numerous questions and issues:

There is scant documentation inside the new code to explain it from my scan through it. All of the code is like this, of course, but I don't see why we don't start documenting our code.

The code is in general intricate and complex. It's tough to imagine at this juncture how we could come reasonably close to testing it thoroughly. What testing scenarios have been completed? The testing alone if done properly should be quite complex -- as complex as there are conditions in the code.

I strongly feel that this should be repackaged as a PLUGIN or made switchable on/off. The reason is that I think we should leave a metta centric "lean and mean" loop available if people don't want the fancy features, and also if they want to create their own stateful mechanisms. I also think the new log should be switchable (from another PR). Vitaly showed me that it could be configured off, but I'd prefer we had switches from practically all NON ESSENTIAL features, especially if they include python, which this does.

I suppose I see the need for some Python code, especially for complex text parsing, but I am not sure we need so much. I feel like SNET is a MeTTa-first organization and we should be writing Metta code. There is a lot of code in context.metta, which is a good. But I think there is also a pretty big new Python program.

Also, I wish we had discussed this design in detail as a group. Maybe it did happen. I feel like OmegaClaw is on the whole going to be a flexible substrate for cognitive architectures. In that sense, hardcoding frame based logic doesn't work. YES -- it can be pluggable, absolutely. But I think hardcoding frames locks us into a determinate design that may be incompatible with future desired cognitive architectures.

I think the frames are related via the embedding same chromadb vector db? There is a means I recall that Patrick built in of using the FAISS facebook embeddings straight in MeTTa. In that way we don't need to create an external association lookup but use native MeTTa. There are some examples of this in my MettaWamJam repo programs.

These are my opinions, of course subject to veto by the powers that be. I think Patrick and Vitaly should review this too. I think it is mandatory actually. It makes a huge design commitment, which while seems good, is hard to foresee the wider effects of. So I think this should be an optional feature, not hardcoded, and consideration given to making the embeddings part of the atomspace proper structure if possible, although that idea needs a lot of work and may be impractical.

@alyona-snet alyona-snet added new-feature New feature or request in-jira The issue has been accepted for fixing labels Aug 10, 2026

@patham9 patham9 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Well-done! I will approve it, but before that, do we already have metrics that show clear benefits of the context frames over the baseline?

@vsbogd vsbogd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some lines are duplicated in the code, some new functions are not used anywhere. The new messages creates completely new frame but description says its result is saved in the current frame.

From the description it is not clear what should happen if user's input is not relevant to the current frame. For example LLM switched to some task and then user said something. How agent can select the frame relevant to the users's input?

Comment thread src/loop.metta
($msg (get-state &prevmsg))
($hadActiveFrame (if $msgnew (cfv2-has-current-frame) False))
; New input becomes frame state before prompting.
($_ (if $msgnew (ctx-ingest-user-message $msg) _))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The comment in implementation says the code of the called functions requires changes. And actually this code creates new frame from the user message each time instead of updating the frame.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good questions and thanks for spotting. So it seems it is actually limited to the last input and is overthrown on new input?

Comment thread src/context.metta
Comment on lines +9 to +15
(= (cfv2StatusActive) Active)
(= (cfv2StatusFocused) Focused)
(= (cfv2StatusSuspended) Suspended)
(= (cfv2StatusBlocked) Blocked)
(= (cfv2StatusCompleted) Completed)
(= (cfv2StatusFailed) Failed)
(= (cfv2StatusArchived) Archived)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For example these functions are not used

Comment thread src/context.metta
Comment on lines +228 to +229
(change-state! &cfv2-current-frame-id ())
(change-state! &cfv2-current-frame-id ())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Duplicated lines example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in-jira The issue has been accepted for fixing new-feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants