History

Move worktree branch auto-rename into provider turn reactor

- Generate and rename temporary `t3code/*` worktree branches on first user turn in `ProviderCommandReactor` - Remove websocket/client branch-generation RPCs and related contract/API surface - Update Codex text-generation prompt to include attachment metadata only when attachments exist, with expanded tests

Julius Marminge committed 8 months ago

Commit 5e55aa31 parent a21095b12 files · +405 −264Browse files

Showing the changes to apps/server/src/git (2 of 12 files). Show all

Unified · Split

2 files
  1. apps/server/src/git/Layers/CodexTextGeneration.test.ts +66 −1
  2. apps/server/src/git/Layers/CodexTextGeneration.ts +10 −7
apps/server/src/git/Layers/CodexTextGeneration.test.ts+66−1
@@ -38,7 +38,19 @@ function makeFakeCodexBinary(dir: string) { · 37 unmodified lines
3838 ' printf "%s\\n" "missing --image input" >&2',
3939 " exit 2",
4040 "fi",
41− "cat >/dev/null",
41+ 'stdin_content="$(cat)"',
42+ 'if [ -n "$T3_FAKE_CODEX_STDIN_MUST_CONTAIN" ]; then',
43+ ' printf "%s" "$stdin_content" | grep -F -- "$T3_FAKE_CODEX_STDIN_MUST_CONTAIN" >/dev/null || {',
44+ ' printf "%s\\n" "stdin missing expected content" >&2',
45+ " exit 3",
46+ " }",
47+ "fi",
48+ 'if [ -n "$T3_FAKE_CODEX_STDIN_MUST_NOT_CONTAIN" ]; then',
49+ ' if printf "%s" "$stdin_content" | grep -F -- "$T3_FAKE_CODEX_STDIN_MUST_NOT_CONTAIN" >/dev/null; then',
50+ ' printf "%s\\n" "stdin contained forbidden content" >&2',
51+ " exit 4",
52+ " fi",
53+ "fi",
4254 'if [ -n "$T3_FAKE_CODEX_STDERR" ]; then',
4355 ' printf "%s\\n" "$T3_FAKE_CODEX_STDERR" >&2',
4456 "fi",
@@ -60,6 +72,8 @@ function withFakeCodexEnv<A, E, R>( · 15 unmodified lines
6072 exitCode?: number;
6173 stderr?: string;
6274 requireImage?: boolean;
75+ stdinMustContain?: string;
76+ stdinMustNotContain?: string;
6377 },
6478 effect: Effect.Effect<A, E, R>,
6579 ) {
@@ -73,6 +87,8 @@ function withFakeCodexEnv<A, E, R>( · 7 unmodified lines
7387 const previousExitCode = process.env.T3_FAKE_CODEX_EXIT_CODE;
7488 const previousStderr = process.env.T3_FAKE_CODEX_STDERR;
7589 const previousRequireImage = process.env.T3_FAKE_CODEX_REQUIRE_IMAGE;
90+ const previousStdinMustContain = process.env.T3_FAKE_CODEX_STDIN_MUST_CONTAIN;
91+ const previousStdinMustNotContain = process.env.T3_FAKE_CODEX_STDIN_MUST_NOT_CONTAIN;
7692
7793 yield* Effect.sync(() => {
7894 process.env.PATH = `${binDir}:${previousPath ?? ""}`;
@@ -95,6 +111,18 @@ function withFakeCodexEnv<A, E, R>( · 16 unmodified lines
95111 } else {
96112 delete process.env.T3_FAKE_CODEX_REQUIRE_IMAGE;
97113 }
114+
115+ if (input.stdinMustContain !== undefined) {
116+ process.env.T3_FAKE_CODEX_STDIN_MUST_CONTAIN = input.stdinMustContain;
117+ } else {
118+ delete process.env.T3_FAKE_CODEX_STDIN_MUST_CONTAIN;
119+ }
120+
121+ if (input.stdinMustNotContain !== undefined) {
122+ process.env.T3_FAKE_CODEX_STDIN_MUST_NOT_CONTAIN = input.stdinMustNotContain;
123+ } else {
124+ delete process.env.T3_FAKE_CODEX_STDIN_MUST_NOT_CONTAIN;
125+ }
98126 });
99127
100128 return {
@@ -103,6 +131,8 @@ function withFakeCodexEnv<A, E, R>( · 2 unmodified lines
103131 previousExitCode,
104132 previousStderr,
105133 previousRequireImage,
134+ previousStdinMustContain,
135+ previousStdinMustNotContain,
106136 };
107137 }),
108138 () => effect,
@@ -133,6 +163,18 @@ function withFakeCodexEnv<A, E, R>( · 24 unmodified lines
133163 } else {
134164 process.env.T3_FAKE_CODEX_REQUIRE_IMAGE = previous.previousRequireImage;
135165 }
166+
167+ if (previous.previousStdinMustContain === undefined) {
168+ delete process.env.T3_FAKE_CODEX_STDIN_MUST_CONTAIN;
169+ } else {
170+ process.env.T3_FAKE_CODEX_STDIN_MUST_CONTAIN = previous.previousStdinMustContain;
171+ }
172+
173+ if (previous.previousStdinMustNotContain === undefined) {
174+ delete process.env.T3_FAKE_CODEX_STDIN_MUST_NOT_CONTAIN;
175+ } else {
176+ process.env.T3_FAKE_CODEX_STDIN_MUST_NOT_CONTAIN = previous.previousStdinMustNotContain;
177+ }
136178 }),
137179 );
138180 }
@@ -202,6 +244,7 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGenerationLive", (it) => { · 63 unmodified lines
202244 output: JSON.stringify({
203245 branch: " Feat/Session ",
204246 }),
247+ stdinMustNotContain: "Image attachments supplied to the model",
205248 },
206249 Effect.gen(function* () {
207250 const textGeneration = yield* TextGeneration;
@@ -216,6 +259,27 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGenerationLive", (it) => { · 8 unmodified lines
216259 ),
217260 );
218261
262+ it.effect("omits attachment metadata section when no attachments are provided", () =>
263+ withFakeCodexEnv(
264+ {
265+ output: JSON.stringify({
266+ branch: "fix/session-timeout",
267+ }),
268+ stdinMustNotContain: "Attachment metadata:",
269+ },
270+ Effect.gen(function* () {
271+ const textGeneration = yield* TextGeneration;
272+
273+ const generated = yield* textGeneration.generateBranchName({
274+ cwd: process.cwd(),
275+ message: "Fix timeout behavior.",
276+ });
277+
278+ expect(generated.branch).toBe("fix/session-timeout");
279+ }),
280+ ),
281+ );
282+
219283 it.effect("passes image attachments through as codex image inputs", () =>
220284 withFakeCodexEnv(
221285 {
@@ -223,6 +287,7 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGenerationLive", (it) => { · 1 unmodified line
223287 branch: "fix/ui-regression",
224288 }),
225289 requireImage: true,
290+ stdinMustContain: "Attachment metadata:",
226291 },
227292 Effect.gen(function* () {
228293 const textGeneration = yield* TextGeneration;
apps/server/src/git/Layers/CodexTextGeneration.ts+10−7
@@ -503,7 +503,7 @@ const makeCodexTextGeneration = Effect.gen(function* () { · 502 unmodified lines
503503 (attachment) => `- ${attachment.name} (${attachment.mimeType}, ${attachment.sizeBytes} bytes)`,
504504 );
505505
506− const prompt = [
506+ const promptSections = [
507507 "You generate concise git branch names.",
508508 "Return a JSON object with key: branch.",
509509 "Rules:",
@@ -512,14 +512,17 @@ const makeCodexTextGeneration = Effect.gen(function* () { · 2 unmodified lines
512512 "- Use plain words only, no issue prefixes and no punctuation-heavy text.",
513513 "- If images are attached, use them as primary context for visual/UI issues.",
514514 "",
515− `Image attachments supplied to the model: ${imagePaths.length}`,
516− "",
517515 "User message:",
518516 limitSection(input.message, 8_000),
519− "",
520− "Attachment metadata:",
521− attachmentLines.length > 0 ? limitSection(attachmentLines.join("\n"), 4_000) : "- none",
522− ].join("\n");
517+ ];
518+ if (attachmentLines.length > 0) {
519+ promptSections.push(
520+ "",
521+ "Attachment metadata:",
522+ limitSection(attachmentLines.join("\n"), 4_000),
523+ );
524+ }
525+ const prompt = promptSections.join("\n");
523526
524527 const generated = yield* runCodexJson({
525528 operation: "generateBranchName",