Skip to content
Merged
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
6 changes: 3 additions & 3 deletions apps/server/src/jobs/document-summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { serialize } from "@chopin/dialect/serialize";
import { assert } from "@chopin/dialect/validate";

import { summaryAgent } from "../harness/agents";
import { openWorkerSession } from "./worker-session";
import { openWorkerSession, workerModel } from "./worker-session";
import type { Config } from "../config";
import type { DocumentTarget } from "../plan/service";
import type { JsonValue } from "../storage/model";
Expand Down Expand Up @@ -295,7 +295,7 @@ class HarnessSummaryEngine {
}
partials = reduced;
}
return { description: partials[0]!, model: this.#config.model };
return { description: partials[0]!, model: workerModel(this.#config.model) };
} finally {
await worker.close();
}
Expand Down Expand Up @@ -339,7 +339,7 @@ export function documentSummaryDefinition(options: DocumentSummaryOptions): JobD
if (serialize(tree) !== target.source) throw new Error("Document source is not canonical.");
let result = target.source.trim()
? await engine(execution, target.source)
: { description: "Empty document", model: options.config.model };
: { description: "Empty document", model: workerModel(options.config.model) };
return {
revision: execution.input.revision,
sourceHash: execution.input.sourceHash,
Expand Down
7 changes: 5 additions & 2 deletions apps/server/src/jobs/research-brief.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { assertResearchContext, researchSources } from "../conversation-plan/res
import { id, knownKeys, record, text, version } from "../conversation-plan/validation-fields";
import type { JsonValue } from "../storage/model";
import { type JobDefinition, type JobExecution, JobExecutionError } from "./registry";
import { openWorkerSession } from "./worker-session";
import { openWorkerSession, workerModel } from "./worker-session";

// Copilot requires a session ceiling of at least 30, even for a single short turn.
const MAX_AI_CREDITS = 30;
Expand Down Expand Up @@ -123,7 +123,10 @@ async function generate(
if (!await credential.authorize() || signal.aborted) {
throw new JobExecutionError("owner-unavailable");
}
return { ...(result.output as { brief: string; sourceIds: string[] }), model: config.model };
return {
...(result.output as { brief: string; sourceIds: string[] }),
model: workerModel(config.model),
};
} finally {
signal.removeEventListener("abort", rejectAbort);
await close?.();
Expand Down
16 changes: 16 additions & 0 deletions apps/server/src/jobs/research-workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,3 +784,19 @@ describe("research workspace execution", () => {
.rejects.toMatchObject({ progressReason: "source-validation-failed" });
});
});

it("research artifacts record the attached client when the operator configured no model", async () => {
let definition = researchEvidenceDefinition({
config: { agent: true, model: "" },
engine: async () => ({ findings: [], sources: [] }),
});
let input = { workspaceId: "workspace", turnId: "turn", query: "Rate limiting a login endpoint" };
let artifact = await definition.execute({
job: { channelId: "channel" },
input,
progress: async () => {},
} as unknown as JobExecution<ResearchEvidenceInput>);

expect(artifact.model).toBe("attached-client");
expect(parseResearchEvidenceArtifact(artifact as unknown as JsonValue)).toEqual(artifact);
});
8 changes: 4 additions & 4 deletions apps/server/src/jobs/research-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as limits from "@chopin/dialect/limits";

import { WEB_SEARCH_MAX_CALLS, WebSearchTimeoutError, webSearchTool } from "../harness/web-search";
import { JobExecutionError } from "./registry";
import { openWorkerSession, type WorkerSession } from "./worker-session";
import { openWorkerSession, workerModel, type WorkerSession } from "./worker-session";
import type { WebSearchFailureDiagnostic } from "../harness/web-search";
import type { researchAgent } from "../harness/agents";
import type { Config } from "../config";
Expand Down Expand Up @@ -1158,7 +1158,7 @@ export function researchEvidenceDefinition(options: ResearchEvidenceOptions): Jo
return parseResearchEvidenceArtifact({
...input,
...evidence,
model: options.config.model,
model: workerModel(options.config.model),
});
},
};
Expand Down Expand Up @@ -1232,7 +1232,7 @@ export function researchAnswerDefinition(options: ResearchAnswerOptions): JobDef
privateFindings: privateValue.findings,
documentRevision: input.document.revision,
documentSourceHash: input.document.sourceHash,
model: options.config.model,
model: workerModel(options.config.model),
});
}

Expand Down Expand Up @@ -1261,7 +1261,7 @@ export function researchAnswerDefinition(options: ResearchAnswerOptions): JobDef
sources: evidence.sources,
documentRevision: input.document.revision,
documentSourceHash: input.document.sourceHash,
model: options.config.model,
model: workerModel(options.config.model),
});
},
};
Expand Down
10 changes: 7 additions & 3 deletions apps/server/src/jobs/version-summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parse } from "@chopin/dialect/parse";
import { serialize } from "@chopin/dialect/serialize";

import { historySummaryAgent } from "../harness/agents";
import { openWorkerSession } from "./worker-session";
import { openWorkerSession, workerModel } from "./worker-session";
import type { Config } from "../config";
import type { JsonValue, StoredDocumentVersion, SummarizeDocumentVersion } from "../storage/model";
import type { JobDefinition, JobExecution } from "./registry";
Expand Down Expand Up @@ -228,7 +228,7 @@ class HarnessVersionSummaryEngine {
aborted,
]);
let output = result.output as { summaries: { id: string; summary: string }[] };
return { summaries: output.summaries, model: this.#config.historyModel };
return { summaries: output.summaries, model: workerModel(this.#config.historyModel) };
} finally {
await worker.close();
}
Expand Down Expand Up @@ -274,7 +274,11 @@ export function versionSummaryDefinition(options: VersionSummaryOptions): JobDef
wanted.set(version.id, version.sourceHash);
}
if (changes.length === 0) {
return { generatorVersion: 1, model: options.config.historyModel, summaries: [] };
return {
generatorVersion: 1,
model: workerModel(options.config.historyModel),
summaries: [],
};
}
let result = await engine(execution, changes);
let summaries: VersionSummaryArtifact["summaries"] = [];
Expand Down
8 changes: 8 additions & 0 deletions apps/server/src/jobs/worker-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ export type WorkerAgent<Session extends Destroyable> = {

export type WorkerSession<Session> = { session: Session; close(): Promise<void> };

/**
* The model a worker's artifact records. Under `HARNESS=remote` the operator may configure none, and the
* attached client then chooses its own.
*/
export function workerModel(configured: string): string {
return configured || "attached-client";
}

async function openAbortable<T extends Destroyable>(
opening: Promise<T>,
aborted: Promise<never>,
Expand Down
Loading