Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
0598941
Redesign agent library and creation with avatars and voice instructions
klopez4212 Oct 9, 2026
d3374b2
Merge main while preserving agent creation and import workflows
klopez4212 Oct 9, 2026
d73c7d3
Validate redesigned agent workflows and add preview snapshots
klopez4212 Oct 9, 2026
149f59a
Fix agent settings regression test import
klopez4212 Oct 9, 2026
2d4f8d0
Update profile and icon coverage for agent redesign
klopez4212 Oct 9, 2026
7bfa0fd
Keep quick model feedback inside the floating picker
klopez4212 Oct 10, 2026
5c54ffe
Merge main and reconcile duplicate agent fixture methods
klopez4212 Oct 10, 2026
caba96a
Fix agent configuration interactions and update browser journeys
klopez4212 Oct 10, 2026
7a67069
Route Codex card configuration through the full editor
klopez4212 Oct 10, 2026
0df5e24
Wait for member list transition in rejection recovery test
klopez4212 Oct 10, 2026
adbadb0
Require explicit application of voice instruction drafts
klopez4212 Oct 10, 2026
aa9b5c8
Fix agent creation dismissal and shared control boundaries
klopez4212 Oct 10, 2026
c869e09
Keep agent recovery controls reachable during setup
klopez4212 Oct 10, 2026
d692922
Wait for current model authentication message in test
klopez4212 Oct 10, 2026
50d0b5e
Recover shared-agent browse reads from byte limits
klopez4212 Oct 10, 2026
f781764
Use supported role query options in browse regression
klopez4212 Oct 10, 2026
ce6cbda
Keep catalog byte-budget regression focused on reads
klopez4212 Oct 10, 2026
b2b536d
Preserve agent setup recovery and shared focus boundaries
klopez4212 Oct 10, 2026
40a68bc
Finish recovered agent setup and bundle native avatar codecs selectively
klopez4212 Oct 10, 2026
09694d6
Use explicit extension for native Vite config loading
klopez4212 Oct 10, 2026
5f3f82a
Fix remaining agent model and instruction focus findings
klopez4212 Oct 11, 2026
5d545e6
Verify pinned native speech archives before linking
klopez4212 Oct 11, 2026
f09a9d3
Exercise instruction recording through the real React hook
klopez4212 Oct 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
[workspace]
members = ["crates/pairing", "crates/plugin-manager", "crates/agent-controller", "crates/credential-store", "src-tauri"]
members = ["crates/pairing", "crates/plugin-manager", "crates/agent-controller", "crates/credential-store", "src-tauri", "vendor/sherpa-onnx-sys"]
default-members = ["crates/plugin-manager"]
resolver = "2"

[patch.crates-io]
sherpa-onnx-sys = { path = "vendor/sherpa-onnx-sys" }
8 changes: 8 additions & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,11 @@ Hermes Agent: the bundled `icons/hermes.png` is reused unchanged from Block Buzz
cropped the border, padded it to square, resized to 64×64 and quantised it to
16 colours. The MIT license terms above also apply to this artwork, with the
Nous Research copyright notice.

## Model family brand marks

DeepSeek, Grok, Kimi, Qwen, and Gemini SVG marks in
`src/shared/design-system/icons/ModelLogos.tsx` are adapted from
[Lobe Icons](https://github.com/lobehub/lobe-icons/tree/c385b2b8d1f9e19aa86e628d4e23c91ee1111a47/packages/static-svg/icons)
at revision `c385b2b8d1f9e19aa86e628d4e23c91ee1111a47`. SVG paths are unchanged; React sizing and accessibility use the shared icon gateway.
The MIT license is preserved in [LOBE-LICENSE.txt](src/shared/design-system/icons/LOBE-LICENSE.txt).
23 changes: 23 additions & 0 deletions crates/agent-controller/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,29 @@ impl Controller {
model_overridden: environment.contains_key("GOOSE_MODEL"),
})
}
/// Native-only instruction drafting follows saved Agent defaults, never the
/// unsaved agent or the process environment. Reuse launch resolution.
pub fn instruction_model_context(&self) -> Result<(String, ModelContext)> {
let saved = self.store.defaults()?;
if saved.harness != "buzz-agent" {
return Err("Voice instruction drafting currently needs Buzz Agent with Databricks v2 in Agent defaults".into());
}
let harness = crate::HarnessEdit {
command: "buzz-agent".into(),
args: vec![],
provider: saved.provider,
model: saved.model,
databricks: None,
integration: None,
configuration: None,
};
let resolved = crate::build_defaults().resolve(&harness, &saved.environment);
let context = model_context(&resolved, &saved.environment)?;
if resolved.model.trim().is_empty() {
return Err("Choose a model in Agent defaults before drafting instructions".into());
}
Ok((resolved.model, context))
}
pub fn draft_model_context(edit: AgentEdit) -> Result<ModelContext> {
let environment = draft_environment(edit.environment);
model_context(&edit.harness, &environment)
Expand Down
30 changes: 30 additions & 0 deletions crates/agent-controller/src/runtime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4260,3 +4260,33 @@ fn codex_saved_adapter_survives_global_install_without_silent_fallback() {
.codex_model_context(&saved.id, saved.revision, edit)
.is_err());
}

#[test]
fn instruction_model_uses_saved_defaults_and_native_overrides_without_writes() {
let dir = tempfile::tempdir().unwrap();
let store = Store::open(dir.path().join("config")).unwrap();
let mut defaults = crate::agent_defaults::AgentDefaults {
harness: "buzz-agent".into(),
provider: "databricks_v2".into(),
model: "saved-model".into(),
..Default::default()
};
defaults
.environment
.insert("DATABRICKS_HOST".into(), "https://workspace.example".into());
defaults
.environment
.insert("BUZZ_AGENT_MODEL".into(), "override-model".into());
store.save_defaults(&defaults).unwrap();
let controller = Controller::new(
store,
Arc::new(Memory),
Err("No runtime".into()),
dir.path().join("ownership"),
);
let (model, context) = controller.instruction_model_context().unwrap();
assert_eq!(model, "override-model");
assert_eq!(context.host.as_deref(), Some("https://workspace.example"));
assert_eq!(controller.store.defaults().unwrap().model, "saved-model");
assert!(controller.store.agents().unwrap().is_empty());
}
37 changes: 36 additions & 1 deletion docs/agent-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ saves the agent, starts it, then publishes its profile. A failed Start or profil
publication retains the saved identity and offers a retry for that step; it never
creates another identity. A native Start response can confirm a saved agent while
reporting that its process could not run. During Create, Start, or profile setup,
**Close** leaves the operation running and keeps recovery **Stop** available through **Manage agent**. Late completion never closes a subsequently opened dialog. If an operation
**Close** is disabled while setup is pending, and **Stop** remains available inside
the setup dialog for each known agent, using the controller's recovery admission.
After Stop is used, recovery feedback remains mounted when setup settles, until
explicit dismissal. Successful setup shows completion with the existing Close
action instead of offering another profile retry. Escape and backdrop clicks retain a dirty draft even after
validation or setup failure. Once setup settles into an error,
**Close** is available even if status refresh still fails. Late completion after a
host unmount never closes a subsequently opened dialog. If an operation
cannot be confirmed, refresh status before repeating it.

Create is blocked with an explanation if this app’s runtime is unavailable;
Expand Down Expand Up @@ -543,6 +550,11 @@ the form; Save first persists the exact native ID/revision, then publishes to th
agent's saved community without restarting it. Older native hosts without
`avatarEditingAvailable` retain the display-only avatar.

New agent creation offers the bundled Gloopies, Fuzzies and Figgies poster packs.
Picker previews are local; the selected versioned HTTPS poster URL is saved through
`AgentEdit.picture`, so published profiles remain usable by other clients. Initials
remain available. See `src/features/agents/avatar-packs/README.md` for provenance.

An omitted picture preserves the saved override; an empty string explicitly removes
it. A changed picture or name durably marks `profilePending` and remains persisted
across restart/reload until publication is confirmed. A successful profile publication
Expand Down Expand Up @@ -1166,3 +1178,26 @@ controls must remain reachable. Linked profiles remain visible on identity cards

Before starting an imported identity, stop the old agent and disable its automatic
startup in the old application. Do not run duplicate copies of the same identity.

### Voice instruction drafts

The desktop create form offers Text and Voice. Voice reuses the voice-note
recorder, limits recordings to two minutes, and encodes mono 16 kHz PCM WAV.
The native host validates size and format before local Parakeet inference via
sherpa-onnx. Audio remains in memory on this device; it is never uploaded.
The current English model is reused from
`~/.buzz/models/parakeet-tdt-ctc-110m-en/{model.int8.onnx,tokens.txt}`. A device
without that model gets an explicit error and can continue with Text; automatic
model provisioning is not implemented.

Only the transcript is sent to the saved Agent defaults model, using the app's
isolated Databricks OAuth connection. Drafting currently supports Buzz Agent
with Databricks v2 defaults and follows native environment selector precedence.
The pinned runtime's model capability manifest selects the gateway wire route.
Other default providers return an explicit unsupported-configuration error.
The transcript remains editable for retry. Generated instructions are a draft;
only Use instructions (or Replace instructions with draft) changes the form.
Closing or switching input mode discards late results, and never creates an
agent. Native work is bounded to one transcription and one draft at a time;
model requests time out after two minutes. Cancelling UI work does not interrupt
already-running local inference or a model request.
12 changes: 9 additions & 3 deletions docs/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@ add-existing membership, Save/recovery and all runner management are out of V1.
- Only definition ID/name, identity public key/name/definition link, and optional
avatar artwork leave the host. Prompts, configuration, credentials and execution receipts are not
projected. This is local library evidence, **not verified ownership**.
- The main individual-agent grid is reserved for native local agents; teams follow
it, with old/importable/relay inventory below. Browser-only hosts cannot establish
- The main individual-agent grid includes native local agents and the current
account’s existing relay identities; teams follow it. Only configured local
agents receive execution controls. Import candidates live in the Import tab;
**Your agents** is the default tab. **Import** opens the existing installation
import flow, and **Browse** reads explicitly shared kind-30175 definitions from
the current relay, with read-only details and paginated discovery. The page
header uses the same navigation styling as Channels. The page has no Refresh
control and omits the legacy-library partial-source warning. Browser-only hosts cannot establish
current local custody: their read-only library lives in a collapsed **Other
agents** section below teams, not in the individual-agent grid.
- The compatibility library shows one compact row per exact identity. Identity
details are available from its overflow button, not an exposed Public key link.
Explicit profile links still supply artwork; names never join identities.
Profiles with no linked identity appear separately; an archived identity does
Profiles with no linked identity are omitted; an archived identity does
not become an empty profile.
- Only distinct keys with the same displayed name need a short npub suffix. Names
alone never create a profile group. Suffix collisions extend deterministically using
Expand Down
Binary file added docs/screenshots/agent-creation/agents.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions scripts/avatar-codecs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { build } from "vite";
import { expect, it } from "vitest";
import { avatarCodecs } from "./avatar-codecs";

it.each([
["macos", 0, 49],
["windows", 49, 0],
["linux", 49, 0],
[undefined, 49, 49],
] as const)(
"emits only supported native avatar codecs for %s",
async (platform, webm, mp4) => {
const result = await build({
configFile: false,
logLevel: "silent",
plugins: [avatarCodecs(platform)],
build: {
write: false,
minify: false,
assetsInlineLimit: 0,
rollupOptions: {
input: "src/features/agents/avatar-packs.ts",
preserveEntrySignatures: "strict",
},
},
});
if (Array.isArray(result) || !("output" in result))
throw new Error("Unexpected build result");
const assets = result.output.filter((item) => item.type === "asset");
expect(
assets.filter((item) => item.fileName.endsWith(".webm")),
).toHaveLength(webm);
expect(
assets.filter((item) => item.fileName.endsWith(".mp4")),
).toHaveLength(mp4);
expect(
assets.filter((item) => item.fileName.endsWith(".png")),
).toHaveLength(49);
},
);
30 changes: 30 additions & 0 deletions scripts/avatar-codecs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Plugin } from "vite";

/** Keep native installs offline-capable without shipping the other engine's codec. */
export function avatarCodecs(platform: string | undefined): Plugin {
const excluded =
platform === "macos"
? "webm"
: platform === "windows" || platform === "linux"
? "mp4"
: undefined;
const empty = "\0unused-avatar-codec";
return {
name: "avatar-codecs",
enforce: "pre",
resolveId(source, importer) {
if (
excluded &&
importer
?.replaceAll("\\", "/")
.endsWith("/features/agents/avatar-packs.ts") &&
source.replaceAll("\\", "/").includes("/avatar-packs/") &&
source.split("?")[0]?.endsWith(`.${excluded}`)
)
return empty;
},
load(id) {
if (id === empty) return "export default undefined;";
},
};
}
3 changes: 3 additions & 0 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ tokio = { version = "1", features = ["sync", "time", "macros", "process", "io-ut
sha2 = "0.10"
hmac = "0.12"
base64 = "0.22"
sherpa-onnx = "=1.13.4"
# Keep the C bindings matched to the safe wrapper.
sherpa-onnx-sys = "=1.13.4"
Comment on lines +38 to +40

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Verify the native speech archive before linking it

These default features enable sherpa-onnx-sys's static build. In the pinned 1.13.4 build script, download_prebuilt_libs downloads a platform tarball from GitHub Releases, unpacks it without checking a digest, and links its Sherpa/ONNX libraries. Cargo.lock authenticates the Rust crate, not those separately downloaded binaries. I found no verified SHERPA_ONNX_ARCHIVE_DIR/SHERPA_ONNX_LIB_DIR provisioning in this repository's .github, scripts, bin, or .cargo build paths.

A replaced release asset can therefore change executable code in the signed app without any lockfile/source change. Pin the approved per-target archive digests and fail closed on mismatch before supplying the verified libraries to Cargo (including cache reuse), or build from pinned source. The version string alone does not pin these native bytes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Fixed in 5d545e6 (hosted head f09a9d3). The workspace patches the pinned sys crate so direct and transitive Cargo builds verify approved SHA-256 pins for all five supported static archives before extraction/linking. Cached/local archives use the same verification; extracted libraries are rebuilt from verified bytes, and unverified LIB_DIR overrides fail closed. Two archive regression tests, direct build-script corruption/override probes, and mandatory type/unit, design-system, and workspace Clippy gates passed. Independent source review found no blockers. Hosted DCO passed; CI is running. Windows/native live speech acceptance remains unverified.

reqwest = { version = "0.13", default-features = false, features = ["rustls", "stream"] }
bytes = "1"
url = "2"
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Info.plist
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict><key>NSMicrophoneUsageDescription</key><string>Buzz uses your microphone to record voice notes you choose to send.</string></dict></plist>
<plist version="1.0"><dict><key>NSMicrophoneUsageDescription</key><string>Buzz uses your microphone for voice notes and local transcription of agent instructions.</string></dict></plist>
2 changes: 2 additions & 0 deletions src-tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ fn main() {
"agent_control_local_clone_settings",
"agent_control_clone_settings",
"agent_control_use_here",
"agent_instruction_transcribe",
"agent_instruction_generate",
"agent_models_begin",
"agent_models_cancel",
"agent_models_run",
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@
"allow-agent-control-local-clone-settings",
"allow-agent-control-clone-settings",
"allow-agent-control-use-here",
"allow-agent-instruction-transcribe",
"allow-agent-instruction-generate",
"allow-agent-models-begin",
"allow-agent-models-cancel",
"allow-agent-models-run",
Expand Down
Loading
Loading