Missing credential: typed error naming the connector - #232
Merged
Merged
Conversation
Red until MissingCredentialError and credentialDeliveryError exist: today a missing credential collapses into a generic Error, losing which connector needs to be connected.
buildCredentialDelivery already resolves which connector's binding is unresolved (reason.binding.provider); the folded-run launch path used to discard that identity into a generic Error string. It now throws connections' MissingCredentialError, carrying the connector id and its CONNECTOR_REGISTRY display name, so a launch halts on a missing credential without guessing and names exactly what needs connecting. Other buildCredentialDelivery failures (ambiguous/no_origin) stay generic, since those are config faults, not something to connect. The existing connect-service chat block, its container, and createChatConnectServiceActions (apps/web) already render a working one-click connect affordance for a named connector and land the user back on success via the existing OAuth/MCP-preset return-path machinery; wiring this new error into that render path — passing the connector id from a mid-run tool failure through to the chat-orchestrator tool-trace output — is the follow-up this unlocks.
Red until the wire detail exists and survives the sidecar-event -> tool-trace path: a tool result whose detail names a missing connector should render the existing connect-service block in the live turn; a normal tool result (no such detail) must render exactly as before.
The launch-time halt (previous commit) only covers a credential unresolved before a run starts. The scenario that actually fires mid-conversation -- an already-running agent hitting a tool with no bound credential -- produced a tool failure with no connect prompt, because ToolResult.detail (the side channel @intx/types/runtime already carries for exactly this) was dropped at two points: folded-runs' toolDoneResult only read callId/content/isError off the sidecar event, and chat-orchestrator's tool-done handler only forwarded content/isError into the tool-trace part. Both now carry detail through. When it parses as a missing-credential signal (packages/connections' new parseMissingCredentialDetail), the chat orchestrator appends the same connect-service block request_connection already posts for the agent-initiated path -- same block type, same ConnectServiceBlockContainer, same createChatConnectServiceActions round-trip through OAuth/MCP-preset connect-and-return -- so a live turn gets a real "Connect GitHub" button instead of a dead-end error, naming the connector via CONNECTOR_REGISTRY's display name rather than its id. A tool result carrying no such detail renders exactly as before. GitHub's pull-request tools are wired end to end as the first mover: their existing NOT_CONNECTED result now carries the detail literally (no new dependency -- a sandboxed tool package agrees with the reader on this wire shape by convention, not by importing it).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
connect-servicechat block (packages/chat/src/blocks.ts), its view + container (packages/chat-ui/src/blocks/connect-service-block*.tsx), andcreateChatConnectServiceActions(apps/web/src/connect-service-actions.ts) already render a real "Connect X" button, round-trip through the existing OAuth/MCP-preset start-and-return routes, and land the user back where they were. Nothing needed to be added or duplicated there.packages/connections/src/credential-error.ts'sMissingCredentialErrorwired intopackages/folded-runs/src/launch.ts.ToolResult.detail(@intx/types/runtime) already exists for carrying structured, non-model-facing metadata off a tool result, but it was being dropped at two points:packages/folded-runs/src/agent-events.ts'stoolDoneResultonly readcallId/content/isErroroff the sidecar event, andpackages/chat/src/chat-orchestrator.ts's tool-done handler only forwardedcontent/isErrorinto the tool-trace part. Both now carrydetailthrough; when it parses (via newpackages/connections/src/missing-credential-detail.ts'sparseMissingCredentialDetail) as a missing-credential signal, the orchestrator appends the sameconnect-serviceblockrequest_connectionalready posts for the agent-initiated path -- same block type, sameConnectServiceBlockContainer, samecreateChatConnectServiceActionsround-trip -- so a live turn gets a real "Connect GitHub" button instead of a dead-end error. The connector is always named viaCONNECTOR_REGISTRY'sdisplayName, never its id.packages/github-tools/src/pull-request-tools.ts) are wired end-to-end as the first mover: their existingNOT_CONNECTEDresult now carries the detail literally, with no new dependency -- a sandboxed tool package agrees with the reader on this wire shape by convention (akind-discriminated literal), the same waytoolDoneResultalready narrowsevent.typewithout importing a shared constant.detail, or adetailthat isn't this shape, or anisError: falseresult, renders exactly as before -- covered by tests inchat-orchestrator.test.tsandagent-events.test.ts.NOT_CONNECTED-style results (granola-tools, linear-tools, reddit-tools, web-search-tools, mcp-tools -- and Jimmy's Giphy tool once it lands) is the same pattern, not a new design.Verification
Per the owner's live directive (their machine OOM'd from concurrent full-repo checks across lanes), repo-root
bun run checkand repo-root lint were not run -- only package-scoped checks:bun teston the touched files acrosspackages/connections,packages/folded-runs,packages/chat,packages/github-tools-- 29 pass, 0 fail.tsc --noEmitinside each of those four packages -- clean.bun run checkwere not run -- left for CI.Test plan
bun run checkMissingCredentialError("github")namesdisplayName: "GitHub", falls back to the raw id for an unregistered connectorcredentialDeliveryError: an"unresolved"failure becomesMissingCredentialErrornaming the connector;"ambiguous"stays genericdetailis{ kind: "missing-credential", connectorId }renders the connect-service block naming the connector via the live turn's accumulated partsNOT_CONNECTEDresult carries the detail; a resolved credential carries none