Documentation/InContextMemory (NextGen Plugin)
v2.0.0-beta.1Snapshot bebdcd1Markdown ↗

InContextMemory (NextGen Plugin)

InContextMemory (NextGen Plugin)

InContextMemoryPluginNextGen is a context plugin that stores key-value pairs directly in the LLM context (not just an index like WorkingMemory). This is ideal for small, frequently-updated state that the LLM needs instant access to without retrieval calls.

Key Difference from WorkingMemory

Feature WorkingMemory InContextMemory
Storage External (in-memory or file) Directly in LLM context
Context visibility Index only (keys + descriptions) Full values visible
Access pattern Requires store_get("notes", key) call Immediate - no retrieval needed
UI integration Host-defined showInUI metadata and onEntriesChanged are available to hosts; core renders no UI
Best for Large data, rarely accessed info Small state, frequently updated, live dashboards
Default capacity 25MB 20 entries, 40000 tokens

Quick Setup

typescript
import { AgentContextNextGen, InContextMemoryPluginNextGen } from 'oneringai';

const ctx = AgentContextNextGen.create({
  model: 'gpt-4.1',
  features: { inContextMemory: true },  // Enables InContextMemoryPluginNextGen
});

// Plugin is automatically registered when feature is enabled
// Access it via the plugin registry
const plugin = ctx.getPlugin('in_context_memory') as InContextMemoryPluginNextGen;
plugin.set('state', 'Current processing state', { step: 1, status: 'active' });

Manual Setup

For more control, you can set up the plugin manually:

typescript
import { AgentContextNextGen, InContextMemoryPluginNextGen } from 'oneringai';

const ctx = AgentContextNextGen.create({ model: 'gpt-4.1' });

// Create and configure plugin
const plugin = new InContextMemoryPluginNextGen({
  maxEntries: 20,
  maxTotalTokens: 40000,
  defaultPriority: 'normal',
  showTimestamps: false,
});

// Register plugin with context
ctx.registerPlugin(plugin);

Configuration Options

typescript
interface InContextMemoryConfig {
  /** Maximum number of entries (default: 20) */
  maxEntries?: number;

  /** Maximum total tokens for all entries (default: 40000) */
  maxTotalTokens?: number;

  /** Default priority for new entries (default: 'normal') */
  defaultPriority?: 'low' | 'normal' | 'high' | 'critical';

  /** Whether to show timestamps in output (default: false) */
  showTimestamps?: boolean;

  /** Callback fired when entries change (set/delete/clear/restore). Debounced at 100ms. */
  onEntriesChanged?: (entries: InContextEntry[]) => void;
}

Available Tools

The LLM manages in-context memory through the unified store_* tools with store="whiteboard" (values are always visible directly in context, so no store_get is needed):

store_set("whiteboard", ...)

Store or update a key-value pair in the live context:

jsonc
// Tool call from LLM
{
  "name": "store_set",
  "arguments": {
    "store": "whiteboard",
    "key": "current_state",
    "data": {
      "description": "Processing state for current task",
      "value": { "step": 3, "status": "active", "errors": [] },
      "priority": "high"     // optional: low, normal, high, critical
    }
  }
}

store_delete("whiteboard", ...)

Remove an entry to free space:

jsonc
// Tool call from LLM
{
  "name": "store_delete",
  "arguments": {
    "store": "whiteboard",
    "key": "temp_data"
  }
}
// Returns: { "deleted": true, "key": "temp_data" }

store_list("whiteboard")

List all entries with metadata:

jsonc
// Tool call from LLM
{
  "name": "store_list",
  "arguments": {
    "store": "whiteboard"
  }
}
// Returns: {
//   "entries": [
//     { "key": "current_state", "description": "...", "priority": "high", "showInUI": true, "updatedAt": 1769798400000 },
//     { "key": "user_prefs", "description": "...", "priority": "normal", "showInUI": false, "updatedAt": 1769798400000 }
//   ],
//   "total": 2
// }

Direct API Access

The plugin provides a programmatic API for direct manipulation:

typescript
const plugin = ctx.getPlugin('in_context_memory') as InContextMemoryPluginNextGen;

// Store entries
plugin.set('state', 'Current state', { step: 1 });
plugin.set('prefs', 'User preferences', { verbose: true }, 'high');
plugin.set('temp', 'Temporary data', 'xyz', 'low');

// Store with UI display (5th argument)
plugin.set('dashboard', 'Live dashboard', '## Status\n- OK', 'normal', true);

// Retrieve
const state = plugin.get('state');        // { step: 1 }
const missing = plugin.get('nonexistent'); // undefined

// Check existence
plugin.has('state');  // true
plugin.has('missing'); // false

// Delete
plugin.delete('temp');  // true (existed and deleted)
plugin.delete('missing'); // false (didn't exist)

// List all entries
const entries = plugin.list();
// [{ key: 'state', description: '...', priority: 'normal', showInUI: false, updatedAt: 1706... }, ...]

// Get entry count
console.log(plugin.list().length);  // 2

// Clear all
plugin.clear();

Priority-Based Eviction

When space is needed (either due to maxEntries or compact() being called), entries are evicted in this order:

  1. Priority: low → normal → high (lowest first)
  2. Age: Within the same priority, oldest entries (by updatedAt) are evicted first
  3. Critical: Entries with priority: 'critical' are never auto-evicted
typescript
// Example: limited to 3 entries
const plugin = new InContextMemoryPluginNextGen({ maxEntries: 3 });
ctx.registerPlugin(plugin);

plugin.set('critical1', 'Critical data', 'value', 'critical');
plugin.set('high1', 'High priority', 'value', 'high');
plugin.set('normal1', 'Normal data', 'value', 'normal');
plugin.set('low1', 'Low priority', 'value', 'low');  // Triggers eviction

// 'normal1' is evicted (lowest priority among non-critical)
console.log(plugin.has('critical1')); // true
console.log(plugin.has('high1'));     // true
console.log(plugin.has('low1'));      // true (just added)
console.log(plugin.has('normal1'));   // false (evicted)

Context Output Format

When the LLM context is prepared, InContextMemory adds a formatted section titled after the store's display name ("Whiteboard"):

markdown
# Whiteboard

**current_state** (high): Processing state for current task
{
  "step": 3,
  "status": "active",
  "errors": []
}

**user_preferences** (normal): User preferences for this session
{
  "theme": "dark",
  "verbose": true
}

Each entry renders as **key** (priority): description followed by a plain fenced, pretty-printed JSON block. The LLM can read this section directly without making any tool calls.

UI Display (showInUI)

Each InContextMemory entry can carry optional showInUI metadata. OneRingAI stores, serializes, and returns the flag, but it does not render a sidebar or define pinning behavior. Those are host-application responsibilities.

The built-in whiteboard schema intentionally does not advertise showInUI to the LLM. The store_set handler still accepts it for compatibility, but an agent will only know to send the field when a host plugin or application instruction explicitly teaches that extension (for example, a UI integration layer). The direct set() API always supports it.

How It Works

  1. Host code sets showInUI: true through the direct set() API, or explicitly extends the LLM's instructions/schema to permit the field.
  2. Host app receives updates via the onEntriesChanged callback (debounced at 100ms).
  3. Host code chooses rendering, sanitization, pinning, and persistence behavior.

Via store_set in a host-enabled UI integration

jsonc
// This field is accepted by the handler, but the default LLM-facing store
// schema does not advertise it. Expose it deliberately in host instructions.
{
  "name": "store_set",
  "arguments": {
    "store": "whiteboard",
    "key": "progress",
    "data": {
      "description": "Task progress dashboard",
      "value": "## Research Progress\n\n| Topic | Status |\n|-------|--------|\n| API Design | Done |\n| Implementation | In Progress |\n\n**Next:** Write tests",
      "priority": "high",
      "showInUI": true
    }
  }
}

Via Direct API

typescript
// Show a progress dashboard in the UI
plugin.set(
  'progress',
  'Task progress',
  '## Progress\n- [x] Step 1: Research\n- [x] Step 2: Design\n- [ ] Step 3: Implement',
  'high',
  true  // showInUI
);

// Update it later (showInUI persists with the entry)
plugin.set('progress', 'Task progress',
  '## Progress\n- [x] Step 1\n- [x] Step 2\n- [x] Step 3: Implement',
  'high',
  true
);

// Hide from UI
plugin.set('progress', 'Task progress', value, 'high', false);

Real-Time Updates with onEntriesChanged

Host applications can subscribe to entry changes to update their UI in real time:

typescript
const plugin = new InContextMemoryPluginNextGen({
  maxEntries: 20,
  onEntriesChanged: (entries) => {
    // Called whenever entries are set, deleted, cleared, or restored
    // Debounced at 100ms to avoid excessive updates during batch operations
    const visibleEntries = entries.filter(e => e.showInUI);
    updateSidebarUI(visibleEntries);
  },
});

The callback fires on: set(), delete(), clear(), restoreState(), and compact().

User Pinning

Host applications can let users pin specific entries regardless of the entry's showInUI value. This is useful when:

  • An agent stores useful state but doesn't mark it as showInUI
  • The user wants to monitor a specific key during a session
  • The agent sets showInUI: false on an entry the user still wants to see

Pin persistence belongs to the host application. A host can store the selected keys per agent so they survive application restarts; OneRingAI supplies the entry data and change callback, not a UI-specific persistence layer.

Rendering

Rendering is not part of OneRingAI. A host may pass string values through its normal Markdown renderer and support features such as:

  • Code blocks with syntax highlighting
  • Tables with alignment
  • LaTeX math ($inline$ and $$block$$)
  • Mermaid diagrams (flowcharts, sequence diagrams, etc.)
  • Vega-Lite charts (bar, line, pie, etc.)
  • Markmap mindmaps
  • Checklists, blockquotes, images, and more

Within the LLM context, objects and arrays are serialized as formatted JSON code blocks. A host UI decides independently how to render every value and must apply its own sanitization policy.

Session Persistence

InContextMemoryPluginNextGen supports full state serialization for session persistence:

typescript
// Save state
const state = plugin.getState();
// state = { entries: [...] }

// Later, restore state
const newPlugin = new InContextMemoryPluginNextGen();
newPlugin.restoreState(state);

When using with AgentContextNextGen, the state is automatically included:

typescript
// AgentContextNextGen synchronously captures plugin state
const ctxState = ctx.getState();

// Restore entire context (including InContextMemory)
const newCtx = AgentContextNextGen.create({
  model: 'gpt-4.1',
  features: { inContextMemory: true },
});
newCtx.restoreState(ctxState);  // Plugins are restored automatically

Use Cases

Ideal for:

  • Current state/status that changes during task execution
  • User preferences for the session (theme, verbosity, etc.)
  • Counters and flags (iteration count, feature flags)
  • Small accumulated results (running totals, collected IDs)
  • Control variables (abort flags, mode switches)
  • Live dashboards (with showInUI: true) — progress trackers, status displays, structured results

Not ideal for (use WorkingMemory instead):

  • Large data (documents, API responses, search results)
  • Rarely accessed reference data
  • Historical data that doesn't need instant access
  • Data that exceeds 4000 tokens

Best Practices

1. Use Appropriate Priorities

typescript
// Critical: Never evicted - for essential state
plugin.set('session_id', 'Session identifier', 'sess_123', 'critical');

// High: Kept as long as possible - important state
plugin.set('user_context', 'User context', { name: 'Alice' }, 'high');

// Normal (default): Standard data
plugin.set('current_step', 'Current step', 3);

// Low: Can be evicted - temporary/reconstructable data
plugin.set('last_check', 'Last health check', Date.now(), 'low');

2. Keep Values Small

typescript
// GOOD: Small, focused values
plugin.set('state', 'Task state', { step: 2, status: 'active' });

// BAD: Large objects (use WorkingMemory instead)
plugin.set('results', 'All results', hugeArrayOfResults);  // Don't do this!

3. Clean Up When Done

typescript
// Delete temporary entries when no longer needed
plugin.delete('temp_calculation');
plugin.delete('iteration_data');

// Or use low priority for auto-cleanup
plugin.set('temp', 'Temporary', value, 'low');

4. Combine with WorkingMemory

Use both systems for their strengths:

typescript
// Large data goes to WorkingMemoryPluginNextGen (index-based)
const memoryPlugin = ctx.getPlugin('working_memory') as WorkingMemoryPluginNextGen;
await memoryPlugin.store('search_results', 'Web search results', largeResults);

// Small, frequently-accessed state goes to InContextMemoryPluginNextGen (full values)
const inContextPlugin = ctx.getPlugin('in_context_memory') as InContextMemoryPluginNextGen;
inContextPlugin.set('search_status', 'Search status', { completed: 3, pending: 2 });

// LLM sees:
// - Memory Index: "search_results: Web search results" (needs store_get("notes", "search_results"))
// - Live Context: Full search_status value (instant access)

Documentation snapshot · 2026-11-02Suggest a correction ↗

Search documentation

Type to search the v2 documentation.