[{"data":1,"prerenderedAt":281},["ShallowReactive",2],{"content-developer\u002Fdecisions\u002F008-process-architecture":3,"surround-\u002Fdeveloper\u002Fdecisions\u002F008-process-architecture":272},{"id":4,"title":5,"body":6,"description":264,"extension":265,"meta":266,"navigation":267,"path":268,"seo":269,"stem":270,"__hash__":271},"content\u002F3.developer\u002Fdecisions\u002F9.008-process-architecture.md","ADR-008: Agent Process Architecture",{"type":7,"value":8,"toc":253},"minimark",[9,26,31,35,67,75,79,82,158,165,170,173,177,180,197,201,206,223,228],[10,11,12,20],"ul",{},[13,14,15,19],"li",{},[16,17,18],"strong",{},"Status:"," Accepted",[13,21,22,25],{},[16,23,24],{},"Date:"," 2026-03-24",[27,28,30],"h2",{"id":29},"context","Context",[32,33,34],"p",{},"The Agent Pipeline processes inbound messages through five steps: context retrieval, classification, action planning, draft generation, and routing. The simplest implementation is a single function that runs all five steps sequentially. But this creates problems:",[36,37,38,44,50,61],"ol",{},[13,39,40,43],{},[16,41,42],{},"No partial retry"," — if draft generation fails (LLM timeout, rate limit), the entire pipeline restarts from context retrieval, wasting LLM calls",[13,45,46,49],{},[16,47,48],{},"No concurrency"," — one long-running pipeline blocks the next message from starting. A 10-second draft generation delays all subsequent messages",[13,51,52,55,56,60],{},[16,53,54],{},"No multi-intent handling"," — a single message asking about billing ",[57,58,59],"em",{},"and"," requesting a feature needs two separate processing paths",[13,62,63,66],{},[16,64,65],{},"No observability"," — a monolithic function provides one timing metric, not per-step breakdown",[32,68,69,70,74],{},"Convex's serverless model naturally supports independent function execution — each ",[71,72,73],"code",{},"internalAction"," runs independently, can be scheduled, retried, and monitored separately.",[27,76,78],{"id":77},"decision","Decision",[32,80,81],{},"Adopt a process-oriented architecture with three process types mapped to Convex primitives:",[83,84,85,104],"table",{},[86,87,88],"thead",{},[89,90,91,95,98,101],"tr",{},[92,93,94],"th",{},"Process",[92,96,97],{},"Convex Primitive",[92,99,100],{},"Pipeline Steps",[92,102,103],{},"Behavior",[105,106,107,124,141],"tbody",{},[89,108,109,115,118,121],{},[110,111,112],"td",{},[16,113,114],{},"Receiver",[110,116,117],{},"HTTP action",[110,119,120],{},"Inbound webhook",[110,122,123],{},"Stateless — stores message, triggers security filter",[89,125,126,131,135,138],{},[110,127,128],{},[16,129,130],{},"Analyzer",[110,132,133],{},[71,134,73],{},[110,136,137],{},"Steps 1–2",[110,139,140],{},"Context retrieval + classification. Can fork for multi-intent messages",[89,142,143,148,152,155],{},[110,144,145],{},[16,146,147],{},"Worker",[110,149,150],{},[71,151,73],{},[110,153,154],{},"Steps 3–5",[110,156,157],{},"Autonomous execution with state machine (running \u002F waiting_for_input \u002F done \u002F failed)",[32,159,160,161,164],{},"A coordinator mutation tracks the pipeline state in the ",[71,162,163],{},"inboundMessages"," table and schedules the next step when the previous one completes. Each step records its timing and result independently.",[166,167,169],"h3",{"id":168},"multi-intent-branching","Multi-intent branching",[32,171,172],{},"When classification detects multiple intents, the coordinator spawns parallel worker processes — one per intent. Each worker runs independently with its own context, action plan, and draft. The routing step merges results when appropriate.",[166,174,176],{"id":175},"retry-semantics","Retry semantics",[32,178,179],{},"Each process type has independent retry behavior:",[10,181,182,187,192],{},[13,183,184,186],{},[16,185,114],{}," — no retry (webhook delivery is the provider's responsibility)",[13,188,189,191],{},[16,190,130],{}," — retry up to 2 times with exponential backoff. If classification repeatedly fails, mark the message for human review",[13,193,194,196],{},[16,195,147],{}," — retry up to 3 times. On persistent failure, save partial progress (the action plan) and route to verification queue with a \"needs manual intervention\" flag",[27,198,200],{"id":199},"consequences","Consequences",[32,202,203],{},[16,204,205],{},"Enables:",[10,207,208,211,214,217,220],{},[13,209,210],{},"Independent retry per step — a failed draft generation retries only the draft, not the full pipeline",[13,212,213],{},"Concurrent processing — multiple messages process simultaneously across organizations",[13,215,216],{},"Per-step observability — timing, cost, and error metrics per pipeline step",[13,218,219],{},"Multi-intent handling — parallel worker branches for complex messages",[13,221,222],{},"Graceful degradation — partial pipeline results are still useful (a classification without a draft is better than nothing)",[32,224,225],{},[16,226,227],{},"Trade-offs:",[10,229,230,244,247,250],{},[13,231,232,233,236,237,236,240,243],{},"More schema fields for state tracking (",[71,234,235],{},"processingState",", ",[71,238,239],{},"retryCount",[71,241,242],{},"stepTimings",")",[13,245,246],{},"Coordinator logic adds complexity vs a simple sequential function",[13,248,249],{},"State machine transitions need careful testing to avoid stuck messages",[13,251,252],{},"Slightly higher latency than a single function call due to scheduling overhead (~50ms per step transition)",{"title":254,"searchDepth":255,"depth":255,"links":256},"",2,[257,258,263],{"id":29,"depth":255,"text":30},{"id":77,"depth":255,"text":78,"children":259},[260,262],{"id":168,"depth":261,"text":169},3,{"id":175,"depth":261,"text":176},{"id":199,"depth":255,"text":200},"Why Owlat uses a process-oriented architecture for the agent pipeline instead of a single sequential function.","md",{},true,"\u002Fdeveloper\u002Fdecisions\u002F008-process-architecture",{"title":5,"description":264},"3.developer\u002Fdecisions\u002F9.008-process-architecture","YoAE2FOedCArH4AkoZmtImx5LTCKuxypf2C4-GYEeRM",[273,277],{"title":274,"path":275,"stem":276,"children":-1},"ADR-007: Pluggable LLM Provider","\u002Fdeveloper\u002Fdecisions\u002F007-pluggable-llm","3.developer\u002Fdecisions\u002F8.007-pluggable-llm",{"title":278,"path":279,"stem":280,"children":-1},"Examples","\u002Fexamples","4.examples\u002F0.index",1774391046072]