mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-24 02:07:16 -07:00
fix: resolve workspace publish failures and scheduler event loop starvation (#28063)
This commit is contained in:
committed by
GitHub
parent
c22137ea0a
commit
be7ba2c22a
@@ -167,6 +167,7 @@ runs:
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm publish \
|
||||
--ignore-scripts \
|
||||
--dry-run="${INPUTS_DRY_RUN}" \
|
||||
--workspace="${INPUTS_CORE_PACKAGE_NAME}" \
|
||||
--tag staging-tmp
|
||||
@@ -215,6 +216,7 @@ runs:
|
||||
shell: 'bash'
|
||||
run: |
|
||||
npm publish \
|
||||
--ignore-scripts \
|
||||
--dry-run="${INPUTS_DRY_RUN}" \
|
||||
--workspace="${INPUTS_CLI_PACKAGE_NAME}" \
|
||||
--tag staging-tmp
|
||||
@@ -242,6 +244,7 @@ runs:
|
||||
# Tag staging for initial release
|
||||
run: |
|
||||
npm publish \
|
||||
--ignore-scripts \
|
||||
--dry-run="${INPUTS_DRY_RUN}" \
|
||||
--workspace="${INPUTS_A2A_PACKAGE_NAME}" \
|
||||
--tag staging-tmp
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
{"method":"generateContent","response":{"candidates":[{"content":{"parts":[{"text":"{\n \"reasoning\": \"Simple task.\",\n \"model_choice\": \"flash\"\n}"}]},"finishReason":"STOP","index":0}]}}
|
||||
{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"read_file","args":{"file_path":"file1.txt"}}},{"functionCall":{"name":"read_file","args":{"file_path":"file2.txt"}}},{"functionCall":{"name":"write_file","args":{"file_path":"output.txt","content":"wave2"}}},{"functionCall":{"name":"read_file","args":{"file_path":"file3.txt"}}},{"functionCall":{"name":"read_file","args":{"file_path":"file4.txt"}}}, {"text":"All waves completed successfully."}]},"finishReason":"STOP","index":0}]}]}
|
||||
{"method":"generateContent","response":{"candidates":[{"content":{"parts":[{"text":"All waves completed successfully."}]},"finishReason":"STOP","index":0}]}}
|
||||
@@ -23,6 +23,7 @@ describe('Parallel Tool Execution Integration', () => {
|
||||
it('should execute [read, read, write, read, read] in correct waves with user approval', async () => {
|
||||
rig.setup('parallel-wave-execution', {
|
||||
fakeResponsesPath: join(import.meta.dirname, 'parallel-tools.responses'),
|
||||
fakeResponsesNonStrict: true,
|
||||
settings: {
|
||||
tools: {
|
||||
core: ['read_file', 'write_file'],
|
||||
@@ -40,19 +41,24 @@ describe('Parallel Tool Execution Integration', () => {
|
||||
|
||||
const run = await rig.runInteractive({ approvalMode: 'default' });
|
||||
|
||||
// 1. Trigger the wave
|
||||
await run.type('ok');
|
||||
await run.type('\r');
|
||||
try {
|
||||
// 1. Trigger the wave
|
||||
await run.type('ok');
|
||||
await run.type('\r');
|
||||
|
||||
// 3. Wait for the write_file prompt.
|
||||
await run.expectText('Allow', 5000);
|
||||
// 3. Wait for the write_file prompt.
|
||||
await run.expectText('Allow', 10000);
|
||||
|
||||
// 4. Press Enter to approve the write_file.
|
||||
await run.type('y');
|
||||
await run.type('\r');
|
||||
// 4. Press Enter to approve the write_file.
|
||||
await run.type('y');
|
||||
await run.type('\r');
|
||||
|
||||
// 5. Wait for the final model response
|
||||
await run.expectText('All waves completed successfully.', 5000);
|
||||
// 5. Wait for the final model response
|
||||
await run.expectText('All waves completed successfully.', 10000);
|
||||
} catch (err) {
|
||||
fs.writeFileSync('pty_output_failure.txt', run.output);
|
||||
throw err;
|
||||
}
|
||||
|
||||
// Verify all tool calls were made and succeeded in the logs
|
||||
await rig.expectToolCallSuccess(['write_file']);
|
||||
@@ -73,5 +79,5 @@ describe('Parallel Tool Execution Integration', () => {
|
||||
expect(fs.readFileSync(join(rig.testDir!, 'output.txt'), 'utf8')).toBe(
|
||||
'wave2',
|
||||
);
|
||||
});
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
@@ -540,7 +540,7 @@ export class Scheduler {
|
||||
|
||||
if (isWaitingForExternal && this.state.isActive) {
|
||||
// Yield to the event loop to allow external events (tool completion, user input) to progress.
|
||||
await new Promise((resolve) => queueMicrotask(() => resolve(true)));
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -365,6 +365,8 @@ export class TestRig {
|
||||
_lastRunStderr?: string;
|
||||
// Path to the copied fake responses file for this test.
|
||||
fakeResponsesPath?: string;
|
||||
// Whether to run fake responses in non-strict mode.
|
||||
fakeResponsesNonStrict?: boolean;
|
||||
// Original fake responses file path for rewriting goldens in record mode.
|
||||
originalFakeResponsesPath?: string;
|
||||
private _interactiveRuns: InteractiveRun[] = [];
|
||||
@@ -377,6 +379,7 @@ export class TestRig {
|
||||
settings?: Record<string, unknown>;
|
||||
state?: Record<string, unknown>;
|
||||
fakeResponsesPath?: string;
|
||||
fakeResponsesNonStrict?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
this.testName = testName;
|
||||
@@ -398,6 +401,7 @@ export class TestRig {
|
||||
if (options.fakeResponsesPath) {
|
||||
this.fakeResponsesPath = join(this.testDir, 'fake-responses.json');
|
||||
this.originalFakeResponsesPath = options.fakeResponsesPath;
|
||||
this.fakeResponsesNonStrict = options.fakeResponsesNonStrict;
|
||||
if (process.env['REGENERATE_MODEL_GOLDENS'] !== 'true') {
|
||||
fs.copyFileSync(options.fakeResponsesPath, this.fakeResponsesPath);
|
||||
}
|
||||
@@ -558,6 +562,8 @@ export class TestRig {
|
||||
if (this.fakeResponsesPath) {
|
||||
if (process.env['REGENERATE_MODEL_GOLDENS'] === 'true') {
|
||||
initialArgs.push('--record-responses', this.fakeResponsesPath);
|
||||
} else if (this.fakeResponsesNonStrict) {
|
||||
initialArgs.push('--fake-responses-non-strict', this.fakeResponsesPath);
|
||||
} else {
|
||||
initialArgs.push('--fake-responses', this.fakeResponsesPath);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user