Skip to content
Draft
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
13 changes: 0 additions & 13 deletions TODO.md

This file was deleted.

1 change: 1 addition & 0 deletions apps/desktop/src/clientPersistence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const clientSettings: ClientSettings = {
sidebarProjectSortOrder: "manual",
sidebarThreadSortOrder: "created_at",
timestampFormat: "24-hour",
toolCallSummaries: true,
};

const savedRegistryRecord: PersistedSavedEnvironmentRecord = {
Expand Down
6 changes: 6 additions & 0 deletions apps/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ function normalizeContextMenuItems(source: readonly ContextMenuItem[]): ContextM
continue;
}

// Header items are decorative section labels for the web fallback only —
// Electron's native menu has no equivalent affordance, so we skip them.
if (sourceItem.header === true) {
continue;
}

const normalizedItem: ContextMenuItem = {
id: sourceItem.id,
label: sourceItem.label,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ export const makeOrchestrationIntegrationHarness = (
const textGenerationLayer = Layer.succeed(TextGeneration, {
generateBranchName: () => Effect.succeed({ branch: "update" }),
generateThreadTitle: () => Effect.succeed({ title: "New thread" }),
generateToolWorkLogSummary: () => Effect.succeed({ line: "Example activity" }),
} as unknown as TextGenerationShape);
const providerCommandReactorLayer = ProviderCommandReactorLive.pipe(
Layer.provideMerge(runtimeServicesLayer),
Expand Down
2 changes: 0 additions & 2 deletions apps/server/scripts/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,6 @@ const buildCmd = Command.make(
cwd: serverDir,
stdout: config.verbose ? "inherit" : "ignore",
stderr: "inherit",
// Windows needs shell mode to resolve `.cmd` shims on PATH.
shell: process.platform === "win32",
}),
);

Expand Down
30 changes: 29 additions & 1 deletion apps/server/src/git/Layers/ClaudeTextGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
buildCommitMessagePrompt,
buildPrContentPrompt,
buildThreadTitlePrompt,
buildToolWorkLogSummaryPrompt,
} from "../Prompts.ts";
import {
normalizeCliError,
Expand Down Expand Up @@ -87,7 +88,8 @@ export const makeClaudeTextGeneration = Effect.fn("makeClaudeTextGeneration")(fu
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle";
| "generateThreadTitle"
| "generateToolWorkLogSummary";
cwd: string;
prompt: string;
outputSchemaJson: S;
Expand Down Expand Up @@ -315,10 +317,36 @@ export const makeClaudeTextGeneration = Effect.fn("makeClaudeTextGeneration")(fu
};
});

const generateToolWorkLogSummary: TextGenerationShape["generateToolWorkLogSummary"] = Effect.fn(
"ClaudeTextGeneration.generateToolWorkLogSummary",
)(function* (input) {
const { prompt, outputSchema } = buildToolWorkLogSummaryPrompt({
label: input.label,
toolTitle: input.toolTitle,
itemType: input.itemType,
requestKind: input.requestKind,
command: input.command,
detailSnippet: input.detailSnippet,
});

const generated = yield* runClaudeJson({
operation: "generateToolWorkLogSummary",
cwd: input.cwd,
prompt,
outputSchemaJson: outputSchema,
modelSelection: input.modelSelection,
});

return {
line: generated.line,
};
});

return {
generateCommitMessage,
generatePrContent,
generateBranchName,
generateThreadTitle,
generateToolWorkLogSummary,
} satisfies TextGenerationShape;
});
33 changes: 31 additions & 2 deletions apps/server/src/git/Layers/CodexTextGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
buildCommitMessagePrompt,
buildPrContentPrompt,
buildThreadTitlePrompt,
buildToolWorkLogSummaryPrompt,
} from "../Prompts.ts";
import {
normalizeCliError,
Expand Down Expand Up @@ -97,7 +98,8 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle",
| "generateThreadTitle"
| "generateToolWorkLogSummary",
attachments: BranchNameGenerationInput["attachments"],
): Effect.fn.Return<MaterializedImageAttachments, TextGenerationError> {
if (!attachments || attachments.length === 0) {
Expand Down Expand Up @@ -141,7 +143,8 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle";
| "generateThreadTitle"
| "generateToolWorkLogSummary";
cwd: string;
prompt: string;
outputSchemaJson: S;
Expand Down Expand Up @@ -379,11 +382,37 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func
} satisfies ThreadTitleGenerationResult;
});

const generateToolWorkLogSummary: TextGenerationShape["generateToolWorkLogSummary"] = Effect.fn(
"CodexTextGeneration.generateToolWorkLogSummary",
)(function* (input) {
const { prompt, outputSchema } = buildToolWorkLogSummaryPrompt({
label: input.label,
toolTitle: input.toolTitle,
itemType: input.itemType,
requestKind: input.requestKind,
command: input.command,
detailSnippet: input.detailSnippet,
});

const generated = yield* runCodexJson({
operation: "generateToolWorkLogSummary",
cwd: input.cwd,
prompt,
outputSchemaJson: outputSchema,
modelSelection: input.modelSelection,
});

return {
line: generated.line,
};
});

return {
generateCommitMessage,
generatePrContent,
generateBranchName,
generateThreadTitle,
generateToolWorkLogSummary,
} satisfies TextGenerationShape;
});

Expand Down
33 changes: 31 additions & 2 deletions apps/server/src/git/Layers/CursorTextGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
buildCommitMessagePrompt,
buildPrContentPrompt,
buildThreadTitlePrompt,
buildToolWorkLogSummaryPrompt,
} from "../Prompts.ts";
import {
extractJsonObject,
Expand All @@ -33,7 +34,8 @@ function mapCursorAcpError(
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle",
| "generateThreadTitle"
| "generateToolWorkLogSummary",
detail: string,
cause: unknown,
): TextGenerationError {
Expand Down Expand Up @@ -74,7 +76,8 @@ export const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(fu
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle";
| "generateThreadTitle"
| "generateToolWorkLogSummary";
cwd: string;
prompt: string;
outputSchemaJson: S;
Expand Down Expand Up @@ -270,11 +273,37 @@ export const makeCursorTextGeneration = Effect.fn("makeCursorTextGeneration")(fu
} satisfies ThreadTitleGenerationResult;
});

const generateToolWorkLogSummary: TextGenerationShape["generateToolWorkLogSummary"] = Effect.fn(
"CursorTextGeneration.generateToolWorkLogSummary",
)(function* (input) {
const { prompt, outputSchema } = buildToolWorkLogSummaryPrompt({
label: input.label,
toolTitle: input.toolTitle,
itemType: input.itemType,
requestKind: input.requestKind,
command: input.command,
detailSnippet: input.detailSnippet,
});

const generated = yield* runCursorJson({
operation: "generateToolWorkLogSummary",
cwd: input.cwd,
prompt,
outputSchemaJson: outputSchema,
modelSelection: input.modelSelection,
});

return {
line: generated.line,
};
});

return {
generateCommitMessage,
generatePrContent,
generateBranchName,
generateThreadTitle,
generateToolWorkLogSummary,
} satisfies TextGenerationShape;
});

Expand Down
20 changes: 20 additions & 0 deletions apps/server/src/git/Layers/GitManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ interface FakeGitTextGeneration {
message: string;
modelSelection: ModelSelection;
}) => Effect.Effect<{ title: string }, TextGenerationError>;
generateToolWorkLogSummary: (input: {
cwd: string;
label: string;
modelSelection: ModelSelection;
}) => Effect.Effect<{ line: string }, TextGenerationError>;
}

type FakePullRequest = NonNullable<FakeGhScenario["pullRequest"]>;
Expand Down Expand Up @@ -292,6 +297,10 @@ function createTextGeneration(overrides: Partial<FakeGitTextGeneration> = {}): T
Effect.succeed({
title: "Update workflow",
}),
generateToolWorkLogSummary: () =>
Effect.succeed({
line: "Task Example tool activity",
}),
...overrides,
};

Expand Down Expand Up @@ -340,6 +349,17 @@ function createTextGeneration(overrides: Partial<FakeGitTextGeneration> = {}): T
}),
),
),
generateToolWorkLogSummary: (input) =>
implementation.generateToolWorkLogSummary(input).pipe(
Effect.mapError(
(cause) =>
new TextGenerationError({
operation: "generateToolWorkLogSummary",
detail: "fake text generation failed",
...(cause !== undefined ? { cause } : {}),
}),
),
),
};
}

Expand Down
32 changes: 30 additions & 2 deletions apps/server/src/git/Layers/OpenCodeTextGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
buildCommitMessagePrompt,
buildPrContentPrompt,
buildThreadTitlePrompt,
buildToolWorkLogSummaryPrompt,
} from "../Prompts.ts";
import { type TextGenerationShape } from "../Services/TextGeneration.ts";
import {
Expand Down Expand Up @@ -156,7 +157,8 @@ export const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration"
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle";
| "generateThreadTitle"
| "generateToolWorkLogSummary";
}) =>
sharedServerMutex.withPermit(
Effect.gen(function* () {
Expand Down Expand Up @@ -266,7 +268,8 @@ export const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration"
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle";
| "generateThreadTitle"
| "generateToolWorkLogSummary";
readonly cwd: string;
readonly prompt: string;
readonly outputSchemaJson: S;
Expand Down Expand Up @@ -455,10 +458,35 @@ export const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration"
};
});

const generateToolWorkLogSummary: TextGenerationShape["generateToolWorkLogSummary"] = Effect.fn(
"OpenCodeTextGeneration.generateToolWorkLogSummary",
)(function* (input) {
const { prompt, outputSchema } = buildToolWorkLogSummaryPrompt({
label: input.label,
toolTitle: input.toolTitle,
itemType: input.itemType,
requestKind: input.requestKind,
command: input.command,
detailSnippet: input.detailSnippet,
});
const generated = yield* runOpenCodeJson({
operation: "generateToolWorkLogSummary",
cwd: input.cwd,
prompt,
outputSchemaJson: outputSchema,
modelSelection: input.modelSelection,
});

return {
line: generated.line,
};
});

return {
generateCommitMessage,
generatePrContent,
generateBranchName,
generateThreadTitle,
generateToolWorkLogSummary,
} satisfies TextGenerationShape;
});
2 changes: 2 additions & 0 deletions apps/server/src/git/Layers/TextGenerationLive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const makeStubTextGeneration = (overrides: Partial<TextGenerationShape>): TextGe
generatePrContent: () => Effect.die("generatePrContent stub not configured for this test"),
generateBranchName: () => Effect.die("generateBranchName stub not configured for this test"),
generateThreadTitle: () => Effect.die("generateThreadTitle stub not configured for this test"),
generateToolWorkLogSummary: () =>
Effect.die("generateToolWorkLogSummary stub not configured for this test"),
...overrides,
});

Expand Down
9 changes: 8 additions & 1 deletion apps/server/src/git/Layers/TextGenerationLive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ import {
} from "../../provider/Services/ProviderInstanceRegistry.ts";
import type { ProviderInstance } from "../../provider/ProviderDriver.ts";
import { TextGeneration, type TextGenerationShape } from "../Services/TextGeneration.ts";
import { sanitizeToolWorkLogSummaryLine } from "../Utils.ts";

type TextGenerationOp =
| "generateCommitMessage"
| "generatePrContent"
| "generateBranchName"
| "generateThreadTitle";
| "generateThreadTitle"
| "generateToolWorkLogSummary";

const resolveInstance = (
registry: ProviderInstanceRegistryShape,
Expand Down Expand Up @@ -85,6 +87,11 @@ export const makeTextGenerationFromRegistry = (
resolveInstance(registry, "generateThreadTitle", input.modelSelection.instanceId).pipe(
Effect.flatMap((tg) => tg.generateThreadTitle(input)),
),
generateToolWorkLogSummary: (input) =>
resolveInstance(registry, "generateToolWorkLogSummary", input.modelSelection.instanceId).pipe(
Effect.flatMap((tg) => tg.generateToolWorkLogSummary(input)),
Effect.map((r) => ({ line: sanitizeToolWorkLogSummaryLine(r.line, input.label) })),
),
});

/**
Expand Down
Loading
Loading