Skip to content

Commit 12e69c7

Browse files
authored
Merge branch 'leader' into fix-bluetooth-race-condition-17974409934683189531
2 parents b38a3ab + ffb0077 commit 12e69c7

8 files changed

Lines changed: 60 additions & 31 deletions

.github/conflict-resolver.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ rules:
1616
strategy: 'ours'
1717
- paths: '*.generated.js'
1818
strategy: 'ours'
19+
20+
# For Playwright VRT snapshots, prefer the incoming version from the feature branch
21+
- paths: '**/*.spec.ts-snapshots/*.png'
22+
strategy: 'theirs'

.github/workflows/conflict-resolver.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ jobs:
5757
with:
5858
ref: ${{ env.SOURCE }}
5959
fetch-depth: 0
60-
token: ${{ secrets.ARI_PAT || secrets.GITHUB_TOKEN }}
60+
token: ${{ secrets.PAT_TOKEN || secrets.ARI_PAT || secrets.GITHUB_TOKEN }}
6161

6262
- name: Validate branches
6363
id: validate_branches
@@ -118,7 +118,7 @@ jobs:
118118
- name: Trigger Gemini Orchestrator
119119
if: steps.validate_branches.outputs.skipped != 'true' && steps.resolve.outputs.unresolved-files == '' && env.PR_NUMBER && env.PR_NUMBER != '0'
120120
env:
121-
GH_TOKEN: ${{ secrets.ARI_PAT || secrets.GITHUB_TOKEN }}
121+
GH_TOKEN: ${{ secrets.PAT_TOKEN || secrets.ARI_PAT || secrets.GITHUB_TOKEN }}
122122
HEAD_SHA: ${{ steps.commit_push.outputs.resolved_sha }}
123123
BASE_SHA: ${{ steps.validate_branches.outputs.base_sha }}
124124
run: |

.github/workflows/reusable-gemini-review.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ jobs:
8080
outputs:
8181
needs-review: ${{ steps.decision.outputs.needs-review }}
8282
skip-reason: ${{ steps.decision.outputs.skip-reason }}
83+
thought-signature: ${{ steps.decision.outputs.thought-signature }}
8384
base_sha: ${{ steps.fetch-shas.outputs.base_sha }}
8485
head_sha: ${{ steps.fetch-shas.outputs.head_sha }}
8586
steps:
@@ -397,6 +398,7 @@ jobs:
397398
PR_DIFF_FILE: pr.diff
398399
FAILED_CHECKS_JSON: ${{ env.FAILED_CHECKS_JSON }}
399400
# Pass other context vars
401+
GEMINI_THOUGHT_SIGNATURE: ${{ needs.analyze-changes.outputs.thought-signature }}
400402
run: |
401403
pnpm tsx scripts/gemini-client.ts \
402404
--preset "review" \
@@ -422,15 +424,22 @@ jobs:
422424
REVIEW_COMMENT=$(jq -r '.reviewComment // empty' review_result.json)
423425
424426
# Check if there's a comment to post
425-
if [ -n "$REVIEW_COMMENT" ]; then
427+
if [[ -n "$REVIEW_COMMENT" && "$REVIEW_COMMENT" != "null" ]]; then
426428
# Create the commit hash line
427429
COMMIT_HASH_MSG="> Reviewed commit: \`${HEAD_SHA}\`"
428430
429431
# Create manual trigger footer
430432
FOOTER="\n\n---\n#### 🤖 [Gemini Manual Trigger Guide](${{ github.server_url }}/${{ github.repository }}/blob/leader/docs/workflows/MANUAL_TRIGGERS.md)"
431433
434+
# Extract the new thought signature if present
435+
NEW_THOUGHT_SIG=$(jq -r '.thoughtSignature // ""' review_result.json)
436+
SIG_MARKER=""
437+
if [[ -n "$NEW_THOUGHT_SIG" && "$NEW_THOUGHT_SIG" != "null" ]]; then
438+
SIG_MARKER="\n\n<!-- thought_signature: ${NEW_THOUGHT_SIG} -->"
439+
fi
440+
432441
# Combine the header and the original comment
433-
FINAL_COMMENT="${COMMIT_HASH_MSG}\n\n${REVIEW_COMMENT}${FOOTER}"
442+
FINAL_COMMENT="${COMMIT_HASH_MSG}\n\n${REVIEW_COMMENT}${FOOTER}${SIG_MARKER}"
434443
435444
# Write to a file to be used by the gh cli command
436445
echo -e "$FINAL_COMMENT" > review_comment.txt

scripts/conflict-resolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ ${JSON.stringify(fileConflicts, null, 2)}
9393
`
9494

9595
try {
96-
const text = await generateContentWithFallback({
96+
const { text } = await generateContentWithFallback({
9797
genAI,
9898
prompt,
9999
config: {

scripts/decide-review-strategy.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ else
131131
NEEDS_REVIEW="true"
132132
SKIP_REASON=""
133133
else
134+
# Extract thought signature if present
135+
THOUGHT_SIG=$(echo "$LAST_COMMENT_BODY" | grep -oP '<!-- thought_signature: \K[a-zA-Z0-9+/=]+(?= -->)' | head -n 1)
136+
if [ -n "$THOUGHT_SIG" ]; then
137+
echo "::info::Extracted thought signature from last review."
138+
echo "thought-signature=$THOUGHT_SIG" >> "$GITHUB_OUTPUT"
139+
fi
140+
134141
# Extract the commit SHA from the last review comment to see if it's outdated.
135142
# Updated regex to handle "Reviewed commit: `sha`", "Reviewed at commit: `sha`", etc.
136143
LAST_REVIEWED_SHA=$(echo "$LAST_COMMENT_BODY" | grep -oP '(?<=> Failed at commit: `)[a-f0-9]{7,40}(?=`)|(?<=Reviewed commit: `)[a-f0-9]{7,40}(?=`)|(?<=Reviewed at commit: `)[a-f0-9]{7,40}(?=`)|(?<=commit: `)[a-f0-9]{7,40}(?=`)|(?<=`)[a-f0-9]{7,40}(?=` commit)' | head -n 1)

scripts/gemini-client.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,10 @@ const outputFile = getArg('--output')
2525
const preset = getArg('--preset')
2626
const instructions = getArg('--instructions')
2727

28-
// List of models to try in order.
29-
// The first model in the list is the primary model, and the rest are fallbacks.
30-
31-
// UPDATED: Aligned with latest model recommendations (Q3 2025+)
32-
// 1. gemini-2.5-flash: Next-gen standard workhorse.
33-
// 2. gemini-2.5-flash-lite: Next-gen ultra-low-cost model.
34-
// 3. gemini-2.0-flash: Previous generation flash model.
35-
// 4. gemini-2.0-flash-lite: Previous generation ultra-low-cost model.
36-
// 5. gemini-2.5-pro: Expensive, high-intelligence fallback.
37-
3828
const defaultFallbacks = [
29+
'gemini-3.1-flash-lite-preview',
3930
'gemini-2.5-flash',
4031
'gemini-2.5-flash-lite',
41-
'gemini-2.0-flash',
42-
'gemini-2.0-flash-lite',
4332
'gemini-2.5-pro',
4433
]
4534

@@ -242,6 +231,7 @@ export interface ReviewContext {
242231
testFiles?: string | undefined
243232
failedChecks: FailedCheck[]
244233
slopAnalysis?: string
234+
thoughtSignature?: string
245235
}
246236

247237
async function main() {
@@ -320,27 +310,45 @@ async function main() {
320310
}
321311
}
322312

313+
type ExtendedGenerateContentRequest = GenerateContentRequest & { thought_signature?: string };
314+
323315
export async function generateContentWithFallback({
324316
genAI,
325317
prompt,
326318
config,
319+
thoughtSignature,
327320
}: {
328321
genAI: GoogleGenerativeAI
329322
prompt: string
330323
config?: Omit<GenerateContentRequest, 'contents'>
331-
}) {
324+
thoughtSignature?: string
325+
}): Promise<{ text: string; thoughtSignature?: string }> {
332326
let lastError: Error | null = null
333327

334328
for (const modelName of MODEL_FALLBACKS) {
335-
console.log(`Attempting to use model: ${modelName}...`)
336329
try {
337330
const model = genAI.getGenerativeModel({ model: modelName })
338-
const result = await model.generateContent({
331+
const request: ExtendedGenerateContentRequest = {
339332
contents: [{ role: 'user', parts: [{ text: prompt }] }],
340333
...config,
341-
})
334+
...(thoughtSignature && { thought_signature: thoughtSignature })
335+
}
336+
337+
const result = await model.generateContent(request)
342338
console.log(`Successfully generated content using ${modelName}.`)
343-
return result.response.text()
339+
340+
const text = result.response.text()
341+
342+
// Capture thought signature from the response if present
343+
const capturedSignature = (
344+
result.response.candidates?.[0] as NonNullable<
345+
typeof result.response.candidates
346+
>[number] & {
347+
thought_signature?: string
348+
}
349+
)?.thought_signature
350+
351+
return { text, thoughtSignature: capturedSignature }
344352
} catch (error: unknown) {
345353
if (error instanceof Error) {
346354
lastError = error
@@ -418,7 +426,7 @@ ${contextContent}
418426
--- Task ---
419427
${task}
420428
`
421-
const text = await generateContentWithFallback({ genAI, prompt })
429+
const { text } = await generateContentWithFallback({ genAI, prompt })
422430
await writeOutput(text, outputFile)
423431
}
424432

@@ -552,6 +560,7 @@ function getReviewContextFromEnv(): ReviewContext {
552560
testFiles: process.env.TEST_FILES,
553561
failedChecks,
554562
slopAnalysis: process.env.SLOP_ANALYSIS || 'Not available.',
563+
thoughtSignature: process.env.GEMINI_THOUGHT_SIGNATURE,
555564
}
556565
}
557566

@@ -731,9 +740,10 @@ async function runReviewPreset(
731740
contextContent,
732741
instructions
733742
)
734-
const text = await generateContentWithFallback({
743+
const { text, thoughtSignature } = await generateContentWithFallback({
735744
genAI,
736745
prompt,
746+
thoughtSignature: context.thoughtSignature,
737747
config: {
738748
generationConfig: {
739749
maxOutputTokens: 4096,
@@ -830,8 +840,10 @@ async function runReviewPreset(
830840
verdict?: string
831841
labels?: string[]
832842
prContext?: unknown
843+
thoughtSignature?: string
833844
}
834845
reviewData.prContext = prContext
846+
reviewData.thoughtSignature ??= thoughtSignature
835847
// It's valid JSON, but we should still check if the content is meaningful.
836848
if (
837849
!reviewData.reviewComment ||

scripts/identify-tech-debt.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export async function main() {
9393

9494
const prompt = promptTemplate.replace('{{diff}}', processedDiff)
9595

96-
const rawResponse = await generateContentWithFallback({
96+
const { text: rawResponse } = await generateContentWithFallback({
9797
genAI,
9898
prompt,
9999
config: {

tests/unit/gemini-client.test.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,9 @@ describe('getModelFallbacks', () => {
6464
delete process.env.GEMINI_MODEL_FALLBACKS
6565
const fallbacks = getModelFallbacks()
6666
expect(fallbacks).toEqual([
67+
'gemini-3.1-flash-lite-preview',
6768
'gemini-2.5-flash',
6869
'gemini-2.5-flash-lite',
69-
'gemini-2.0-flash',
70-
'gemini-2.0-flash-lite',
7170
'gemini-2.5-pro',
7271
])
7372
})
@@ -107,10 +106,9 @@ describe('getModelFallbacks', () => {
107106
process.env.GEMINI_MODEL_FALLBACKS = ''
108107
const fallbacks = getModelFallbacks()
109108
expect(fallbacks).toEqual([
109+
'gemini-3.1-flash-lite-preview',
110110
'gemini-2.5-flash',
111111
'gemini-2.5-flash-lite',
112-
'gemini-2.0-flash',
113-
'gemini-2.0-flash-lite',
114112
'gemini-2.5-pro',
115113
])
116114
expect(consoleWarnSpy).toHaveBeenCalledWith(
@@ -126,10 +124,9 @@ describe('getModelFallbacks', () => {
126124
process.env.GEMINI_MODEL_FALLBACKS = 'invalid1, invalid2'
127125
const fallbacks = getModelFallbacks()
128126
expect(fallbacks).toEqual([
127+
'gemini-3.1-flash-lite-preview',
129128
'gemini-2.5-flash',
130129
'gemini-2.5-flash-lite',
131-
'gemini-2.0-flash',
132-
'gemini-2.0-flash-lite',
133130
'gemini-2.5-pro',
134131
])
135132
expect(consoleWarnSpy).toHaveBeenCalledWith(

0 commit comments

Comments
 (0)