The workspace that turns a model into an agent

QwenPaw's central engineering problem is not how to call a language model; it is how to turn one user request into a bounded, stateful, recoverable run. This chapter follows that path from a channel or Console through the Workspace, Runtime, AgentBuilder, agent loop, and response envelope. The aim is practical: once the boundaries are clear, readers can understand why the same agent can be reached from different front doors and why its effective tools depend on the request that is being processed.

A Workspace owns more than a prompt

The Workspace is QwenPaw's unit of operational ownership. It has a workspace directory and a service graph around the agent: sessions and chats, memory, communication channels, external Drivers, scheduled jobs, task tracking, and per-workspace plugin registries. This is not a list of optional accessories beside the model. These services determine what state exists, how a request is associated with an agent, and which capabilities can participate in the run.

A useful boundary is the difference between a workspace and a process-wide singleton. If two agent profiles share one unexamined global memory store, a preference or project detail can leak across identities. If every channel implements its own session rules, the same user may appear as several unrelated conversations. QwenPaw instead gives each workspace an agent identity, directory, and service ownership boundary. Multiple workspaces can still run in one application, but their state is not supposed to be reconstructed from a global bag of conversations on every request.

The service graph also gives startup and failure a structure. Services are described declaratively, started in priority order, and can be initialized concurrently when their lifecycle permits it. Some services are optional: a failure can leave the workspace without that feature rather than preventing every other part from starting. A service reused during a configuration reload is checked for compatibility before it is retained. A memory backend, for example, may be unavailable and temporarily fall back to another supported backend. That is a useful continuity policy, but it is also a boundary: a workspace that started without its intended memory service should not be described as behaviorally identical to a fully configured one.

This ownership model is what makes a profile more than a name and a system prompt. Its state includes the sessions, chats, jobs, skills, memory, and persona material associated with the workspace. The request can be bound to that identity before the model is called. The model's eventual answer is therefore the visible end of a sequence of ownership decisions: which workspace was selected, which configuration was loaded, and which services were available when the turn began.

The request passes through a fixed runtime path

QwenPaw's Runtime is the orchestrator for one request. It normalizes the incoming object, creates a request context and response envelope, and runs lifecycle hooks around a small number of fixed agent-touching steps. Before the model is involved, pre-dispatch hooks may inspect or short-circuit the request. Slash commands can be handled directly. Other hooks can add context, skip the agent, or stop processing before an expensive build occurs.

If the request continues, the Runtime builds an agent and then executes it. The separation matters. Dispatch logic does not need to know how a model is constructed, and the model loop does not need to know whether its input arrived through a browser or a messaging platform. Post-build and pre-execution hooks still have places to contribute, but the runtime retains a recognizable spine: prepare the request, build the agent, execute it, finalize the response.

sequenceDiagram participant C as Channel or Console participant R as Request runtime participant B as AgentBuilder participant A as QwenPawAgent participant G as Governance participant T as Tool or Driver participant S as Session store C->>R: AgentRequest R->>R: Normalize, dispatch hooks, slash commands R->>B: Build with workspace context B->>G: Create request-scoped governance B->>A: Inject model, prompt, tools, memory R->>A: Execute request A->>G: Check a tool call G->>T: Allow, sandbox, or ask T-->>A: Tool result A-->>C: Stream events and response R->>S: Save session state

The diagram's most important boundary is not the arrow from model to tool. It is the handoff from the Workspace into request construction. The Runtime supplies the current request context; the Builder turns that context and the agent configuration into an effective agent. The agent loop then reasons with the model and reaches tools through the controls that were assembled for that run.

This path also explains why a channel is not a second agent implementation. A channel converts native input into QwenPaw's request envelope, derives a session identity, and submits it to the workspace task tracker. It later consumes the same response events, including text, reasoning, tool output, and completion state, while rendering them in a channel-appropriate way. A Console event and a message from an external service can have different presentation rules while still entering the same lifecycle.

AgentBuilder decides what this run can see

AgentBuilder is the composition boundary between the persistent workspace and the transient turn. It loads the selected agent configuration, resolves the effective skills for the request, determines active modes, and asks the workspace for tools that satisfy the current gates. It can add tools for coding or visual context, Driver capabilities supplied by external integrations, memory-search tools, and the tools needed by an optional Scroll context strategy.

The result is deliberately narrower than “all tools installed in the application.” Tool availability can depend on the agent's configuration, active mode, enabled feature, selected skills, channel context, and a subagent whitelist. The local workspace filters descriptors before wrapping them with the policy-aware tool adapter. A plugin may have registered a capability globally, but that does not mean every agent or every turn sees it.

The Builder also creates the request-scoped ResourceGovernor against the workspace and effective project directories. That detail connects composition to safety. The tool list and the paths used by those tools must agree about what the request is operating on. A project switch made for one session should affect the policy and the sandbox mounts for that session, rather than leaving the prompt pointed at one directory while the governance layer checks another.

Only after these decisions does the Builder create the model and formatter, build the prompt, assemble middleware, and instantiate QwenPawAgent. The agent receives the model, system prompt, toolkit, middlewares, configuration, workspace, and optional context manager as dependencies. This design keeps the agent class from silently constructing its own world. Its behavior is the result of a composition step that can be inspected conceptually: model plus prompt plus tools plus memory plus policy plus request context.

That per-request construction has a practical consequence. Changing a skill, approval level, project directory, active mode, or model slot can change what the next request sees without requiring every capability to become a permanent property of the agent's identity. It also creates operational work: the system must rebuild or refresh the right components when configuration changes, and it must not assume that a reused service remains compatible with a new workspace state.

A concrete comparison makes the boundary easier to see. Suppose the same agent receives “prepare the project status update” through the Console and through a messaging channel. The two inputs may contain different metadata and use different reply mechanisms, but the channel adapter should first turn each into the common request shape. The Runtime can then dispatch control commands, establish the request context, and select the workspace without embedding Console-specific or messaging-specific reasoning in the agent. The response travels back through the originating surface, while the agent's session and workspace state remain owned by QwenPaw rather than by the transport.

The Runtime's hook phases are important because they keep this translation and control work explicit. A pre-dispatch hook can reject or answer a request before agent construction. Slash-command dispatch can handle an operation such as stopping or inspecting state without asking the model to interpret it. A post-dispatch or pre-build hook can add trusted context or decide that an agent run should be skipped. After construction, post-build and pre-execution hooks can observe the assembled agent, while post-response and finalization hooks handle persistence and cleanup. The names matter less than the ownership rule: each intervention has a place in the lifecycle, and the fixed path remains legible when a feature is absent.

The same structure limits accidental coupling. A channel does not need to know how memory is indexed. A memory service does not need to know how a message is rendered as a card or a terminal stream. A plugin contributing a middleware does not need to replace the agent's execution loop. The boundaries are not only abstractions for developers; they are also failure boundaries. If a channel cannot render a particular modality, that does not automatically mean the workspace lost the session. If an optional service is unavailable, the Runtime can still make the distinction between a request that needs that service and one that does not.

There is a trade-off. A request-time composition boundary makes behavior more precise, but it also makes effective behavior harder to infer from a single global configuration screen. The active mode, channel, skill set, project directory, subagent restrictions, model capability, and governance state can all affect the final toolkit. This is the cost of refusing to treat every installed capability as universally available. Operationally, the system must make the effective configuration observable enough for a user to understand why a tool is present, absent, allowed, or waiting for approval.

Hooks extend the path without replacing it

Plugins and modes can contribute hooks, slash commands, middleware, prompt sections, tools, channels, memory backends, and other behavior. The important design choice is where those contributions enter. The Runtime's hook phases provide named points before dispatch, after dispatch, before and after agent build, before execution, after response, on error, and during finalization. A plugin can participate in a known phase instead of taking over the entire request loop.

This is a form of structural restraint. Extensibility is valuable when a new capability can observe or modify the part of the lifecycle it actually owns. A memory-related middleware can participate in prompt or reply processing; a command can short-circuit before an agent is built; a mode can prepare a turn and influence the available tools. The fixed build and execute path remains understandable even as the registry grows.

The boundary is not absolute isolation. A plugin still supplies code and can introduce dependency, maintenance, and trust costs. A hook can fail, a tool can be unavailable, and a third-party provider can behave differently from the core runtime. The architecture limits where such behavior is attached and how it is cleaned up; it cannot make every extension correct by definition.

Failure is part of the normal lifecycle

A long-running assistant must preserve more than successful replies. QwenPaw's Runtime has explicit cancellation and error paths. When a turn is interrupted, it attempts to save the agent state, inject partial streamed text where appropriate, and close dangling tool calls so a resumed session does not contain an unmatched call with no result. When an ordinary error occurs, it records the failure, runs error hooks, emits an error envelope, and still closes the agent and its downstream services.

This is a different attitude from treating cancellation as a lost request. A user who presses Stop may have already received part of a response or caused a tool to begin work. If that partial state disappears, the next session can misread the conversation or repeat an action. Persisting an interrupted turn is therefore a consistency measure. It does not guarantee that an external side effect can be undone, but it preserves the local record of what happened and prevents malformed state from silently crossing the session boundary.

The same principle applies to streaming. Channels can receive incremental reasoning or message events, while the runtime keeps the response envelope and completion status coherent. A channel may choose to display only final text, show tool progress, or update a native message as deltas arrive. Presentation can vary; ownership of the run remains in the Runtime and Workspace.

The result is a system that has two kinds of stability. The first is functional stability: a normal request reaches the model, tools, and response path. The second is state stability: cancellation, optional services, plugin hooks, and provider errors leave the workspace in a recoverable condition or fail visibly rather than quietly fabricating continuity. The second kind is easy to miss when an assistant is judged only by the quality of its final paragraph.

The next pressure point is now clear. Even a well-defined request lifecycle cannot keep every previous turn in the model's live prompt forever. A long tool-running task will eventually outgrow the context window. QwenPaw's next design problem is how to reduce that live context while preserving the work the agent may need to recover.

References