AgenticAI — a WebView2 agent UI
Source: samples/AgenticAI/agenticai.prg (+ agenticai.hbp, build.bat)
AgenticAI is a FiveWin GUI front-end for the ccharbour agentic engine.
It runs the same streaming chat + tool-calling loop that powers the console
cc.exe (CC_Client / CC_AgentRun), but renders it as a
modern web chat panel hosted in an embedded Edge WebView2
(TWebView2) that fills a resizable dialog — no RichEdit, no .rc.
What the panel shows
- Streaming bubbles — the assistant answer streams live as plain
text; at the end of the turn the raw markdown is re-rendered (tables, code blocks,
lists) with
marked.js. - Collapsible "N actions" panel — per-tool rows with icons (file / terminal / search / globe / memory), a pending spinner that becomes a green check, or a red X on error.
- Permit / reject card — when "Auto-approve" is off, every
mutating tool (
shell/write/edit) shows a confirmation card and the turn blocks until you decide. - ask_user card — a multiple-choice question wired to the webview (replaces ccharbour's console selector, which cannot prompt without a console).
- "Code generated" bar with a View Changes (Diff) toggle that renders the ccharbour diff with red/green lines.
- Slash commands —
/key <api-key>sets the LLM key at runtime, plus/tools,/clear,/help.
PRG ↔ page bridge
PRG drives the page with oWeb:Eval( jsFunc(...) ); the page calls back with
SendToFWH( action, text ), delivered to TWebView2:bOnBind.
The full local tool set (read / write / edit / glob / grep / shell / web_search /
web_fetch / memory) is registered and wrapped in a permission gate.
Three gotchas worth remembering
| Problem | Cause & fix |
|---|---|
| Permit / ask / stop click deadlocks mid-turn | WebView2 does not deliver a second bound-function call while the first
bOnBind is still on the stack. So send only queues the
prompt; a TTimer launches the turn from WM_TIMER, outside any
bOnBind, where the nested permit/ask/stop clicks are delivered. |
| Accents / emoji mojibake | WebView2_Eval converts its argument from the ANSI codepage. Pass every
non-ASCII codepoint as a pure-ASCII \uXXXX-escaped JS string literal
(surrogate pairs for emoji) so it is codepage-independent. |
| The whole <script> silently failed | A Harbour TEXT INTO block is C-escape-processed: '\n' inside
JS became a real line feed and broke the string. Keep the embedded JS backslash-free
— use String.fromCharCode(10) and character-class regexes
([0-9], [ ]) instead of \n, \d,
\s. |
Build & run
Multi-module (GUI prg + ccharbour core), so it is built with its own
build.bat (hbmk2 + agenticai.hbp), not
samples/build_new.bat. It needs the WebView2 runtime installed and an LLM
key (env DEEPSEEK_API_KEY … or /key at runtime).
cd /d C:\fwteam\samples\AgenticAI
build.bat