mirror of
https://github.com/stablyai/orca.git
synced 2026-10-02 00:02:05 +00:00
test(native-chat): pin the route connection fallback on the un-mocked resolver
The suite that covers the builder stages `getConnectionIdFromState`, so it can characterize the fallback but cannot catch a defect that lives in owner resolution itself. This one runs the real resolution over real store rows: two repos publishing the same worktree id on different hosts, which is the documented case where the owner cannot be named and `undefined` is returned. Red with both fix files at the previous head, green with them. Reverts the two caller pins added to the route census — the feasibility predicate is exported from the planner, which the census already permits, so it passes unedited and needs no permit clause.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { buildAgentLaunchRouteInput, type AgentLaunchRouteStore } from './agent-launch-route-input'
|
||||
import { getConnectionIdFromState } from './connection-owner-resolution'
|
||||
import { planAgentSessionLaunch } from './agent-session-launch-plan'
|
||||
|
||||
// Deliberately un-mocked: the defect this pins lives in the owner resolution itself, so a suite
|
||||
// that stages `getConnectionIdFromState` cannot catch it. Grok is the agent the answer routes on —
|
||||
// only agents whose hook discloses no transcript path read the local-readability input at all.
|
||||
const NATIVE_CHAT_SETTINGS = { experimentalNativeChat: true, openAgentTabsInChatByDefault: true }
|
||||
const WORKTREE_ID = 'repo-1::/repo/wt-1'
|
||||
const WORKSPACE = { kind: 'git-worktree', worktreeId: WORKTREE_ID, repoId: 'repo-1' } as const
|
||||
|
||||
/** Rival repos publishing the same worktree id on different hosts: the documented case where owner
|
||||
* resolution refuses to name a connection rather than authorize a local read of a remote path. */
|
||||
function storeWithAmbiguousWorktreeRows(
|
||||
repoConnectionId: string | null
|
||||
): AgentLaunchRouteStore & { repos: unknown[] } {
|
||||
return {
|
||||
settings: NATIVE_CHAT_SETTINGS,
|
||||
repos: [{ id: 'repo-1', path: '/repo', connectionId: repoConnectionId }],
|
||||
worktreesByRepo: {
|
||||
'repo-1': [{ id: WORKTREE_ID, repoId: 'repo-1', hostId: null }],
|
||||
'repo-2': [{ id: WORKTREE_ID, repoId: 'repo-1', hostId: 'ssh:other-box' }]
|
||||
}
|
||||
} as unknown as AgentLaunchRouteStore & { repos: unknown[] }
|
||||
}
|
||||
|
||||
describe('launch route transcript readability', () => {
|
||||
it('cannot name the connection from the worktree when its rows disagree', () => {
|
||||
// The premise of the fallback: this is what returns `undefined`, and `undefined` is not
|
||||
// evidence that the transcript is unreadable.
|
||||
expect(
|
||||
getConnectionIdFromState(storeWithAmbiguousWorktreeRows(null), WORKTREE_ID)
|
||||
).toBeUndefined()
|
||||
})
|
||||
|
||||
it('falls back to the local repo rather than downgrading native chat to a terminal', () => {
|
||||
const store = storeWithAmbiguousWorktreeRows(null)
|
||||
|
||||
expect(
|
||||
buildAgentLaunchRouteInput(store, { agent: 'grok', workspace: WORKSPACE })
|
||||
.nativeChatTranscriptIsLocalReadable
|
||||
).toBe(true)
|
||||
expect(planAgentSessionLaunch(store, { agent: 'grok', workspace: WORKSPACE }).route).toBe(
|
||||
'legacy-native-chat'
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps a remote repo off native chat through the same fallback', () => {
|
||||
const store = storeWithAmbiguousWorktreeRows('build-box')
|
||||
|
||||
expect(planAgentSessionLaunch(store, { agent: 'grok', workspace: WORKSPACE }).route).toBe(
|
||||
'terminal-tui'
|
||||
)
|
||||
})
|
||||
|
||||
it('has no repo to fall back to when the workspace names none', () => {
|
||||
const store = storeWithAmbiguousWorktreeRows(null)
|
||||
|
||||
expect(
|
||||
planAgentSessionLaunch(store, {
|
||||
agent: 'grok',
|
||||
workspace: { kind: 'git-worktree', worktreeId: WORKTREE_ID }
|
||||
}).route
|
||||
).toBe('terminal-tui')
|
||||
})
|
||||
})
|
||||
@@ -25,12 +25,6 @@ const LAUNCH_AGENT_IN_NEW_TAB_CALLERS = [
|
||||
const ROUTE_RESOLVER_DEFINITION = 'src/renderer/src/lib/agent-launch-routing.ts'
|
||||
const ROUTE_PLANNER = 'src/renderer/src/lib/agent-session-launch-plan.ts'
|
||||
const DIRECT_ROUTE_RESOLVER_CALL = /\b(?:resolveAgentLaunchRoute|structuredAgentLaunchSupported)\(/
|
||||
// Why: asking whether a structured session is POSSIBLE is a query, not a launch decision, so it is
|
||||
// allowed outside the planner — but only through the planner's own predicate, and only from the
|
||||
// surfaces pinned here. A UI that builds a plan to answer it is the bypass this census catches.
|
||||
const STRUCTURED_FEASIBILITY_QUERY_CALLERS = [
|
||||
'src/renderer/src/components/right-sidebar/ai-vault-session-resume-in-chat-workspace.ts'
|
||||
]
|
||||
// Why: adopting a verdict bypasses the resolver by design (a persisted quick-create request, a
|
||||
// resume whose gate already planned), so each adopter is pinned rather than trusted by convention.
|
||||
const VERDICT_ADOPTERS = [
|
||||
@@ -66,25 +60,6 @@ describe('agent launch routing caller census', () => {
|
||||
expect(directCallers).toEqual([ROUTE_PLANNER])
|
||||
})
|
||||
|
||||
it('pins every production caller of the structured feasibility query', async () => {
|
||||
const callers = (await productionFiles())
|
||||
.filter((file) => file !== ROUTE_PLANNER)
|
||||
.filter((file) =>
|
||||
readFileSync(join(REPO_ROOT, file), 'utf8').includes(
|
||||
'structuredAgentSessionLaunchFeasible('
|
||||
)
|
||||
)
|
||||
.sort()
|
||||
expect(callers).toEqual([...STRUCTURED_FEASIBILITY_QUERY_CALLERS].sort())
|
||||
})
|
||||
|
||||
it('keeps the feasibility query out of every launch decision', async () => {
|
||||
// A query caller that also plans a launch has re-crossed the line the split exists to draw.
|
||||
for (const file of STRUCTURED_FEASIBILITY_QUERY_CALLERS) {
|
||||
expect(readFileSync(join(REPO_ROOT, file), 'utf8')).not.toContain('planAgentSessionLaunch(')
|
||||
}
|
||||
})
|
||||
|
||||
it('pins every production adopter of a planned verdict', async () => {
|
||||
const adopters = (await productionFiles())
|
||||
.filter((file) => file !== ROUTE_PLANNER)
|
||||
|
||||
Reference in New Issue
Block a user