Skip to content

perf: gate perf logs and dedup build_config_update on first message#8627

Merged
baxen merged 2 commits intomainfrom
baxen/first-message-perf
Apr 17, 2026
Merged

perf: gate perf logs and dedup build_config_update on first message#8627
baxen merged 2 commits intomainfrom
baxen/first-message-perf

Conversation

@baxen
Copy link
Copy Markdown
Collaborator

@baxen baxen commented Apr 17, 2026

Two small wins for first-message latency, discovered while tracing the full lifecycle from "new tab" → first token.

1. Gate perf logs so they're off by default

Previously, [perf:...] logs fired unconditionally on every session, both in the Rust backend (info!) and the goose2 frontend (console.log). Useful for debugging, noisy otherwise.

  • Rust: info!(target: "perf", ...)debug!(target: "perf", ...) (35 sites in goose-acp/src/server.rs). Silent by default, on with RUST_LOG=perf=debug.
  • Frontend: 41 console.log("[perf:...") call sites across 9 files replaced with a gated perfLog() helper at src/shared/lib/perfLog.ts. Logs only when import.meta.env.DEV or localStorage['goose.perf'] === '1'.
  • justfile: just dev and just dev-debug export RUST_LOG=${RUST_LOG:-perf=debug,info} so local dev gets perf logs out of the box, overrideable.
  • AGENTS.md: documents the toggles.

2. Remove redundant build_config_update on setProvider

While tracing the first-message path, I noticed build_config_update — which does an HTTP GET to the Databricks serving-endpoints API — was being called twice per set_config_option("provider"):

  1. Once inside the internal update_provider helper (result discarded).
  2. Once in the handler tail (to build the response + notification).

The first call was only needed to populate the response of the now-unused _goose/session/provider/update ACP custom method (on_update_provider). That method had no callers inside this repo, and set_config_option is the standard replacement.

Changes

  • Deleted UpdateProviderRequest / UpdateProviderResponse from crates/goose-sdk/src/custom_requests.rs.
  • Deleted on_update_provider handler and the _goose/session/provider/update custom method registration from crates/goose-acp/src/server.rs.
  • Internal update_provider helper now returns () and no longer calls build_config_update.
  • Regenerated crates/goose-acp/acp-schema.json, crates/goose-acp/acp-meta.json, and ui/sdk/src/generated/*.
  • Rewrote the one affected test (crates/goose-acp/tests/custom_requests_test.rs) to use set_config_option.

Measured impact

End-to-end "new tab → first message sent → stream ended" (Databricks, default model):

Phase Before After Δ
setProvider (server total) 2737ms 2600ms ~1 Databricks round-trip saved
sendMessage (client total) 7034ms 6526ms −508ms

The remaining set_config_option cost is almost entirely one fetch_recommended_models call against Databricks (measured at ~950ms – 2300ms across runs — highly variable). That's the next target, but worth its own PR.

Validation

  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test -p goose-acp -p goose-sdk
  • just check (biome, file-sizes, i18n, typecheck) in ui/goose2

Not in this PR

  • Caching / prefetching fetch_recommended_models (biggest remaining win, ~1–2s).
  • Frontend skipping setProvider when the server default already matches.
  • Parallelizing agent_setup extension loads (~500ms on the critical path).

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3945362b11

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/goose-acp/src/server.rs Outdated
Comment on lines +773 to +774
Ok(_) => info!(
target: "perf",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Demote perf-target logs to debug level

This log site still uses info!(target: "perf", ...), so any runtime configured with RUST_LOG=info will emit high-volume perf traces from hot paths and defeat the intended "perf logs only when explicitly enabled" behavior. Converting perf-target instrumentation to debug! keeps normal info logging usable while preserving opt-in perf tracing via RUST_LOG=perf=debug,....

Useful? React with 👍 / 👎.

baxen added 2 commits April 17, 2026 12:28
Backend (goose-acp): demote perf logs from info! to debug! with
target: "perf". Off by default; enable with RUST_LOG=perf=debug.

Frontend (goose2): add shared/lib/perfLog.ts which no-ops unless
Vite DEV or localStorage['goose.perf']='1'. Replace all bare
console.log('[perf:...') call sites with perfLog(...).

Dev ergonomics: just dev and just dev-debug export
RUST_LOG=perf=debug,info so the child goose serve emits perf
logs without extra setup. Documented the toggles in AGENTS.md
and refreshed the file-size justifications for AppShell and
ChatView to reflect the gated logging.

Signed-off-by: Bradley Axen <baxen@squareup.com>
The custom _goose/session/provider/update method duplicated the SACP 11
set_config_option path for config_id="provider". Having both meant:

  1. Two separate wire entry points for the same operation.
  2. The set_config_option handler called build_config_update twice
     per request — once inside update_provider (which built and
     discarded the Vec<SessionConfigOption>) and once in the handler
     tail. On providers that refresh their model list over HTTP
     (e.g. Databricks) each call costs ~1s, for ~2s of wasted work
     per provider switch.

Nothing in this codebase calls the custom method; goose2 uses
set_config_option exclusively.

Changes:
  - Remove UpdateProviderRequest/UpdateProviderResponse from goose-sdk.
  - Remove on_update_provider from goose-acp server.
  - Change internal update_provider helper to return () and stop
    calling build_config_update at the end — the set_config_option
    handler's single trailing build_config_update is now the only one.
  - Rewrite test_provider_switching_updates_session_state to exercise
    the set_config_option path three times instead of the removed
    custom method.
  - Regenerate acp-schema.json, acp-meta.json, and ui/sdk/src/generated.

Verified:
  - cargo test -p goose-acp (35 passed)
  - cargo clippy --all-targets -- -D warnings
  - ui/goose2 pnpm typecheck
Signed-off-by: Bradley Axen <baxen@squareup.com>
@baxen baxen force-pushed the baxen/first-message-perf branch from 3945362 to f993a3f Compare April 17, 2026 19:30
@baxen baxen enabled auto-merge April 17, 2026 19:30
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f993a3f593

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 47 to 48
method: "_goose/providers/list",
requestType: "ListProvidersRequest",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep provider-update RPC until text UI is migrated

This change removes the _goose/session/provider/update extension method from the generated SDK/protocol surface, but the text UI still calls client.goose.GooseSessionProviderUpdate(...) during provider/model apply (ui/text/src/configure.tsx:435). As soon as ui/text picks up this SDK/protocol revision, that onboarding/configure path will fail (missing client method or method-not-found from server), which blocks provider setup in the terminal product. Please keep a compatibility shim (or migrate ui/text in the same commit) before deleting this RPC.

Useful? React with 👍 / 👎.

Comment thread ui/goose2/justfile
Comment on lines +122 to 125
export RUST_LOG="${RUST_LOG:-perf=debug,info}"
PROJECT_DIR=$(pwd)
GOOSE_BIN="${PROJECT_DIR}/../../target/debug/goose"
export GOOSE_BIN
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore VITE_PORT initialization in dev-debug

The dev-debug recipe now enables set -u but no longer sets VITE_PORT before using ${VITE_PORT} in EXTRA_CONFIG_ARGS, so the recipe exits early with an unbound-variable error instead of launching the app. This breaks a documented local workflow for anyone running just dev-debug; reintroduce VITE_PORT={{ vite_port }} (and export it) as done in dev.

Useful? React with 👍 / 👎.

@baxen baxen added this pull request to the merge queue Apr 17, 2026
Merged via the queue into main with commit 8a51e34 Apr 17, 2026
26 checks passed
@baxen baxen deleted the baxen/first-message-perf branch April 17, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants