Skip to content

office manager

github-actions[bot] edited this page Oct 14, 2026 · 5 revisions

OfficeManager — the 16-bit office view of your agents

OfficeManager is a web app served by AgentBridge at http://localhost:5290/OfficeManager. It renders every live agent instance of the AIOrchestrator engine as an employee in a 16-bit top-down office, and lets you drive conversations from a text-adventure style chat.

The big picture

An employee is an agent instance. There is always a pool of idle employees that wander around the office saying "I have nothing to do" — they are not backed by any agent. Every other employee is the visual representation of one agent or subagent instance, no matter how that instance was created:

Created by Employee behaviour
TUI chat, /v1/chat/completions (session), SIP, Telegram Appears at the door when the conversation starts, works at a desk while the agent runs, returns to the door and disappears when the conversation closes (idle timeout or explicit close)
Stateless one-shot API call (/v1/chat/completions without session_id) Appears when the run starts, works at a desk, returns to the door when the run ends
A subagent launched by any agent Same as above, tied to the subagent session lifecycle
Other applications that host AIOrchestrator directly (e.g. the AIOffice desktop app) They forward their agent lifecycle events to AgentBridge (AgentHarness.ForwardGlobalProgressTo → POST /v1/office/events), so those agents appear as employees too

Stateless employees are never hidden. A stateless request is a legitimate agent instance — often a small task created by an agent or a tool (a quick lookup, a file check, a sub-step). OfficeManager is also a granular monitoring surface: you see every one of those instances appear, work at a desk and leave, in real time. Hiding them would defeat the purpose of the office.

While an agent is executing a tool, its speech bubble shows the tool class and the method, each split into words: FileTool.FileSearch → "File Tool, File Search".

Playing the game

  • Arrows move the boss — the human user's avatar. After 10 seconds without input the boss goes into auto-pilot: it wanders on its own (never attracted to desks, cannot hire by contact) and, while agents are working, keeps an eye on them with supervision lines ("I'm watching you!", "Get to work, slackers!", …). Any arrow key ends the auto-pilot.
  • Tab / click an employee to hire (engage) it; Esc releases it — and on a session employee it closes the conversation (the employee walks back to the door and disappears).
  • The bottom chat sends prompts to the engaged employee and shows the responses. Typed text appears in the bubble above the boss's head.
    • As soon as you send a task the employee leaves for a desk and starts working at it, even while he is still your hire: you keep talking to him and he does not wait until you pick somebody else.
    • Chatting with an idle employee creates a new agent for it: it becomes a real session employee and a replacement idle employee appears at the door, so you can always spawn a new parallel agent.
    • You never have to pick an employee first. If nobody is hired — or the one you are talking to is busy or cannot be chatted with — your request is assigned automatically: to a free employee (one with no task in hand) when there is one, or, when the whole office is busy, to a brand-new employee hired just for the request, who appears at the door already working on it. A deliberate hire that is free always keeps priority, so the conversation you chose is never taken from under you.
    • Subagent / one-shot employees are visual only — their conversation belongs to their parent agent.

Seeing who is working, and answering from the office

OfficeManager is built so you can read the whole office at a glance and reply to an employee without leaving the view.

  • Names are always shown. Every employee that is backed by a real agent wears a nameplate above its head, so you can tell at once who is who. The idle pool employee shows "unoccupied" instead.

  • Side roster ("ON THE JOB"). A panel on the right lists every employee that currently has a task. Each row shows what the employee is doing, then the completion bar and the status:

    • a "Currently doing" line with the request the employee is working on — the first line of what the user asked (long requests are shortened to two lines, the full text is in the tooltip);
    • WORKING (blue) — the agent is running; the bar fills as it completes its steps;
    • NEEDS YOU (yellow) — the agent answered and is waiting for your reply;
    • DONE (green) — the task finished. The line stays readable after the run ends, so you can see what each worker has finished, not only what it is doing right now.

    An employee whose request the office cannot know (a subagent launched by another agent, or an instance forwarded by a different application) shows the tool it has in hand instead — PresentationTool.CreatePresentation reads as "Presentation Tool, Create Presentation". The panel hides itself when nobody is working. Clicking a row opens that employee's answer window.

  • Message icon and answer window. When an employee needs something from you to go on (its reply reads like a question or a request), a small speech-bubble icon appears above its head. Click the icon (or the employee's row in the roster) to open a window showing what the employee is currently doing and its progress bar first, then what it needs from you, with a text field to answer right there — your answer goes to the same conversation, exactly as if you had hired the employee and typed in the chat. The task line and the bar keep updating while the window is open, and never disturb the answer you are typing. The icon clears as soon as you answer.

How it works

AgentBridge and OfficeManager talk over a duplex WebSocket (/ws/office): the server pushes employee lifecycle events (spawn/assign/running/method/task/progress/needs/closed + chat messages), the browser sends chat_send, chat_hire (to hire a brand-new employee for a request when no employee is free) and close. The progress event carries the agent's step count (the completion bar), needs says whether the employee is waiting on you or has finished, and task carries the request the employee is working on. AgentBridge reports that request for every chat it starts — from the terminal, the HTTP API, Telegram or the office itself — right before the run begins, so the line is already there when the employee appears at the door. The full wire protocol is documented in OfficeBridge.cs (AgentBridge source).

Agents created by other processes are reflected by calling AgentHarness.ForwardGlobalProgressTo("http://localhost:5290") once at their startup (the AIOffice desktop app does this automatically; the URL is AgentBridge:Url in its appsettings). The forwarding is best-effort — an unreachable AgentBridge is never an error for the chat pipeline.

The OfficeManager app ships next to the executable (same rule as docs/) and never calls external services: the pixel font is bundled locally.

Third-party clients without session_id (dynamic-hash correlation)

session_id is a proprietary additive extension of /v1/chat/completions — it is not part of the OpenAI spec, so a third-party implementation may never send it. Without it, a multi-message chat would be a sequence of stateless one-shot agent instances (one employee per message). To keep such a chat as ONE conversation (one persistent employee), AgentBridge correlates stateless requests by content:

  • after every exchange the full transcript (roles + texts, including the assistant reply) is hashed with SHA-256 into a hash → session dictionary — the hash is dynamic, it changes at every output message;
  • the next request's transcript minus its last message (the "previous part" the client resends) is hashed the same way; a hit routes the request to that conversation, creating and seeding the session when the first message was processed one-shot.

Inherent limit: correlation needs the client to resend the accumulated transcript (which most OpenAI-style SDKs do). A client that sends only the newest message has no "previous part" to hash: those requests stay one-shot — short-lived employees that remain fully visible as granular monitoring (see above). Clients that want the canonical mapping should send session_id (one employee per chat, guaranteed).

Clone this wiki locally