I built a 4-agent AI workflow in Angular. Here's what I learned.
- Agentic AI
- Angular
- Architecture
Why four agents, not one big prompt
Most "agentic" demos are a single LLM call with a system prompt and a few tools bolted on. That works for a video. It falls apart the moment you need the front-end to stay responsive while an agent is mid-task, or when one bad tool call shouldn't take down the whole flow.
So I split the workflow into four cooperating agents, each with a narrow job:
- Planner — turns a user request into a task graph
- Retriever — pulls context (docs, code, tickets) relevant to the current step
- Executor — calls tools and mutates state
- Reviewer — checks the executor's output before it's surfaced to the user
The moment I stopped treating "the agent" as one entity and started treating it as a small distributed system, the Angular integration got a lot easier to reason about.
Where Angular actually fits
The interesting part isn't the LLM orchestration — that's mostly server-side. It's how the front-end stays in sync with a process that can take anywhere from 2 to 40 seconds and can partially fail.
I ended up modeling the whole thing as a signal-based state machine:
type AgentStep = 'planning' | 'retrieving' | 'executing' | 'reviewing' | 'done' | 'error';
@Injectable({ providedIn: 'root' })
export class AgentWorkflowStore {
private readonly step = signal<AgentStep>('planning');
private readonly log = signal<string[]>([]);
readonly currentStep = this.step.asReadonly();
readonly isBusy = computed(() => this.step() !== 'done' && this.step() !== 'error');
transition(next: AgentStep, message?: string) {
this.step.set(next);
if (message) {
this.log.update((entries) => [...entries, message]);
}
}
}
Every agent emits a step transition over SSE. The UI never guesses what's happening — it renders whatever the store says, which means the "thinking" state is never a lie.
What actually broke in production
- Silent partial failures — the Reviewer agent would sometimes approve output that
the Executor only half-completed. Fix: the Executor now returns an explicit
completed: boolean, not just a result payload. - Token budget cliffs — the Retriever would occasionally stuff too much context into the Executor's prompt, causing a hard truncation mid-task. Fix: budget enforcement moved from "best effort" to a hard cap with graceful degradation.
- UI state drift on reconnect — if a user refreshed mid-workflow, the front-end had
no way to resume. Fix: every step transition is now persisted, so the store can
rehydrate from the last known step instead of resetting to
planning.
What I'd do differently
Start with the state machine, not the prompts. I spent the first two weeks tuning agent prompts and the next two weeks rebuilding the front-end state model because the prompts assumed a happy path that never survives contact with real users.