be4025e276c6cd19c66e4534d1b809ba13724251
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
be4025e276 |
v0.8.11: theme the settings dialog's fields and buttons
The Basic style paints its own controls: the two text fields came out as white boxes on the dark panel and the buttons looked nothing like the rest of the window. Both fields now carry the surface, border and focus colors the chat cards use (same shape as AskDialog's field), and the buttons follow the composer: Close is a quiet bordered button, Use this is the accent one. No behavior change; 36/36 UI checks still pass and the dialog was looked at again through CST_APP_SHOT. Version 0.8.11. |
||
|
|
69842edf16 |
v0.8.10: settings dialog (provider, model, key), window starts on a provider
The window could be started, but it could not be pointed anywhere: a provider,
a model and a key only came in on the command line. The gear in the header now
opens a dialog that changes all three on the engine's live config.
AgentCore (app/src/core/AgentCore.*):
- providers(): the engine's preset table (cst_provider_count/at), with base
URL, the remembered or preset model, whether a key exists and where it comes
from (cst_creds_resolve: "saved", or the environment variable), the preset's
key variable and the source ("built-in" / "user"). A key is read into a local
buffer only to answer "is there one"; it never leaves the C++ side.
- modelChoices(provider): the provider's own list (cst_provider_models), the
fetched cache (cst_ps_cached -- which writes through its out-parameters, so
it takes a real int, not NULL: passing one cost a segfault) and the
remembered pick. No network. modelInfo() is cst_model_info + its "200K ·
text only" label; usage() is cst_agent_usage for the session and the turn.
- useProvider(provider, model, key) -> "" or a reason: a different provider
goes through cst_ps_switch_provider() (the key is verified against /models
before it is saved; offline it is kept unverified and the header says so),
a key for the current one through cst_ps_set_key(), and the model is
remembered in settings.json. syncConfig() takes the engine's config back
over the app's copy, so provider/model/approval read correctly afterwards.
The engine's session is never touched by a switch.
- open() no longer starts with an empty provider: it takes the one the engine
used last (settings.json), else the built-in default, plus that provider's
base URL and model. Without this the first turn could not be sent at all and
no entry in the dialog was "in use".
QML (app/qml/SettingsDialog.qml, Main.qml):
- a modal dialog with the themed surface the other dialogs use (the Basic
style's light panel washes out the dark theme), the provider list with its
key state, a model field with the info label and clickable candidates, a
password field for a new key, the session's token counters, and a note that
reports what the last "Use this" answered.
Tests: 8 more checks -- the presets are readable, an unknown provider is
refused, the counters are readable, the gear opens the panel, the rows exist, a
model typed into the field reaches the engine, the note says so, Close puts the
dialog away. 36 checks pass. --uitest also points XDG_CONFIG_HOME at its
scratch directory now, so a run cannot rewrite the user's settings.json or
credentials, and CST_APP_SHOT writes shot.png at the end plus
shot-settings.png while the dialog is open (that is how the dialog above was
reviewed on a machine without a screen).
Verified: 36/36 UI checks, --selftest, ctest cst-app-selftest, make check rc=0,
and a screenshot of the dialog.
Version 0.8.10.
|
||
|
|
f5d340bd2a |
v0.8.9: sessions in the Qt front end, transcript replay, UI test helpers
A conversation is now something the window can pick. The sidebar lists the
workspace's stored sessions and switching replays one into the view.
Sessions (app/src/core/AgentCore.*, app/qml/SessionRow.qml, Sidebar.qml):
- AgentCore::open() resolves the workspace's current session through
cst_agent_store_resolve_default() before the engine starts. Without it the
engine opened session.jsonl in the process's working directory, next to a
session list that stayed empty.
- sessionId property; sessions() (id, title, firstUser, messages, mtime in ms,
current); newSession(), switchSession(), deleteSession() (moves the engine
off a session it has open first), renameSession(); sessionChanged and
sessionListChanged signals. No mutation runs during a turn.
- history() turns the open session back into the rows the live signals build
(kind/role/text/name/state/detail/output/exitCode/complete): system prompt
skipped, notes and attachments shown, assistant reasoning as a think row,
tool_calls_json as one card per call, and each result paired with its call
the way findTool() pairs the live stream. A call with no result keeps state
"unfinished" ("no result"), so a replay never shows a spinner that cannot
stop. Main.qml replays on sessionChanged.
- SessionRow.qml is a file of its own: as an inline component it would not see
the Repeater's modelData. Session controls are disabled while a turn runs.
Tests (app/src/ui/UiTest.cpp, app/src/main.cpp):
- the fixture session is written through the store's own API (a tool call with
its result), then the checks click its row, assert the five replayed rows and
the paired result, start two new sessions (the view empties), delete one by
its button (the open one stays), and switch back. 28 checks in total.
- item() falls back to the visual tree: delegates a model owns are not always
in the window's QObject tree, which is why the rows were invisible to
findChild even though they were on screen.
- --uitest drives a scratch workspace unless --workspace is given; it creates
and deletes sessions. CST_APP_SHOT=file saves the window as a PNG when the
run ends and CST_APP_DUMP=1 prints the session rows seen; both are how the
layout gets looked at on a machine without a screen.
QML: ThinkBlock's click target is a TapHandler on its row (a MouseArea anchored
inside a layout is undefined behavior and Qt said so).
Verified: 28/28 UI checks, --selftest, ctest cst-app-selftest, make check rc=0,
and a screenshot of a replayed session (cards, tool card with its result, the
think block, the sidebar list).
Version 0.8.9.
|
||
|
|
da812cc7e8 |
v0.8.8: Qt front end redesign, responsive shell, UI input tests
The window is no longer one file pretending to be a chat box. The transcript, the run panel, the composer and the two consent dialogs are their own QML components over one Theme singleton, and the shell around them adapts to the screen: docked and scrollable on a desktop, a slide-out drawer on a phone. QML (app/qml/, new except Main.qml): - Theme.qml: single QML singleton, dark Breeze-flavoured tokens (surface, border, accent, text/textDim/textFaint, radius, pad, gap, sizes, monospace); diffLineColor() for unified-diff rows, compactBreakpoint 880, touchTarget 34, segmentHeight 30, headerHeight 42. - ChatView.qml: a row-type dispatcher over the transcript model (message, thought, tool, note), follow-the-tail scrolling with a "jump to latest" button once the user scrolls up, and an empty state that says where the agent runs and what it can do. - MessageCard.qml, ThinkBlock.qml, NoteLine.qml, ToolCard.qml (status pill, arguments, collapsible output, 500-line cut, diff colouring, spinner while the call runs), TodoPanel.qml. - Sidebar.qml: workspace/provider/status, mode and approval segmented rows, plan switch, the engine's todo list, version footer; scrolls, so a short window still reaches every control. - Composer.qml: auto-growing field, Enter sends / Shift+Enter newlines, red Stop while a turn runs, autocorrect hints off, finger-sized targets. - ConsentDialog.qml (Deny / Once / Always -> CST_PERM_*) and AskDialog.qml (the model's options become buttons, free text stays possible). - Main.qml: shell with header, draggable sidebar splitter (hover feedback, 200-560 px, double-click resets), transcript, composer, the two dialogs, Esc to cancel and Ctrl+L to clear. Under 880 px the sidebar becomes a drawer with a scrim instead of squeezing the chat away. AgentCore / main.cpp: - provider, model, approval and planMode are properties now; approval and plan mode write back into the engine's config, and renderMarkdown() calls cst_web_md_html(), so a table or a code fence looks like the WebUI's. - the todo hook writes m_todo on the GUI thread (it was written from the worker thread before: a data race on a QString member). - --size WxH for the window (the layout tests drive it), and the Basic style is chosen by default: the Breeze Quick style registers its types with relative URLs, which floods the log and breaks the composer. UI tests (app/src/ui/): - --uitest drives the real window with synthesized input and exits with the number of failures: 15 checks over docking/drawer transitions, mouse clicks and touch taps reaching the engine's mode, the plan switch, the composer arming the send button, and a 460x900 -> 1200x820 resize round trip. - every control the tests touch carries an objectName; the sidebar's implicitHeight binding loop is gone. Tests: cst-app-selftest and --uitest pass in the standalone app build, ctest cst-app-selftest passes in the repo build (38/38 on the host). Version 0.8.8. |
||
|
|
5ba215b36c |
v0.8.7: tool capability metadata, in-process engine, Qt app, Android engine
The engine can be embedded now instead of only driven from a terminal: the same objects link into a Qt front end (app/) that owns a cst_agent_t inside its own process -- no port, no token, no second process -- and that front end now runs on the desktop and, engine-side, on the phone. Capability metadata (include/cst_tools.h, src/tools/registry.c): - cst_tool_def_t gains perm_name, platforms and available (a probe that returns a reason), so a permission is addressable by name and a tool can say why it cannot run here. - cst_platform_name(), cst_tool_platform_ok(), cst_tool_available(), cst_tool_meta_reload(), cst_tool_perm_name() and CST_PLAT_DESKTOP[]. - cst_tool_register() may take over a built-in name that is not runnable on this platform, so a front end replaces it with its own implementation. - the registry entries carry their class (delete_file -> "delete"), the desktop clipboard tools carry a clipboard probe; find/active/run gate on it. - /api/settings.tools[] exposes perm_name, platforms, available, why and the declared parameters. Engine as a library (Makefile, CMakeLists.txt): - libcstcore.a from the CORE_OBJ set, and a CMake cstcore target shared by the CLI and by app/ (-DCST_BUILD_APP=ON): the engine is compiled once. - Android branch for the vendored sashidown: a per-ABI archive built with the NDK's aarch64-linux-android24-clang wrapper, because CMake's compiler is plain clang and keeps --target/--sysroot in its own variables. Qt front end (app/, new): - AgentCore wraps one cst_agent_t: turns run on a worker thread, every cst_agent_hooks_t callback becomes a Qt signal, and the two hooks that need an answer (on_permission, on_ask_user) block the worker until the GUI replies; mode, approval and plan mode go through the engine's config. - ToolProvider hands the front end's tools to the engine (owner "app:*"); the Linux one is notification_send with a probe for notify-send/D-Bus. - Main.qml: transcript, tool blocks, consent dialog (Deny/Once/Always -> CST_PERM_*), ask_user, mode switch, Esc to cancel; --selftest stays headless and runs the embedding checks without QML. Android (scripts/, docs/android.md, new): - scripts/build_third_party_android.sh builds static mbedTLS + libcurl for an ABI (CA path /system/etc/security/cacerts); build_android.sh builds cst-agent, libcstcore.a and the test binaries for the phone, can push them and run the whole suite there. - sandbox_exec.c keeps the plain exec path on Android: the seccomp supervisor compiled in and the probe reported "seccomp", but writes outside the workspace were not denied on the device -- claiming a sandbox that does not hold is worse than reporting none. - tests/test_diff.c compares layouts only against real GNU diffutils: toybox's diff prints the same hunk header with its own hunk/context rules. Tests: test_tool_meta (metadata, platform gate, probe reasons, takeover of a built-in name) and test_embed (in-process embedding contract) are new; the existing registry/llm_body assertions now follow availability. 38 test binaries pass on the host, 36/36 on arm64-v8a Android 16, cst-app-selftest passes in both the standalone app/ build and the repo build. Version 0.8.7. |