Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"build": "node scripts/cli.ts build",
"build:bundle": "tsdown",
"start": "node dist/bin.mjs",
"prepare": "effect-language-service patch",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:process-reaper": "vitest run src/server.test.ts src/provider/Layers/ClaudeAdapter.test.ts src/provider/Layers/ProviderSessionDirectory.test.ts src/provider/Layers/ProviderSessionReaper.test.ts src/provider/Layers/CodexAdapter.test.ts"
Expand Down
20 changes: 16 additions & 4 deletions apps/server/src/geminiCliServerManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ describe("GeminiCliServerManager", () => {
provider: ProviderDriverKind.make("geminiCli"),
runtimeMode: "full-access",
cwd: "/tmp",
modelSelection: { instanceId: ProviderInstanceId.make("geminiCli"), model: "gemini-2.5-pro" },
modelSelection: {
instanceId: ProviderInstanceId.make("geminiCli"),
model: "gemini-2.5-pro",
},
});

expect(session.provider).toBe("geminiCli");
Expand Down Expand Up @@ -288,13 +291,19 @@ describe("GeminiCliServerManager", () => {
threadId: asThreadId("thread-1"),
provider: ProviderDriverKind.make("geminiCli"),
runtimeMode: "full-access",
modelSelection: { instanceId: ProviderInstanceId.make("geminiCli"), model: "gemini-3-flash" },
modelSelection: {
instanceId: ProviderInstanceId.make("geminiCli"),
model: "gemini-3-flash",
},
});
await manager.startSession({
threadId: asThreadId("thread-2"),
provider: ProviderDriverKind.make("geminiCli"),
runtimeMode: "full-access",
modelSelection: { instanceId: ProviderInstanceId.make("geminiCli"), model: "gemini-2.5-pro" },
modelSelection: {
instanceId: ProviderInstanceId.make("geminiCli"),
model: "gemini-2.5-pro",
},
});

const sessions = manager.listSessions();
Expand Down Expand Up @@ -717,7 +726,10 @@ describe.skipIf(!hasGemini || process.env.RUN_GEMINI_LIVE_TESTS !== "1")(
threadId: asThreadId("live-thread"),
provider: ProviderDriverKind.make("geminiCli"),
runtimeMode: "full-access",
modelSelection: { instanceId: ProviderInstanceId.make("geminiCli"), model: "gemini-2.5-flash" },
modelSelection: {
instanceId: ProviderInstanceId.make("geminiCli"),
model: "gemini-2.5-flash",
},
});

const result = await manager.sendTurn({
Expand Down
7 changes: 3 additions & 4 deletions apps/server/src/kiloServerManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ import {
} from "./kilo/types.ts";

vi.mock("./kilo/serverLifecycle.ts", async () => {
const actual =
await vi.importActual<typeof import("./kilo/serverLifecycle.ts")>(
"./kilo/serverLifecycle.ts",
);
const actual = await vi.importActual<typeof import("./kilo/serverLifecycle.ts")>(
"./kilo/serverLifecycle.ts",
);
return {
...actual,
ensureServer: vi.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
has_actionable_proposed_plan AS "hasActionableProposedPlan",
deleted_at AS "deletedAt"
FROM projection_threads
WHERE json_extract(model_selection_json, '$.provider') IN ('codex','copilot','claudeAgent','cursor','opencode','geminiCli','amp','kilo')
ORDER BY created_at ASC, thread_id ASC
`,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ layer("021_RepairProjectionThreadProposedPlanImplementationColumns", (it) => {
!columnsBeforeRepair.some((column) => column.name === "implementation_thread_id"),
);

yield* runMigrations();
// Only run through the repair migration itself (registered id 24).
// Running the rest of the chain (e.g. migration #28 touches
// `model_selection_json`) would fail because the faked-as-ran
// migration 16 never actually executed in this scenario, so the
// column doesn't exist. The test only asserts the repair migration's
// own behavior, so stopping after it is safe and accurate.
yield* runMigrations({ toMigrationInclusive: 24 });

const columnsAfterRepair = yield* sql<{ readonly name: string }>`
PRAGMA table_info(projection_thread_proposed_plans)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ layer("026_CanonicalizeModelSelectionOptions", (it) => {
Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;

yield* runMigrations({ toMigrationInclusive: 25 });
yield* runMigrations({ toMigrationInclusive: 27 });

yield* sql`
INSERT INTO projection_projects (
Expand Down Expand Up @@ -276,7 +276,7 @@ layer("026_CanonicalizeModelSelectionOptions", (it) => {
)
`;

yield* runMigrations({ toMigrationInclusive: 26 });
yield* runMigrations({ toMigrationInclusive: 28 });

// Projection projects
const projectRows = yield* sql<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,30 @@ layer("027_028_ProviderInstanceIdColumns", (it) => {
Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;

yield* runMigrations({ toMigrationInclusive: 26 });
yield* runMigrations({ toMigrationInclusive: 28 });
yield* sql`
ALTER TABLE provider_session_runtime
ADD COLUMN provider_instance_id TEXT
`;

yield* runMigrations({ toMigrationInclusive: 28 });
yield* runMigrations({ toMigrationInclusive: 30 });

const migrations = yield* sql<{
readonly migration_id: number;
readonly name: string;
}>`
SELECT migration_id, name
FROM effect_sql_migrations
WHERE migration_id IN (27, 28)
WHERE migration_id IN (29, 30)
ORDER BY migration_id
`;
assert.deepStrictEqual(migrations, [
{
migration_id: 27,
migration_id: 29,
name: "ProviderSessionRuntimeInstanceId",
},
{
migration_id: 28,
migration_id: 30,
name: "ProjectionThreadSessionInstanceId",
},
]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@ import * as NodeSqliteClient from "../NodeSqliteClient.ts";
const layer = it.layer(Layer.mergeAll(NodeSqliteClient.layerMemory()));

layer("029_BackfillForkProviderInstanceIds", (it) => {
it.effect(
"backfills provider_instance_id for fork drivers across both routing tables",
() =>
Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;
it.effect("backfills provider_instance_id for fork drivers across both routing tables", () =>
Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;

// Run all migrations up to (and including) 028 so the
// `provider_instance_id` column exists but is left NULL for
// historical rows.
yield* runMigrations({ toMigrationInclusive: 28 });
// Run all migrations up to (and including) 028 so the
// `provider_instance_id` column exists but is left NULL for
// historical rows.
yield* runMigrations({ toMigrationInclusive: 30 });

// Seed a project + thread for each fork driver to satisfy the
// foreign-key relationships used by the projection tables.
const forkKinds = ["amp", "copilot", "geminiCli", "kilo"] as const;
for (const kind of forkKinds) {
yield* sql`
// Seed a project + thread for each fork driver to satisfy the
// foreign-key relationships used by the projection tables.
const forkKinds = ["amp", "copilot", "geminiCli", "kilo"] as const;
for (const kind of forkKinds) {
yield* sql`
INSERT INTO projection_projects (
project_id,
title,
Expand All @@ -46,7 +44,7 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
)
`;

yield* sql`
yield* sql`
INSERT INTO projection_threads (
thread_id,
project_id,
Expand Down Expand Up @@ -79,7 +77,7 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
)
`;

yield* sql`
yield* sql`
INSERT INTO projection_thread_sessions (
thread_id,
status,
Expand All @@ -106,7 +104,7 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
)
`;

yield* sql`
yield* sql`
INSERT INTO provider_session_runtime (
thread_id,
provider_name,
Expand All @@ -130,11 +128,11 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
NULL
)
`;
}
}

// Also seed a non-fork (upstream) driver row to verify the
// backfill leaves it untouched.
yield* sql`
// Also seed a non-fork (upstream) driver row to verify the
// backfill leaves it untouched.
yield* sql`
INSERT INTO projection_projects (
project_id,
title,
Expand All @@ -156,7 +154,7 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
NULL
)
`;
yield* sql`
yield* sql`
INSERT INTO projection_threads (
thread_id,
project_id,
Expand Down Expand Up @@ -188,7 +186,7 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
NULL
)
`;
yield* sql`
yield* sql`
INSERT INTO projection_thread_sessions (
thread_id,
status,
Expand All @@ -214,7 +212,7 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
NULL
)
`;
yield* sql`
yield* sql`
INSERT INTO provider_session_runtime (
thread_id,
provider_name,
Expand All @@ -239,53 +237,53 @@ layer("029_BackfillForkProviderInstanceIds", (it) => {
)
`;

// Run migration 029.
yield* runMigrations({ toMigrationInclusive: 31 });
// Run migration 029.
yield* runMigrations({ toMigrationInclusive: 31 });

// Each fork row should now have its `provider_instance_id` set
// to the matching driver kind (the default instance id).
for (const kind of forkKinds) {
const sessionRows = yield* sql<{ readonly providerInstanceId: string }>`
// Each fork row should now have its `provider_instance_id` set
// to the matching driver kind (the default instance id).
for (const kind of forkKinds) {
const sessionRows = yield* sql<{ readonly providerInstanceId: string }>`
SELECT provider_instance_id AS "providerInstanceId"
FROM projection_thread_sessions
WHERE thread_id = ${`thread-${kind}`}
`;
assert.deepStrictEqual(sessionRows, [{ providerInstanceId: kind }]);
assert.deepStrictEqual(sessionRows, [{ providerInstanceId: kind }]);

const runtimeRows = yield* sql<{ readonly providerInstanceId: string }>`
const runtimeRows = yield* sql<{ readonly providerInstanceId: string }>`
SELECT provider_instance_id AS "providerInstanceId"
FROM provider_session_runtime
WHERE thread_id = ${`thread-${kind}`}
`;
assert.deepStrictEqual(runtimeRows, [{ providerInstanceId: kind }]);
}
assert.deepStrictEqual(runtimeRows, [{ providerInstanceId: kind }]);
}

// The upstream-driver row must be untouched (still NULL).
const claudeSession = yield* sql<{
readonly providerInstanceId: string | null;
}>`
// The upstream-driver row must be untouched (still NULL).
const claudeSession = yield* sql<{
readonly providerInstanceId: string | null;
}>`
SELECT provider_instance_id AS "providerInstanceId"
FROM projection_thread_sessions
WHERE thread_id = 'thread-claude'
`;
assert.deepStrictEqual(claudeSession, [{ providerInstanceId: null }]);
assert.deepStrictEqual(claudeSession, [{ providerInstanceId: null }]);

const claudeRuntime = yield* sql<{
readonly providerInstanceId: string | null;
}>`
const claudeRuntime = yield* sql<{
readonly providerInstanceId: string | null;
}>`
SELECT provider_instance_id AS "providerInstanceId"
FROM provider_session_runtime
WHERE thread_id = 'thread-claude'
`;
assert.deepStrictEqual(claudeRuntime, [{ providerInstanceId: null }]);
}),
assert.deepStrictEqual(claudeRuntime, [{ providerInstanceId: null }]);
}),
);

it.effect("is idempotent — re-running does not overwrite already-set ids", () =>
Effect.gen(function* () {
const sql = yield* SqlClient.SqlClient;

yield* runMigrations({ toMigrationInclusive: 28 });
yield* runMigrations({ toMigrationInclusive: 30 });

yield* sql`
INSERT INTO projection_projects (
Expand Down
5 changes: 1 addition & 4 deletions apps/server/src/provider/Drivers/GeminiCliDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ import { ServerConfig } from "../../config.ts";
import { makeGeminiCliTextGeneration } from "../../textGeneration/GeminiCliTextGeneration.ts";
import { ProviderDriverError } from "../Errors.ts";
import { makeGeminiCliAdapter } from "../Layers/GeminiCliAdapter.ts";
import {
checkGeminiCliStatus,
makePendingGeminiCliProvider,
} from "../Layers/GeminiCliProvider.ts";
import { checkGeminiCliStatus, makePendingGeminiCliProvider } from "../Layers/GeminiCliProvider.ts";
import { ProviderEventLoggers } from "../Layers/ProviderEventLoggers.ts";
import { makeManagedServerProvider } from "../makeManagedServerProvider.ts";
import {
Expand Down
4 changes: 3 additions & 1 deletion apps/server/src/provider/Layers/AmpProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,9 @@ export const checkAmpStatus = Effect.fn("checkAmpStatus")(function* (
});
});

export const makePendingAmpProvider = (ampSettings: GenericProviderSettings): ServerProviderDraft => {
export const makePendingAmpProvider = (
ampSettings: GenericProviderSettings,
): ServerProviderDraft => {
const checkedAt = new Date().toISOString();
const models = providerModelsFromSettings(
BUILT_IN_MODELS,
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/provider/Layers/CodexAdapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1123,7 +1123,7 @@ it.effect("flushes managed native logs when the adapter layer shuts down", () =>
const threadLogPath = path.join(tempDir, "thread-logger.log");
assert.equal(fs.existsSync(threadLogPath), true);
const contents = fs.readFileSync(threadLogPath, "utf8");
assert.match(contents, /NTIVE: .*"message":"native flush test"/);
assert.match(contents, /NATIVE: .*"message":"native flush test"/);
} finally {
if (!scopeClosed) {
yield* Scope.close(scope, Exit.void);
Expand Down
Loading
Loading