feat(opencode): rename InstanceStore to InstanceRuntime and refine model schema

Rename the `InstanceStore` module to `InstanceRuntime` across all consumer
sites to better reflect its role as a runtime lifecycle manager rather than
a persistence layer. Update the kilo-gateway route dependency key from
`InstanceStore` to `Instances` for clarity.

Additional changes:
- Replace `Schema.Number` with `Schema.Finite` for `recommendedIndex` in
  both the provider and models schemas
- Inject `InstanceStore.Service` into the ProviderAuth layer and use its
  `disposeAll()` method instead of escaping to a raw promise
- Remove obsolete `getBootstrapRunEffect` usage from indexing startup tests
- Add missing `warnings` method to the test config fixture
This commit is contained in:
Imanol Maiztegui
2026-05-19 11:37:49 +02:00
parent 8e053f34b5
commit 4523bf99cb
15 changed files with 29 additions and 34 deletions
+3 -3
View File
@@ -41,7 +41,7 @@ interface KiloRoutesDeps extends ImportDeps {
Auth: Auth
ModelCache: ModelCache
z: Z
InstanceStore: { disposeAllInstances(): Promise<void> }
Instances: { disposeAllInstances(): Promise<void> }
}
const FIM_TIMEOUT_MS = 30_000
@@ -88,7 +88,7 @@ export function createKiloRoutes(deps: KiloRoutesDeps) {
SessionCreatedEvent,
Identifier,
ModelCache,
InstanceStore,
Instances,
} = deps
const Organization = z.object({
@@ -211,7 +211,7 @@ export function createKiloRoutes(deps: KiloRoutesDeps) {
{
auth: Auth,
clear: () => ModelCache.clear("kilo"),
dispose: () => InstanceStore.disposeAllInstances(),
dispose: () => Instances.disposeAllInstances(),
},
organizationId,
),
+2 -2
View File
@@ -3,7 +3,7 @@ import { cmd } from "./cmd"
import { bootstrap } from "../bootstrap"
import { KiloSessions } from "@/kilo-sessions/kilo-sessions"
import { Instance } from "@/project/instance"
import { InstanceStore } from "@/project/instance-store"
import { InstanceRuntime } from "@/project/instance-runtime"
export const RemoteCommand = cmd({
command: "remote",
@@ -18,7 +18,7 @@ export const RemoteCommand = cmd({
const shutdown = async () => {
try {
KiloSessions.disableRemote()
await InstanceStore.disposeInstance(Instance.current)
await InstanceRuntime.disposeInstance(Instance.current)
} finally {
abort.abort()
}
+2 -2
View File
@@ -3,7 +3,7 @@ import { Server } from "../../server/server"
import { effectCmd } from "../effect-cmd"
import { withNetworkOptions, resolveNetworkOptions } from "../network"
import { Flag } from "@opencode-ai/core/flag/flag"
import { InstanceStore } from "../../project/instance-store" // kilocode_change
import { InstanceRuntime } from "../../project/instance-runtime" // kilocode_change
export const ServeCommand = effectCmd({
command: "serve",
@@ -27,7 +27,7 @@ export const ServeCommand = effectCmd({
new Promise<void>((resolve) => {
const shutdown = async () => {
try {
await InstanceStore.disposeAllInstances()
await InstanceRuntime.disposeAllInstances()
await server.stop(true)
} finally {
resolve()
+2 -2
View File
@@ -4,7 +4,7 @@ import { UI } from "../ui"
import { effectCmd } from "../effect-cmd"
import { withNetworkOptions, resolveNetworkOptions } from "../network"
import { Flag } from "@opencode-ai/core/flag/flag"
import { InstanceStore } from "../../project/instance-store" // kilocode_change
import { InstanceRuntime } from "../../project/instance-runtime" // kilocode_change
import open from "open"
import { networkInterfaces } from "os"
@@ -86,7 +86,7 @@ export const WebCommand = effectCmd({
new Promise<void>((resolve) => {
const shutdown = async () => {
try {
await InstanceStore.disposeAllInstances()
await InstanceRuntime.disposeAllInstances()
await server.stop(true)
} finally {
resolve()
+2 -2
View File
@@ -39,7 +39,7 @@ import { RollCallCommand } from "./kilocode/cli/cmd/roll-call" // kilocode_chang
import { DevSetupCommand, DevAliasCommand } from "./kilocode/cli/dev-setup" // kilocode_change
// kilocode_change start - Import telemetry, instance disposal, and legacy migration
import { Telemetry } from "@kilocode/kilo-telemetry"
import { InstanceStore } from "./project/instance-store" // kilocode_change
import { InstanceRuntime } from "./project/instance-runtime" // kilocode_change
import { migrateLegacyKiloAuth, ENV_FEATURE, ENV_VERSION } from "@kilocode/kilo-gateway"
// kilocode_change - set feature for tracking. 'serve' is spawned by other services
@@ -321,7 +321,7 @@ try {
await Telemetry.shutdown()
// kilocode_change end
await InstanceStore.disposeAllInstances() // kilocode_change - safety net disposal (no-op if already disposed)
await InstanceRuntime.disposeAllInstances() // kilocode_change - safety net disposal (no-op if already disposed)
// Some subprocesses don't react properly to SIGTERM and similar signals.
// Most notably, some docker-container-based MCP servers don't handle such signals unless
@@ -5,7 +5,7 @@ import { Glob } from "@opencode-ai/core/util/glob"
import * as Truncate from "../../tool/truncate"
import { Config } from "../../config/config"
import { Instance } from "../../project/instance"
import { InstanceStore } from "../../project/instance-store"
import { InstanceRuntime } from "../../project/instance-runtime"
import { makeRuntime } from "@/effect/run-service"
import z from "zod"
import path from "path"
@@ -512,5 +512,5 @@ export async function remove(name: string) {
if (!found) throw new RemoveError({ name, message: "no agent file found on disk" })
await InstanceStore.disposeInstance(Instance.current)
await InstanceRuntime.disposeInstance(Instance.current)
}
@@ -31,7 +31,7 @@ export const KILO_BUNDLED_PROVIDERS: Record<string, () => Promise<(options: any)
// ---------------------------------------------------------------------------
export const KILO_MODEL_SCHEMA_EXTENSIONS = {
recommendedIndex: Schema.optional(Schema.Number),
recommendedIndex: Schema.optional(Schema.Finite),
prompt: Schema.optional(Schema.Literals(PROMPTS)),
isFree: Schema.optional(Schema.Boolean),
ai_sdk_provider: Schema.optional(Schema.Literals(AI_SDK_PROVIDERS)),
@@ -20,7 +20,7 @@ import { errors } from "../../server/error"
import { ModelCache } from "../../provider/model-cache"
import { Database } from "../../storage/db"
import { Instance } from "../../project/instance"
import { InstanceStore } from "../../project/instance-store"
import { InstanceRuntime } from "../../project/instance-runtime"
import { Session } from "../../session/session"
import { Identifier } from "../../id/id"
import { SessionTable, MessageTable, PartTable } from "../../session/session.sql"
@@ -49,7 +49,7 @@ export function register(app: Hono): Hono {
z,
Database,
Instance,
InstanceStore,
Instances: InstanceRuntime,
SessionTable,
MessageTable,
PartTable,
@@ -3,7 +3,7 @@
// Imported by ../../server/server.ts with minimal kilocode_change markers.
import { ModelCache } from "../../provider/model-cache"
import { InstanceStore } from "../../project/instance-store"
import { InstanceRuntime } from "../../project/instance-runtime"
/** Extra paths to skip request logging for */
export function skipLogging(path: string): boolean {
@@ -21,7 +21,7 @@ export function corsOrigin(input: string): string | undefined {
/** Invalidate model cache and provider state after auth change */
export async function authChanged(providerID: string) {
ModelCache.clear(providerID)
await InstanceStore.disposeAllInstances()
await InstanceRuntime.disposeAllInstances()
}
export const DOC_TITLE = "kilo"
+4 -2
View File
@@ -113,11 +113,13 @@ interface State {
export class Service extends Context.Service<Service, Interface>()("@opencode/ProviderAuth") {}
export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> = Layer.effect(
export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service | InstanceStore.Service> = Layer.effect(
// kilocode_change
Service,
Effect.gen(function* () {
const auth = yield* Auth.Service
const plugin = yield* Plugin.Service
const store = yield* InstanceStore.Service // kilocode_change
const state = yield* InstanceState.make<State>(
Effect.fn("ProviderAuth.state")(function* () {
const plugins = yield* plugin.list()
@@ -234,7 +236,7 @@ export const layer: Layer.Layer<Service, never, Auth.Service | Plugin.Service> =
}
Telemetry.trackAuthSuccess(input.providerID)
ModelCache.clear(input.providerID)
yield* Effect.promise(() => InstanceStore.disposeAllInstances())
yield* store.disposeAll()
// kilocode_change end
})
+1 -1
View File
@@ -75,7 +75,7 @@ export const Model = Schema.Struct({
}),
),
// kilocode_change start
recommendedIndex: Schema.optional(Schema.Number),
recommendedIndex: Schema.optional(Schema.Finite),
prompt: Schema.optional(Schema.Literals(PROMPTS)),
isFree: Schema.optional(Schema.Boolean),
ai_sdk_provider: Schema.optional(Schema.Literals(AI_SDK_PROVIDERS)),
+1
View File
@@ -12,6 +12,7 @@ export function make(overrides: Partial<Config.Interface> = {}) {
invalidate: () => Effect.void,
directories: () => Effect.succeed([]),
waitForDependencies: () => Effect.void,
warnings: () => Effect.succeed([]),
...overrides,
})
}
@@ -3,7 +3,7 @@ import { Effect } from "effect"
import path from "path"
import type { Permission } from "../../src/permission"
import { Instance } from "../../src/project/instance"
import { InstanceStore } from "../../src/project/instance-store"
import { InstanceRuntime } from "../../src/project/instance-runtime"
import { WithInstance } from "../../src/project/with-instance"
import { SessionID, MessageID } from "../../src/session/schema"
import { assertExternalDirectory } from "../../src/tool/external-directory"
@@ -50,7 +50,7 @@ describe("kilocode external directory boundaries", () => {
try {
await assertExternalDirectory(ctx, file)
} finally {
await InstanceStore.disposeInstance(Instance.current)
await InstanceRuntime.disposeInstance(Instance.current)
}
},
})
@@ -74,7 +74,7 @@ describe("kilocode external directory boundaries", () => {
try {
await assertExternalDirectory(ctx, file)
} finally {
await InstanceStore.disposeInstance(Instance.current)
await InstanceRuntime.disposeInstance(Instance.current)
}
},
})
@@ -2,7 +2,6 @@ import { afterEach, describe, expect, spyOn, test } from "bun:test"
import { CodeIndexManager } from "@kilocode/kilo-indexing/engine"
import type { Config } from "../../src/config/config"
import { GlobalBus } from "../../src/bus/global"
import { getBootstrapRunEffect } from "../../src/effect/app-runtime"
import { KiloIndexing } from "../../src/kilocode/indexing"
import { WithInstance } from "../../src/project/with-instance"
import { Server } from "../../src/server/server"
@@ -185,7 +184,6 @@ describe("indexing startup degradation", () => {
try {
await WithInstance.provide({
directory: tmp.path,
init: await getBootstrapRunEffect(),
fn: async () => {
await called(init)
expect((await KiloIndexing.current()).state).toBe("In Progress")
@@ -213,7 +211,6 @@ describe("indexing startup degradation", () => {
try {
await WithInstance.provide({
directory: tmp.path,
init: await getBootstrapRunEffect(),
fn: async () => {
const status = await wait(() => KiloIndexing.current(), "Error")
@@ -238,7 +235,6 @@ describe("indexing startup degradation", () => {
try {
await WithInstance.provide({
directory: tmp.path,
init: await getBootstrapRunEffect(),
fn: async () => {
await called(init)
@@ -261,7 +257,6 @@ describe("indexing startup degradation", () => {
await WithInstance.provide({
directory: tmp.path,
init: await getBootstrapRunEffect(),
fn: async () => {
const status = await KiloIndexing.current()
@@ -302,7 +297,6 @@ describe("indexing startup degradation", () => {
try {
await WithInstance.provide({
directory: tmp.path,
init: await getBootstrapRunEffect(),
fn: async () => {
await called(init)
expect(init.mock.calls[0]?.[0]).toMatchObject({
@@ -335,7 +329,6 @@ describe("indexing startup degradation", () => {
try {
await WithInstance.provide({
directory: tmp.path,
init: await getBootstrapRunEffect(),
fn: async () => {
await called(init)
expect(init.mock.calls[0]?.[0]).toMatchObject({
@@ -360,7 +353,6 @@ describe("indexing startup degradation", () => {
try {
await WithInstance.provide({
directory: tmp.path,
init: await getBootstrapRunEffect(),
fn: async () => {
const status = await KiloIndexing.current()
@@ -5,7 +5,7 @@ import path from "path"
import { tmpdir } from "../fixture/fixture"
import { Global } from "@opencode-ai/core/global"
import { Instance } from "../../src/project/instance"
import { InstanceStore } from "../../src/project/instance-store"
import { InstanceRuntime } from "../../src/project/instance-runtime"
import { WithInstance } from "../../src/project/with-instance"
import { Plugin } from "../../src/plugin/index"
import { ModelsDev } from "@/provider/models"
@@ -2513,7 +2513,7 @@ test("plugin config providers persist after instance dispose", async () => {
// kilocode_change start
await WithInstance.provide({
directory: tmp.path,
fn: () => InstanceStore.disposeInstance(Instance.current),
fn: () => InstanceRuntime.disposeInstance(Instance.current),
})
// kilocode_change end