fix(server): use persisted session directory for existing-session routes (#29640)
This commit is contained in:
+8
-5
@@ -159,14 +159,14 @@ function planWorkspaceRequest(
|
|||||||
|
|
||||||
function planRequest(
|
function planRequest(
|
||||||
request: HttpServerRequest.HttpServerRequest,
|
request: HttpServerRequest.HttpServerRequest,
|
||||||
sessionWorkspaceID?: WorkspaceID,
|
session?: Session.Info,
|
||||||
): Effect.Effect<RequestPlan, never, Workspace.Service> {
|
): Effect.Effect<RequestPlan, never, Workspace.Service> {
|
||||||
return Effect.gen(function* () {
|
return Effect.gen(function* () {
|
||||||
const url = requestURL(request)
|
const url = requestURL(request)
|
||||||
const envWorkspaceID = configuredWorkspaceID()
|
const envWorkspaceID = configuredWorkspaceID()
|
||||||
const workspaceID = url.pathname.startsWith("/api/")
|
const workspaceID = url.pathname.startsWith("/api/")
|
||||||
? selectedV2WorkspaceID(url, sessionWorkspaceID)
|
? selectedV2WorkspaceID(url, session?.workspaceID)
|
||||||
: selectedWorkspaceID(url, sessionWorkspaceID)
|
: selectedWorkspaceID(url, session?.workspaceID)
|
||||||
if (workspaceID === InvalidWorkspaceID) return RequestPlan.InvalidWorkspace()
|
if (workspaceID === InvalidWorkspaceID) return RequestPlan.InvalidWorkspace()
|
||||||
const workspace = yield* resolveWorkspace(workspaceID, envWorkspaceID)
|
const workspace = yield* resolveWorkspace(workspaceID, envWorkspaceID)
|
||||||
|
|
||||||
@@ -178,7 +178,10 @@ function planRequest(
|
|||||||
return yield* planWorkspaceRequest(request, url, workspace)
|
return yield* planWorkspaceRequest(request, url, workspace)
|
||||||
}
|
}
|
||||||
|
|
||||||
return RequestPlan.Local({ directory: defaultDirectory(request, url), workspaceID: envWorkspaceID ?? workspaceID })
|
return RequestPlan.Local({
|
||||||
|
directory: session?.directory || defaultDirectory(request, url),
|
||||||
|
workspaceID: envWorkspaceID ?? workspaceID,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +229,7 @@ function routeHttpApiWorkspace<E>(
|
|||||||
Effect.catchDefect(() => Effect.succeed(undefined)),
|
Effect.catchDefect(() => Effect.succeed(undefined)),
|
||||||
)
|
)
|
||||||
: undefined
|
: undefined
|
||||||
const plan = yield* planRequest(request, session?.workspaceID)
|
const plan = yield* planRequest(request, session)
|
||||||
return yield* routeWorkspace(client, effect, plan)
|
return yield* routeWorkspace(client, effect, plan)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { afterEach, describe, expect } from "bun:test"
|
|||||||
import { mkdir } from "node:fs/promises"
|
import { mkdir } from "node:fs/promises"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import { Cause, Effect, Exit, Layer } from "effect"
|
import { Cause, Effect, Exit, Layer } from "effect"
|
||||||
|
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||||
import { Flag } from "@opencode-ai/core/flag/flag"
|
import { Flag } from "@opencode-ai/core/flag/flag"
|
||||||
import { registerAdapter } from "../../src/control-plane/adapters"
|
import { registerAdapter } from "../../src/control-plane/adapters"
|
||||||
import type { WorkspaceAdapter } from "../../src/control-plane/types"
|
import type { WorkspaceAdapter } from "../../src/control-plane/types"
|
||||||
@@ -27,7 +28,9 @@ import * as DateTime from "effect/DateTime"
|
|||||||
import * as Log from "@opencode-ai/core/util/log"
|
import * as Log from "@opencode-ai/core/util/log"
|
||||||
import { eq } from "drizzle-orm"
|
import { eq } from "drizzle-orm"
|
||||||
import { resetDatabase } from "../fixture/db"
|
import { resetDatabase } from "../fixture/db"
|
||||||
import { disposeAllInstances, TestInstance } from "../fixture/fixture"
|
import { disposeAllInstances, provideInstanceEffect, TestInstance, tmpdirScoped } from "../fixture/fixture"
|
||||||
|
import { TestLLMServer } from "../lib/llm-server"
|
||||||
|
import { testProviderConfig } from "../lib/test-provider"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
void Log.init({ print: false })
|
void Log.init({ print: false })
|
||||||
@@ -368,6 +371,43 @@ describe("session HttpApi", () => {
|
|||||||
{ git: true, config: { formatter: false, lsp: false } },
|
{ git: true, config: { formatter: false, lsp: false } },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.live("uses the persisted session directory for prompt requests", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const llm = yield* TestLLMServer
|
||||||
|
yield* llm.text("ok", { usage: { input: 1, output: 1 } })
|
||||||
|
|
||||||
|
const config = testProviderConfig(llm.url)
|
||||||
|
const sessionDirectory = yield* tmpdirScoped({ git: true, config })
|
||||||
|
const requestDirectory = yield* tmpdirScoped({ git: true, config })
|
||||||
|
const session = yield* createSession({ title: "directory regression" }).pipe(provideInstanceEffect(sessionDirectory))
|
||||||
|
|
||||||
|
const response = yield* request(
|
||||||
|
`${pathFor(SessionPaths.prompt, { sessionID: session.id })}?directory=${encodeURIComponent(requestDirectory)}`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
agent: "build",
|
||||||
|
model: { providerID: "test", modelID: "test-model" },
|
||||||
|
parts: [{ type: "text", text: "which directory?" }],
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
yield* responseJson(response)
|
||||||
|
|
||||||
|
const messages = yield* Session.use
|
||||||
|
.messages({ sessionID: session.id })
|
||||||
|
.pipe(provideInstanceEffect(sessionDirectory), Effect.orDie)
|
||||||
|
const assistant = messages.find((message) => message.info.role === "assistant")
|
||||||
|
expect(assistant?.info.role === "assistant" ? assistant.info.path : undefined).toEqual({
|
||||||
|
cwd: sessionDirectory,
|
||||||
|
root: sessionDirectory,
|
||||||
|
})
|
||||||
|
}).pipe(Effect.provide(TestLLMServer.layer), Effect.provide(CrossSpawnSpawner.defaultLayer)),
|
||||||
|
)
|
||||||
|
|
||||||
it.instance(
|
it.instance(
|
||||||
"returns v2 public request errors for cursor and workspace query failures",
|
"returns v2 public request errors for cursor and workspace query failures",
|
||||||
() =>
|
() =>
|
||||||
|
|||||||
Reference in New Issue
Block a user