Feature: worktree view customization and stability fixes (#805)

* Changes from feature/worktree-view-customization

* Feature: Git sync, set-tracking, and push divergence handling (#796)

* Add quick-add feature with improved workflows (#802)

* Changes from feature/quick-add

* feat: Clarify system prompt and improve error handling across services. Address PR Feedback

* feat: Improve PR description parsing and refactor event handling

* feat: Add context options to pipeline orchestrator initialization

* fix: Deduplicate React and handle CJS interop for use-sync-external-store

Resolve "Cannot read properties of null (reading 'useState')" errors by
deduplicating React/react-dom and ensuring use-sync-external-store is
bundled together with React to prevent CJS packages from resolving to
different React instances.

* Changes from feature/worktree-view-customization

* refactor: Remove unused worktree swap and highlight props

* refactor: Consolidate feature completion logic and improve thinking level defaults

* feat: Increase max turn limit to 10000

- Update DEFAULT_MAX_TURNS from 1000 to 10000 in settings-helpers.ts and agent-executor.ts
- Update MAX_ALLOWED_TURNS from 2000 to 10000 in settings-helpers.ts
- Update UI clamping logic from 2000 to 10000 in app-store.ts
- Update fallback values from 1000 to 10000 in use-settings-sync.ts
- Update default value from 1000 to 10000 in DEFAULT_GLOBAL_SETTINGS
- Update documentation to reflect new range: 1-10000

Allows agents to perform up to 10000 turns for complex feature execution.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* feat: Add model resolution, improve session handling, and enhance UI stability

* refactor: Remove unused sync and tracking branch props from worktree components

* feat: Add PR number update functionality to worktrees. Address pr feedback

* feat: Optimize Gemini CLI startup and add tool result tracking

* refactor: Improve error handling and simplify worktree task cleanup

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-02-23 20:31:25 -08:00
committed by GitHub
parent e7504b247f
commit 0330c70261
72 changed files with 3667 additions and 1173 deletions

View File

@@ -188,6 +188,125 @@ describe('agent-service.ts', () => {
expect(mockEvents.emit).toHaveBeenCalled();
});
it('should emit tool_result events from provider stream', async () => {
const mockProvider = {
getName: () => 'gemini',
executeQuery: async function* () {
yield {
type: 'assistant',
message: {
role: 'assistant',
content: [
{
type: 'tool_use',
name: 'Read',
tool_use_id: 'tool-1',
input: { file_path: 'README.md' },
},
],
},
};
yield {
type: 'assistant',
message: {
role: 'assistant',
content: [
{
type: 'tool_result',
tool_use_id: 'tool-1',
content: 'File contents here',
},
],
},
};
yield {
type: 'result',
subtype: 'success',
};
},
};
vi.mocked(ProviderFactory.getProviderForModel).mockReturnValue(mockProvider as any);
vi.mocked(promptBuilder.buildPromptWithImages).mockResolvedValue({
content: 'Hello',
hasImages: false,
});
await service.sendMessage({
sessionId: 'session-1',
message: 'Hello',
});
expect(mockEvents.emit).toHaveBeenCalledWith(
'agent:stream',
expect.objectContaining({
sessionId: 'session-1',
type: 'tool_result',
tool: {
name: 'Read',
input: {
toolUseId: 'tool-1',
content: 'File contents here',
},
},
})
);
});
it('should emit tool_result with unknown tool name for unregistered tool_use_id', async () => {
const mockProvider = {
getName: () => 'gemini',
executeQuery: async function* () {
// Yield tool_result WITHOUT a preceding tool_use (unregistered tool_use_id)
yield {
type: 'assistant',
message: {
role: 'assistant',
content: [
{
type: 'tool_result',
tool_use_id: 'unregistered-id',
content: 'Some result content',
},
],
},
};
yield {
type: 'result',
subtype: 'success',
};
},
};
vi.mocked(ProviderFactory.getProviderForModel).mockReturnValue(mockProvider as any);
vi.mocked(promptBuilder.buildPromptWithImages).mockResolvedValue({
content: 'Hello',
hasImages: false,
});
await service.sendMessage({
sessionId: 'session-1',
message: 'Hello',
});
expect(mockEvents.emit).toHaveBeenCalledWith(
'agent:stream',
expect.objectContaining({
sessionId: 'session-1',
type: 'tool_result',
tool: {
name: 'unknown',
input: {
toolUseId: 'unregistered-id',
content: 'Some result content',
},
},
})
);
});
it('should handle images in message', async () => {
const mockProvider = {
getName: () => 'claude',