{"record":{"id":"f497926b0df22732","repo":"sipeed/picoclaw","slug":"seahorse-assemble-w","errorCode":null,"errorMessage":"seahorse assemble: %w","messagePattern":"seahorse assemble: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/agent/context_seahorse.go","lineNumber":116,"sourceCode":"\tif budget <= 0 {\n\t\tbudget = 100000\n\t}\n\n\t// Reserve space for model response (spec lines 1400-1410)\n\teffectiveBudget := budget - req.MaxTokens\n\tif effectiveBudget <= 0 {\n\t\t// MaxTokens >= budget is a configuration problem\n\t\t// Use 50% as minimum to avoid guaranteed overflow\n\t\tlogger.WarnCF(\"agent\", \"MaxTokens >= budget, using 50% fallback\",\n\t\t\tmap[string]any{\"budget\": budget, \"max_tokens\": req.MaxTokens})\n\t\teffectiveBudget = budget / 2\n\t}\n\n\tresult, err := m.engine.Assemble(ctx, req.SessionKey, seahorse.AssembleInput{\n\t\tBudget: effectiveBudget,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"seahorse assemble: %w\", err)\n\t}\n\n\thistory := seahorseToProviderMessages(result)\n\n\t// Summary is already formatted as XML with system prompt addition by assembler\n\treturn &AssembleResponse{\n\t\tHistory: history,\n\t\tSummary: result.Summary,\n\t}, nil\n}\n\n// Compact compresses conversation history via seahorse summarization.\nfunc (m *seahorseContextManager) Compact(ctx context.Context, req *CompactRequest) error {\n\tif req == nil {\n\t\treturn nil\n\t}\n\n\t// For retry (LLM overflow), use aggressive CompactUntilUnder to guarantee","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/agent/context_seahorse.go#L98-L134","documentation":"seahorseContextManager.Assemble builds the prompt context within a token budget by calling engine.Assemble on the session DB; any engine failure is wrapped as 'seahorse assemble: %w'. Unlike engine creation (which falls back to legacy), an Assemble error propagates into the turn pipeline (pipeline_setup.go / turn_coord.go), failing that agent turn. The code just above also halves the budget when MaxTokens >= budget, so pathological budget settings surface here indirectly.","triggerScenarios":"engine.Assemble fails mid-turn: seahorse.db becomes unreadable or corrupt, rows for the session are malformed, or the engine was closed (e.g. agent Close racing an in-flight turn).","commonSituations":"Disk filling up or being yanked mid-run; a second picoclaw instance writing the same DB; deleting workspace files while the bot runs; schema drift after upgrading picoclaw with an old seahorse.db.","solutions":["Read the wrapped engine error to distinguish I/O corruption from locking","Restart picoclaw — transient SQLite locks from a crashed process clear on restart","For corruption, rename/remove seahorse.db (or the affected session's data) so seahorse rebuilds it","Configure the context budget above the model's max_tokens to avoid the 50%-budget fallback path","Enforce one process per workspace to stop concurrent DB writers"],"exampleFix":"// config — before: budget smaller than max_tokens forces the 50% fallback\n\"agents\": { \"defaults\": { \"max_tokens\": 8192, \"context_window\": 4096 } }\n\n// after: budget exceeds max_tokens\n\"agents\": { \"defaults\": { \"max_tokens\": 8192, \"context_window\": 131072 } }","handlingStrategy":"try-catch","validationCode":"if cfg.Agents.Defaults.MaxTokens > 0 && cfg.Agents.Defaults.ContextWindow > 0 &&\n    cfg.Agents.Defaults.MaxTokens >= cfg.Agents.Defaults.ContextWindow {\n    return fmt.Errorf(\"max_tokens (%d) must be smaller than context budget (%d)\",\n        cfg.Agents.Defaults.MaxTokens, cfg.Agents.Defaults.ContextWindow)\n}","typeGuard":null,"tryCatchPattern":"resp, err := ctxMgr.Assemble(ctx, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"seahorse assemble\") {\n        // degrade for this turn: fall back to trimmed legacy history instead of failing the turn\n        log.Printf(\"seahorse assemble failed (%v); using legacy assembly\", err)\n        resp, err = legacyMgr.Assemble(ctx, req)\n    }\n    if err != nil {\n        return nil, err\n    }\n}","preventionTips":["Keep context budget strictly greater than max_tokens to avoid the 50% fallback path","Back up or snapshot seahorse.db before upgrades that touch session schema","Never share a workspace directory between concurrent picoclaw instances"],"tags":["go","picoclaw","seahorse","sqlite","context-manager","runtime"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}