Modify Queue Status to only relevant tasks (#398)

* feat: Update Honcho system benchmarks

* fix: Align with runner common functions and fixed basedpyright issues

* fix: Address coderabbit issues

* chore: Address Ruff Errors

* fix: Queue Status to remove unhelpful info

* chore: (docs) Add docs for dreaming and buffering

* chore: Remove claude workflow

---------

Co-authored-by: 3un01a <3un01a@plasticlabs.ai>
This commit is contained in:
Vineeth Voruganti 2026-02-23 22:54:21 -05:00 committed by GitHub
parent 2631209256
commit 3b1e964372
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 259 additions and 97 deletions

View File

@ -1,95 +0,0 @@
name: Claude Code
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
pull_request_review:
types: [submitted]
jobs:
claude-review:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 15
concurrency:
group: claude-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
plugins: 'code-review@claude-code-plugins'
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
claude_args: '--model claude-opus-4-6'
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
claude:
if: |
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')) ||
(github.event_name == 'pull_request_review_comment' &&
contains(github.event.comment.body, '@claude') &&
(github.event.comment.author_association == 'OWNER' ||
github.event.comment.author_association == 'MEMBER' ||
github.event.comment.author_association == 'COLLABORATOR')) ||
(github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@claude') &&
(github.event.review.author_association == 'OWNER' ||
github.event.review.author_association == 'MEMBER' ||
github.event.review.author_association == 'COLLABORATOR'))
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
claude_args: '--model claude-opus-4-6'
# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
# prompt: 'Update the pull request description to include a summary of changes.'
# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr:*)'

View File

@ -64,6 +64,7 @@
"group": "Advanced",
"pages": [
"v3/documentation/features/advanced/overview",
"v3/documentation/features/advanced/dreaming",
"v3/documentation/features/advanced/queue-status",
"v3/documentation/features/advanced/reasoning-configuration",
"v3/documentation/features/advanced/representation-scopes",

View File

@ -64,6 +64,16 @@ The reasoning outputs--conclusions, summaries, peer cards--are stored as part of
The diagram above shows how agents write messages to Honcho, which triggers reasoning that updates peer representations. Agents can then query representations to get additional context for their next response.
### Token Batching
Rather than running inference on every individual message, Honcho accumulates messages in the queue and processes them as a batch once the total token count of pending messages for a given peer representation crosses a threshold--roughly **1,000 tokens** at the current batch size. This keeps ingestion costs down, since Honcho charges based on reasoning passes, and ensures each pass has a meaningful amount of context to work with. At ~1,000 tokens the batch comfortably fits in the context window of any modern LLM, so no content is lost.
If a user sends several short messages in a row (e.g., "yes", "ok", "sounds good"), those messages sit in the queue until enough content has accumulated. Once the threshold is met, the full batch is processed together in a single reasoning call.
<Note>
This batching only applies to **representation** tasks (conclusion extraction). Summary and dream tasks have their own scheduling logic and are not subject to the token threshold.
</Note>
## Balances & Design Choices
Off-the-shelf LLMs can perform formal logical reasoning, but they aren't optimized for it. Honcho uses custom models trained specifically for logical rigor (following formal reasoning rules rather than plausible-sounding text), structured output (consistent JSON schema with premises and conclusions), and efficiency (smaller, faster models tuned for this specific task). This allows Honcho to reason more reliably and at lower cost than general-purpose frontier LLMs.

View File

@ -0,0 +1,140 @@
---
title: 'Dreaming'
description: 'How Honcho continuously improves memory through autonomous consolidation'
icon: 'cloud-moon'
---
<Warning>
Dreaming is an experimental feature under active development. The scheduling heuristics, specialist behavior, and configuration options described here are subject to change as we iterate on the approach.
</Warning>
Honcho's reasoning system extracts conclusions from every message as it arrives. Over time, this produces a large body of knowledge--some of which is redundant, outdated, or missing higher-order patterns that only become visible across many interactions. **Dreaming** is the process that addresses this: an autonomous, periodic consolidation cycle that refines the peer representation by reasoning over existing conclusions.
Think of it like sleep for a memory system. The "waking" reasoning process captures what happened. The dreaming process reflects on what it all means.
## What Dreaming Does
A dream cycle runs two specialized agents in sequence:
### 1. Deduction
The deduction specialist performs logical inference over existing conclusions. It autonomously explores the observation space and looks for:
- **Knowledge updates**: When the same fact has changed over time (e.g., "works at Company A" followed later by "works at Company B"), it deletes the outdated conclusion and creates a new one reflecting the current state.
- **Logical implications**: Conclusions that follow necessarily from existing premises but weren't captured during real-time processing.
- **Contradictions**: Conflicting conclusions that need resolution.
- **Peer card updates**: Key biographical facts (name, location, occupation) that should be recorded on the peer card for quick access.
### 2. Induction
The induction specialist identifies patterns across multiple conclusions. It looks for:
- **Behavioral tendencies**: Recurring behaviors observed across different contexts (e.g., "tends to reschedule meetings when stressed").
- **Preferences**: Consistent choices that indicate underlying preferences.
- **Personality traits**: Stable characteristics inferred from multiple data points.
- **Correlations**: Relationships between different aspects of behavior.
Inductive conclusions require evidence from at least two source conclusions--patterns need more than a single data point. Each pattern is assigned a confidence level based on the number of supporting observations.
## When Dreams Are Scheduled
Dreams are triggered automatically based on a set of heuristics designed to balance freshness with efficiency:
### Conditions
All of the following must be true for a dream to be scheduled:
1. **Document threshold**: At least 50 new conclusions have been created since the last dream for that peer representation.
2. **Minimum cooldown**: At least 8 hours have passed since the last dream for that peer representation.
3. **Dreaming is enabled**: The workspace and/or session configuration has `dream.enabled` set to `true` (the default).
### Idle timeout
When the threshold conditions are met, a dream is **not** immediately executed. Instead, a timer is set (default: 60 minutes) that waits for user inactivity. If new messages arrive during the waiting period, the pending dream is cancelled and the timer resets. This prevents dreaming while the user is actively interacting, ensuring the system consolidates only after the conversation has settled.
Once the idle timeout expires without interruption, the dream task is enqueued for processing.
### Manual scheduling
You can also trigger a dream explicitly via the API:
<CodeGroup>
```python Python
honcho.workspaces.schedule_dream(
observer="user-peer-name",
observed="user-peer-name",
)
```
```typescript TypeScript
await honcho.workspaces.scheduleDream({
observer: "user-peer-name",
observed: "user-peer-name",
});
```
</CodeGroup>
Manual dreams bypass the threshold and cooldown checks, but are still subject to deduplication--if a dream is already pending or in progress for the same peer representation, the request is a no-op.
## Scope
Dreams operate at the **peer representation** level--specifically, a (workspace, observer, observed) tuple. This means:
- A dream consolidates conclusions for a specific observer's view of a specific observed peer.
- In the common case of self-observation (where the observer and observed are the same peer), the dream consolidates that peer's own representation.
- Dreams do not span across workspaces or across different peer pairs.
## Deduplication and Safety
The system includes several safeguards to prevent wasted work:
- **No concurrent dreams**: If a dream is already being processed for a given peer representation, a new one will not be enqueued.
- **No duplicate pending dreams**: If a dream is already queued and waiting, a second enqueue request is skipped.
- **Cancellation on new activity**: When new messages arrive for a peer, any pending (not yet started) dream for that peer is cancelled. This ensures the dream always runs on the most up-to-date set of conclusions.
## Configuration
Dreams can be enabled or disabled at the workspace or session level:
<CodeGroup>
```python Python
# Disable dreams for a workspace
honcho.set_configuration({
"dream": {"enabled": False}
})
# Disable dreams for a specific session
session = honcho.session("my-session", config={
"dream": {"enabled": False}
})
```
```typescript TypeScript
// Disable dreams for a workspace
await honcho.setConfiguration({
dream: { enabled: false }
});
// Disable dreams for a specific session
const session = await honcho.session("my-session", {
config: {
dream: { enabled: false }
}
});
```
</CodeGroup>
Dreaming is automatically disabled if reasoning itself is disabled, since there would be no conclusions to consolidate.
<CardGroup cols={2}>
<Card title="Reasoning" icon="gears" href="/v3/documentation/core-concepts/reasoning">
Learn how Honcho reasons over messages to produce conclusions
</Card>
<Card title="Configuration" icon="wrench" href="/v3/documentation/features/advanced/reasoning-configuration">
Full configuration reference for reasoning, summaries, and dreams
</Card>
<Card title="Queue Status" icon="list-check" href="/v3/documentation/features/advanced/queue-status">
Monitor dream tasks alongside other background processing
</Card>
<Card title="Schedule Dream API" icon="calendar" href="/v3/api-reference/endpoint/workspaces/schedule-dream">
API reference for manually triggering dreams
</Card>
</CardGroup>

View File

@ -9,6 +9,7 @@ Advanced features give you fine-grained control over Honcho's behavior and imple
## Configuration & Monitoring
- [Dreaming](/v3/documentation/features/advanced/dreaming) - Autonomous memory consolidation and self-improvement
- [Queue Status](/v3/documentation/features/advanced/queue-status) - Monitor background processing and reasoning tasks
- [Configuration](/v3/documentation/features/advanced/reasoning-configuration) - Configure reasoning models and behavior
- [Summarizer](/v3/documentation/features/advanced/summarizer) - Automatic session summarization

View File

@ -74,6 +74,26 @@ work_units will be processed in parallel
- If local representations are turned in a Session then a message will
generate an additional work unit for every peer that has `observe_others=True`
### Tracked task types
The queue status endpoint reports on the following task types:
| Task Type | Description |
|---|---|
| **representation** | Memory formation — the deriver processes messages and extracts observations about peers |
| **summary** | Session summarization — creates short and long summaries at configurable message intervals |
| **dream** | Memory consolidation — explores and consolidates observations to improve memory quality |
Internal infrastructure tasks (such as webhook delivery, resource deletion, and
vector reconciliation) are **not** included in queue status counts.
<Note>
**Completed counts are not lifetime totals.** Honcho periodically cleans up
processed queue items to keep the queue table lean. As a result,
`completed_work_units` reflects items completed since the last cleanup cycle,
not the total number of items ever processed.
</Note>
The `queue_status` method can take additional
parameters to scope the status to a specific work unit:

View File

@ -22,6 +22,12 @@ async def get_queue_status(
"""
Get the processing queue status, optionally filtered by observer, sender, and/or session.
Only tracks user-facing task types: representation, summary, and dream.
Internal infrastructure tasks (reconciler, webhook, deletion) are excluded.
Note: completed_work_units reflects items since the last periodic queue
cleanup, not lifetime totals.
Args:
db: Database session
workspace_name: Name of the workspace
@ -69,6 +75,10 @@ async def get_deriver_status(
)
# Task types surfaced by the queue status endpoint.
_TRACKED_TASK_TYPES = ("representation", "summary", "dream")
def _build_queue_status_query(
workspace_name: str,
session_name: str | None,
@ -119,6 +129,9 @@ def _build_queue_status_query(
stmt = stmt.where(models.QueueItem.workspace_name == workspace_name)
# Only include user-facing task types
stmt = stmt.where(models.QueueItem.task_type.in_(_TRACKED_TASK_TYPES))
if session_name is not None:
stmt = stmt.join(
models.Session, models.QueueItem.session_id == models.Session.id

View File

@ -171,6 +171,11 @@ async def get_queue_status(
"""
Get the processing queue status for a Workspace, optionally scoped to an observer, sender,
and/or session.
Only tracks user-facing task types (representation, summary, dream).
Internal infrastructure tasks (reconciler, webhook, deletion) are excluded.
Note: completed counts reflect items since the last periodic queue cleanup,
not lifetime totals.
"""
try:
return await crud.get_queue_status(

View File

@ -799,10 +799,19 @@ class SessionQueueStatus(BaseModel):
class QueueStatus(BaseModel):
"""Aggregated processing queue status."""
"""Aggregated processing queue status.
Tracks user-facing task types only: representation, summary, and dream.
Internal infrastructure tasks (reconciler, webhook, deletion) are excluded.
Note: completed_work_units reflects items since the last periodic queue
cleanup, not lifetime totals.
"""
total_work_units: int = Field(description="Total work units")
completed_work_units: int = Field(description="Completed work units")
completed_work_units: int = Field(
description="Completed work units (since last periodic cleanup)"
)
in_progress_work_units: int = Field(
description="Work units currently being processed"
)

View File

@ -256,6 +256,64 @@ class TestDeriverStatusEndpoint:
)
assert session_totals == [1, 2, 3]
async def test_get_queue_status_excludes_internal_task_types(
self,
client: TestClient,
db_session: AsyncSession,
sample_data: tuple[models.Workspace, models.Peer],
):
"""Test that internal task types (reconciler, webhook, deletion) are excluded from counts"""
workspace, peer = sample_data
session = models.Session(workspace_name=workspace.name, name="test_session")
db_session.add(session)
await db_session.commit()
await db_session.refresh(session)
# Add one representation item (should be counted)
rep_payload = {
"observed": peer.name,
"observer": peer.name,
"task_type": "representation",
"workspace_name": workspace.name,
"session_name": session.name,
}
db_session.add(
models.QueueItem(
session_id=session.id,
task_type="representation",
work_unit_key=construct_work_unit_key(workspace.name, rep_payload),
payload=rep_payload,
processed=False,
workspace_name=workspace.name,
)
)
# Add internal task types (should NOT be counted)
for task_type in ("reconciler", "webhook", "deletion"):
internal_payload = {
"task_type": task_type,
"workspace_name": workspace.name,
}
db_session.add(
models.QueueItem(
session_id=None,
task_type=task_type,
work_unit_key=f"{task_type}:{workspace.name}:internal",
payload=internal_payload,
processed=False,
workspace_name=workspace.name,
)
)
await db_session.commit()
response = client.get(f"/v3/workspaces/{workspace.name}/queue/status")
assert response.status_code == 200
json_response = response.json()
# Only the representation item should appear
assert json_response["total_work_units"] == 1
assert json_response["pending_work_units"] == 1
async def test_get_deriver_status_empty_parameters(
self, client: TestClient, sample_data: tuple[models.Workspace, models.Peer]
):