Skip to content

experimental genie ask: multi-turn conversations via --session/-s#5762

Open
lennartkats-db wants to merge 17 commits into
mainfrom
genie-ask-improvements
Open

experimental genie ask: multi-turn conversations via --session/-s#5762
lennartkats-db wants to merge 17 commits into
mainfrom
genie-ask-improvements

Conversation

@lennartkats-db

Copy link
Copy Markdown
Contributor

Changes

Adds multi-turn conversations to databricks experimental genie ask:

  • -s, --session <label> continues a conversation across calls. The label is any string you pick; it maps to the server conversation id in a local store (~/.databricks/genie-conversations.json, same pattern as cmd/sandbox/state.go), so you never copy an id around:
    SESSION=$$   # the shell's pid makes a handy per-session label
    databricks experimental genie ask --session $SESSION "what tables are in samples.wanderbricks?"
    databricks experimental genie ask --session $SESSION "how many did you just list?"
    
  • The server only accepts conversation ids it issued, so a label pointing at an expired/unknown conversation fails open: forget the dead mapping, note it on stderr, and retry as a fresh conversation. All store I/O is best-effort — any read/write error (perms, corrupt file, full disk) degrades to "no persistence", never to a failed ask.
  • Ctrl-C and kill (SIGINT + SIGTERM) cancel the stream cleanly instead of dumping context canceled — SIGTERM matters because agents stop child processes with it.

Tests

Unit tests for the store (round-trip, host scoping, TTL, corrupt-file recovery) and the resolve/fail-open/store orchestration (first-use, reuse, dead-mapping retry, error-after-output, cancel). Verified live on dogfood: reuse threads context, distinct labels stay independent, a seeded dead mapping fails open + remaps, parallel different-label sessions are independent, and SIGINT/SIGTERM exit cleanly.

…g header

The /api/2.0/data-rooms/tools/onechat/responses endpoint is workspace-scoped.
Without the org-id header the gateway rejects the request with "Credential was
not sent or was of an unsupported type for this API" even when auth is otherwise
valid (reproduced live on dogfood). Resolve it from cfg.WorkspaceID and send it,
matching how workspace-scoped routing works elsewhere.

Co-authored-by: Isaac
…e ask

--conversation continues a prior conversation: the request field is camelCase
conversationId carrying the conversation_id from response.completed (the backend
ignores the snake_case form; verified live). The id is surfaced as a text footer
and in --output json so the next turn can use it.

A scoped signal.NotifyContext makes Ctrl-C cancel the stream cleanly ("Cancelled.",
exit 1) rather than dumping "context canceled"; kept distinct from the stall path.

Stacked on the X-Databricks-Org-Id header fix.

Acceptance: the JSON golden gains conversation_id (updated here); the text-mode
sections also gain a "Continue this conversation" footer that still needs
regenerating with 'go test ./acceptance -run TestAccept/experimental/genie/ask
-update' (requires jq>=1.7, unavailable where this was built).

Co-authored-by: Isaac
Switch the workspace routing header from the hardcoded legacy X-Databricks-Org-Id
to the canonical auth.WorkspaceIDHeaders helper (X-Databricks-Workspace-Id),
matching how `databricks api` and the SDK route workspace-scoped calls.
Re-verified live on dogfood; tests assert the canonical header.

Co-authored-by: Isaac
Propagate the canonical-header fix onto this stacked branch (matching the org-id
fix PR) so merging it doesn't regress the routing header. Sends
X-Databricks-Workspace-Id; tests assert it.

Co-authored-by: Isaac
The auth.WorkspaceIDHeaders call sites elsewhere carry no comment; this one
shouldn't either.

Co-authored-by: Isaac
Advance the stack base so this PR's diff shows only the multi-turn + Ctrl-C
changes, not the header fix it builds on.

Co-authored-by: Isaac
--conversation/-c now takes a client-chosen label (any string) instead of a
server conversation id. The label maps to the server conversation id in a local
cache (libs/cache, keyed by host+label), so follow-ups just reuse the same label:

  genie ask -c q3 'what tables are in samples.wanderbricks?'
  genie ask -c q3 'how many did you just list?'

The server only accepts conversation ids it generated, so a label that maps to an
expired/unknown id fails open: the command forgets the dead mapping, notes it on
stderr, and retries as a fresh conversation. Drops the stdout/stderr footer.

Co-authored-by: Isaac
…rchestration

Move the label->server-conversation-id map from libs/cache to
~/.databricks/genie-conversations.json, matching the cmd/sandbox/state.go store
pattern (0600 file / 0700 dir, atomic tmp+rename, per-entry TTL, fails open).

Extract the resolve/fail-open/store flow into askWithConversation so it is unit
tested directly: first-use stores, reuse refreshes, a dead mapping fails open
(forget + retry fresh), output-before-error is not retried, and a cancel keeps
the mapping.

Co-authored-by: Isaac
-c is the conventional short flag for --continue, so reserve it (and avoid the
clash) by naming the session-label flag --session/-s instead.

Co-authored-by: Isaac
Match the filestore.go atomic-write idiom: defer Close, tmp.Chmod on the handle.
No behavior change.

Co-authored-by: Isaac
- Rename label -> session id throughout; store maps sessionId -> conversationId.
- Store as a nested host -> sessionId -> entry map (drops the host+"\n"+label key).
- Windows-safe store path via filepath.Join(home, ".databricks", ...).
- Cancel on SIGTERM as well as SIGINT (agents stop children with SIGTERM).
- Warn on stderr when --session is combined with --raw (no conversation tracked).
- Recover from a corrupt store file (treat as empty); add a regression test.
- Doc cleanups: Returns-style render comments, clearer warehouse-id note, trim others.

Co-authored-by: Isaac
Resolves the phantom conflict in client_test.go (#5735 squash-merged into main
while this branch carries the same header fix via merge): keep this branch's
version, which uses the updated 3-arg BuildRequest signature.

Co-authored-by: Isaac
@eng-dev-ecosystem-bot

eng-dev-ecosystem-bot commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Integration test report

Commit: 0c0b043

Run: 28429148686

Env 🟨​KNOWN 🔄​flaky 💚​RECOVERED 🙈​SKIP ✅​pass 🙈​skip Time
🟨​ aws linux 7 1 13 230 1037 5:13
🟨​ aws windows 7 1 13 232 1035 5:43
💚​ aws-ucws linux 8 13 314 955 4:43
💚​ aws-ucws windows 8 13 316 953 3:10
🔄​ azure linux 3 1 15 228 1036 5:27
💚​ azure windows 2 15 232 1034 2:54
💚​ azure-ucws linux 2 15 316 952 4:31
💚​ azure-ucws windows 2 15 318 950 2:56
💚​ gcp linux 2 15 229 1038 3:22
💚​ gcp windows 2 15 231 1036 2:31
23 interesting tests: 13 SKIP, 7 KNOWN, 3 flaky
Test Name aws linux aws windows aws-ucws linux aws-ucws windows azure linux azure windows azure-ucws linux azure-ucws windows gcp linux gcp windows
🟨​ TestAccept 🟨​K 🟨​K 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R 💚​R
🙈​ TestAccept/bundle/invariant/no_drift 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/permissions 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/with_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions 🟨​K 🟨​K 💚​R 💚​R 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=direct 🟨​K 🟨​K 💚​R 💚​R
🟨​ TestAccept/bundle/resources/permissions/jobs/destroy_without_mgmtperms/without_permissions/DATABRICKS_BUNDLE_ENGINE=terraform 🟨​K 🟨​K 💚​R 💚​R
🙈​ TestAccept/bundle/resources/postgres_branches/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/recreate 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/replace_existing 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/update_protected 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_branches/without_branch_id 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_endpoints/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/postgres_projects/update_display_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/synced_database_tables/basic 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_endpoints/drift/recreated_same_name 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/bundle/resources/vector_search_indexes/recreate/embedding_dimension 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🙈​ TestAccept/ssh/connection 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S 🙈​S
🔄​ TestFetchRepositoryInfoAPI_FromRepo 💚​R 💚​R 💚​R 💚​R 🔄​f 💚​R 💚​R 💚​R 💚​R 💚​R
🔄​ TestFetchRepositoryInfoAPI_FromRepo/root ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p
🔄​ TestFetchRepositoryInfoAPI_FromRepo/subdir ✅​p ✅​p ✅​p ✅​p 🔄​f ✅​p ✅​p ✅​p ✅​p ✅​p

…rror

The multi-turn work surfaces conversation_id in --output json; the protocol-drift
acceptance golden still expected the pre-conversation_id error shape. Add the
captured conversation_id line so the golden matches actual output.

Co-authored-by: Isaac

@simonfaltum simonfaltum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

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.

3 participants