跪拜 Guibai
← Back to the summary

Building a HarmonyOS Agent Workbench That Shows Intent, Not Chat

When integrating agent capabilities into a HarmonyOS application, the easiest misstep is to start by building a chat box. An input field, a send button, a list of bubbles—it seems to run quickly, but what you actually need to see during joint debugging isn't a single reply; it's what stage the task is currently in: whether the service is online, what intent the model has identified, which tool it's preparing to call, whether confirmation is needed, and where the error falls when it fails.

This time, what was built is a more engineering-oriented Agent workbench. The page doesn't pursue complex interactions, retaining only a few necessary objects: a local Agent Gateway, an ArkUI message list, Network Kit requests, intent routing results, and error states. Its goal isn't to let users chat idly with a model, but to give a clear status to an end-side task from input to routing.

First, get the service behind the end-side running

The workbench page can't be propped up by static data. Here, an Agent Gateway is first started on an M1 Mac local machine, listening on 127.0.0.1:18081. The large model Key is only placed in the Gateway's environment variables; the HarmonyOS end only accesses the local service and does not write the Key into the ArkTS code.

Local Agent Gateway Startup

This Gateway provides a few basic interfaces: /health is used to determine if the service is reachable, and /llm/route is used to convert natural language tasks into structured intents. The service status and intent results displayed later on the page both come from these two interfaces.

The /health return shows status: ok and the service name, indicating that the object the end-side needs to connect to already exists. Using curl to verify first here is to break down the problem: if the terminal can't access it, the page failure in DevEco isn't an ArkUI issue.

Health Check Interface Return

Next, a direct request is made to /llm/route, with the input: "What is the current status of this Gateway machine?". The returned result is no longer a piece of natural language, but a structured object containing intent, tool, needConfirm, and routeSource.

Intent Routing Interface Return

The difference between a workbench and a chat box is already visible here. A chat box cares about "how the model replies"; an Agent workbench cares about "what task the model has determined, and which capability it is preparing to hand the task to for execution." The ArkUI page that follows simply places this chain onto the end-side.

Starting from an empty project in DevEco Studio

The project is a new blank HarmonyOS application created in DevEco Studio, and entry/src/main/ets/pages/Index.ets can be seen in the directory. At the beginning, there is no complex engineering structure, just a page file and network permissions.

Creating HarmonyAgentLab Project

A very small message model is defined in the page: role indicates the source, status indicates the state, content holds the display text after the interface returns, and time records the local time. This model isn't complex, but it's more suitable for carrying the Agent process than simply concatenating strings.

There are only four core states:

@State inputText: string = 'What is the current status of this Gateway machine?'
@State messages: MessageItem[] = []
@State sending: boolean = false
@State serviceText: string = 'Not checked'

messages is responsible for carrying user input, assistant analysis, and errors; sending controls repeated clicks; serviceText is used to hold the return result of /health. The page looks very light at first, but it has already separated the "task status" from ordinary text.

Running the Page in DevEco Studio

Network permissions are placed in entry/src/main/module.json5. Without this step, even perfectly written page code might be blocked by network permissions at runtime.

{
  "name": "ohos.permission.INTERNET"
}

A principle is maintained here: the end-side is only responsible for requesting the Gateway and displaying status; it does not save the model Key on the end-side, nor does it stuff tool execution logic into the ArkTS page.

Health check enters the page first

A "Health Check" button is placed in the upper right corner of the page. Clicking it requests /health, and the service status is displayed directly at the top of the page. This button seems unremarkable, but it's very useful during joint debugging: it can quickly distinguish between "the page code is wrong" and "the Gateway isn't started."

HarmonyOS End Completes Health Check

After the health check passes, the page is no longer an isolated UI. It can already access the local Agent Gateway from the HarmonyOS end, and three things—Network Kit, end-side permissions, and the server-side port—are all running through.

Input a sentence, the page displays intent instead of a chat reply

The input box is pre-filled with a real joint debugging question:

What is the current status of this Gateway machine?

After clicking send, the page first inserts a user message, then inserts an assistant / pending message. After the interface returns, the pending message is replaced with the structured routing result:

intent=Check Gateway machine status
tool=local_status
needConfirm=false
source=llm
reason=The user wants to view the system, disk, and load summary of the current Gateway machine

HarmonyOS End Displays User Intent Routing

This step is the core of the workbench. The end-side does not directly display a reply like "the machine status looks normal," but first displays the tool selected by the model. The user can see that this task will be handed to local_status, and also that it doesn't require secondary confirmation. For an Agent entry point, these fields are more important than a smooth reply: they determine whether the user can judge if this task is trustworthy and executable.

The postRoute in the page does only three things: sends the request, parses the return, and updates the message status.

const route = JSON.parse(String(data.result)) as RouteResult
const content = 'intent=' + String(route.intent) + '\n' +
  'tool=' + String(route.tool) + '\n' +
  'needConfirm=' + String(route.needConfirm) + '\n' +
  'source=' + String(route.routeSource) + '\n' +
  'reason=' + String(route.reason)

To make the status visible, the message is not directly appended with the final result, but first displays as pending, then is replaced with success. This detail affects the actual user experience: the user knows the request has been sent and won't mistakenly think the button didn't register due to network waiting.

Error states must also enter the workbench

An Agent page cannot only handle the success path. Here, the Gateway address is temporarily changed to an incorrect one, causing the page request to fail. After failure, error / failed appears in the message list, with the content retaining the error information returned by Network Kit.

Unreachable State Under Incorrect Address

This failure state is more useful than popping up a generic prompt. It keeps the problem within the current task context: what the user sent before, which step failed afterward, and what the failure information is, all on the same page. During joint debugging, there's no need to switch back to the terminal to guess whether the service didn't start, the port was written incorrectly, or permissions weren't configured.

An engineering boundary is also exposed here: when the Previewer or simulator accesses 127.0.0.1, it's necessary to confirm that it points to the Mac's local service. If switching to LAN access, the Gateway needs to be started with 0.0.0.0, and the end-side address must also be changed to the Mac's LAN IP. Problems that can be solved on the local machine don't need to be detoured to a Linux server.

The workbench's boundary should fall on task status

This workbench only connects to two interfaces, /health and /llm/route, a very small scope, but it has already separated the things most easily mixed up in an end-side Agent entry point: service reachability, user input, model routing, execution status, and error feedback.

Chat UIs often only care whether a message has returned; a task workbench also cares whether the returned content can guide the next operation. intent explains what the task is understood as, tool explains which capability is prepared for use, needConfirm explains whether more cautious handling is needed, and reason explains why the model made this judgment. After the page lays out these fields, the user doesn't need to guess what the system actually did from a piece of natural language.

Judging from the results of this joint debugging, when integrating Agent capabilities on the HarmonyOS end, the ArkUI page must at least bear three responsibilities:

  1. Allow the user to initiate a task.
  2. Make the model's judgment process visible.
  3. Keep the failure state within the task context.

An ordinary chat box can only accomplish the first thing. An Agent workbench needs to do two more steps to be suitable for placement in a real application flow.

This implementation verified four points: the local Gateway is accessible, Network Kit can initiate requests from the HarmonyOS end, natural language tasks can be routed into structured results, and an incorrect address can form a clear failure state on the page. The page's functionality isn't large, but it advances the Agent entry point from "able to chat" to "able to see the task process." Once this step is done well, the end-side interaction is qualified to carry real tasks, rather than just staying within a Q&A shell.