mirror of
https://github.com/block/buzz.git
synced 2026-11-05 00:41:28 +00:00
chore(desktop): reclaim file-size headroom for permission-policy fields
The relocation added required struct fields (permissionPolicy and friends) to files already at their line-count ratchet ceiling. Condense verbose doc comments, dedup the respond-to indicator label, and drop a redundant single-arg cn() so MessageRow.tsx, import.rs, the two managed-agent test modules, readiness.rs, and types.ts sit back at or below their caps. Behavior-neutral: no runtime logic changes. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
This commit is contained in:
@@ -126,8 +126,7 @@ pub struct AgentSnapshotImportResult {
|
||||
///
|
||||
/// This is the single authoritative selection path for all import-time
|
||||
/// allowlist and behavioral decisions. It is extracted as a pure, testable
|
||||
/// function so that unit tests exercise the exact production logic rather
|
||||
/// than a reconstruction of it.
|
||||
/// function so unit tests exercise the exact production logic.
|
||||
///
|
||||
/// # UI contract
|
||||
///
|
||||
@@ -148,9 +147,8 @@ pub struct AgentSnapshotImportResult {
|
||||
/// and there is no coherent value to write.
|
||||
///
|
||||
/// Non-allowlist + non-empty + Clear: preserve the source mode but empty the
|
||||
/// list. Only allowlist-mode requires a mode downgrade on Clear, because
|
||||
/// `allowlist` without entries is an invalid state. Non-allowlist modes
|
||||
/// remain valid with an empty list.
|
||||
/// list. Only allowlist-mode requires a mode downgrade on Clear, because
|
||||
/// `allowlist` without entries is an invalid state.
|
||||
pub(crate) fn resolve_snapshot_import_behavior(
|
||||
raw_respond_to: Option<&str>,
|
||||
raw_allowlist: &[String],
|
||||
@@ -313,8 +311,7 @@ pub(crate) fn decode_snapshot_from_bytes(
|
||||
/// (the owner identity or the named local agent record).
|
||||
///
|
||||
/// Returns the decoded manifest and whether it came from a locked envelope.
|
||||
/// When neither endpoint exists, fails closed with the locked-card refusal —
|
||||
/// never partial plaintext, never crypto details.
|
||||
/// When neither endpoint exists, fails closed with the locked-card refusal.
|
||||
pub(crate) fn decode_snapshot_for_import(
|
||||
file_bytes: &[u8],
|
||||
owner_keys: Option<&nostr::Keys>,
|
||||
@@ -363,11 +360,10 @@ where
|
||||
/// envelope's two exact key endpoints; a card that cannot be unlocked fails
|
||||
/// with the locked-card refusal (shown directly to the user), never a
|
||||
/// partial preview. Identity-recovery mode is tolerated: owner keys are
|
||||
/// simply unavailable, so only the agent-record endpoint can unlock.
|
||||
/// unavailable, so only the agent-record endpoint can unlock.
|
||||
///
|
||||
/// Returns an `AgentSnapshotImportPreview` or a descriptive error. Errors
|
||||
/// represent irrecoverable failures (corrupt / unsupported / locked-to-
|
||||
/// someone-else file) and are shown directly to the user.
|
||||
/// Returns an `AgentSnapshotImportPreview` or a descriptive error shown
|
||||
/// directly to the user (corrupt / unsupported / locked-to-someone-else).
|
||||
#[tauri::command]
|
||||
pub async fn preview_agent_snapshot_import(
|
||||
file_bytes: Vec<u8>,
|
||||
@@ -446,8 +442,8 @@ pub(crate) fn build_agent_snapshot_import_preview(
|
||||
/// via `sync_managed_agent_profile`.
|
||||
/// 4. Memory — for each opted-in entry, build a fresh `kind:30174` event
|
||||
/// with `engram::build_event` under the new agent↔owner conversation
|
||||
/// key and POST it to the relay. Failures are collected and returned as
|
||||
/// `memory_errors`; the agent itself is already created.
|
||||
/// key and POST it. Failures are collected as `memory_errors`; the
|
||||
/// agent itself is already created.
|
||||
///
|
||||
/// Importing the same file twice yields two distinct agents with different
|
||||
/// keypairs. No source identity material (pubkey, nsec, auth_tag, relay_url,
|
||||
@@ -459,8 +455,7 @@ pub async fn confirm_agent_snapshot_import(
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<AgentSnapshotImportResult, String> {
|
||||
// ── Phase 1: validate (no writes) ────────────────────────────────────────
|
||||
// Locked cards unlock only via this machine's exact key endpoints;
|
||||
// anything else fails closed here, before key generation.
|
||||
// Locked cards unlock only via this machine's exact key endpoints.
|
||||
let snapshot = {
|
||||
let owner_keys = state.signing_keys().ok();
|
||||
let records = {
|
||||
|
||||
@@ -1408,8 +1408,7 @@ fn registry_warm_then_try_record_resolves_custom_id() {
|
||||
/// NOT silently fall back to buzz-agent.
|
||||
///
|
||||
/// This test would fail if save/delete commands do not call
|
||||
/// warm_harness_registry_from_dir transactionally, or if try_record_agent_command
|
||||
/// silently falls back to default_agent_command() for dangling ids.
|
||||
/// warm_harness_registry_from_dir transactionally.
|
||||
#[test]
|
||||
fn registry_delete_then_try_record_returns_dangling_error() {
|
||||
use crate::managed_agents::custom_harnesses::{
|
||||
@@ -1718,9 +1717,7 @@ fn builtin_catalog_entry_has_empty_definition_env() {
|
||||
// These drive `discover_acp_runtimes_from` itself and land a save/delete in
|
||||
// the window between its directory scan and its registry publish (via the
|
||||
// `pre_publish_test_hook` seam). They red if discovery's final line reverts
|
||||
// to publishing its pre-probe `loaded_defs` snapshot — the original bug —
|
||||
// unlike the `custom_harnesses` seam tests, which pin only the fresh-read
|
||||
// contract of `warm_harness_registry_locked`.
|
||||
// to publishing its pre-probe `loaded_defs` snapshot — the original bug.
|
||||
|
||||
/// RAII guard: installs the pre-publish hook, clears it on drop (even on
|
||||
/// panic) so a failing test cannot poison later ones.
|
||||
|
||||
@@ -111,10 +111,9 @@ pub(crate) struct EffectiveHarnessDescriptor {
|
||||
///
|
||||
/// Returns `Err("DANGLING_HARNESS_ID:<id>")` when the record (or its linked
|
||||
/// persona) references a runtime id that no longer exists in the registry —
|
||||
/// the same typed error produced by `try_record_agent_command`. Callers that
|
||||
/// cannot meaningfully continue with a dangling id (e.g. `spawn_agent_child`)
|
||||
/// propagate the error; callers that degrade gracefully may use
|
||||
/// `.unwrap_or_else(|_| …)`.
|
||||
/// the same typed error produced by `try_record_agent_command`. Callers that
|
||||
/// cannot continue with a dangling id (e.g. `spawn_agent_child`) propagate the
|
||||
/// error; callers that degrade gracefully may use `.unwrap_or_else(|_| …)`.
|
||||
///
|
||||
/// Does NOT require an `AppHandle` so it is fully unit-testable.
|
||||
///
|
||||
@@ -396,9 +395,8 @@ impl AgentReadiness {
|
||||
/// * **unknown / custom command**: always `Ready` (no requirements known).
|
||||
///
|
||||
/// Databricks note: `DATABRICKS_TOKEN` is `.unwrap_or_default()` in
|
||||
/// `buzz-agent/src/config.rs:143` — it is an escape hatch for static tokens
|
||||
/// but the normal path is OAuth PKCE. We intentionally do NOT mark the
|
||||
/// token as required to avoid a false NotReady for users on OAuth.
|
||||
/// `buzz-agent/src/config.rs:143` — an escape hatch for static tokens, but
|
||||
/// the normal path is OAuth PKCE, so we do NOT mark the token as required.
|
||||
pub(crate) fn agent_readiness(effective: &EffectiveAgentEnv) -> AgentReadiness {
|
||||
let runtime = known_acp_runtime(&effective.effective_command);
|
||||
let missing = collect_missing_requirements(effective, runtime);
|
||||
|
||||
@@ -1014,8 +1014,7 @@ fn invalid_pubkey_resolves_no_pair_key() {
|
||||
// Linux used an AND-gate (name + marker) — wrong for custom harnesses.
|
||||
// Fix: all platforms gate on `process_has_buzz_marker` alone; the receipt path
|
||||
// is verified below via `valid_agent_runtime_receipt_with` (injectable),
|
||||
// which no longer takes a name-check predicate at all — reinstating an
|
||||
// AND-gate would be a signature change these tests would catch.
|
||||
// which no longer takes a name-check predicate at all.
|
||||
|
||||
// ── Collector-discriminating sweep tests (C-9 / Thufir F6) ──────────────────
|
||||
//
|
||||
|
||||
@@ -167,8 +167,7 @@ export const MessageRow = React.memo(
|
||||
videoReviewCommentRootId?: string;
|
||||
videoReviewContext?: VideoReviewContext;
|
||||
}) {
|
||||
// Keep the transient send state with its timestamp rather than collapsing
|
||||
// it into a grouped message row with no header.
|
||||
// Keep transient send state on its own row, never a headerless group row.
|
||||
const isDisplayedAsContinuation = isContinuation && !message.pending;
|
||||
const [expandedDiffId, setExpandedDiffId] = React.useState<string | null>(
|
||||
null,
|
||||
@@ -247,10 +246,9 @@ export const MessageRow = React.memo(
|
||||
() => resolveMentionProps(message.tags, profiles),
|
||||
[profiles, message.tags],
|
||||
);
|
||||
// "Is this pubkey an agent" = the community-scoped baseline every surface
|
||||
// shares (managed ∪ relay) plus the pubkey's own profile `isAgent` flag from this surface's lookup. Both are per-pubkey
|
||||
// O(1) checks — no per-row rescan of `profiles` (that duplicated parent
|
||||
// work in every mounted row and re-ran on each profile-lookup change).
|
||||
// "Is this pubkey an agent" = the community-scoped baseline (managed ∪
|
||||
// relay) plus the pubkey's own profile `isAgent` flag — both O(1) per
|
||||
// pubkey, no per-row rescan of `profiles`.
|
||||
const knownAgentPubkeys = useKnownAgentPubkeys();
|
||||
const isKnownAgentPubkey = React.useCallback(
|
||||
(pubkey: string) => {
|
||||
@@ -439,10 +437,9 @@ export const MessageRow = React.memo(
|
||||
emojiOnly &&
|
||||
"text-4xl leading-tight [&_p]:leading-tight [&_img[data-custom-emoji]]:h-[1.45em] [&_img[data-custom-emoji]]:align-middle [&_button:has(img[data-custom-emoji])]:align-middle",
|
||||
)}
|
||||
// Only pass the author pubkey for agent-authored messages so
|
||||
// config-nudge cards can authenticate the sender. Uses the
|
||||
// raw event signer (signerPubkey), not a relay-delegated display
|
||||
// author, because the agent itself must have signed the card.
|
||||
// Author pubkey only for agent messages, so config-nudge cards
|
||||
// authenticate the sender. Uses the raw event signer
|
||||
// (signerPubkey), not a relay-delegated author.
|
||||
configNudgeAuthorPubkey={getConfigNudgeAuthorPubkey(
|
||||
message,
|
||||
isKnownAgentPubkey,
|
||||
@@ -474,6 +471,10 @@ export const MessageRow = React.memo(
|
||||
|
||||
const showRespondToIndicator =
|
||||
message.respondTo === "anyone" || message.respondTo === "allowlist";
|
||||
const respondToIndicatorLabel =
|
||||
message.respondTo === "anyone"
|
||||
? "Anyone can send instructions to this agent"
|
||||
: "Selected people can send instructions to this agent";
|
||||
|
||||
const avatarNode = (
|
||||
<div className="relative shrink-0">
|
||||
@@ -488,20 +489,10 @@ export const MessageRow = React.memo(
|
||||
!hideAgentAccessBadge &&
|
||||
!isThreadReplyLayout ? (
|
||||
<span
|
||||
className={cn(
|
||||
"absolute -bottom-0.5 -right-0.5 flex h-3 w-3 items-center justify-center rounded-full bg-background",
|
||||
)}
|
||||
className="absolute -bottom-0.5 -right-0.5 flex h-3 w-3 items-center justify-center rounded-full bg-background"
|
||||
role="img"
|
||||
aria-label={
|
||||
message.respondTo === "anyone"
|
||||
? "Anyone can send instructions to this agent"
|
||||
: "Selected people can send instructions to this agent"
|
||||
}
|
||||
title={
|
||||
message.respondTo === "anyone"
|
||||
? "Anyone can send instructions to this agent"
|
||||
: "Selected people can send instructions to this agent"
|
||||
}
|
||||
aria-label={respondToIndicatorLabel}
|
||||
title={respondToIndicatorLabel}
|
||||
>
|
||||
{message.respondTo === "anyone" ? (
|
||||
<AlertTriangle
|
||||
@@ -940,8 +931,8 @@ export const MessageRow = React.memo(
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
// Callbacks (onReply, onToggleReaction) intentionally excluded: inline arrows
|
||||
// from parent create new refs every render — including them defeats memo.
|
||||
// Callbacks (onReply, onToggleReaction) excluded: parent inline arrows get
|
||||
// new refs every render, so including them would defeat memo.
|
||||
},
|
||||
(prev, next) =>
|
||||
prev.message.id === next.message.id &&
|
||||
@@ -953,18 +944,15 @@ export const MessageRow = React.memo(
|
||||
prev.message.ownerLabel === next.message.ownerLabel &&
|
||||
prev.message.avatarUrl === next.message.avatarUrl &&
|
||||
prev.message.accent === next.message.accent &&
|
||||
// The header timestamp and hover gutter both derive from createdAt (the
|
||||
// old `time` prop was the same value pre-formatted; this row reads neither).
|
||||
// Header timestamp and hover gutter both derive from createdAt.
|
||||
prev.message.createdAt === next.message.createdAt &&
|
||||
prev.message.depth === next.message.depth &&
|
||||
prev.message.kind === next.message.kind &&
|
||||
prev.message.pending === next.message.pending &&
|
||||
prev.message.edited === next.message.edited &&
|
||||
prev.message.editSignerPubkey === next.message.editSignerPubkey &&
|
||||
// Value comparisons, not identity: these arrays are rebuilt with fresh
|
||||
// identities on every ingest/refetch even when unchanged — identity
|
||||
// checks made every row re-render on every streamed event in an open
|
||||
// thread (see messageRowEquality.ts).
|
||||
// Value comparisons, not identity: these arrays get fresh identities on
|
||||
// every ingest/refetch even when unchanged (see messageRowEquality.ts).
|
||||
reactionsEqual(prev.message.reactions, next.message.reactions) &&
|
||||
tagsEqual(prev.message.tags, next.message.tags) &&
|
||||
prev.message.role === next.message.role &&
|
||||
|
||||
@@ -739,8 +739,7 @@ export type AgentPersona = {
|
||||
|
||||
/**
|
||||
* A catalog publication's coordinate: the owner who published it and the
|
||||
* `d`-tag identifying the persona within that owner's catalog. Mirrors the
|
||||
* backend `CatalogSource`.
|
||||
* `d`-tag identifying the persona within that owner's catalog.
|
||||
*/
|
||||
export type CatalogSourceCoordinate = {
|
||||
ownerPubkey: string;
|
||||
@@ -954,8 +953,8 @@ export type ForumThreadResponse = {
|
||||
*
|
||||
* The event-id tiebreak is load-bearing: thread replies routinely share a
|
||||
* `createdAt` second (bursty threads), so a timestamp-only cursor would skip
|
||||
* every tied reply past the page limit. The pair `(createdAt, eventId)` orders
|
||||
* replies unambiguously and lets paging resume strictly after the last event.
|
||||
* every tied reply past the page limit. `(createdAt, eventId)` orders replies
|
||||
* unambiguously and lets paging resume strictly after the last event.
|
||||
*/
|
||||
export type ThreadCursor = {
|
||||
createdAt: number;
|
||||
@@ -976,8 +975,7 @@ export type ThreadRepliesResponse = {
|
||||
* The event-id tiebreak is load-bearing for the dense-second case: the relay
|
||||
* orders `created_at DESC, id ASC` and advances past a second denser than one
|
||||
* page with `id > eventId`. A bare `createdAt` (`until`) cursor cannot escape
|
||||
* such a second — it re-returns the same slice forever, leaving older history
|
||||
* unreachable. `(createdAt, eventId)` moves strictly older every page.
|
||||
* such a second. `(createdAt, eventId)` moves strictly older every page.
|
||||
*/
|
||||
export type ChannelPageCursor = {
|
||||
createdAt: number;
|
||||
@@ -997,9 +995,7 @@ export type ChannelMessagesPageResponse = {
|
||||
* Global agent configuration defaults applied to ALL agents.
|
||||
*
|
||||
* Lowest user-settable layer — per-agent and persona values win on any key
|
||||
* collision. Mirrors the Rust `GlobalAgentConfig` struct.
|
||||
*
|
||||
* Precedence: baked floor < global < persona < per-agent.
|
||||
* collision. Precedence: baked floor < global < persona < per-agent.
|
||||
*/
|
||||
export type GlobalAgentConfig = {
|
||||
/** Global env vars injected into all agents unconditionally. */
|
||||
|
||||
Reference in New Issue
Block a user