Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/claw-wall/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (
backgroundContextSize = 10
defaultTailLimit = 40
defaultAwarenessLimit = 60
defaultTailMaxChars = 8 * 1024
defaultTailMaxChars = 32 * 1024
)

const (
Expand Down
15 changes: 11 additions & 4 deletions cmd/claw/compose_up.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const (
conversationWallFeedSince = "24h"
conversationWallFeedLimit = 40
conversationWallAwarenessLimit = 60
conversationWallFeedMaxChars = 8 * 1024
conversationWallFeedMaxChars = 32 * 1024
conversationWallBufferLimit = 5000
conversationWallPollInterval = "30"
conversationWallRetention = "24h"
Expand Down Expand Up @@ -1810,7 +1810,7 @@ func injectConversationWall(p *pod.Pod, resolvedClaws map[string]*driver.Resolve
continue
}
settings := conversationWallChannelContext(p, svc)
awarenessSettings := conversationWallChannelAwarenessContext()
awarenessSettings := conversationWallChannelAwarenessContext(p, svc)
svc.Claw.Feeds = appendConversationWallAwarenessFeed(svc.Claw.Feeds, channelIDs, awarenessSettings)
svc.Claw.Feeds = appendConversationWallFeed(svc.Claw.Feeds, channelIDs, settings)
svc.Claw.Tools = appendConversationWallToolPolicy(svc.Claw.Tools)
Expand Down Expand Up @@ -1898,12 +1898,19 @@ func conversationWallChannelContext(p *pod.Pod, svc *pod.Service) conversationWa
return settings
}

func conversationWallChannelAwarenessContext() conversationWallContextSettings {
return conversationWallContextSettings{
func conversationWallChannelAwarenessContext(p *pod.Pod, svc *pod.Service) conversationWallContextSettings {
settings := conversationWallContextSettings{
Since: conversationWallFeedSince,
Limit: conversationWallAwarenessLimit,
MaxChars: conversationWallFeedMaxChars,
}
if p != nil && p.Context != nil {
settings = applyConversationWallChannelContext(settings, p.Context.Channel)
}
if svc != nil && svc.Claw != nil && svc.Claw.Context != nil {
settings = applyConversationWallChannelContext(settings, svc.Claw.Context.Channel)
}
return settings
}

func applyConversationWallChannelContext(settings conversationWallContextSettings, cfg *pod.ChannelContextConfig) conversationWallContextSettings {
Expand Down
14 changes: 7 additions & 7 deletions cmd/claw/compose_up_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3209,7 +3209,7 @@ func TestBuildFeedManifestUsesOrdinalClawID(t *testing.T) {
{
Name: conversationWallFeedName,
Source: conversationWallServiceName,
Path: "/channel-context?consumer={claw_id}&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=8192",
Path: "/channel-context?consumer={claw_id}&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=32768",
TTL: conversationWallFeedTTL,
},
},
Expand All @@ -3225,10 +3225,10 @@ func TestBuildFeedManifestUsesOrdinalClawID(t *testing.T) {
if len(feeds) != 1 {
t.Fatalf("expected one feed, got %d", len(feeds))
}
if feeds[0].Path != "/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=8192" {
if feeds[0].Path != "/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=32768" {
t.Fatalf("expected ordinal claw_id substitution, got %q", feeds[0].Path)
}
if feeds[0].URL != "http://claw-wall:8080/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=8192" {
if feeds[0].URL != "http://claw-wall:8080/channel-context?consumer=trader-1&channels=chan-a,chan-b&mode=tail&since=24h&limit=40&max_chars=32768" {
t.Fatalf("expected ordinal wall URL, got %q", feeds[0].URL)
}
}
Expand Down Expand Up @@ -3938,14 +3938,14 @@ func TestInjectConversationWallAddsServiceAndFeed(t *testing.T) {
if awarenessFeed.Source != conversationWallServiceName {
t.Fatalf("expected claw-wall awareness source, got %+v", awarenessFeed)
}
if awarenessFeed.Path != "/channel-awareness?channels=chan-1,chan-2&since=24h&limit=60&max_chars=8192&context_kind=raw_window" {
if awarenessFeed.Path != "/channel-awareness?channels=chan-1,chan-2&since=24h&limit=60&max_chars=32768&context_kind=raw_window" {
t.Fatalf("unexpected awareness feed path: %q", awarenessFeed.Path)
}
contextFeed := testFeedByName(t, traderFeeds, conversationWallFeedName)
if contextFeed.Source != conversationWallServiceName {
t.Fatalf("expected claw-wall context source, got %+v", contextFeed)
}
if contextFeed.Path != "/channel-context?consumer={claw_id}&channels=chan-1,chan-2&mode=tail&since=24h&limit=40&max_chars=8192" {
if contextFeed.Path != "/channel-context?consumer={claw_id}&channels=chan-1,chan-2&mode=tail&since=24h&limit=40&max_chars=32768" {
t.Fatalf("unexpected wall feed path: %q", contextFeed.Path)
}
traderTools := p.Services["trader"].Claw.Tools
Expand Down Expand Up @@ -3999,7 +3999,7 @@ func TestInjectConversationWallHonorsChannelContextConfig(t *testing.T) {
t.Fatalf("expected trader feed, got %+v", traderFeeds)
}
traderAwareness := testFeedByName(t, traderFeeds, conversationWallAwarenessName)
if traderAwareness.Path != "/channel-awareness?channels=chan-1&since=24h&limit=60&max_chars=8192&context_kind=raw_window" {
if traderAwareness.Path != "/channel-awareness?channels=chan-1&since=6h&limit=25&max_chars=4096&context_kind=raw_window" {
t.Fatalf("unexpected trader awareness path: %q", traderAwareness.Path)
}
traderContext := testFeedByName(t, traderFeeds, conversationWallFeedName)
Expand All @@ -4012,7 +4012,7 @@ func TestInjectConversationWallHonorsChannelContextConfig(t *testing.T) {
t.Fatalf("expected scout feed, got %+v", scoutFeeds)
}
scoutAwareness := testFeedByName(t, scoutFeeds, conversationWallAwarenessName)
if scoutAwareness.Path != "/channel-awareness?channels=chan-1&since=24h&limit=60&max_chars=8192&context_kind=raw_window" {
if scoutAwareness.Path != "/channel-awareness?channels=chan-1&since=30m&limit=8&max_chars=1024&context_kind=raw_window" {
t.Fatalf("unexpected scout awareness path: %q", scoutAwareness.Path)
}
scoutContext := testFeedByName(t, scoutFeeds, conversationWallFeedName)
Expand Down
2 changes: 1 addition & 1 deletion cmd/claw/skill_data/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ The proxy sits between agents and LLM providers. Agents get bearer tokens, proxy

### claw-wall sidecar

Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window, internally bounded) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.
Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window; `x-claw.context.channel.max-chars` tunes both feeds together, default 32 KB) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.

## Generated Artifacts

Expand Down
2 changes: 1 addition & 1 deletion site/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ outline: deep

## Unreleased

<!-- Nothing yet -->
- **Channel feeds carry the whole conversation, not just the tail** — the default `max_chars` cap on both `channel-context` and `channel-awareness` feeds is raised from 8 KB to 32 KB so 24h on a modestly-active channel actually fits, and `channel-awareness` now honors the existing `x-claw.context.channel` tuning block (pod and service level). One knob raises both feeds together; busy production rooms can crank `max-chars` to 64-256 KB so the awareness surface covers a meaningful slice of the day rather than the last handful of messages. Closes [#242](https://github.com/mostlydev/clawdapus/issues/242).

## v0.17.1 <Badge type="tip" text="Latest" /> {#v0-17-1}

Expand Down
12 changes: 6 additions & 6 deletions site/guide/pod-yaml.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,20 +211,20 @@ services:

## Channel Context Tuning

When any cllama-enabled service has Discord channels in its handles, `claw up` auto-injects the `claw-wall` sidecar and a `channel-context` feed for each consuming agent. The feed serves the recent room transcript so a mentioned agent sees the conversation that prompted it (see [Social Topology · Channel Context Feed](/guide/social-topology#channel-context-feed-claw-wall)). Tune the generated tail with `x-claw.context.channel`:
When any cllama-enabled service has Discord channels in its handles, `claw up` auto-injects the `claw-wall` sidecar plus two feeds for each consuming agent: `channel-context` (cursored delta tail, mention/turn context) and `channel-awareness` (uncursored last-24h raw window, always-on memory of the room). Both feeds share the same tuning knob — see [Social Topology · Channel Context Feed](/guide/social-topology#channel-context-feed-claw-wall). Tune them with `x-claw.context.channel`:

```yaml
x-claw:
pod: trading-desk
context:
channel:
since: 24h # window covered by the tail (default 24h)
limit: 40 # max messages returned (default 40)
max-chars: 8192 # byte cap on rendered body (default 8192)
buffer: 5000 # per-channel safety cap in the wall sidecar (default 5000)
since: 24h # window covered by the feeds (default 24h)
limit: 40 # max messages returned (default: 40 for channel-context, 60 for channel-awareness)
max-chars: 32768 # byte cap on rendered body (default 32 KB)
buffer: 5000 # per-channel safety cap in the wall sidecar (default 5000)
```

Service-level `x-claw.context.channel` overrides pod-level values for that service. `buffer` is shared across the pod, so when services disagree the largest value wins, with the built-in 5000-message floor still applied. `since` accepts any Go duration (`30m`, `2h15m`, `24h`). Set `max_chars` if you prefer the underscore alias; mixing the two with conflicting values is a parse error.
Service-level `x-claw.context.channel` overrides pod-level values for that service. The same block tunes both `channel-context` and `channel-awareness` — busy production rooms typically want `max-chars` somewhere in the 64-256 KB range so the 24h awareness feed actually covers a meaningful slice of the day rather than the last handful of messages. `buffer` is shared across the pod, so when services disagree the largest value wins, with the built-in 5000-message floor still applied. `since` accepts any Go duration (`30m`, `2h15m`, `24h`). Set `max_chars` if you prefer the underscore alias; mixing the two with conflicting values is a parse error.

The wall serves `mode=tail` (non-consuming, latest-N walk) by default. Starting in v0.14.0, cllama drives the feed as a delta-since-watermark by adding `after=<channel_id>:<message_id>` cursors to the URL, so each turn fetches only new messages instead of re-pasting the full tail. `since` and `limit` from `x-claw.context.channel` remain the bootstrap and dual-cap bounds. The wall's retention horizon and startup backfill budget are sidecar env settings (`CLAW_WALL_RETENTION`, `CLAW_WALL_BACKFILL_MAX_PAGES`) rather than pod-YAML schema. See [Social Topology · Cursored Append-Only Deltas](/guide/social-topology#cursored-append-only-deltas) for the proxy-side model. The legacy cursor/mailbox path remains callable as `mode=delta` for any consumer that genuinely wants oldest-unread paging; generated feeds do not use it.

Expand Down
2 changes: 1 addition & 1 deletion skills/clawdapus/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ The proxy sits between agents and LLM providers. Agents get bearer tokens, proxy

### claw-wall sidecar

Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window, internally bounded) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.
Auto-injected by `claw up` when any cllama-enabled service has Discord channel IDs. Polls Discord channels and serves the recent channel transcript to agents through `channel-context` tail feeds; legacy unread-mailbox cursor paging remains available as `mode=delta`. On startup, wall backfills Discord history before its first forward poll up to `CLAW_WALL_RETENTION` (default `24h`) and `CLAW_WALL_BACKFILL_MAX_PAGES` (default `25`), while `CLAW_WALL_LIMIT` is a per-channel safety cap (default `5000`). Configure the generated tail window with pod or service `x-claw.context.channel` (`since`, `limit`, `max-chars`, `buffer`). Since `v0.15.0` channel-consuming services also get a default-on `channel-awareness` feed (uncursored 24h raw window; `x-claw.context.channel.max-chars` tunes both feeds together, default 32 KB) plus two cllama-mediated retrieval tools - `search_channel_context` and `get_channel_messages` - auto-subscribed via a compiler-owned claw-wall descriptor. Feed headers include `backfill_status`; `partial` or `rate_limited` means the backing window did not fully satisfy the requested horizon. Calls are gated by a generated per-agent channel allowlist, claw-wall service-token auth, and forwarded `X-Claw-ID`. The service name `claw-wall` is reserved - declaring it in `claw-pod.yml` is a hard error.

## Generated Artifacts

Expand Down
Loading