Просмотр исходного кода

fix(server): use persisted session directory for existing-session routes (#29640)

James Long 3 месяцев назад
Родитель
Сommit
69910f361c

+ 8 - 5
packages/opencode/src/server/routes/instance/httpapi/middleware/workspace-routing.ts

@@ -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)
-      : selectedWorkspaceID(url, sessionWorkspaceID)
+      ? selectedV2WorkspaceID(url, session?.workspaceID)
+      : 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)
   })
   })
 }
 }

+ 41 - 1
packages/opencode/test/server/httpapi-session.test.ts

@@ -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",
     () =>
     () =>