@didim365/agent-cli-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.last_build +0 -0
- package/dist/docs/00_project/ai_adapter/01-overview.md +172 -0
- package/dist/docs/00_project/ai_adapter/02-architecture.md +448 -0
- package/dist/docs/00_project/ai_adapter/03-technical-design.md +1470 -0
- package/dist/docs/00_project/ai_adapter/04-integration-design.md +1934 -0
- package/dist/docs/00_project/ai_adapter/05-implementation-plan.md +336 -0
- package/dist/docs/00_project/ai_adapter/06-didiaistudio-plan.md +559 -0
- package/dist/docs/00_project/ai_adapter/README.md +145 -0
- package/dist/docs/00_project/ai_adapter/agent_service_openapi.json +1 -0
- package/dist/docs/00_project/ai_adapter/didimStudi-AISTUDIO /341/204/213/341/205/254/341/204/207/341/205/256 /341/204/211/341/205/245/341/204/207/341/205/265/341/204/211/341/205/263 /341/204/221/341/205/263/341/206/257/341/204/205/341/205/251/341/204/213/341/205/256 /341/204/213/341/205/247/341/206/253/341/204/200/341/205/247/341/206/257 /341/204/207/341/205/241/341/206/274/341/204/211/341/205/265/341/206/250-100226-093925.pdf +0 -0
- package/dist/docs/00_project/ai_adapter/event-mapping-matrix.md +148 -0
- package/dist/docs/00_project/ai_adapter/migration-plan.md +205 -0
- package/dist/docs/00_project/ai_adapter/template/00_vibecoding_workflow.md +627 -0
- package/dist/docs/00_project/ai_adapter/template/01_todolist_performance_template.md +436 -0
- package/dist/docs/00_project/ai_adapter/template/02_code_review_template.md +248 -0
- package/dist/docs/00_project/ai_adapter/template/03_work_result_report_template.md +133 -0
- package/dist/docs/00_project/ai_adapter/template/100_Python_Performance_Guide.md +472 -0
- package/dist/docs/00_project/ai_adapter/template/99_TDD_plan.md +123 -0
- package/dist/docs/00_project/ai_adapter/todolist/00_master_implementation_plan.md +433 -0
- package/dist/docs/00_project/ai_adapter/todolist/phase1_foundation_todolist.md +726 -0
- package/dist/docs/00_project/ai_adapter/todolist/phase2_core_refactoring_todolist.md +974 -0
- package/dist/docs/00_project/ai_adapter/todolist/phase3_handoff.md +203 -0
- package/dist/docs/00_project/ai_adapter/todolist/phase3_provider_extension_todolist.md +1382 -0
- package/dist/docs/00_project/ai_adapter/utility-migration.md +237 -0
- package/dist/docs/00_project/ai_adapter/working_history/.gitkeep +0 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase1_M1.0_/354/275/224/353/223/234/354/235/270/353/262/244/355/206/240/353/246/254_20260201.md +197 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase1_M1.1_/355/203/200/354/236/205/354/204/244/352/263/204_20260201.md +185 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase1_M1.2_Adapter/354/235/270/355/224/204/353/235/274_20260203.md +378 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase1_M1.3_Provider/354/204/240/355/203/235_20260206.md +269 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase1_M1.4_/354/234/240/355/213/270/353/246/254/355/213/260/353/247/210/354/235/264/352/267/270/353/240/210/354/235/264/354/205/230_20260206.md +86 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_ETC_/354/227/260/352/270/260/354/236/221/354/227/205/354/240/225/353/246/254_20260208.md +157 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_M2.0_/353/224/224/353/240/211/355/206/240/353/246/254/354/236/254/352/265/254/354/204/261_20260207.md +107 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_M2.1_ContentGenerator/354/235/270/355/204/260/355/216/230/354/235/264/354/212/244/354/236/254/354/240/225/354/235/230_20260207.md +630 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_M2.2_EventMapper/352/265/254/355/230/204_20260207.md +372 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_M2.3_GeminiAdapter/352/265/254/355/230/204_20260208.md +205 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_M2.4_ModelConfigService/355/230/270/355/231/230/353/240/210/354/235/264/354/226/264_20260208.md +275 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_M2.5_/354/234/240/355/213/270/353/246/254/355/213/260/353/240/210/354/235/264/354/226/264/353/246/254/355/214/251/355/206/240/353/247/201_20260208.md +239 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase2_M2.6_/353/235/274/354/232/260/355/214/205/353/240/210/354/235/264/354/226/264/355/203/200/354/236/205/353/217/205/353/246/275/355/231/224_20260208.md +228 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_ETC_/352/270/260/353/263/270/354/273/250/355/205/215/354/212/244/355/212/270/355/214/214/354/235/274/353/252/205AGENTS/354/240/204/355/231/230_20260211.md +470 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.0.1_Gemini/354/240/204/354/232/251/355/214/214/354/235/274/353/254/274/353/246/254/354/240/201/354/235/264/353/217/231_20260209.md +271 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.0.2_messageInspectors/353/247/210/354/235/264/352/267/270/353/240/210/354/235/264/354/205/230_20260209.md +330 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.0.3_/355/205/224/353/240/210/353/251/224/355/212/270/353/246/254Agent/353/217/205/353/246/275/355/231/224_20260209.md +251 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.0.4_/353/263/200/355/231/230/353/270/214/353/246/277/354/247/200/354/240/225/353/246/254_20260209.md +136 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.0.5_/353/237/260/355/203/200/354/236/204/354/213/244/355/226/211/352/262/275/353/241/234/354/227/260/352/262/260_20260209.md +232 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.1.0_Claude/354/202/254/354/240/204/354/244/200/353/271/204_20260209.md +191 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.1.1_ClaudeAdapter/352/265/254/355/230/204_20260209.md +225 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.1.2_ClaudeConverter/352/263/240/353/217/204/355/231/224_20260209.md +171 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.1.3_ClaudeStreamError/352/263/240/353/217/204/355/231/224_20260209.md +198 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.1.4_ClaudeErrorMapping_20260209.md +98 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.2.A_OpenAIAdapterCore_20260210.md +264 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.2.B_OpenAIStreamConverter_20260210.md +204 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.3.2_/353/252/250/353/215/270/355/205/234/355/224/214/353/246/277/355/233/205/353/263/264/354/231/204_20260211.md +106 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.3_OpenAICompatibleAdapter_20260211.md +251 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.4.2_E2E/355/205/214/354/212/244/355/212/270/354/213/234/353/202/230/353/246/254/354/230/244_20260210.md +264 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.4.3_/354/204/261/353/212/245/355/232/214/352/267/200/355/205/214/354/212/244/355/212/270_20260211.md +176 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.4.5_/354/225/210/354/240/225/355/231/224/354/236/221/354/227/205_20260211.md +204 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.4.A_CLI/355/206/265/355/225/251_3Provider/355/206/265/355/225/251/355/205/214/354/212/244/355/212/270_20260210.md +316 -0
- package/dist/docs/00_project/ai_adapter/working_history/Phase3_M3.4.A_UI/354/203/201/355/203/234/353/260/224/354/210/230/354/240/225_20260210.md +262 -0
- package/dist/docs/00_project/ai_adapter/working_history/phase2_tradeoff_EventType/354/240/204/355/231/230_20260208.md +286 -0
- package/dist/docs/00_project/white_labeling/template/00_vibecoding_workflow.md +627 -0
- package/dist/docs/00_project/white_labeling/template/01_todolist_performance_template.md +400 -0
- package/dist/docs/00_project/white_labeling/template/02_code_review_template.md +248 -0
- package/dist/docs/00_project/white_labeling/template/03_work_result_report_template.md +133 -0
- package/dist/docs/00_project/white_labeling/template/100_Python_Performance_Guide.md +472 -0
- package/dist/docs/00_project/white_labeling/template/99_TDD_plan.md +123 -0
- package/dist/docs/00_project/white_labeling/todolist/Phase_CLI/355/214/250/355/202/244/354/247/200/353/252/205/353/263/200/352/262/275_todolist.md +431 -0
- package/dist/docs/00_project/white_labeling/working_history/Phase_CLI/355/214/250/355/202/244/354/247/200/353/252/205/353/263/200/352/262/275_20260214.md +238 -0
- package/dist/docs/00_project/white_labeling//354/225/261/352/265/254/354/241/260.md +310 -0
- package/dist/docs/CONTRIBUTING.md +554 -0
- package/dist/docs/ai_adapter/01-overview.md +155 -0
- package/dist/docs/ai_adapter/02-architecture.md +452 -0
- package/dist/docs/ai_adapter/03-technical-design.md +1470 -0
- package/dist/docs/ai_adapter/04-integration-design.md +1904 -0
- package/dist/docs/ai_adapter/05-implementation-plan.md +312 -0
- package/dist/docs/ai_adapter/06-didiaistudio-plan.md +559 -0
- package/dist/docs/ai_adapter/README.md +118 -0
- package/dist/docs/ai_adapter/agent_service_openapi.json +1 -0
- package/dist/docs/ai_adapter/didimStudi-AISTUDIO /341/204/213/341/205/254/341/204/207/341/205/256 /341/204/211/341/205/245/341/204/207/341/205/265/341/204/211/341/205/263 /341/204/221/341/205/263/341/206/257/341/204/205/341/205/251/341/204/213/341/205/256 /341/204/213/341/205/247/341/206/253/341/204/200/341/205/247/341/206/257 /341/204/207/341/205/241/341/206/274/341/204/211/341/205/265/341/206/250-100226-093925.pdf +0 -0
- package/dist/docs/ai_adapter/event-mapping-matrix.md +140 -0
- package/dist/docs/ai_adapter/migration-plan.md +205 -0
- package/dist/docs/ai_adapter/template/00_vibecoding_workflow.md +636 -0
- package/dist/docs/ai_adapter/template/01_todolist_performance_template.md +372 -0
- package/dist/docs/ai_adapter/template/02_code_review_template.md +220 -0
- package/dist/docs/ai_adapter/template/03_work_result_report_template.md +120 -0
- package/dist/docs/ai_adapter/template/100_Python_Performance_Guide.md +453 -0
- package/dist/docs/ai_adapter/template/99_TDD_plan.md +111 -0
- package/dist/docs/ai_adapter/todolist/00_master_implementation_plan.md +433 -0
- package/dist/docs/ai_adapter/todolist/phase1_foundation_todolist.md +726 -0
- package/dist/docs/ai_adapter/todolist/phase2_core_refactoring_todolist.md +974 -0
- package/dist/docs/ai_adapter/todolist/phase3_handoff.md +203 -0
- package/dist/docs/ai_adapter/todolist/phase3_provider_extension_todolist.md +1382 -0
- package/dist/docs/ai_adapter/utility-migration.md +237 -0
- package/dist/docs/ai_adapter/working_history/.gitkeep +0 -0
- package/dist/docs/ai_adapter/working_history/Phase1_M1.0_/354/275/224/353/223/234/354/235/270/353/262/244/355/206/240/353/246/254_20260201.md +185 -0
- package/dist/docs/ai_adapter/working_history/Phase1_M1.1_/355/203/200/354/236/205/354/204/244/352/263/204_20260201.md +185 -0
- package/dist/docs/ai_adapter/working_history/Phase1_M1.2_Adapter/354/235/270/355/224/204/353/235/274_20260203.md +378 -0
- package/dist/docs/ai_adapter/working_history/Phase1_M1.3_Provider/354/204/240/355/203/235_20260206.md +269 -0
- package/dist/docs/ai_adapter/working_history/Phase1_M1.4_/354/234/240/355/213/270/353/246/254/355/213/260/353/247/210/354/235/264/352/267/270/353/240/210/354/235/264/354/205/230_20260206.md +86 -0
- package/dist/docs/ai_adapter/working_history/Phase2_ETC_/354/227/260/352/270/260/354/236/221/354/227/205/354/240/225/353/246/254_20260208.md +157 -0
- package/dist/docs/ai_adapter/working_history/Phase2_M2.0_/353/224/224/353/240/211/355/206/240/353/246/254/354/236/254/352/265/254/354/204/261_20260207.md +107 -0
- package/dist/docs/ai_adapter/working_history/Phase2_M2.1_ContentGenerator/354/235/270/355/204/260/355/216/230/354/235/264/354/212/244/354/236/254/354/240/225/354/235/230_20260207.md +630 -0
- package/dist/docs/ai_adapter/working_history/Phase2_M2.2_EventMapper/352/265/254/355/230/204_20260207.md +372 -0
- package/dist/docs/ai_adapter/working_history/Phase2_M2.3_GeminiAdapter/352/265/254/355/230/204_20260208.md +205 -0
- package/dist/docs/ai_adapter/working_history/Phase2_M2.4_ModelConfigService/355/230/270/355/231/230/353/240/210/354/235/264/354/226/264_20260208.md +275 -0
- package/dist/docs/ai_adapter/working_history/Phase2_M2.5_/354/234/240/355/213/270/353/246/254/355/213/260/353/240/210/354/235/264/354/226/264/353/246/254/355/214/251/355/206/240/353/247/201_20260208.md +239 -0
- package/dist/docs/ai_adapter/working_history/Phase2_M2.6_/353/235/274/354/232/260/355/214/205/353/240/210/354/235/264/354/226/264/355/203/200/354/236/205/353/217/205/353/246/275/355/231/224_20260208.md +228 -0
- package/dist/docs/ai_adapter/working_history/Phase3_ETC_/352/270/260/353/263/270/354/273/250/355/205/215/354/212/244/355/212/270/355/214/214/354/235/274/353/252/205AGENTS/354/240/204/355/231/230_20260211.md +367 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.0.1_Gemini/354/240/204/354/232/251/355/214/214/354/235/274/353/254/274/353/246/254/354/240/201/354/235/264/353/217/231_20260209.md +271 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.0.2_messageInspectors/353/247/210/354/235/264/352/267/270/353/240/210/354/235/264/354/205/230_20260209.md +330 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.0.3_/355/205/224/353/240/210/353/251/224/355/212/270/353/246/254Agent/353/217/205/353/246/275/355/231/224_20260209.md +251 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.0.4_/353/263/200/355/231/230/353/270/214/353/246/277/354/247/200/354/240/225/353/246/254_20260209.md +136 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.0.5_/353/237/260/355/203/200/354/236/204/354/213/244/355/226/211/352/262/275/353/241/234/354/227/260/352/262/260_20260209.md +232 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.1.0_Claude/354/202/254/354/240/204/354/244/200/353/271/204_20260209.md +191 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.1.1_ClaudeAdapter/352/265/254/355/230/204_20260209.md +225 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.1.2_ClaudeConverter/352/263/240/353/217/204/355/231/224_20260209.md +171 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.1.3_ClaudeStreamError/352/263/240/353/217/204/355/231/224_20260209.md +198 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.1.4_ClaudeErrorMapping_20260209.md +98 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.2.A_OpenAIAdapterCore_20260210.md +264 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.2.B_OpenAIStreamConverter_20260210.md +204 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.3.2_/353/252/250/353/215/270/355/205/234/355/224/214/353/246/277/355/233/205/353/263/264/354/231/204_20260211.md +106 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.3_OpenAICompatibleAdapter_20260211.md +251 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.4.2_E2E/355/205/214/354/212/244/355/212/270/354/213/234/353/202/230/353/246/254/354/230/244_20260210.md +264 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.4.3_/354/204/261/353/212/245/355/232/214/352/267/200/355/205/214/354/212/244/355/212/270_20260211.md +176 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.4.5_/354/225/210/354/240/225/355/231/224/354/236/221/354/227/205_20260211.md +204 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.4.A_CLI/355/206/265/355/225/251_3Provider/355/206/265/355/225/251/355/205/214/354/212/244/355/212/270_20260210.md +316 -0
- package/dist/docs/ai_adapter/working_history/Phase3_M3.4.A_UI/354/203/201/355/203/234/353/260/224/354/210/230/354/240/225_20260210.md +262 -0
- package/dist/docs/ai_adapter/working_history/phase2_tradeoff_EventType/354/240/204/355/231/230_20260208.md +286 -0
- package/dist/docs/api/index.md +5 -0
- package/dist/docs/api/providers.md +56 -0
- package/dist/docs/architecture.md +80 -0
- package/dist/docs/assets/connected_devtools.png +0 -0
- package/dist/docs/assets/gemini-screenshot.png +0 -0
- package/dist/docs/assets/monitoring-dashboard-logs.png +0 -0
- package/dist/docs/assets/monitoring-dashboard-metrics.png +0 -0
- package/dist/docs/assets/monitoring-dashboard-overview.png +0 -0
- package/dist/docs/assets/release_patch.png +0 -0
- package/dist/docs/assets/theme-ansi-light.png +0 -0
- package/dist/docs/assets/theme-ansi.png +0 -0
- package/dist/docs/assets/theme-atom-one.png +0 -0
- package/dist/docs/assets/theme-ayu-light.png +0 -0
- package/dist/docs/assets/theme-ayu.png +0 -0
- package/dist/docs/assets/theme-custom.png +0 -0
- package/dist/docs/assets/theme-default-light.png +0 -0
- package/dist/docs/assets/theme-default.png +0 -0
- package/dist/docs/assets/theme-dracula.png +0 -0
- package/dist/docs/assets/theme-github-light.png +0 -0
- package/dist/docs/assets/theme-github.png +0 -0
- package/dist/docs/assets/theme-google-light.png +0 -0
- package/dist/docs/assets/theme-xcode-light.png +0 -0
- package/dist/docs/change_model/model_command_multi_provider_plan.md +221 -0
- package/dist/docs/change_model/model_command_multi_provider_todolist.md +206 -0
- package/dist/docs/changelogs/index.md +726 -0
- package/dist/docs/changelogs/latest.md +370 -0
- package/dist/docs/changelogs/preview.md +332 -0
- package/dist/docs/cli/authentication.md +3 -0
- package/dist/docs/cli/checkpointing.md +94 -0
- package/dist/docs/cli/commands.md +375 -0
- package/dist/docs/cli/custom-commands.md +315 -0
- package/dist/docs/cli/enterprise.md +565 -0
- package/dist/docs/cli/gemini-ignore.md +71 -0
- package/dist/docs/cli/gemini-md.md +108 -0
- package/dist/docs/cli/generation-settings.md +210 -0
- package/dist/docs/cli/headless.md +388 -0
- package/dist/docs/cli/index.md +65 -0
- package/dist/docs/cli/keyboard-shortcuts.md +129 -0
- package/dist/docs/cli/model-routing.md +42 -0
- package/dist/docs/cli/model.md +62 -0
- package/dist/docs/cli/sandbox.md +171 -0
- package/dist/docs/cli/session-management.md +158 -0
- package/dist/docs/cli/settings.md +130 -0
- package/dist/docs/cli/skills.md +188 -0
- package/dist/docs/cli/system-prompt.md +125 -0
- package/dist/docs/cli/telemetry.md +826 -0
- package/dist/docs/cli/themes.md +235 -0
- package/dist/docs/cli/token-caching.md +20 -0
- package/dist/docs/cli/trusted-folders.md +95 -0
- package/dist/docs/cli/tutorials/skills-getting-started.md +124 -0
- package/dist/docs/cli/tutorials.md +87 -0
- package/dist/docs/cli/uninstall.md +65 -0
- package/dist/docs/configuration.md +108 -0
- package/dist/docs/core/index.md +105 -0
- package/dist/docs/core/long-term-memory-design.md +254 -0
- package/dist/docs/core/long-term-memory-proposal.md +112 -0
- package/dist/docs/core/memport.md +246 -0
- package/dist/docs/core/policy-engine.md +300 -0
- package/dist/docs/core/tools-api.md +131 -0
- package/dist/docs/examples/proxy-script.md +83 -0
- package/dist/docs/extensions/best-practices.md +139 -0
- package/dist/docs/extensions/index.md +44 -0
- package/dist/docs/extensions/reference.md +312 -0
- package/dist/docs/extensions/releasing.md +183 -0
- package/dist/docs/extensions/writing-extensions.md +283 -0
- package/dist/docs/faq.md +154 -0
- package/dist/docs/get-started/authentication.md +321 -0
- package/dist/docs/get-started/configuration-v1.md +888 -0
- package/dist/docs/get-started/configuration.md +1567 -0
- package/dist/docs/get-started/examples.md +219 -0
- package/dist/docs/get-started/gemini-3.md +101 -0
- package/dist/docs/get-started/index.md +71 -0
- package/dist/docs/get-started/installation.md +141 -0
- package/dist/docs/hooks/best-practices.md +677 -0
- package/dist/docs/hooks/index.md +178 -0
- package/dist/docs/hooks/reference.md +322 -0
- package/dist/docs/hooks/writing-hooks.md +450 -0
- package/dist/docs/ide-integration/ide-companion-spec.md +267 -0
- package/dist/docs/ide-integration/index.md +202 -0
- package/dist/docs/index.md +153 -0
- package/dist/docs/integration-tests.md +211 -0
- package/dist/docs/issue-and-pr-automation.md +134 -0
- package/dist/docs/local-development.md +128 -0
- package/dist/docs/mermaid/context.mmd +103 -0
- package/dist/docs/mermaid/render-path.mmd +64 -0
- package/dist/docs/migration.md +78 -0
- package/dist/docs/npm.md +62 -0
- package/dist/docs/providers.md +136 -0
- package/dist/docs/quota-and-pricing.md +158 -0
- package/dist/docs/release-confidence.md +164 -0
- package/dist/docs/releases.md +539 -0
- package/dist/docs/sidebar.json +140 -0
- package/dist/docs/tools/file-system.md +217 -0
- package/dist/docs/tools/index.md +98 -0
- package/dist/docs/tools/mcp-server.md +1068 -0
- package/dist/docs/tools/memory.md +54 -0
- package/dist/docs/tools/shell.md +260 -0
- package/dist/docs/tools/todos.md +57 -0
- package/dist/docs/tools/web-fetch.md +59 -0
- package/dist/docs/tools/web-search.md +42 -0
- package/dist/docs/tos-privacy.md +96 -0
- package/dist/docs/troubleshooting.md +173 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/src/__mocks__/fs/promises.d.ts +11 -0
- package/dist/src/__mocks__/fs/promises.js +17 -0
- package/dist/src/__mocks__/fs/promises.js.map +1 -0
- package/dist/src/agents/a2a-client-manager.d.ts +77 -0
- package/dist/src/agents/a2a-client-manager.js +173 -0
- package/dist/src/agents/a2a-client-manager.js.map +1 -0
- package/dist/src/agents/a2a-client-manager.test.d.ts +6 -0
- package/dist/src/agents/a2a-client-manager.test.js +220 -0
- package/dist/src/agents/a2a-client-manager.test.js.map +1 -0
- package/dist/src/agents/a2aUtils.d.ts +29 -0
- package/dist/src/agents/a2aUtils.js +113 -0
- package/dist/src/agents/a2aUtils.js.map +1 -0
- package/dist/src/agents/a2aUtils.test.d.ts +6 -0
- package/dist/src/agents/a2aUtils.test.js +147 -0
- package/dist/src/agents/a2aUtils.test.js.map +1 -0
- package/dist/src/agents/acknowledgedAgents.d.ts +18 -0
- package/dist/src/agents/acknowledgedAgents.js +58 -0
- package/dist/src/agents/acknowledgedAgents.js.map +1 -0
- package/dist/src/agents/acknowledgedAgents.test.d.ts +6 -0
- package/dist/src/agents/acknowledgedAgents.test.js +70 -0
- package/dist/src/agents/acknowledgedAgents.test.js.map +1 -0
- package/dist/src/agents/agent-scheduler.d.ts +33 -0
- package/dist/src/agents/agent-scheduler.js +29 -0
- package/dist/src/agents/agent-scheduler.js.map +1 -0
- package/dist/src/agents/agent-scheduler.test.d.ts +6 -0
- package/dist/src/agents/agent-scheduler.test.js +56 -0
- package/dist/src/agents/agent-scheduler.test.js.map +1 -0
- package/dist/src/agents/agentLoader.d.ts +73 -0
- package/dist/src/agents/agentLoader.js +268 -0
- package/dist/src/agents/agentLoader.js.map +1 -0
- package/dist/src/agents/agentLoader.test.d.ts +6 -0
- package/dist/src/agents/agentLoader.test.js +304 -0
- package/dist/src/agents/agentLoader.test.js.map +1 -0
- package/dist/src/agents/cli-help-agent.d.ts +24 -0
- package/dist/src/agents/cli-help-agent.js +88 -0
- package/dist/src/agents/cli-help-agent.js.map +1 -0
- package/dist/src/agents/cli-help-agent.test.d.ts +6 -0
- package/dist/src/agents/cli-help-agent.test.js +67 -0
- package/dist/src/agents/cli-help-agent.test.js.map +1 -0
- package/dist/src/agents/codebase-investigator.d.ts +47 -0
- package/dist/src/agents/codebase-investigator.js +159 -0
- package/dist/src/agents/codebase-investigator.js.map +1 -0
- package/dist/src/agents/codebase-investigator.test.d.ts +6 -0
- package/dist/src/agents/codebase-investigator.test.js +42 -0
- package/dist/src/agents/codebase-investigator.test.js.map +1 -0
- package/dist/src/agents/generalist-agent.d.ts +21 -0
- package/dist/src/agents/generalist-agent.js +60 -0
- package/dist/src/agents/generalist-agent.js.map +1 -0
- package/dist/src/agents/generalist-agent.test.d.ts +6 -0
- package/dist/src/agents/generalist-agent.test.js +31 -0
- package/dist/src/agents/generalist-agent.test.js.map +1 -0
- package/dist/src/agents/local-executor.d.ts +111 -0
- package/dist/src/agents/local-executor.js +884 -0
- package/dist/src/agents/local-executor.js.map +1 -0
- package/dist/src/agents/local-executor.test.d.ts +6 -0
- package/dist/src/agents/local-executor.test.js +1577 -0
- package/dist/src/agents/local-executor.test.js.map +1 -0
- package/dist/src/agents/local-invocation.d.ts +45 -0
- package/dist/src/agents/local-invocation.js +101 -0
- package/dist/src/agents/local-invocation.js.map +1 -0
- package/dist/src/agents/local-invocation.test.d.ts +6 -0
- package/dist/src/agents/local-invocation.test.js +228 -0
- package/dist/src/agents/local-invocation.test.js.map +1 -0
- package/dist/src/agents/registry.d.ts +84 -0
- package/dist/src/agents/registry.js +346 -0
- package/dist/src/agents/registry.js.map +1 -0
- package/dist/src/agents/registry.test.d.ts +6 -0
- package/dist/src/agents/registry.test.js +773 -0
- package/dist/src/agents/registry.test.js.map +1 -0
- package/dist/src/agents/registry_acknowledgement.test.d.ts +6 -0
- package/dist/src/agents/registry_acknowledgement.test.js +130 -0
- package/dist/src/agents/registry_acknowledgement.test.js.map +1 -0
- package/dist/src/agents/remote-invocation.d.ts +35 -0
- package/dist/src/agents/remote-invocation.js +127 -0
- package/dist/src/agents/remote-invocation.js.map +1 -0
- package/dist/src/agents/remote-invocation.test.d.ts +6 -0
- package/dist/src/agents/remote-invocation.test.js +213 -0
- package/dist/src/agents/remote-invocation.test.js.map +1 -0
- package/dist/src/agents/subagent-tool-wrapper.d.ts +38 -0
- package/dist/src/agents/subagent-tool-wrapper.js +51 -0
- package/dist/src/agents/subagent-tool-wrapper.js.map +1 -0
- package/dist/src/agents/subagent-tool-wrapper.test.d.ts +6 -0
- package/dist/src/agents/subagent-tool-wrapper.test.js +109 -0
- package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -0
- package/dist/src/agents/subagent-tool.d.ts +15 -0
- package/dist/src/agents/subagent-tool.js +61 -0
- package/dist/src/agents/subagent-tool.js.map +1 -0
- package/dist/src/agents/types.d.ts +171 -0
- package/dist/src/agents/types.js +23 -0
- package/dist/src/agents/types.js.map +1 -0
- package/dist/src/agents/utils.d.ts +15 -0
- package/dist/src/agents/utils.js +29 -0
- package/dist/src/agents/utils.js.map +1 -0
- package/dist/src/agents/utils.test.d.ts +6 -0
- package/dist/src/agents/utils.test.js +87 -0
- package/dist/src/agents/utils.test.js.map +1 -0
- package/dist/src/availability/errorClassification.d.ts +7 -0
- package/dist/src/availability/errorClassification.js +20 -0
- package/dist/src/availability/errorClassification.js.map +1 -0
- package/dist/src/availability/fallbackIntegration.test.d.ts +6 -0
- package/dist/src/availability/fallbackIntegration.test.js +58 -0
- package/dist/src/availability/fallbackIntegration.test.js.map +1 -0
- package/dist/src/availability/modelAvailabilityService.d.ts +36 -0
- package/dist/src/availability/modelAvailabilityService.js +87 -0
- package/dist/src/availability/modelAvailabilityService.js.map +1 -0
- package/dist/src/availability/modelAvailabilityService.test.d.ts +6 -0
- package/dist/src/availability/modelAvailabilityService.test.js +140 -0
- package/dist/src/availability/modelAvailabilityService.test.js.map +1 -0
- package/dist/src/availability/modelPolicy.d.ts +49 -0
- package/dist/src/availability/modelPolicy.js +7 -0
- package/dist/src/availability/modelPolicy.js.map +1 -0
- package/dist/src/availability/policyCatalog.d.ts +24 -0
- package/dist/src/availability/policyCatalog.js +106 -0
- package/dist/src/availability/policyCatalog.js.map +1 -0
- package/dist/src/availability/policyCatalog.test.d.ts +6 -0
- package/dist/src/availability/policyCatalog.test.js +70 -0
- package/dist/src/availability/policyCatalog.test.js.map +1 -0
- package/dist/src/availability/policyHelpers.d.ts +52 -0
- package/dist/src/availability/policyHelpers.js +143 -0
- package/dist/src/availability/policyHelpers.js.map +1 -0
- package/dist/src/availability/policyHelpers.test.d.ts +6 -0
- package/dist/src/availability/policyHelpers.test.js +220 -0
- package/dist/src/availability/policyHelpers.test.js.map +1 -0
- package/dist/src/availability/testUtils.d.ts +10 -0
- package/dist/src/availability/testUtils.js +22 -0
- package/dist/src/availability/testUtils.js.map +1 -0
- package/dist/src/code_assist/admin/admin_controls.d.ts +23 -0
- package/dist/src/code_assist/admin/admin_controls.js +88 -0
- package/dist/src/code_assist/admin/admin_controls.js.map +1 -0
- package/dist/src/code_assist/admin/admin_controls.test.d.ts +6 -0
- package/dist/src/code_assist/admin/admin_controls.test.js +200 -0
- package/dist/src/code_assist/admin/admin_controls.test.js.map +1 -0
- package/dist/src/code_assist/codeAssist.d.ts +12 -0
- package/dist/src/code_assist/codeAssist.js +31 -0
- package/dist/src/code_assist/codeAssist.js.map +1 -0
- package/dist/src/code_assist/codeAssist.test.d.ts +6 -0
- package/dist/src/code_assist/codeAssist.test.js +102 -0
- package/dist/src/code_assist/codeAssist.test.js.map +1 -0
- package/dist/src/code_assist/converter.d.ts +75 -0
- package/dist/src/code_assist/converter.js +161 -0
- package/dist/src/code_assist/converter.js.map +1 -0
- package/dist/src/code_assist/converter.test.d.ts +6 -0
- package/dist/src/code_assist/converter.test.js +391 -0
- package/dist/src/code_assist/converter.test.js.map +1 -0
- package/dist/src/code_assist/experiments/client_metadata.d.ts +12 -0
- package/dist/src/code_assist/experiments/client_metadata.js +51 -0
- package/dist/src/code_assist/experiments/client_metadata.js.map +1 -0
- package/dist/src/code_assist/experiments/client_metadata.test.d.ts +6 -0
- package/dist/src/code_assist/experiments/client_metadata.test.js +96 -0
- package/dist/src/code_assist/experiments/client_metadata.test.js.map +1 -0
- package/dist/src/code_assist/experiments/experiments.d.ts +17 -0
- package/dist/src/code_assist/experiments/experiments.js +57 -0
- package/dist/src/code_assist/experiments/experiments.js.map +1 -0
- package/dist/src/code_assist/experiments/experiments.test.d.ts +6 -0
- package/dist/src/code_assist/experiments/experiments.test.js +93 -0
- package/dist/src/code_assist/experiments/experiments.test.js.map +1 -0
- package/dist/src/code_assist/experiments/experiments_local.test.d.ts +6 -0
- package/dist/src/code_assist/experiments/experiments_local.test.js +115 -0
- package/dist/src/code_assist/experiments/experiments_local.test.js.map +1 -0
- package/dist/src/code_assist/experiments/flagNames.d.ts +16 -0
- package/dist/src/code_assist/experiments/flagNames.js +16 -0
- package/dist/src/code_assist/experiments/flagNames.js.map +1 -0
- package/dist/src/code_assist/experiments/types.d.ts +35 -0
- package/dist/src/code_assist/experiments/types.js +7 -0
- package/dist/src/code_assist/experiments/types.js.map +1 -0
- package/dist/src/code_assist/oauth-credential-storage.d.ts +25 -0
- package/dist/src/code_assist/oauth-credential-storage.js +109 -0
- package/dist/src/code_assist/oauth-credential-storage.js.map +1 -0
- package/dist/src/code_assist/oauth-credential-storage.test.d.ts +6 -0
- package/dist/src/code_assist/oauth-credential-storage.test.js +198 -0
- package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -0
- package/dist/src/code_assist/oauth2.d.ts +24 -0
- package/dist/src/code_assist/oauth2.js +538 -0
- package/dist/src/code_assist/oauth2.js.map +1 -0
- package/dist/src/code_assist/oauth2.test.d.ts +6 -0
- package/dist/src/code_assist/oauth2.test.js +1065 -0
- package/dist/src/code_assist/oauth2.test.js.map +1 -0
- package/dist/src/code_assist/server.d.ts +50 -0
- package/dist/src/code_assist/server.js +227 -0
- package/dist/src/code_assist/server.js.map +1 -0
- package/dist/src/code_assist/server.test.d.ts +6 -0
- package/dist/src/code_assist/server.test.js +453 -0
- package/dist/src/code_assist/server.test.js.map +1 -0
- package/dist/src/code_assist/setup.d.ts +46 -0
- package/dist/src/code_assist/setup.js +179 -0
- package/dist/src/code_assist/setup.js.map +1 -0
- package/dist/src/code_assist/setup.test.d.ts +6 -0
- package/dist/src/code_assist/setup.test.js +517 -0
- package/dist/src/code_assist/setup.test.js.map +1 -0
- package/dist/src/code_assist/telemetry.d.ts +14 -0
- package/dist/src/code_assist/telemetry.js +157 -0
- package/dist/src/code_assist/telemetry.js.map +1 -0
- package/dist/src/code_assist/telemetry.test.d.ts +6 -0
- package/dist/src/code_assist/telemetry.test.js +301 -0
- package/dist/src/code_assist/telemetry.test.js.map +1 -0
- package/dist/src/code_assist/types.d.ts +303 -0
- package/dist/src/code_assist/types.js +92 -0
- package/dist/src/code_assist/types.js.map +1 -0
- package/dist/src/commands/extensions.d.ts +7 -0
- package/dist/src/commands/extensions.js +9 -0
- package/dist/src/commands/extensions.js.map +1 -0
- package/dist/src/commands/extensions.test.d.ts +6 -0
- package/dist/src/commands/extensions.test.js +19 -0
- package/dist/src/commands/extensions.test.js.map +1 -0
- package/dist/src/commands/init.d.ts +7 -0
- package/dist/src/commands/init.js +54 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/init.test.d.ts +6 -0
- package/dist/src/commands/init.test.js +25 -0
- package/dist/src/commands/init.test.js.map +1 -0
- package/dist/src/commands/memory.d.ts +11 -0
- package/dist/src/commands/memory.js +89 -0
- package/dist/src/commands/memory.js.map +1 -0
- package/dist/src/commands/memory.test.d.ts +6 -0
- package/dist/src/commands/memory.test.js +182 -0
- package/dist/src/commands/memory.test.js.map +1 -0
- package/dist/src/commands/restore.d.ts +9 -0
- package/dist/src/commands/restore.js +46 -0
- package/dist/src/commands/restore.js.map +1 -0
- package/dist/src/commands/restore.test.d.ts +6 -0
- package/dist/src/commands/restore.test.js +137 -0
- package/dist/src/commands/restore.test.js.map +1 -0
- package/dist/src/commands/types.d.ts +41 -0
- package/dist/src/commands/types.js +7 -0
- package/dist/src/commands/types.js.map +1 -0
- package/dist/src/config/config.d.ts +696 -0
- package/dist/src/config/config.js +1567 -0
- package/dist/src/config/config.js.map +1 -0
- package/dist/src/config/config.test.d.ts +6 -0
- package/dist/src/config/config.test.js +1811 -0
- package/dist/src/config/config.test.js.map +1 -0
- package/dist/src/config/constants.d.ts +13 -0
- package/dist/src/config/constants.js +20 -0
- package/dist/src/config/constants.js.map +1 -0
- package/dist/src/config/defaultModelConfigs.d.ts +7 -0
- package/dist/src/config/defaultModelConfigs.js +231 -0
- package/dist/src/config/defaultModelConfigs.js.map +1 -0
- package/dist/src/config/flashFallback.test.d.ts +6 -0
- package/dist/src/config/flashFallback.test.js +63 -0
- package/dist/src/config/flashFallback.test.js.map +1 -0
- package/dist/src/config/models.d.ts +67 -0
- package/dist/src/config/models.js +144 -0
- package/dist/src/config/models.js.map +1 -0
- package/dist/src/config/models.test.d.ts +6 -0
- package/dist/src/config/models.test.js +146 -0
- package/dist/src/config/models.test.js.map +1 -0
- package/dist/src/config/storage.d.ts +44 -0
- package/dist/src/config/storage.js +139 -0
- package/dist/src/config/storage.js.map +1 -0
- package/dist/src/config/storage.test.d.ts +6 -0
- package/dist/src/config/storage.test.js +115 -0
- package/dist/src/config/storage.test.js.map +1 -0
- package/dist/src/confirmation-bus/index.d.ts +7 -0
- package/dist/src/confirmation-bus/index.js +8 -0
- package/dist/src/confirmation-bus/index.js.map +1 -0
- package/dist/src/confirmation-bus/message-bus.d.ts +24 -0
- package/dist/src/confirmation-bus/message-bus.js +120 -0
- package/dist/src/confirmation-bus/message-bus.js.map +1 -0
- package/dist/src/confirmation-bus/message-bus.test.d.ts +6 -0
- package/dist/src/confirmation-bus/message-bus.test.js +170 -0
- package/dist/src/confirmation-bus/message-bus.test.js.map +1 -0
- package/dist/src/confirmation-bus/types.d.ts +141 -0
- package/dist/src/confirmation-bus/types.js +25 -0
- package/dist/src/confirmation-bus/types.js.map +1 -0
- package/dist/src/core/apiKeyCredentialStorage.d.ts +17 -0
- package/dist/src/core/apiKeyCredentialStorage.js +64 -0
- package/dist/src/core/apiKeyCredentialStorage.js.map +1 -0
- package/dist/src/core/apiKeyCredentialStorage.test.d.ts +6 -0
- package/dist/src/core/apiKeyCredentialStorage.test.js +71 -0
- package/dist/src/core/apiKeyCredentialStorage.test.js.map +1 -0
- package/dist/src/core/baseLlmClient.d.ts +131 -0
- package/dist/src/core/baseLlmClient.js +282 -0
- package/dist/src/core/baseLlmClient.js.map +1 -0
- package/dist/src/core/baseLlmClient.test.d.ts +6 -0
- package/dist/src/core/baseLlmClient.test.js +569 -0
- package/dist/src/core/baseLlmClient.test.js.map +1 -0
- package/dist/src/core/baseLlmClient_new_types.test.d.ts +1 -0
- package/dist/src/core/baseLlmClient_new_types.test.js +387 -0
- package/dist/src/core/baseLlmClient_new_types.test.js.map +1 -0
- package/dist/src/core/client.d.ts +71 -0
- package/dist/src/core/client.js +882 -0
- package/dist/src/core/client.js.map +1 -0
- package/dist/src/core/client.test.d.ts +6 -0
- package/dist/src/core/client.test.js +2654 -0
- package/dist/src/core/client.test.js.map +1 -0
- package/dist/src/core/contentGenerator.d.ts +55 -0
- package/dist/src/core/contentGenerator.js +201 -0
- package/dist/src/core/contentGenerator.js.map +1 -0
- package/dist/src/core/contentGenerator.multiProvider.test.d.ts +6 -0
- package/dist/src/core/contentGenerator.multiProvider.test.js +314 -0
- package/dist/src/core/contentGenerator.multiProvider.test.js.map +1 -0
- package/dist/src/core/contentGenerator.test.d.ts +6 -0
- package/dist/src/core/contentGenerator.test.js +299 -0
- package/dist/src/core/contentGenerator.test.js.map +1 -0
- package/dist/src/core/contentGenerator_new_types.test.d.ts +6 -0
- package/dist/src/core/contentGenerator_new_types.test.js +292 -0
- package/dist/src/core/contentGenerator_new_types.test.js.map +1 -0
- package/dist/src/core/coreToolHookTriggers.d.ts +23 -0
- package/dist/src/core/coreToolHookTriggers.js +195 -0
- package/dist/src/core/coreToolHookTriggers.js.map +1 -0
- package/dist/src/core/coreToolHookTriggers.test.d.ts +6 -0
- package/dist/src/core/coreToolHookTriggers.test.js +159 -0
- package/dist/src/core/coreToolHookTriggers.test.js.map +1 -0
- package/dist/src/core/coreToolScheduler.d.ts +50 -0
- package/dist/src/core/coreToolScheduler.js +703 -0
- package/dist/src/core/coreToolScheduler.js.map +1 -0
- package/dist/src/core/coreToolScheduler.test.d.ts +6 -0
- package/dist/src/core/coreToolScheduler.test.js +1684 -0
- package/dist/src/core/coreToolScheduler.test.js.map +1 -0
- package/dist/src/core/fakeContentGenerator.d.ts +49 -0
- package/dist/src/core/fakeContentGenerator.js +76 -0
- package/dist/src/core/fakeContentGenerator.js.map +1 -0
- package/dist/src/core/fakeContentGenerator.test.d.ts +6 -0
- package/dist/src/core/fakeContentGenerator.test.js +127 -0
- package/dist/src/core/fakeContentGenerator.test.js.map +1 -0
- package/dist/src/core/geminiChat.d.ts +11 -0
- package/dist/src/core/geminiChat.js +12 -0
- package/dist/src/core/geminiChat.js.map +1 -0
- package/dist/src/core/geminiChat.test.d.ts +6 -0
- package/dist/src/core/geminiChat.test.js +1773 -0
- package/dist/src/core/geminiChat.test.js.map +1 -0
- package/dist/src/core/geminiChat_network_retry.test.d.ts +6 -0
- package/dist/src/core/geminiChat_network_retry.test.js +201 -0
- package/dist/src/core/geminiChat_network_retry.test.js.map +1 -0
- package/dist/src/core/geminiRequest.d.ts +13 -0
- package/dist/src/core/geminiRequest.js +11 -0
- package/dist/src/core/geminiRequest.js.map +1 -0
- package/dist/src/core/logger.d.ts +65 -0
- package/dist/src/core/logger.js +368 -0
- package/dist/src/core/logger.js.map +1 -0
- package/dist/src/core/logger.test.d.ts +6 -0
- package/dist/src/core/logger.test.js +550 -0
- package/dist/src/core/logger.test.js.map +1 -0
- package/dist/src/core/loggingContentGenerator.d.ts +35 -0
- package/dist/src/core/loggingContentGenerator.js +254 -0
- package/dist/src/core/loggingContentGenerator.js.map +1 -0
- package/dist/src/core/loggingContentGenerator.test.d.ts +6 -0
- package/dist/src/core/loggingContentGenerator.test.js +221 -0
- package/dist/src/core/loggingContentGenerator.test.js.map +1 -0
- package/dist/src/core/prompts-substitution.test.d.ts +6 -0
- package/dist/src/core/prompts-substitution.test.js +101 -0
- package/dist/src/core/prompts-substitution.test.js.map +1 -0
- package/dist/src/core/prompts.d.ts +18 -0
- package/dist/src/core/prompts.js +522 -0
- package/dist/src/core/prompts.js.map +1 -0
- package/dist/src/core/prompts.test.d.ts +6 -0
- package/dist/src/core/prompts.test.js +391 -0
- package/dist/src/core/prompts.test.js.map +1 -0
- package/dist/src/core/recordingContentGenerator.d.ts +25 -0
- package/dist/src/core/recordingContentGenerator.js +138 -0
- package/dist/src/core/recordingContentGenerator.js.map +1 -0
- package/dist/src/core/recordingContentGenerator.test.d.ts +6 -0
- package/dist/src/core/recordingContentGenerator.test.js +101 -0
- package/dist/src/core/recordingContentGenerator.test.js.map +1 -0
- package/dist/src/core/tokenLimits.d.ts +10 -0
- package/dist/src/core/tokenLimits.js +22 -0
- package/dist/src/core/tokenLimits.js.map +1 -0
- package/dist/src/core/tokenLimits.test.d.ts +6 -0
- package/dist/src/core/tokenLimits.test.js +30 -0
- package/dist/src/core/tokenLimits.test.js.map +1 -0
- package/dist/src/core/turn.d.ts +11 -0
- package/dist/src/core/turn.js +18 -0
- package/dist/src/core/turn.js.map +1 -0
- package/dist/src/core/turn.test.d.ts +6 -0
- package/dist/src/core/turn.test.js +739 -0
- package/dist/src/core/turn.test.js.map +1 -0
- package/dist/src/fallback/handler.d.ts +7 -0
- package/dist/src/fallback/handler.js +110 -0
- package/dist/src/fallback/handler.js.map +1 -0
- package/dist/src/fallback/handler.test.d.ts +6 -0
- package/dist/src/fallback/handler.test.js +242 -0
- package/dist/src/fallback/handler.test.js.map +1 -0
- package/dist/src/fallback/types.d.ts +31 -0
- package/dist/src/fallback/types.js +7 -0
- package/dist/src/fallback/types.js.map +1 -0
- package/dist/src/generated/git-commit.d.ts +7 -0
- package/dist/src/generated/git-commit.js +10 -0
- package/dist/src/generated/git-commit.js.map +1 -0
- package/dist/src/hooks/hookAggregator.d.ts +68 -0
- package/dist/src/hooks/hookAggregator.js +279 -0
- package/dist/src/hooks/hookAggregator.js.map +1 -0
- package/dist/src/hooks/hookAggregator.test.d.ts +6 -0
- package/dist/src/hooks/hookAggregator.test.js +387 -0
- package/dist/src/hooks/hookAggregator.test.js.map +1 -0
- package/dist/src/hooks/hookEventHandler.d.ts +120 -0
- package/dist/src/hooks/hookEventHandler.js +339 -0
- package/dist/src/hooks/hookEventHandler.js.map +1 -0
- package/dist/src/hooks/hookEventHandler.test.d.ts +6 -0
- package/dist/src/hooks/hookEventHandler.test.js +603 -0
- package/dist/src/hooks/hookEventHandler.test.js.map +1 -0
- package/dist/src/hooks/hookPlanner.d.ts +42 -0
- package/dist/src/hooks/hookPlanner.js +103 -0
- package/dist/src/hooks/hookPlanner.js.map +1 -0
- package/dist/src/hooks/hookPlanner.test.d.ts +6 -0
- package/dist/src/hooks/hookPlanner.test.js +315 -0
- package/dist/src/hooks/hookPlanner.test.js.map +1 -0
- package/dist/src/hooks/hookRegistry.d.ts +75 -0
- package/dist/src/hooks/hookRegistry.js +215 -0
- package/dist/src/hooks/hookRegistry.js.map +1 -0
- package/dist/src/hooks/hookRegistry.test.d.ts +6 -0
- package/dist/src/hooks/hookRegistry.test.js +529 -0
- package/dist/src/hooks/hookRegistry.test.js.map +1 -0
- package/dist/src/hooks/hookRunner.d.ts +44 -0
- package/dist/src/hooks/hookRunner.js +328 -0
- package/dist/src/hooks/hookRunner.js.map +1 -0
- package/dist/src/hooks/hookRunner.test.d.ts +6 -0
- package/dist/src/hooks/hookRunner.test.js +606 -0
- package/dist/src/hooks/hookRunner.test.js.map +1 -0
- package/dist/src/hooks/hookSystem.d.ts +110 -0
- package/dist/src/hooks/hookSystem.js +311 -0
- package/dist/src/hooks/hookSystem.js.map +1 -0
- package/dist/src/hooks/hookSystem.test.d.ts +6 -0
- package/dist/src/hooks/hookSystem.test.js +330 -0
- package/dist/src/hooks/hookSystem.test.js.map +1 -0
- package/dist/src/hooks/hookSystem_new_types.test.d.ts +6 -0
- package/dist/src/hooks/hookSystem_new_types.test.js +243 -0
- package/dist/src/hooks/hookSystem_new_types.test.js.map +1 -0
- package/dist/src/hooks/hookTranslator.d.ts +113 -0
- package/dist/src/hooks/hookTranslator.js +233 -0
- package/dist/src/hooks/hookTranslator.js.map +1 -0
- package/dist/src/hooks/hookTranslator.test.d.ts +6 -0
- package/dist/src/hooks/hookTranslator.test.js +192 -0
- package/dist/src/hooks/hookTranslator.test.js.map +1 -0
- package/dist/src/hooks/index.d.ts +16 -0
- package/dist/src/hooks/index.js +16 -0
- package/dist/src/hooks/index.js.map +1 -0
- package/dist/src/hooks/trustedHooks.d.ts +28 -0
- package/dist/src/hooks/trustedHooks.js +90 -0
- package/dist/src/hooks/trustedHooks.js.map +1 -0
- package/dist/src/hooks/trustedHooks.test.d.ts +6 -0
- package/dist/src/hooks/trustedHooks.test.js +154 -0
- package/dist/src/hooks/trustedHooks.test.js.map +1 -0
- package/dist/src/hooks/types.d.ts +462 -0
- package/dist/src/hooks/types.js +363 -0
- package/dist/src/hooks/types.js.map +1 -0
- package/dist/src/hooks/types.test.d.ts +6 -0
- package/dist/src/hooks/types.test.js +278 -0
- package/dist/src/hooks/types.test.js.map +1 -0
- package/dist/src/ide/constants.d.ts +9 -0
- package/dist/src/ide/constants.js +10 -0
- package/dist/src/ide/constants.js.map +1 -0
- package/dist/src/ide/detect-ide.d.ts +105 -0
- package/dist/src/ide/detect-ide.js +121 -0
- package/dist/src/ide/detect-ide.js.map +1 -0
- package/dist/src/ide/detect-ide.test.d.ts +6 -0
- package/dist/src/ide/detect-ide.test.js +195 -0
- package/dist/src/ide/detect-ide.test.js.map +1 -0
- package/dist/src/ide/ide-client.d.ts +113 -0
- package/dist/src/ide/ide-client.js +669 -0
- package/dist/src/ide/ide-client.js.map +1 -0
- package/dist/src/ide/ide-client.test.d.ts +6 -0
- package/dist/src/ide/ide-client.test.js +753 -0
- package/dist/src/ide/ide-client.test.js.map +1 -0
- package/dist/src/ide/ide-installer.d.ts +14 -0
- package/dist/src/ide/ide-installer.js +156 -0
- package/dist/src/ide/ide-installer.js.map +1 -0
- package/dist/src/ide/ide-installer.test.d.ts +6 -0
- package/dist/src/ide/ide-installer.test.js +193 -0
- package/dist/src/ide/ide-installer.test.js.map +1 -0
- package/dist/src/ide/ideContext.d.ts +44 -0
- package/dist/src/ide/ideContext.js +101 -0
- package/dist/src/ide/ideContext.js.map +1 -0
- package/dist/src/ide/ideContext.test.d.ts +6 -0
- package/dist/src/ide/ideContext.test.js +393 -0
- package/dist/src/ide/ideContext.test.js.map +1 -0
- package/dist/src/ide/process-utils.d.ts +21 -0
- package/dist/src/ide/process-utils.js +181 -0
- package/dist/src/ide/process-utils.js.map +1 -0
- package/dist/src/ide/process-utils.test.d.ts +6 -0
- package/dist/src/ide/process-utils.test.js +151 -0
- package/dist/src/ide/process-utils.test.js.map +1 -0
- package/dist/src/ide/types.d.ts +486 -0
- package/dist/src/ide/types.js +138 -0
- package/dist/src/ide/types.js.map +1 -0
- package/dist/src/index.d.ts +142 -0
- package/dist/src/index.js +157 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/index.test.d.ts +6 -0
- package/dist/src/index.test.js +53 -0
- package/dist/src/index.test.js.map +1 -0
- package/dist/src/mcp/auth-provider.d.ts +16 -0
- package/dist/src/mcp/auth-provider.js +7 -0
- package/dist/src/mcp/auth-provider.js.map +1 -0
- package/dist/src/mcp/google-auth-provider.d.ts +33 -0
- package/dist/src/mcp/google-auth-provider.js +118 -0
- package/dist/src/mcp/google-auth-provider.js.map +1 -0
- package/dist/src/mcp/google-auth-provider.test.d.ts +6 -0
- package/dist/src/mcp/google-auth-provider.test.js +167 -0
- package/dist/src/mcp/google-auth-provider.test.js.map +1 -0
- package/dist/src/mcp/oauth-provider.d.ts +160 -0
- package/dist/src/mcp/oauth-provider.js +729 -0
- package/dist/src/mcp/oauth-provider.js.map +1 -0
- package/dist/src/mcp/oauth-provider.test.d.ts +6 -0
- package/dist/src/mcp/oauth-provider.test.js +1355 -0
- package/dist/src/mcp/oauth-provider.test.js.map +1 -0
- package/dist/src/mcp/oauth-token-storage.d.ts +65 -0
- package/dist/src/mcp/oauth-token-storage.js +181 -0
- package/dist/src/mcp/oauth-token-storage.js.map +1 -0
- package/dist/src/mcp/oauth-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/oauth-token-storage.test.js +305 -0
- package/dist/src/mcp/oauth-token-storage.test.js.map +1 -0
- package/dist/src/mcp/oauth-utils.d.ts +142 -0
- package/dist/src/mcp/oauth-utils.js +289 -0
- package/dist/src/mcp/oauth-utils.js.map +1 -0
- package/dist/src/mcp/oauth-utils.test.d.ts +6 -0
- package/dist/src/mcp/oauth-utils.test.js +289 -0
- package/dist/src/mcp/oauth-utils.test.js.map +1 -0
- package/dist/src/mcp/sa-impersonation-provider.d.ts +27 -0
- package/dist/src/mcp/sa-impersonation-provider.js +113 -0
- package/dist/src/mcp/sa-impersonation-provider.js.map +1 -0
- package/dist/src/mcp/sa-impersonation-provider.test.d.ts +6 -0
- package/dist/src/mcp/sa-impersonation-provider.test.js +117 -0
- package/dist/src/mcp/sa-impersonation-provider.test.js.map +1 -0
- package/dist/src/mcp/token-storage/base-token-storage.d.ts +19 -0
- package/dist/src/mcp/token-storage/base-token-storage.js +36 -0
- package/dist/src/mcp/token-storage/base-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/base-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/base-token-storage.test.js +151 -0
- package/dist/src/mcp/token-storage/base-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/file-token-storage.d.ts +24 -0
- package/dist/src/mcp/token-storage/file-token-storage.js +145 -0
- package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js +238 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.d.ts +23 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.js +78 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +193 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/index.d.ts +11 -0
- package/dist/src/mcp/token-storage/index.js +12 -0
- package/dist/src/mcp/token-storage/index.js.map +1 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +35 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.js +246 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js +305 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/types.d.ts +44 -0
- package/dist/src/mcp/token-storage/types.js +11 -0
- package/dist/src/mcp/token-storage/types.js.map +1 -0
- package/dist/src/mocks/msw.d.ts +6 -0
- package/dist/src/mocks/msw.js +8 -0
- package/dist/src/mocks/msw.js.map +1 -0
- package/dist/src/output/json-formatter.d.ts +11 -0
- package/dist/src/output/json-formatter.js +33 -0
- package/dist/src/output/json-formatter.js.map +1 -0
- package/dist/src/output/json-formatter.test.d.ts +6 -0
- package/dist/src/output/json-formatter.test.js +294 -0
- package/dist/src/output/json-formatter.test.js.map +1 -0
- package/dist/src/output/stream-json-formatter.d.ts +32 -0
- package/dist/src/output/stream-json-formatter.js +58 -0
- package/dist/src/output/stream-json-formatter.js.map +1 -0
- package/dist/src/output/stream-json-formatter.test.d.ts +6 -0
- package/dist/src/output/stream-json-formatter.test.js +477 -0
- package/dist/src/output/stream-json-formatter.test.js.map +1 -0
- package/dist/src/output/types.d.ts +85 -0
- package/dist/src/output/types.js +22 -0
- package/dist/src/output/types.js.map +1 -0
- package/dist/src/policy/config.d.ts +31 -0
- package/dist/src/policy/config.js +355 -0
- package/dist/src/policy/config.js.map +1 -0
- package/dist/src/policy/config.test.d.ts +6 -0
- package/dist/src/policy/config.test.js +598 -0
- package/dist/src/policy/config.test.js.map +1 -0
- package/dist/src/policy/index.d.ts +9 -0
- package/dist/src/policy/index.js +10 -0
- package/dist/src/policy/index.js.map +1 -0
- package/dist/src/policy/persistence.test.d.ts +6 -0
- package/dist/src/policy/persistence.test.js +154 -0
- package/dist/src/policy/persistence.test.js.map +1 -0
- package/dist/src/policy/policies/agent.toml +31 -0
- package/dist/src/policy/policies/discovered.toml +8 -0
- package/dist/src/policy/policies/plan.toml +73 -0
- package/dist/src/policy/policies/read-only.toml +56 -0
- package/dist/src/policy/policies/write.toml +78 -0
- package/dist/src/policy/policies/yolo.toml +32 -0
- package/dist/src/policy/policy-engine.d.ts +59 -0
- package/dist/src/policy/policy-engine.js +336 -0
- package/dist/src/policy/policy-engine.js.map +1 -0
- package/dist/src/policy/policy-engine.test.d.ts +6 -0
- package/dist/src/policy/policy-engine.test.js +1299 -0
- package/dist/src/policy/policy-engine.test.js.map +1 -0
- package/dist/src/policy/policy-updater.test.d.ts +6 -0
- package/dist/src/policy/policy-updater.test.js +116 -0
- package/dist/src/policy/policy-updater.test.js.map +1 -0
- package/dist/src/policy/shell-safety.test.d.ts +6 -0
- package/dist/src/policy/shell-safety.test.js +438 -0
- package/dist/src/policy/shell-safety.test.js.map +1 -0
- package/dist/src/policy/stable-stringify.d.ts +58 -0
- package/dist/src/policy/stable-stringify.js +122 -0
- package/dist/src/policy/stable-stringify.js.map +1 -0
- package/dist/src/policy/toml-loader.d.ts +45 -0
- package/dist/src/policy/toml-loader.js +364 -0
- package/dist/src/policy/toml-loader.js.map +1 -0
- package/dist/src/policy/toml-loader.test.d.ts +6 -0
- package/dist/src/policy/toml-loader.test.js +409 -0
- package/dist/src/policy/toml-loader.test.js.map +1 -0
- package/dist/src/policy/types.d.ts +215 -0
- package/dist/src/policy/types.js +44 -0
- package/dist/src/policy/types.js.map +1 -0
- package/dist/src/policy/utils.d.ts +21 -0
- package/dist/src/policy/utils.js +45 -0
- package/dist/src/policy/utils.js.map +1 -0
- package/dist/src/policy/utils.test.d.ts +6 -0
- package/dist/src/policy/utils.test.js +92 -0
- package/dist/src/policy/utils.test.js.map +1 -0
- package/dist/src/prompts/mcp-prompts.d.ts +8 -0
- package/dist/src/prompts/mcp-prompts.js +13 -0
- package/dist/src/prompts/mcp-prompts.js.map +1 -0
- package/dist/src/prompts/mcp-prompts.test.d.ts +6 -0
- package/dist/src/prompts/mcp-prompts.test.js +39 -0
- package/dist/src/prompts/mcp-prompts.test.js.map +1 -0
- package/dist/src/prompts/prompt-registry.d.ts +34 -0
- package/dist/src/prompts/prompt-registry.js +64 -0
- package/dist/src/prompts/prompt-registry.js.map +1 -0
- package/dist/src/prompts/prompt-registry.test.d.ts +6 -0
- package/dist/src/prompts/prompt-registry.test.js +96 -0
- package/dist/src/prompts/prompt-registry.test.js.map +1 -0
- package/dist/src/providers/__tests__/bundleSize.test.d.ts +6 -0
- package/dist/src/providers/__tests__/bundleSize.test.js +75 -0
- package/dist/src/providers/__tests__/bundleSize.test.js.map +1 -0
- package/dist/src/providers/__tests__/errorHandling.integration.test.d.ts +6 -0
- package/dist/src/providers/__tests__/errorHandling.integration.test.js +339 -0
- package/dist/src/providers/__tests__/errorHandling.integration.test.js.map +1 -0
- package/dist/src/providers/__tests__/multiProvider.integration.test.d.ts +6 -0
- package/dist/src/providers/__tests__/multiProvider.integration.test.js +419 -0
- package/dist/src/providers/__tests__/multiProvider.integration.test.js.map +1 -0
- package/dist/src/providers/__tests__/performance.test.d.ts +6 -0
- package/dist/src/providers/__tests__/performance.test.js +270 -0
- package/dist/src/providers/__tests__/performance.test.js.map +1 -0
- package/dist/src/providers/__tests__/providerConfigIntegration.test.d.ts +6 -0
- package/dist/src/providers/__tests__/providerConfigIntegration.test.js +245 -0
- package/dist/src/providers/__tests__/providerConfigIntegration.test.js.map +1 -0
- package/dist/src/providers/baseAdapter.d.ts +61 -0
- package/dist/src/providers/baseAdapter.js +77 -0
- package/dist/src/providers/baseAdapter.js.map +1 -0
- package/dist/src/providers/baseAdapter.test.d.ts +1 -0
- package/dist/src/providers/baseAdapter.test.js +142 -0
- package/dist/src/providers/baseAdapter.test.js.map +1 -0
- package/dist/src/providers/claude/adapter.d.ts +58 -0
- package/dist/src/providers/claude/adapter.js +184 -0
- package/dist/src/providers/claude/adapter.js.map +1 -0
- package/dist/src/providers/claude/adapter.test.d.ts +6 -0
- package/dist/src/providers/claude/adapter.test.js +628 -0
- package/dist/src/providers/claude/adapter.test.js.map +1 -0
- package/dist/src/providers/claude/bootstrap.d.ts +15 -0
- package/dist/src/providers/claude/bootstrap.js +38 -0
- package/dist/src/providers/claude/bootstrap.js.map +1 -0
- package/dist/src/providers/claude/bootstrap.test.d.ts +6 -0
- package/dist/src/providers/claude/bootstrap.test.js +74 -0
- package/dist/src/providers/claude/bootstrap.test.js.map +1 -0
- package/dist/src/providers/claude/converter.d.ts +92 -0
- package/dist/src/providers/claude/converter.js +427 -0
- package/dist/src/providers/claude/converter.js.map +1 -0
- package/dist/src/providers/claude/converter.test.d.ts +6 -0
- package/dist/src/providers/claude/converter.test.js +1002 -0
- package/dist/src/providers/claude/converter.test.js.map +1 -0
- package/dist/src/providers/claude/exports.test.d.ts +6 -0
- package/dist/src/providers/claude/exports.test.js +40 -0
- package/dist/src/providers/claude/exports.test.js.map +1 -0
- package/dist/src/providers/claude/index.d.ts +13 -0
- package/dist/src/providers/claude/index.js +14 -0
- package/dist/src/providers/claude/index.js.map +1 -0
- package/dist/src/providers/configAdapter.d.ts +106 -0
- package/dist/src/providers/configAdapter.js +139 -0
- package/dist/src/providers/configAdapter.js.map +1 -0
- package/dist/src/providers/configAdapter.test.d.ts +1 -0
- package/dist/src/providers/configAdapter.test.js +150 -0
- package/dist/src/providers/configAdapter.test.js.map +1 -0
- package/dist/src/providers/contentResolver.d.ts +93 -0
- package/dist/src/providers/contentResolver.js +152 -0
- package/dist/src/providers/contentResolver.js.map +1 -0
- package/dist/src/providers/contentResolver.test.d.ts +1 -0
- package/dist/src/providers/contentResolver.test.js +89 -0
- package/dist/src/providers/contentResolver.test.js.map +1 -0
- package/dist/src/providers/errors.d.ts +145 -0
- package/dist/src/providers/errors.js +255 -0
- package/dist/src/providers/errors.js.map +1 -0
- package/dist/src/providers/events.d.ts +294 -0
- package/dist/src/providers/events.js +128 -0
- package/dist/src/providers/events.js.map +1 -0
- package/dist/src/providers/factory.d.ts +103 -0
- package/dist/src/providers/factory.js +123 -0
- package/dist/src/providers/factory.js.map +1 -0
- package/dist/src/providers/factory.test.d.ts +1 -0
- package/dist/src/providers/factory.test.js +151 -0
- package/dist/src/providers/factory.test.js.map +1 -0
- package/dist/src/providers/gemini/adapter.d.ts +59 -0
- package/dist/src/providers/gemini/adapter.js +135 -0
- package/dist/src/providers/gemini/adapter.js.map +1 -0
- package/dist/src/providers/gemini/adapterBridge.d.ts +31 -0
- package/dist/src/providers/gemini/adapterBridge.js +40 -0
- package/dist/src/providers/gemini/adapterBridge.js.map +1 -0
- package/dist/src/providers/gemini/adapterBridge.test.d.ts +6 -0
- package/dist/src/providers/gemini/adapterBridge.test.js +164 -0
- package/dist/src/providers/gemini/adapterBridge.test.js.map +1 -0
- package/dist/src/providers/gemini/bootstrap.d.ts +15 -0
- package/dist/src/providers/gemini/bootstrap.js +39 -0
- package/dist/src/providers/gemini/bootstrap.js.map +1 -0
- package/dist/src/providers/gemini/bootstrap.test.d.ts +6 -0
- package/dist/src/providers/gemini/bootstrap.test.js +72 -0
- package/dist/src/providers/gemini/bootstrap.test.js.map +1 -0
- package/dist/src/providers/gemini/chat.d.ts +173 -0
- package/dist/src/providers/gemini/chat.js +747 -0
- package/dist/src/providers/gemini/chat.js.map +1 -0
- package/dist/src/providers/gemini/configConverter.d.ts +38 -0
- package/dist/src/providers/gemini/configConverter.js +166 -0
- package/dist/src/providers/gemini/configConverter.js.map +1 -0
- package/dist/src/providers/gemini/configConverter.test.d.ts +6 -0
- package/dist/src/providers/gemini/configConverter.test.js +218 -0
- package/dist/src/providers/gemini/configConverter.test.js.map +1 -0
- package/dist/src/providers/gemini/converter.d.ts +66 -0
- package/dist/src/providers/gemini/converter.js +270 -0
- package/dist/src/providers/gemini/converter.js.map +1 -0
- package/dist/src/providers/gemini/errorClassifier.d.ts +38 -0
- package/dist/src/providers/gemini/errorClassifier.js +51 -0
- package/dist/src/providers/gemini/errorClassifier.js.map +1 -0
- package/dist/src/providers/gemini/errorClassifier.test.d.ts +6 -0
- package/dist/src/providers/gemini/errorClassifier.test.js +83 -0
- package/dist/src/providers/gemini/errorClassifier.test.js.map +1 -0
- package/dist/src/providers/gemini/eventMapper.d.ts +56 -0
- package/dist/src/providers/gemini/eventMapper.js +337 -0
- package/dist/src/providers/gemini/eventMapper.js.map +1 -0
- package/dist/src/providers/gemini/eventMapper.test.d.ts +6 -0
- package/dist/src/providers/gemini/eventMapper.test.js +502 -0
- package/dist/src/providers/gemini/eventMapper.test.js.map +1 -0
- package/dist/src/providers/gemini/exports.test.d.ts +6 -0
- package/dist/src/providers/gemini/exports.test.js +90 -0
- package/dist/src/providers/gemini/exports.test.js.map +1 -0
- package/dist/src/providers/gemini/featureFlag.d.ts +31 -0
- package/dist/src/providers/gemini/featureFlag.js +68 -0
- package/dist/src/providers/gemini/featureFlag.js.map +1 -0
- package/dist/src/providers/gemini/featureFlag.test.d.ts +6 -0
- package/dist/src/providers/gemini/featureFlag.test.js +139 -0
- package/dist/src/providers/gemini/featureFlag.test.js.map +1 -0
- package/dist/src/providers/gemini/geminiAdapter.test.d.ts +6 -0
- package/dist/src/providers/gemini/geminiAdapter.test.js +279 -0
- package/dist/src/providers/gemini/geminiAdapter.test.js.map +1 -0
- package/dist/src/providers/gemini/geminiConverter.test.d.ts +6 -0
- package/dist/src/providers/gemini/geminiConverter.test.js +474 -0
- package/dist/src/providers/gemini/geminiConverter.test.js.map +1 -0
- package/dist/src/providers/gemini/geminiParity.test.d.ts +6 -0
- package/dist/src/providers/gemini/geminiParity.test.js +754 -0
- package/dist/src/providers/gemini/geminiParity.test.js.map +1 -0
- package/dist/src/providers/gemini/geminiStream.d.ts +60 -0
- package/dist/src/providers/gemini/geminiStream.js +50 -0
- package/dist/src/providers/gemini/geminiStream.js.map +1 -0
- package/dist/src/providers/gemini/geminiStream.test.d.ts +6 -0
- package/dist/src/providers/gemini/geminiStream.test.js +391 -0
- package/dist/src/providers/gemini/geminiStream.test.js.map +1 -0
- package/dist/src/providers/gemini/historyBuilder.d.ts +64 -0
- package/dist/src/providers/gemini/historyBuilder.js +116 -0
- package/dist/src/providers/gemini/historyBuilder.js.map +1 -0
- package/dist/src/providers/gemini/historyBuilder.test.d.ts +6 -0
- package/dist/src/providers/gemini/historyBuilder.test.js +207 -0
- package/dist/src/providers/gemini/historyBuilder.test.js.map +1 -0
- package/dist/src/providers/gemini/index.d.ts +21 -0
- package/dist/src/providers/gemini/index.js +22 -0
- package/dist/src/providers/gemini/index.js.map +1 -0
- package/dist/src/providers/gemini/requestBuilder.d.ts +55 -0
- package/dist/src/providers/gemini/requestBuilder.js +141 -0
- package/dist/src/providers/gemini/requestBuilder.js.map +1 -0
- package/dist/src/providers/gemini/requestBuilder.test.d.ts +6 -0
- package/dist/src/providers/gemini/requestBuilder.test.js +358 -0
- package/dist/src/providers/gemini/requestBuilder.test.js.map +1 -0
- package/dist/src/providers/gemini/streamConverter.d.ts +40 -0
- package/dist/src/providers/gemini/streamConverter.js +50 -0
- package/dist/src/providers/gemini/streamConverter.js.map +1 -0
- package/dist/src/providers/gemini/streamConverter.test.d.ts +6 -0
- package/dist/src/providers/gemini/streamConverter.test.js +131 -0
- package/dist/src/providers/gemini/streamConverter.test.js.map +1 -0
- package/dist/src/providers/gemini/turn.d.ts +29 -0
- package/dist/src/providers/gemini/turn.js +230 -0
- package/dist/src/providers/gemini/turn.js.map +1 -0
- package/dist/src/providers/gemini/typeConversion.d.ts +51 -0
- package/dist/src/providers/gemini/typeConversion.js +165 -0
- package/dist/src/providers/gemini/typeConversion.js.map +1 -0
- package/dist/src/providers/gemini/types.d.ts +158 -0
- package/dist/src/providers/gemini/types.js +47 -0
- package/dist/src/providers/gemini/types.js.map +1 -0
- package/dist/src/providers/index.d.ts +37 -0
- package/dist/src/providers/index.js +68 -0
- package/dist/src/providers/index.js.map +1 -0
- package/dist/src/providers/legacyAliases.d.ts +97 -0
- package/dist/src/providers/legacyAliases.js +26 -0
- package/dist/src/providers/legacyAliases.js.map +1 -0
- package/dist/src/providers/modelSpec.d.ts +104 -0
- package/dist/src/providers/modelSpec.js +107 -0
- package/dist/src/providers/modelSpec.js.map +1 -0
- package/dist/src/providers/modelSpec.test.d.ts +1 -0
- package/dist/src/providers/modelSpec.test.js +119 -0
- package/dist/src/providers/modelSpec.test.js.map +1 -0
- package/dist/src/providers/openai/adapter.d.ts +55 -0
- package/dist/src/providers/openai/adapter.js +165 -0
- package/dist/src/providers/openai/adapter.js.map +1 -0
- package/dist/src/providers/openai/adapter.test.d.ts +6 -0
- package/dist/src/providers/openai/adapter.test.js +274 -0
- package/dist/src/providers/openai/adapter.test.js.map +1 -0
- package/dist/src/providers/openai/bootstrap.d.ts +15 -0
- package/dist/src/providers/openai/bootstrap.js +38 -0
- package/dist/src/providers/openai/bootstrap.js.map +1 -0
- package/dist/src/providers/openai/bootstrap.test.d.ts +6 -0
- package/dist/src/providers/openai/bootstrap.test.js +76 -0
- package/dist/src/providers/openai/bootstrap.test.js.map +1 -0
- package/dist/src/providers/openai/converter.d.ts +122 -0
- package/dist/src/providers/openai/converter.js +473 -0
- package/dist/src/providers/openai/converter.js.map +1 -0
- package/dist/src/providers/openai/converter.test.d.ts +6 -0
- package/dist/src/providers/openai/converter.test.js +1133 -0
- package/dist/src/providers/openai/converter.test.js.map +1 -0
- package/dist/src/providers/openai/index.d.ts +13 -0
- package/dist/src/providers/openai/index.js +14 -0
- package/dist/src/providers/openai/index.js.map +1 -0
- package/dist/src/providers/openai-compatible/__tests__/compatibility.test.d.ts +6 -0
- package/dist/src/providers/openai-compatible/__tests__/compatibility.test.js +356 -0
- package/dist/src/providers/openai-compatible/__tests__/compatibility.test.js.map +1 -0
- package/dist/src/providers/openai-compatible/adapter.d.ts +40 -0
- package/dist/src/providers/openai-compatible/adapter.js +85 -0
- package/dist/src/providers/openai-compatible/adapter.js.map +1 -0
- package/dist/src/providers/openai-compatible/adapter.test.d.ts +6 -0
- package/dist/src/providers/openai-compatible/adapter.test.js +240 -0
- package/dist/src/providers/openai-compatible/adapter.test.js.map +1 -0
- package/dist/src/providers/openai-compatible/bootstrap.d.ts +16 -0
- package/dist/src/providers/openai-compatible/bootstrap.js +76 -0
- package/dist/src/providers/openai-compatible/bootstrap.js.map +1 -0
- package/dist/src/providers/openai-compatible/bootstrap.test.d.ts +6 -0
- package/dist/src/providers/openai-compatible/bootstrap.test.js +145 -0
- package/dist/src/providers/openai-compatible/bootstrap.test.js.map +1 -0
- package/dist/src/providers/openai-compatible/index.d.ts +14 -0
- package/dist/src/providers/openai-compatible/index.js +14 -0
- package/dist/src/providers/openai-compatible/index.js.map +1 -0
- package/dist/src/providers/openai-compatible/promptBuilder.d.ts +89 -0
- package/dist/src/providers/openai-compatible/promptBuilder.js +123 -0
- package/dist/src/providers/openai-compatible/promptBuilder.js.map +1 -0
- package/dist/src/providers/openai-compatible/promptBuilder.test.d.ts +6 -0
- package/dist/src/providers/openai-compatible/promptBuilder.test.js +154 -0
- package/dist/src/providers/openai-compatible/promptBuilder.test.js.map +1 -0
- package/dist/src/providers/providerConfig.d.ts +143 -0
- package/dist/src/providers/providerConfig.js +92 -0
- package/dist/src/providers/providerConfig.js.map +1 -0
- package/dist/src/providers/providerConfig.test.d.ts +1 -0
- package/dist/src/providers/providerConfig.test.js +145 -0
- package/dist/src/providers/providerConfig.test.js.map +1 -0
- package/dist/src/providers/providerConfigIntegration.d.ts +95 -0
- package/dist/src/providers/providerConfigIntegration.js +180 -0
- package/dist/src/providers/providerConfigIntegration.js.map +1 -0
- package/dist/src/providers/providerConfigIntegration.test.d.ts +6 -0
- package/dist/src/providers/providerConfigIntegration.test.js +187 -0
- package/dist/src/providers/providerConfigIntegration.test.js.map +1 -0
- package/dist/src/providers/providerSelector.d.ts +91 -0
- package/dist/src/providers/providerSelector.js +221 -0
- package/dist/src/providers/providerSelector.js.map +1 -0
- package/dist/src/providers/providerSelector.test.d.ts +1 -0
- package/dist/src/providers/providerSelector.test.js +199 -0
- package/dist/src/providers/providerSelector.test.js.map +1 -0
- package/dist/src/providers/providerTypes.d.ts +94 -0
- package/dist/src/providers/providerTypes.js +119 -0
- package/dist/src/providers/providerTypes.js.map +1 -0
- package/dist/src/providers/providerTypes.test.d.ts +1 -0
- package/dist/src/providers/providerTypes.test.js +95 -0
- package/dist/src/providers/providerTypes.test.js.map +1 -0
- package/dist/src/providers/registry.d.ts +109 -0
- package/dist/src/providers/registry.js +131 -0
- package/dist/src/providers/registry.js.map +1 -0
- package/dist/src/providers/registry.test.d.ts +1 -0
- package/dist/src/providers/registry.test.js +207 -0
- package/dist/src/providers/registry.test.js.map +1 -0
- package/dist/src/providers/streamAssembler.d.ts +113 -0
- package/dist/src/providers/streamAssembler.js +180 -0
- package/dist/src/providers/streamAssembler.js.map +1 -0
- package/dist/src/providers/streamAssembler.test.d.ts +1 -0
- package/dist/src/providers/streamAssembler.test.js +247 -0
- package/dist/src/providers/streamAssembler.test.js.map +1 -0
- package/dist/src/providers/telemetryBridge.d.ts +89 -0
- package/dist/src/providers/telemetryBridge.js +108 -0
- package/dist/src/providers/telemetryBridge.js.map +1 -0
- package/dist/src/providers/telemetryBridge.test.d.ts +6 -0
- package/dist/src/providers/telemetryBridge.test.js +235 -0
- package/dist/src/providers/telemetryBridge.test.js.map +1 -0
- package/dist/src/providers/types.d.ts +318 -0
- package/dist/src/providers/types.js +16 -0
- package/dist/src/providers/types.js.map +1 -0
- package/dist/src/providers/types.test.d.ts +6 -0
- package/dist/src/providers/types.test.js +253 -0
- package/dist/src/providers/types.test.js.map +1 -0
- package/dist/src/resources/resource-registry.d.ts +30 -0
- package/dist/src/resources/resource-registry.js +57 -0
- package/dist/src/resources/resource-registry.js.map +1 -0
- package/dist/src/resources/resource-registry.test.d.ts +6 -0
- package/dist/src/resources/resource-registry.test.js +54 -0
- package/dist/src/resources/resource-registry.test.js.map +1 -0
- package/dist/src/routing/modelRouterService.d.ts +23 -0
- package/dist/src/routing/modelRouterService.js +80 -0
- package/dist/src/routing/modelRouterService.js.map +1 -0
- package/dist/src/routing/modelRouterService.test.d.ts +6 -0
- package/dist/src/routing/modelRouterService.test.js +106 -0
- package/dist/src/routing/modelRouterService.test.js.map +1 -0
- package/dist/src/routing/routingStrategy.d.ts +65 -0
- package/dist/src/routing/routingStrategy.js +7 -0
- package/dist/src/routing/routingStrategy.js.map +1 -0
- package/dist/src/routing/strategies/classifierStrategy.d.ts +12 -0
- package/dist/src/routing/strategies/classifierStrategy.js +156 -0
- package/dist/src/routing/strategies/classifierStrategy.js.map +1 -0
- package/dist/src/routing/strategies/classifierStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/classifierStrategy.test.js +249 -0
- package/dist/src/routing/strategies/classifierStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/compositeStrategy.d.ts +26 -0
- package/dist/src/routing/strategies/compositeStrategy.js +70 -0
- package/dist/src/routing/strategies/compositeStrategy.js.map +1 -0
- package/dist/src/routing/strategies/compositeStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/compositeStrategy.test.js +124 -0
- package/dist/src/routing/strategies/compositeStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/defaultStrategy.d.ts +12 -0
- package/dist/src/routing/strategies/defaultStrategy.js +21 -0
- package/dist/src/routing/strategies/defaultStrategy.js.map +1 -0
- package/dist/src/routing/strategies/defaultStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/defaultStrategy.test.js +102 -0
- package/dist/src/routing/strategies/defaultStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/fallbackStrategy.d.ts +12 -0
- package/dist/src/routing/strategies/fallbackStrategy.js +33 -0
- package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -0
- package/dist/src/routing/strategies/fallbackStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/fallbackStrategy.test.js +96 -0
- package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/numericalClassifierStrategy.d.ts +13 -0
- package/dist/src/routing/strategies/numericalClassifierStrategy.js +171 -0
- package/dist/src/routing/strategies/numericalClassifierStrategy.js.map +1 -0
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js +367 -0
- package/dist/src/routing/strategies/numericalClassifierStrategy.test.js.map +1 -0
- package/dist/src/routing/strategies/overrideStrategy.d.ts +15 -0
- package/dist/src/routing/strategies/overrideStrategy.js +29 -0
- package/dist/src/routing/strategies/overrideStrategy.js.map +1 -0
- package/dist/src/routing/strategies/overrideStrategy.test.d.ts +6 -0
- package/dist/src/routing/strategies/overrideStrategy.test.js +59 -0
- package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -0
- package/dist/src/safety/built-in.d.ts +21 -0
- package/dist/src/safety/built-in.js +106 -0
- package/dist/src/safety/built-in.js.map +1 -0
- package/dist/src/safety/built-in.test.d.ts +6 -0
- package/dist/src/safety/built-in.test.js +199 -0
- package/dist/src/safety/built-in.test.js.map +1 -0
- package/dist/src/safety/checker-runner.d.ts +48 -0
- package/dist/src/safety/checker-runner.js +219 -0
- package/dist/src/safety/checker-runner.js.map +1 -0
- package/dist/src/safety/checker-runner.test.d.ts +6 -0
- package/dist/src/safety/checker-runner.test.js +238 -0
- package/dist/src/safety/checker-runner.test.js.map +1 -0
- package/dist/src/safety/context-builder.d.ts +23 -0
- package/dist/src/safety/context-builder.js +47 -0
- package/dist/src/safety/context-builder.js.map +1 -0
- package/dist/src/safety/context-builder.test.d.ts +6 -0
- package/dist/src/safety/context-builder.test.js +49 -0
- package/dist/src/safety/context-builder.test.js.map +1 -0
- package/dist/src/safety/protocol.d.ts +88 -0
- package/dist/src/safety/protocol.js +15 -0
- package/dist/src/safety/protocol.js.map +1 -0
- package/dist/src/safety/registry.d.ts +26 -0
- package/dist/src/safety/registry.js +65 -0
- package/dist/src/safety/registry.js.map +1 -0
- package/dist/src/safety/registry.test.d.ts +6 -0
- package/dist/src/safety/registry.test.js +31 -0
- package/dist/src/safety/registry.test.js.map +1 -0
- package/dist/src/scheduler/confirmation.d.ts +49 -0
- package/dist/src/scheduler/confirmation.js +180 -0
- package/dist/src/scheduler/confirmation.js.map +1 -0
- package/dist/src/scheduler/confirmation.test.d.ts +6 -0
- package/dist/src/scheduler/confirmation.test.js +325 -0
- package/dist/src/scheduler/confirmation.test.js.map +1 -0
- package/dist/src/scheduler/policy.d.ts +25 -0
- package/dist/src/scheduler/policy.js +103 -0
- package/dist/src/scheduler/policy.js.map +1 -0
- package/dist/src/scheduler/policy.test.d.ts +6 -0
- package/dist/src/scheduler/policy.test.js +299 -0
- package/dist/src/scheduler/policy.test.js.map +1 -0
- package/dist/src/scheduler/scheduler.d.ts +61 -0
- package/dist/src/scheduler/scheduler.js +355 -0
- package/dist/src/scheduler/scheduler.js.map +1 -0
- package/dist/src/scheduler/scheduler.test.d.ts +6 -0
- package/dist/src/scheduler/scheduler.test.js +822 -0
- package/dist/src/scheduler/scheduler.test.js.map +1 -0
- package/dist/src/scheduler/state-manager.d.ts +73 -0
- package/dist/src/scheduler/state-manager.js +356 -0
- package/dist/src/scheduler/state-manager.js.map +1 -0
- package/dist/src/scheduler/state-manager.test.d.ts +6 -0
- package/dist/src/scheduler/state-manager.test.js +429 -0
- package/dist/src/scheduler/state-manager.test.js.map +1 -0
- package/dist/src/scheduler/tool-executor.d.ts +22 -0
- package/dist/src/scheduler/tool-executor.js +196 -0
- package/dist/src/scheduler/tool-executor.js.map +1 -0
- package/dist/src/scheduler/tool-executor.test.d.ts +6 -0
- package/dist/src/scheduler/tool-executor.test.js +232 -0
- package/dist/src/scheduler/tool-executor.test.js.map +1 -0
- package/dist/src/scheduler/tool-modifier.d.ts +23 -0
- package/dist/src/scheduler/tool-modifier.js +50 -0
- package/dist/src/scheduler/tool-modifier.js.map +1 -0
- package/dist/src/scheduler/tool-modifier.test.d.ts +6 -0
- package/dist/src/scheduler/tool-modifier.test.js +159 -0
- package/dist/src/scheduler/tool-modifier.test.js.map +1 -0
- package/dist/src/scheduler/types.d.ts +114 -0
- package/dist/src/scheduler/types.js +7 -0
- package/dist/src/scheduler/types.js.map +1 -0
- package/dist/src/services/chatCompressionService.d.ts +41 -0
- package/dist/src/services/chatCompressionService.js +339 -0
- package/dist/src/services/chatCompressionService.js.map +1 -0
- package/dist/src/services/chatCompressionService.test.d.ts +6 -0
- package/dist/src/services/chatCompressionService.test.js +573 -0
- package/dist/src/services/chatCompressionService.test.js.map +1 -0
- package/dist/src/services/chatRecordingService.d.ts +165 -0
- package/dist/src/services/chatRecordingService.js +409 -0
- package/dist/src/services/chatRecordingService.js.map +1 -0
- package/dist/src/services/chatRecordingService.test.d.ts +6 -0
- package/dist/src/services/chatRecordingService.test.js +486 -0
- package/dist/src/services/chatRecordingService.test.js.map +1 -0
- package/dist/src/services/contextManager.d.ts +29 -0
- package/dist/src/services/contextManager.js +71 -0
- package/dist/src/services/contextManager.js.map +1 -0
- package/dist/src/services/contextManager.test.d.ts +6 -0
- package/dist/src/services/contextManager.test.js +104 -0
- package/dist/src/services/contextManager.test.js.map +1 -0
- package/dist/src/services/environmentSanitization.d.ts +15 -0
- package/dist/src/services/environmentSanitization.js +142 -0
- package/dist/src/services/environmentSanitization.js.map +1 -0
- package/dist/src/services/environmentSanitization.test.d.ts +6 -0
- package/dist/src/services/environmentSanitization.test.js +284 -0
- package/dist/src/services/environmentSanitization.test.js.map +1 -0
- package/dist/src/services/fileDiscoveryService.d.ts +33 -0
- package/dist/src/services/fileDiscoveryService.js +69 -0
- package/dist/src/services/fileDiscoveryService.js.map +1 -0
- package/dist/src/services/fileDiscoveryService.test.d.ts +6 -0
- package/dist/src/services/fileDiscoveryService.test.js +223 -0
- package/dist/src/services/fileDiscoveryService.test.js.map +1 -0
- package/dist/src/services/fileSystemService.d.ts +31 -0
- package/dist/src/services/fileSystemService.js +18 -0
- package/dist/src/services/fileSystemService.js.map +1 -0
- package/dist/src/services/fileSystemService.test.d.ts +6 -0
- package/dist/src/services/fileSystemService.test.js +41 -0
- package/dist/src/services/fileSystemService.test.js.map +1 -0
- package/dist/src/services/gitService.d.ts +23 -0
- package/dist/src/services/gitService.js +123 -0
- package/dist/src/services/gitService.js.map +1 -0
- package/dist/src/services/gitService.test.d.ts +6 -0
- package/dist/src/services/gitService.test.js +264 -0
- package/dist/src/services/gitService.test.js.map +1 -0
- package/dist/src/services/loopDetectionService.d.ts +107 -0
- package/dist/src/services/loopDetectionService.js +436 -0
- package/dist/src/services/loopDetectionService.js.map +1 -0
- package/dist/src/services/loopDetectionService.test.d.ts +6 -0
- package/dist/src/services/loopDetectionService.test.js +881 -0
- package/dist/src/services/loopDetectionService.test.js.map +1 -0
- package/dist/src/services/modelConfig.golden.test.d.ts +6 -0
- package/dist/src/services/modelConfig.golden.test.js +74 -0
- package/dist/src/services/modelConfig.golden.test.js.map +1 -0
- package/dist/src/services/modelConfig.integration.test.d.ts +6 -0
- package/dist/src/services/modelConfig.integration.test.js +247 -0
- package/dist/src/services/modelConfig.integration.test.js.map +1 -0
- package/dist/src/services/modelConfigBridge.d.ts +75 -0
- package/dist/src/services/modelConfigBridge.js +116 -0
- package/dist/src/services/modelConfigBridge.js.map +1 -0
- package/dist/src/services/modelConfigBridge.test.d.ts +6 -0
- package/dist/src/services/modelConfigBridge.test.js +410 -0
- package/dist/src/services/modelConfigBridge.test.js.map +1 -0
- package/dist/src/services/modelConfigService.d.ts +86 -0
- package/dist/src/services/modelConfigService.js +215 -0
- package/dist/src/services/modelConfigService.js.map +1 -0
- package/dist/src/services/modelConfigService.test.d.ts +6 -0
- package/dist/src/services/modelConfigService.test.js +868 -0
- package/dist/src/services/modelConfigService.test.js.map +1 -0
- package/dist/src/services/modelConfigServiceTestUtils.d.ts +10 -0
- package/dist/src/services/modelConfigServiceTestUtils.js +17 -0
- package/dist/src/services/modelConfigServiceTestUtils.js.map +1 -0
- package/dist/src/services/sessionSummaryService.d.ts +28 -0
- package/dist/src/services/sessionSummaryService.js +131 -0
- package/dist/src/services/sessionSummaryService.js.map +1 -0
- package/dist/src/services/sessionSummaryService.test.d.ts +6 -0
- package/dist/src/services/sessionSummaryService.test.js +785 -0
- package/dist/src/services/sessionSummaryService.test.js.map +1 -0
- package/dist/src/services/sessionSummaryUtils.d.ts +16 -0
- package/dist/src/services/sessionSummaryUtils.js +137 -0
- package/dist/src/services/sessionSummaryUtils.js.map +1 -0
- package/dist/src/services/sessionSummaryUtils.test.d.ts +6 -0
- package/dist/src/services/sessionSummaryUtils.test.js +160 -0
- package/dist/src/services/sessionSummaryUtils.test.js.map +1 -0
- package/dist/src/services/shellExecutionService.d.ts +107 -0
- package/dist/src/services/shellExecutionService.js +654 -0
- package/dist/src/services/shellExecutionService.js.map +1 -0
- package/dist/src/services/shellExecutionService.test.d.ts +6 -0
- package/dist/src/services/shellExecutionService.test.js +1080 -0
- package/dist/src/services/shellExecutionService.test.js.map +1 -0
- package/dist/src/services/test-data/resolved-aliases-retry.golden.json +238 -0
- package/dist/src/services/test-data/resolved-aliases.golden.json +238 -0
- package/dist/src/skills/builtin/skill-creator/SKILL.md +382 -0
- package/dist/src/skills/builtin/skill-creator/scripts/init_skill.cjs +235 -0
- package/dist/src/skills/builtin/skill-creator/scripts/package_skill.cjs +102 -0
- package/dist/src/skills/builtin/skill-creator/scripts/validate_skill.cjs +127 -0
- package/dist/src/skills/skillLoader.d.ts +31 -0
- package/dist/src/skills/skillLoader.js +133 -0
- package/dist/src/skills/skillLoader.js.map +1 -0
- package/dist/src/skills/skillLoader.test.d.ts +6 -0
- package/dist/src/skills/skillLoader.test.js +185 -0
- package/dist/src/skills/skillLoader.test.js.map +1 -0
- package/dist/src/skills/skillManager.d.ts +69 -0
- package/dist/src/skills/skillManager.js +138 -0
- package/dist/src/skills/skillManager.js.map +1 -0
- package/dist/src/skills/skillManager.test.d.ts +6 -0
- package/dist/src/skills/skillManager.test.js +297 -0
- package/dist/src/skills/skillManager.test.js.map +1 -0
- package/dist/src/telemetry/activity-detector.d.ts +41 -0
- package/dist/src/telemetry/activity-detector.js +61 -0
- package/dist/src/telemetry/activity-detector.js.map +1 -0
- package/dist/src/telemetry/activity-detector.test.d.ts +6 -0
- package/dist/src/telemetry/activity-detector.test.js +136 -0
- package/dist/src/telemetry/activity-detector.test.js.map +1 -0
- package/dist/src/telemetry/activity-monitor.d.ts +116 -0
- package/dist/src/telemetry/activity-monitor.js +209 -0
- package/dist/src/telemetry/activity-monitor.js.map +1 -0
- package/dist/src/telemetry/activity-monitor.test.d.ts +6 -0
- package/dist/src/telemetry/activity-monitor.test.js +251 -0
- package/dist/src/telemetry/activity-monitor.test.js.map +1 -0
- package/dist/src/telemetry/activity-types.d.ts +19 -0
- package/dist/src/telemetry/activity-types.js +21 -0
- package/dist/src/telemetry/activity-types.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +172 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +1316 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +19 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +964 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +150 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +377 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -0
- package/dist/src/telemetry/config.d.ts +31 -0
- package/dist/src/telemetry/config.js +78 -0
- package/dist/src/telemetry/config.js.map +1 -0
- package/dist/src/telemetry/config.test.d.ts +6 -0
- package/dist/src/telemetry/config.test.js +149 -0
- package/dist/src/telemetry/config.test.js.map +1 -0
- package/dist/src/telemetry/constants.d.ts +6 -0
- package/dist/src/telemetry/constants.js +7 -0
- package/dist/src/telemetry/constants.js.map +1 -0
- package/dist/src/telemetry/file-exporters.d.ts +29 -0
- package/dist/src/telemetry/file-exporters.js +62 -0
- package/dist/src/telemetry/file-exporters.js.map +1 -0
- package/dist/src/telemetry/gcp-exporters.d.ts +35 -0
- package/dist/src/telemetry/gcp-exporters.js +120 -0
- package/dist/src/telemetry/gcp-exporters.js.map +1 -0
- package/dist/src/telemetry/gcp-exporters.test.d.ts +6 -0
- package/dist/src/telemetry/gcp-exporters.test.js +318 -0
- package/dist/src/telemetry/gcp-exporters.test.js.map +1 -0
- package/dist/src/telemetry/high-water-mark-tracker.d.ts +43 -0
- package/dist/src/telemetry/high-water-mark-tracker.js +88 -0
- package/dist/src/telemetry/high-water-mark-tracker.js.map +1 -0
- package/dist/src/telemetry/high-water-mark-tracker.test.d.ts +6 -0
- package/dist/src/telemetry/high-water-mark-tracker.test.js +152 -0
- package/dist/src/telemetry/high-water-mark-tracker.test.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +33 -0
- package/dist/src/telemetry/index.js +44 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/dist/src/telemetry/integration.test.circular.d.ts +6 -0
- package/dist/src/telemetry/integration.test.circular.js +54 -0
- package/dist/src/telemetry/integration.test.circular.js.map +1 -0
- package/dist/src/telemetry/loggers.d.ts +46 -0
- package/dist/src/telemetry/loggers.js +517 -0
- package/dist/src/telemetry/loggers.js.map +1 -0
- package/dist/src/telemetry/loggers.test.circular.d.ts +6 -0
- package/dist/src/telemetry/loggers.test.circular.js +107 -0
- package/dist/src/telemetry/loggers.test.circular.js.map +1 -0
- package/dist/src/telemetry/loggers.test.d.ts +6 -0
- package/dist/src/telemetry/loggers.test.js +1618 -0
- package/dist/src/telemetry/loggers.test.js.map +1 -0
- package/dist/src/telemetry/memory-monitor.d.ts +149 -0
- package/dist/src/telemetry/memory-monitor.js +335 -0
- package/dist/src/telemetry/memory-monitor.js.map +1 -0
- package/dist/src/telemetry/memory-monitor.test.d.ts +6 -0
- package/dist/src/telemetry/memory-monitor.test.js +472 -0
- package/dist/src/telemetry/memory-monitor.test.js.map +1 -0
- package/dist/src/telemetry/metrics.d.ts +533 -0
- package/dist/src/telemetry/metrics.js +852 -0
- package/dist/src/telemetry/metrics.js.map +1 -0
- package/dist/src/telemetry/metrics.test.d.ts +6 -0
- package/dist/src/telemetry/metrics.test.js +1176 -0
- package/dist/src/telemetry/metrics.test.js.map +1 -0
- package/dist/src/telemetry/rate-limiter.d.ts +48 -0
- package/dist/src/telemetry/rate-limiter.js +100 -0
- package/dist/src/telemetry/rate-limiter.js.map +1 -0
- package/dist/src/telemetry/rate-limiter.test.d.ts +6 -0
- package/dist/src/telemetry/rate-limiter.test.js +207 -0
- package/dist/src/telemetry/rate-limiter.test.js.map +1 -0
- package/dist/src/telemetry/sanitize.d.ts +25 -0
- package/dist/src/telemetry/sanitize.js +48 -0
- package/dist/src/telemetry/sanitize.js.map +1 -0
- package/dist/src/telemetry/sanitize.test.d.ts +6 -0
- package/dist/src/telemetry/sanitize.test.js +279 -0
- package/dist/src/telemetry/sanitize.test.js.map +1 -0
- package/dist/src/telemetry/sdk.d.ts +16 -0
- package/dist/src/telemetry/sdk.js +324 -0
- package/dist/src/telemetry/sdk.js.map +1 -0
- package/dist/src/telemetry/sdk.test.d.ts +6 -0
- package/dist/src/telemetry/sdk.test.js +360 -0
- package/dist/src/telemetry/sdk.test.js.map +1 -0
- package/dist/src/telemetry/semantic.d.ts +110 -0
- package/dist/src/telemetry/semantic.js +375 -0
- package/dist/src/telemetry/semantic.js.map +1 -0
- package/dist/src/telemetry/semantic.test.d.ts +6 -0
- package/dist/src/telemetry/semantic.test.js +387 -0
- package/dist/src/telemetry/semantic.test.js.map +1 -0
- package/dist/src/telemetry/semantic.truncation.test.d.ts +1 -0
- package/dist/src/telemetry/semantic.truncation.test.js +92 -0
- package/dist/src/telemetry/semantic.truncation.test.js.map +1 -0
- package/dist/src/telemetry/startupProfiler.d.ts +51 -0
- package/dist/src/telemetry/startupProfiler.js +170 -0
- package/dist/src/telemetry/startupProfiler.js.map +1 -0
- package/dist/src/telemetry/startupProfiler.test.d.ts +6 -0
- package/dist/src/telemetry/startupProfiler.test.js +285 -0
- package/dist/src/telemetry/startupProfiler.test.js.map +1 -0
- package/dist/src/telemetry/telemetry-utils.d.ts +6 -0
- package/dist/src/telemetry/telemetry-utils.js +14 -0
- package/dist/src/telemetry/telemetry-utils.js.map +1 -0
- package/dist/src/telemetry/telemetry-utils.test.d.ts +6 -0
- package/dist/src/telemetry/telemetry-utils.test.js +41 -0
- package/dist/src/telemetry/telemetry-utils.test.js.map +1 -0
- package/dist/src/telemetry/telemetry.test.d.ts +6 -0
- package/dist/src/telemetry/telemetry.test.js +57 -0
- package/dist/src/telemetry/telemetry.test.js.map +1 -0
- package/dist/src/telemetry/telemetryAttributes.d.ts +8 -0
- package/dist/src/telemetry/telemetryAttributes.js +19 -0
- package/dist/src/telemetry/telemetryAttributes.js.map +1 -0
- package/dist/src/telemetry/tool-call-decision.d.ts +13 -0
- package/dist/src/telemetry/tool-call-decision.js +29 -0
- package/dist/src/telemetry/tool-call-decision.js.map +1 -0
- package/dist/src/telemetry/trace.d.ts +46 -0
- package/dist/src/telemetry/trace.js +121 -0
- package/dist/src/telemetry/trace.js.map +1 -0
- package/dist/src/telemetry/types.d.ts +597 -0
- package/dist/src/telemetry/types.js +1495 -0
- package/dist/src/telemetry/types.js.map +1 -0
- package/dist/src/telemetry/uiTelemetry.d.ts +76 -0
- package/dist/src/telemetry/uiTelemetry.js +154 -0
- package/dist/src/telemetry/uiTelemetry.js.map +1 -0
- package/dist/src/telemetry/uiTelemetry.test.d.ts +6 -0
- package/dist/src/telemetry/uiTelemetry.test.js +584 -0
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -0
- package/dist/src/test-utils/config.d.ts +17 -0
- package/dist/src/test-utils/config.js +32 -0
- package/dist/src/test-utils/config.js.map +1 -0
- package/dist/src/test-utils/index.d.ts +6 -0
- package/dist/src/test-utils/index.js +7 -0
- package/dist/src/test-utils/index.js.map +1 -0
- package/dist/src/test-utils/mock-message-bus.d.ts +43 -0
- package/dist/src/test-utils/mock-message-bus.js +96 -0
- package/dist/src/test-utils/mock-message-bus.js.map +1 -0
- package/dist/src/test-utils/mock-tool.d.ts +69 -0
- package/dist/src/test-utils/mock-tool.js +123 -0
- package/dist/src/test-utils/mock-tool.js.map +1 -0
- package/dist/src/test-utils/mockWorkspaceContext.d.ts +13 -0
- package/dist/src/test-utils/mockWorkspaceContext.js +24 -0
- package/dist/src/test-utils/mockWorkspaceContext.js.map +1 -0
- package/dist/src/tools/activate-skill.d.ts +27 -0
- package/dist/src/tools/activate-skill.js +133 -0
- package/dist/src/tools/activate-skill.js.map +1 -0
- package/dist/src/tools/activate-skill.test.d.ts +6 -0
- package/dist/src/tools/activate-skill.test.js +113 -0
- package/dist/src/tools/activate-skill.test.js.map +1 -0
- package/dist/src/tools/ask-user.d.ts +20 -0
- package/dist/src/tools/ask-user.js +142 -0
- package/dist/src/tools/ask-user.js.map +1 -0
- package/dist/src/tools/ask-user.test.d.ts +6 -0
- package/dist/src/tools/ask-user.test.js +187 -0
- package/dist/src/tools/ask-user.test.js.map +1 -0
- package/dist/src/tools/base-tool-invocation.test.d.ts +6 -0
- package/dist/src/tools/base-tool-invocation.test.js +85 -0
- package/dist/src/tools/base-tool-invocation.test.js.map +1 -0
- package/dist/src/tools/confirmation-policy.test.d.ts +6 -0
- package/dist/src/tools/confirmation-policy.test.js +143 -0
- package/dist/src/tools/confirmation-policy.test.js.map +1 -0
- package/dist/src/tools/constants.d.ts +7 -0
- package/dist/src/tools/constants.js +8 -0
- package/dist/src/tools/constants.js.map +1 -0
- package/dist/src/tools/diffOptions.d.ts +9 -0
- package/dist/src/tools/diffOptions.js +50 -0
- package/dist/src/tools/diffOptions.js.map +1 -0
- package/dist/src/tools/diffOptions.test.d.ts +6 -0
- package/dist/src/tools/diffOptions.test.js +172 -0
- package/dist/src/tools/diffOptions.test.js.map +1 -0
- package/dist/src/tools/edit.d.ts +79 -0
- package/dist/src/tools/edit.js +747 -0
- package/dist/src/tools/edit.js.map +1 -0
- package/dist/src/tools/edit.test.d.ts +6 -0
- package/dist/src/tools/edit.test.js +729 -0
- package/dist/src/tools/edit.test.js.map +1 -0
- package/dist/src/tools/get-internal-docs.d.ts +27 -0
- package/dist/src/tools/get-internal-docs.js +122 -0
- package/dist/src/tools/get-internal-docs.js.map +1 -0
- package/dist/src/tools/get-internal-docs.test.d.ts +6 -0
- package/dist/src/tools/get-internal-docs.test.js +57 -0
- package/dist/src/tools/get-internal-docs.test.js.map +1 -0
- package/dist/src/tools/glob.d.ts +57 -0
- package/dist/src/tools/glob.js +241 -0
- package/dist/src/tools/glob.js.map +1 -0
- package/dist/src/tools/glob.test.d.ts +6 -0
- package/dist/src/tools/glob.test.js +433 -0
- package/dist/src/tools/glob.test.js.map +1 -0
- package/dist/src/tools/grep.d.ts +48 -0
- package/dist/src/tools/grep.js +509 -0
- package/dist/src/tools/grep.js.map +1 -0
- package/dist/src/tools/grep.test.d.ts +6 -0
- package/dist/src/tools/grep.test.js +328 -0
- package/dist/src/tools/grep.test.js.map +1 -0
- package/dist/src/tools/ls.d.ts +69 -0
- package/dist/src/tools/ls.js +208 -0
- package/dist/src/tools/ls.js.map +1 -0
- package/dist/src/tools/ls.test.d.ts +6 -0
- package/dist/src/tools/ls.test.js +242 -0
- package/dist/src/tools/ls.test.js.map +1 -0
- package/dist/src/tools/mcp-client-manager.d.ts +93 -0
- package/dist/src/tools/mcp-client-manager.js +338 -0
- package/dist/src/tools/mcp-client-manager.js.map +1 -0
- package/dist/src/tools/mcp-client-manager.test.d.ts +6 -0
- package/dist/src/tools/mcp-client-manager.test.js +251 -0
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -0
- package/dist/src/tools/mcp-client.d.ts +243 -0
- package/dist/src/tools/mcp-client.js +1334 -0
- package/dist/src/tools/mcp-client.js.map +1 -0
- package/dist/src/tools/mcp-client.test.d.ts +6 -0
- package/dist/src/tools/mcp-client.test.js +1346 -0
- package/dist/src/tools/mcp-client.test.js.map +1 -0
- package/dist/src/tools/mcp-tool.d.ts +49 -0
- package/dist/src/tools/mcp-tool.js +300 -0
- package/dist/src/tools/mcp-tool.js.map +1 -0
- package/dist/src/tools/mcp-tool.test.d.ts +6 -0
- package/dist/src/tools/mcp-tool.test.js +657 -0
- package/dist/src/tools/mcp-tool.test.js.map +1 -0
- package/dist/src/tools/memoryTool.d.ts +42 -0
- package/dist/src/tools/memoryTool.js +269 -0
- package/dist/src/tools/memoryTool.js.map +1 -0
- package/dist/src/tools/memoryTool.test.d.ts +6 -0
- package/dist/src/tools/memoryTool.test.js +302 -0
- package/dist/src/tools/memoryTool.test.js.map +1 -0
- package/dist/src/tools/message-bus-integration.test.d.ts +6 -0
- package/dist/src/tools/message-bus-integration.test.js +169 -0
- package/dist/src/tools/message-bus-integration.test.js.map +1 -0
- package/dist/src/tools/modifiable-tool.d.ts +36 -0
- package/dist/src/tools/modifiable-tool.js +110 -0
- package/dist/src/tools/modifiable-tool.js.map +1 -0
- package/dist/src/tools/modifiable-tool.test.d.ts +6 -0
- package/dist/src/tools/modifiable-tool.test.js +237 -0
- package/dist/src/tools/modifiable-tool.test.js.map +1 -0
- package/dist/src/tools/read-file.d.ts +36 -0
- package/dist/src/tools/read-file.js +133 -0
- package/dist/src/tools/read-file.js.map +1 -0
- package/dist/src/tools/read-file.test.d.ts +6 -0
- package/dist/src/tools/read-file.test.js +376 -0
- package/dist/src/tools/read-file.test.js.map +1 -0
- package/dist/src/tools/read-many-files.d.ts +54 -0
- package/dist/src/tools/read-many-files.js +355 -0
- package/dist/src/tools/read-many-files.js.map +1 -0
- package/dist/src/tools/read-many-files.test.d.ts +6 -0
- package/dist/src/tools/read-many-files.test.js +567 -0
- package/dist/src/tools/read-many-files.test.js.map +1 -0
- package/dist/src/tools/ripGrep.d.ts +74 -0
- package/dist/src/tools/ripGrep.js +398 -0
- package/dist/src/tools/ripGrep.js.map +1 -0
- package/dist/src/tools/ripGrep.test.d.ts +6 -0
- package/dist/src/tools/ripGrep.test.js +1139 -0
- package/dist/src/tools/ripGrep.test.js.map +1 -0
- package/dist/src/tools/shell.d.ts +32 -0
- package/dist/src/tools/shell.js +381 -0
- package/dist/src/tools/shell.js.map +1 -0
- package/dist/src/tools/shell.test.d.ts +6 -0
- package/dist/src/tools/shell.test.js +526 -0
- package/dist/src/tools/shell.test.js.map +1 -0
- package/dist/src/tools/tool-error.d.ts +70 -0
- package/dist/src/tools/tool-error.js +92 -0
- package/dist/src/tools/tool-error.js.map +1 -0
- package/dist/src/tools/tool-names.d.ts +40 -0
- package/dist/src/tools/tool-names.js +92 -0
- package/dist/src/tools/tool-names.js.map +1 -0
- package/dist/src/tools/tool-names.test.d.ts +6 -0
- package/dist/src/tools/tool-names.test.js +43 -0
- package/dist/src/tools/tool-names.test.js.map +1 -0
- package/dist/src/tools/tool-registry.d.ts +103 -0
- package/dist/src/tools/tool-registry.js +429 -0
- package/dist/src/tools/tool-registry.js.map +1 -0
- package/dist/src/tools/tool-registry.test.d.ts +6 -0
- package/dist/src/tools/tool-registry.test.js +461 -0
- package/dist/src/tools/tool-registry.test.js.map +1 -0
- package/dist/src/tools/tools.d.ts +330 -0
- package/dist/src/tools/tools.js +405 -0
- package/dist/src/tools/tools.js.map +1 -0
- package/dist/src/tools/tools.test.d.ts +6 -0
- package/dist/src/tools/tools.test.js +207 -0
- package/dist/src/tools/tools.test.js.map +1 -0
- package/dist/src/tools/web-fetch.d.ts +35 -0
- package/dist/src/tools/web-fetch.js +299 -0
- package/dist/src/tools/web-fetch.js.map +1 -0
- package/dist/src/tools/web-fetch.test.d.ts +6 -0
- package/dist/src/tools/web-fetch.test.js +442 -0
- package/dist/src/tools/web-fetch.test.js.map +1 -0
- package/dist/src/tools/web-search.d.ts +50 -0
- package/dist/src/tools/web-search.js +141 -0
- package/dist/src/tools/web-search.js.map +1 -0
- package/dist/src/tools/web-search.test.d.ts +6 -0
- package/dist/src/tools/web-search.test.js +214 -0
- package/dist/src/tools/web-search.test.js.map +1 -0
- package/dist/src/tools/write-file.d.ts +53 -0
- package/dist/src/tools/write-file.js +318 -0
- package/dist/src/tools/write-file.js.map +1 -0
- package/dist/src/tools/write-file.test.d.ts +6 -0
- package/dist/src/tools/write-file.test.js +681 -0
- package/dist/src/tools/write-file.test.js.map +1 -0
- package/dist/src/tools/write-todos.d.ts +50 -0
- package/dist/src/tools/write-todos.js +194 -0
- package/dist/src/tools/write-todos.js.map +1 -0
- package/dist/src/tools/write-todos.test.d.ts +6 -0
- package/dist/src/tools/write-todos.test.js +90 -0
- package/dist/src/tools/write-todos.test.js.map +1 -0
- package/dist/src/utils/apiConversionUtils.d.ts +12 -0
- package/dist/src/utils/apiConversionUtils.js +46 -0
- package/dist/src/utils/apiConversionUtils.js.map +1 -0
- package/dist/src/utils/apiConversionUtils.test.d.ts +6 -0
- package/dist/src/utils/apiConversionUtils.test.js +150 -0
- package/dist/src/utils/apiConversionUtils.test.js.map +1 -0
- package/dist/src/utils/bfsFileSearch.d.ts +32 -0
- package/dist/src/utils/bfsFileSearch.js +136 -0
- package/dist/src/utils/bfsFileSearch.js.map +1 -0
- package/dist/src/utils/bfsFileSearch.test.d.ts +6 -0
- package/dist/src/utils/bfsFileSearch.test.js +227 -0
- package/dist/src/utils/bfsFileSearch.test.js.map +1 -0
- package/dist/src/utils/browser.d.ts +13 -0
- package/dist/src/utils/browser.js +50 -0
- package/dist/src/utils/browser.js.map +1 -0
- package/dist/src/utils/channel.d.ts +19 -0
- package/dist/src/utils/channel.js +49 -0
- package/dist/src/utils/channel.js.map +1 -0
- package/dist/src/utils/channel.test.d.ts +6 -0
- package/dist/src/utils/channel.test.js +170 -0
- package/dist/src/utils/channel.test.js.map +1 -0
- package/dist/src/utils/checkpointUtils.d.ts +82 -0
- package/dist/src/utils/checkpointUtils.js +117 -0
- package/dist/src/utils/checkpointUtils.js.map +1 -0
- package/dist/src/utils/checkpointUtils.test.d.ts +6 -0
- package/dist/src/utils/checkpointUtils.test.js +229 -0
- package/dist/src/utils/checkpointUtils.test.js.map +1 -0
- package/dist/src/utils/constants.d.ts +7 -0
- package/dist/src/utils/constants.js +8 -0
- package/dist/src/utils/constants.js.map +1 -0
- package/dist/src/utils/customHeaderUtils.d.ts +9 -0
- package/dist/src/utils/customHeaderUtils.js +34 -0
- package/dist/src/utils/customHeaderUtils.js.map +1 -0
- package/dist/src/utils/customHeaderUtils.test.d.ts +6 -0
- package/dist/src/utils/customHeaderUtils.test.js +77 -0
- package/dist/src/utils/customHeaderUtils.test.js.map +1 -0
- package/dist/src/utils/debugLogger.d.ts +28 -0
- package/dist/src/utils/debugLogger.js +61 -0
- package/dist/src/utils/debugLogger.js.map +1 -0
- package/dist/src/utils/debugLogger.test.d.ts +6 -0
- package/dist/src/utils/debugLogger.test.js +69 -0
- package/dist/src/utils/debugLogger.test.js.map +1 -0
- package/dist/src/utils/delay.d.ts +16 -0
- package/dist/src/utils/delay.js +43 -0
- package/dist/src/utils/delay.js.map +1 -0
- package/dist/src/utils/delay.test.d.ts +6 -0
- package/dist/src/utils/delay.test.js +88 -0
- package/dist/src/utils/delay.test.js.map +1 -0
- package/dist/src/utils/editCorrector.d.ts +54 -0
- package/dist/src/utils/editCorrector.js +594 -0
- package/dist/src/utils/editCorrector.js.map +1 -0
- package/dist/src/utils/editCorrector.test.d.ts +6 -0
- package/dist/src/utils/editCorrector.test.js +533 -0
- package/dist/src/utils/editCorrector.test.js.map +1 -0
- package/dist/src/utils/editor.d.ts +39 -0
- package/dist/src/utils/editor.js +219 -0
- package/dist/src/utils/editor.js.map +1 -0
- package/dist/src/utils/editor.test.d.ts +6 -0
- package/dist/src/utils/editor.test.js +429 -0
- package/dist/src/utils/editor.test.js.map +1 -0
- package/dist/src/utils/environmentContext.d.ts +23 -0
- package/dist/src/utils/environmentContext.js +81 -0
- package/dist/src/utils/environmentContext.js.map +1 -0
- package/dist/src/utils/environmentContext.test.d.ts +6 -0
- package/dist/src/utils/environmentContext.test.js +114 -0
- package/dist/src/utils/environmentContext.test.js.map +1 -0
- package/dist/src/utils/errorParsing.d.ts +8 -0
- package/dist/src/utils/errorParsing.js +65 -0
- package/dist/src/utils/errorParsing.js.map +1 -0
- package/dist/src/utils/errorParsing.test.d.ts +6 -0
- package/dist/src/utils/errorParsing.test.js +84 -0
- package/dist/src/utils/errorParsing.test.js.map +1 -0
- package/dist/src/utils/errorReporting.d.ts +14 -0
- package/dist/src/utils/errorReporting.js +89 -0
- package/dist/src/utils/errorReporting.js.map +1 -0
- package/dist/src/utils/errorReporting.test.d.ts +6 -0
- package/dist/src/utils/errorReporting.test.js +133 -0
- package/dist/src/utils/errorReporting.test.js.map +1 -0
- package/dist/src/utils/errors.d.ts +53 -0
- package/dist/src/utils/errors.js +145 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/errors.test.d.ts +6 -0
- package/dist/src/utils/errors.test.js +155 -0
- package/dist/src/utils/errors.test.js.map +1 -0
- package/dist/src/utils/events.d.ts +198 -0
- package/dist/src/utils/events.js +127 -0
- package/dist/src/utils/events.js.map +1 -0
- package/dist/src/utils/events.test.d.ts +6 -0
- package/dist/src/utils/events.test.js +237 -0
- package/dist/src/utils/events.test.js.map +1 -0
- package/dist/src/utils/exitCodes.d.ts +12 -0
- package/dist/src/utils/exitCodes.js +13 -0
- package/dist/src/utils/exitCodes.js.map +1 -0
- package/dist/src/utils/extensionLoader.d.ts +86 -0
- package/dist/src/utils/extensionLoader.js +208 -0
- package/dist/src/utils/extensionLoader.js.map +1 -0
- package/dist/src/utils/extensionLoader.test.d.ts +6 -0
- package/dist/src/utils/extensionLoader.test.js +176 -0
- package/dist/src/utils/extensionLoader.test.js.map +1 -0
- package/dist/src/utils/fetch.d.ts +12 -0
- package/dist/src/utils/fetch.js +55 -0
- package/dist/src/utils/fetch.js.map +1 -0
- package/dist/src/utils/fileDiffUtils.d.ts +18 -0
- package/dist/src/utils/fileDiffUtils.js +37 -0
- package/dist/src/utils/fileDiffUtils.js.map +1 -0
- package/dist/src/utils/fileDiffUtils.test.d.ts +6 -0
- package/dist/src/utils/fileDiffUtils.test.js +84 -0
- package/dist/src/utils/fileDiffUtils.test.js.map +1 -0
- package/dist/src/utils/fileUtils.d.ts +85 -0
- package/dist/src/utils/fileUtils.js +490 -0
- package/dist/src/utils/fileUtils.js.map +1 -0
- package/dist/src/utils/fileUtils.test.d.ts +6 -0
- package/dist/src/utils/fileUtils.test.js +780 -0
- package/dist/src/utils/fileUtils.test.js.map +1 -0
- package/dist/src/utils/filesearch/crawlCache.d.ts +25 -0
- package/dist/src/utils/filesearch/crawlCache.js +57 -0
- package/dist/src/utils/filesearch/crawlCache.js.map +1 -0
- package/dist/src/utils/filesearch/crawlCache.test.d.ts +6 -0
- package/dist/src/utils/filesearch/crawlCache.test.js +103 -0
- package/dist/src/utils/filesearch/crawlCache.test.js.map +1 -0
- package/dist/src/utils/filesearch/crawler.d.ts +16 -0
- package/dist/src/utils/filesearch/crawler.js +67 -0
- package/dist/src/utils/filesearch/crawler.js.map +1 -0
- package/dist/src/utils/filesearch/crawler.test.d.ts +6 -0
- package/dist/src/utils/filesearch/crawler.test.js +495 -0
- package/dist/src/utils/filesearch/crawler.test.js.map +1 -0
- package/dist/src/utils/filesearch/fileSearch.d.ts +39 -0
- package/dist/src/utils/filesearch/fileSearch.js +192 -0
- package/dist/src/utils/filesearch/fileSearch.js.map +1 -0
- package/dist/src/utils/filesearch/fileSearch.test.d.ts +6 -0
- package/dist/src/utils/filesearch/fileSearch.test.js +663 -0
- package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -0
- package/dist/src/utils/filesearch/ignore.d.ts +42 -0
- package/dist/src/utils/filesearch/ignore.js +106 -0
- package/dist/src/utils/filesearch/ignore.js.map +1 -0
- package/dist/src/utils/filesearch/ignore.test.d.ts +6 -0
- package/dist/src/utils/filesearch/ignore.test.js +144 -0
- package/dist/src/utils/filesearch/ignore.test.js.map +1 -0
- package/dist/src/utils/filesearch/result-cache.d.ts +33 -0
- package/dist/src/utils/filesearch/result-cache.js +59 -0
- package/dist/src/utils/filesearch/result-cache.js.map +1 -0
- package/dist/src/utils/filesearch/result-cache.test.d.ts +6 -0
- package/dist/src/utils/filesearch/result-cache.test.js +46 -0
- package/dist/src/utils/filesearch/result-cache.test.js.map +1 -0
- package/dist/src/utils/flashFallback.test.d.ts +6 -0
- package/dist/src/utils/flashFallback.test.js +103 -0
- package/dist/src/utils/flashFallback.test.js.map +1 -0
- package/dist/src/utils/formatters.d.ts +7 -0
- package/dist/src/utils/formatters.js +17 -0
- package/dist/src/utils/formatters.js.map +1 -0
- package/dist/src/utils/formatters.test.d.ts +6 -0
- package/dist/src/utils/formatters.test.js +26 -0
- package/dist/src/utils/formatters.test.js.map +1 -0
- package/dist/src/utils/geminiIgnoreParser.d.ts +29 -0
- package/dist/src/utils/geminiIgnoreParser.js +81 -0
- package/dist/src/utils/geminiIgnoreParser.js.map +1 -0
- package/dist/src/utils/geminiIgnoreParser.test.d.ts +6 -0
- package/dist/src/utils/geminiIgnoreParser.test.js +98 -0
- package/dist/src/utils/geminiIgnoreParser.test.js.map +1 -0
- package/dist/src/utils/geminiTypeConversion.d.ts +11 -0
- package/dist/src/utils/geminiTypeConversion.js +12 -0
- package/dist/src/utils/geminiTypeConversion.js.map +1 -0
- package/dist/src/utils/geminiTypeConversion.test.d.ts +6 -0
- package/dist/src/utils/geminiTypeConversion.test.js +310 -0
- package/dist/src/utils/geminiTypeConversion.test.js.map +1 -0
- package/dist/src/utils/generateContentResponseUtilities.d.ts +15 -0
- package/dist/src/utils/generateContentResponseUtilities.js +186 -0
- package/dist/src/utils/generateContentResponseUtilities.js.map +1 -0
- package/dist/src/utils/generateContentResponseUtilities.test.d.ts +6 -0
- package/dist/src/utils/generateContentResponseUtilities.test.js +512 -0
- package/dist/src/utils/generateContentResponseUtilities.test.js.map +1 -0
- package/dist/src/utils/getFolderStructure.d.ts +31 -0
- package/dist/src/utils/getFolderStructure.js +243 -0
- package/dist/src/utils/getFolderStructure.js.map +1 -0
- package/dist/src/utils/getFolderStructure.test.d.ts +6 -0
- package/dist/src/utils/getFolderStructure.test.js +283 -0
- package/dist/src/utils/getFolderStructure.test.js.map +1 -0
- package/dist/src/utils/getPty.d.ts +19 -0
- package/dist/src/utils/getPty.js +23 -0
- package/dist/src/utils/getPty.js.map +1 -0
- package/dist/src/utils/gitIgnoreParser.d.ts +19 -0
- package/dist/src/utils/gitIgnoreParser.js +169 -0
- package/dist/src/utils/gitIgnoreParser.js.map +1 -0
- package/dist/src/utils/gitIgnoreParser.test.d.ts +6 -0
- package/dist/src/utils/gitIgnoreParser.test.js +243 -0
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -0
- package/dist/src/utils/gitUtils.d.ts +17 -0
- package/dist/src/utils/gitUtils.js +61 -0
- package/dist/src/utils/gitUtils.js.map +1 -0
- package/dist/src/utils/googleErrors.d.ts +104 -0
- package/dist/src/utils/googleErrors.js +165 -0
- package/dist/src/utils/googleErrors.js.map +1 -0
- package/dist/src/utils/googleErrors.test.d.ts +6 -0
- package/dist/src/utils/googleErrors.test.js +309 -0
- package/dist/src/utils/googleErrors.test.js.map +1 -0
- package/dist/src/utils/googleQuotaErrors.d.ts +51 -0
- package/dist/src/utils/googleQuotaErrors.js +250 -0
- package/dist/src/utils/googleQuotaErrors.js.map +1 -0
- package/dist/src/utils/googleQuotaErrors.test.d.ts +6 -0
- package/dist/src/utils/googleQuotaErrors.test.js +548 -0
- package/dist/src/utils/googleQuotaErrors.test.js.map +1 -0
- package/dist/src/utils/httpErrors.d.ts +18 -0
- package/dist/src/utils/httpErrors.js +36 -0
- package/dist/src/utils/httpErrors.js.map +1 -0
- package/dist/src/utils/ignorePatterns.d.ts +103 -0
- package/dist/src/utils/ignorePatterns.js +220 -0
- package/dist/src/utils/ignorePatterns.js.map +1 -0
- package/dist/src/utils/ignorePatterns.test.d.ts +6 -0
- package/dist/src/utils/ignorePatterns.test.js +246 -0
- package/dist/src/utils/ignorePatterns.test.js.map +1 -0
- package/dist/src/utils/installationManager.d.ts +16 -0
- package/dist/src/utils/installationManager.js +51 -0
- package/dist/src/utils/installationManager.js.map +1 -0
- package/dist/src/utils/installationManager.test.d.ts +6 -0
- package/dist/src/utils/installationManager.test.js +93 -0
- package/dist/src/utils/installationManager.test.js.map +1 -0
- package/dist/src/utils/language-detection.d.ts +6 -0
- package/dist/src/utils/language-detection.js +101 -0
- package/dist/src/utils/language-detection.js.map +1 -0
- package/dist/src/utils/llm-edit-fixer.d.ts +26 -0
- package/dist/src/utils/llm-edit-fixer.js +152 -0
- package/dist/src/utils/llm-edit-fixer.js.map +1 -0
- package/dist/src/utils/llm-edit-fixer.test.d.ts +6 -0
- package/dist/src/utils/llm-edit-fixer.test.js +223 -0
- package/dist/src/utils/llm-edit-fixer.test.js.map +1 -0
- package/dist/src/utils/llmUtils.d.ts +38 -0
- package/dist/src/utils/llmUtils.js +64 -0
- package/dist/src/utils/llmUtils.js.map +1 -0
- package/dist/src/utils/llmUtils.test.d.ts +6 -0
- package/dist/src/utils/llmUtils.test.js +196 -0
- package/dist/src/utils/llmUtils.test.js.map +1 -0
- package/dist/src/utils/memoryDiscovery.d.ts +40 -0
- package/dist/src/utils/memoryDiscovery.js +421 -0
- package/dist/src/utils/memoryDiscovery.js.map +1 -0
- package/dist/src/utils/memoryDiscovery.test.d.ts +6 -0
- package/dist/src/utils/memoryDiscovery.test.js +542 -0
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -0
- package/dist/src/utils/memoryImportProcessor.d.ts +42 -0
- package/dist/src/utils/memoryImportProcessor.js +273 -0
- package/dist/src/utils/memoryImportProcessor.js.map +1 -0
- package/dist/src/utils/memoryImportProcessor.test.d.ts +6 -0
- package/dist/src/utils/memoryImportProcessor.test.js +581 -0
- package/dist/src/utils/memoryImportProcessor.test.js.map +1 -0
- package/dist/src/utils/messageInspectors.d.ts +16 -0
- package/dist/src/utils/messageInspectors.js +24 -0
- package/dist/src/utils/messageInspectors.js.map +1 -0
- package/dist/src/utils/nextSpeakerChecker.d.ts +12 -0
- package/dist/src/utils/nextSpeakerChecker.js +97 -0
- package/dist/src/utils/nextSpeakerChecker.js.map +1 -0
- package/dist/src/utils/nextSpeakerChecker.test.d.ts +6 -0
- package/dist/src/utils/nextSpeakerChecker.test.js +191 -0
- package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -0
- package/dist/src/utils/package.d.ts +26 -0
- package/dist/src/utils/package.js +28 -0
- package/dist/src/utils/package.js.map +1 -0
- package/dist/src/utils/partUtils.d.ts +76 -0
- package/dist/src/utils/partUtils.js +237 -0
- package/dist/src/utils/partUtils.js.map +1 -0
- package/dist/src/utils/partUtils.test.d.ts +6 -0
- package/dist/src/utils/partUtils.test.js +397 -0
- package/dist/src/utils/partUtils.test.js.map +1 -0
- package/dist/src/utils/pathCorrector.d.ts +25 -0
- package/dist/src/utils/pathCorrector.js +43 -0
- package/dist/src/utils/pathCorrector.js.map +1 -0
- package/dist/src/utils/pathCorrector.test.d.ts +6 -0
- package/dist/src/utils/pathCorrector.test.js +87 -0
- package/dist/src/utils/pathCorrector.test.js.map +1 -0
- package/dist/src/utils/pathReader.d.ts +17 -0
- package/dist/src/utils/pathReader.js +92 -0
- package/dist/src/utils/pathReader.js.map +1 -0
- package/dist/src/utils/pathReader.test.d.ts +6 -0
- package/dist/src/utils/pathReader.test.js +406 -0
- package/dist/src/utils/pathReader.test.js.map +1 -0
- package/dist/src/utils/paths.d.ts +78 -0
- package/dist/src/utils/paths.js +311 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/dist/src/utils/paths.test.d.ts +6 -0
- package/dist/src/utils/paths.test.js +402 -0
- package/dist/src/utils/paths.test.js.map +1 -0
- package/dist/src/utils/promptIdContext.d.ts +13 -0
- package/dist/src/utils/promptIdContext.js +23 -0
- package/dist/src/utils/promptIdContext.js.map +1 -0
- package/dist/src/utils/quotaErrorDetection.d.ts +16 -0
- package/dist/src/utils/quotaErrorDetection.js +19 -0
- package/dist/src/utils/quotaErrorDetection.js.map +1 -0
- package/dist/src/utils/retry.d.ts +43 -0
- package/dist/src/utils/retry.js +337 -0
- package/dist/src/utils/retry.js.map +1 -0
- package/dist/src/utils/retry.test.d.ts +6 -0
- package/dist/src/utils/retry.test.js +548 -0
- package/dist/src/utils/retry.test.js.map +1 -0
- package/dist/src/utils/retry_llm_error.test.d.ts +6 -0
- package/dist/src/utils/retry_llm_error.test.js +280 -0
- package/dist/src/utils/retry_llm_error.test.js.map +1 -0
- package/dist/src/utils/safeJsonStringify.d.ts +13 -0
- package/dist/src/utils/safeJsonStringify.js +49 -0
- package/dist/src/utils/safeJsonStringify.js.map +1 -0
- package/dist/src/utils/safeJsonStringify.test.d.ts +6 -0
- package/dist/src/utils/safeJsonStringify.test.js +61 -0
- package/dist/src/utils/safeJsonStringify.test.js.map +1 -0
- package/dist/src/utils/schemaValidator.d.ts +21 -0
- package/dist/src/utils/schemaValidator.js +59 -0
- package/dist/src/utils/schemaValidator.js.map +1 -0
- package/dist/src/utils/schemaValidator.test.d.ts +6 -0
- package/dist/src/utils/schemaValidator.test.js +113 -0
- package/dist/src/utils/schemaValidator.test.js.map +1 -0
- package/dist/src/utils/secure-browser-launcher.d.ts +23 -0
- package/dist/src/utils/secure-browser-launcher.js +165 -0
- package/dist/src/utils/secure-browser-launcher.js.map +1 -0
- package/dist/src/utils/secure-browser-launcher.test.d.ts +6 -0
- package/dist/src/utils/secure-browser-launcher.test.js +149 -0
- package/dist/src/utils/secure-browser-launcher.test.js.map +1 -0
- package/dist/src/utils/security.d.ts +16 -0
- package/dist/src/utils/security.js +88 -0
- package/dist/src/utils/security.js.map +1 -0
- package/dist/src/utils/security.test.d.ts +1 -0
- package/dist/src/utils/security.test.js +121 -0
- package/dist/src/utils/security.test.js.map +1 -0
- package/dist/src/utils/session.d.ts +6 -0
- package/dist/src/utils/session.js +8 -0
- package/dist/src/utils/session.js.map +1 -0
- package/dist/src/utils/shell-utils.d.ts +118 -0
- package/dist/src/utils/shell-utils.integration.test.d.ts +1 -0
- package/dist/src/utils/shell-utils.integration.test.js +58 -0
- package/dist/src/utils/shell-utils.integration.test.js.map +1 -0
- package/dist/src/utils/shell-utils.js +708 -0
- package/dist/src/utils/shell-utils.js.map +1 -0
- package/dist/src/utils/shell-utils.test.d.ts +6 -0
- package/dist/src/utils/shell-utils.test.js +437 -0
- package/dist/src/utils/shell-utils.test.js.map +1 -0
- package/dist/src/utils/stdio.d.ts +32 -0
- package/dist/src/utils/stdio.js +85 -0
- package/dist/src/utils/stdio.js.map +1 -0
- package/dist/src/utils/stdio.test.d.ts +6 -0
- package/dist/src/utils/stdio.test.js +47 -0
- package/dist/src/utils/stdio.test.js.map +1 -0
- package/dist/src/utils/summarizer.d.ts +27 -0
- package/dist/src/utils/summarizer.js +50 -0
- package/dist/src/utils/summarizer.js.map +1 -0
- package/dist/src/utils/summarizer.test.d.ts +6 -0
- package/dist/src/utils/summarizer.test.js +152 -0
- package/dist/src/utils/summarizer.test.js.map +1 -0
- package/dist/src/utils/systemEncoding.d.ts +40 -0
- package/dist/src/utils/systemEncoding.js +150 -0
- package/dist/src/utils/systemEncoding.js.map +1 -0
- package/dist/src/utils/systemEncoding.test.d.ts +6 -0
- package/dist/src/utils/systemEncoding.test.js +369 -0
- package/dist/src/utils/systemEncoding.test.js.map +1 -0
- package/dist/src/utils/terminal.d.ts +18 -0
- package/dist/src/utils/terminal.js +50 -0
- package/dist/src/utils/terminal.js.map +1 -0
- package/dist/src/utils/terminalSerializer.d.ts +25 -0
- package/dist/src/utils/terminalSerializer.js +432 -0
- package/dist/src/utils/terminalSerializer.js.map +1 -0
- package/dist/src/utils/terminalSerializer.test.d.ts +6 -0
- package/dist/src/utils/terminalSerializer.test.js +193 -0
- package/dist/src/utils/terminalSerializer.test.js.map +1 -0
- package/dist/src/utils/testUtils.d.ts +29 -0
- package/dist/src/utils/testUtils.js +70 -0
- package/dist/src/utils/testUtils.js.map +1 -0
- package/dist/src/utils/textUtils.d.ts +26 -0
- package/dist/src/utils/textUtils.js +55 -0
- package/dist/src/utils/textUtils.js.map +1 -0
- package/dist/src/utils/textUtils.test.d.ts +6 -0
- package/dist/src/utils/textUtils.test.js +76 -0
- package/dist/src/utils/textUtils.test.js.map +1 -0
- package/dist/src/utils/thoughtUtils.d.ts +21 -0
- package/dist/src/utils/thoughtUtils.js +39 -0
- package/dist/src/utils/thoughtUtils.js.map +1 -0
- package/dist/src/utils/thoughtUtils.test.d.ts +6 -0
- package/dist/src/utils/thoughtUtils.test.js +78 -0
- package/dist/src/utils/thoughtUtils.test.js.map +1 -0
- package/dist/src/utils/tokenCalculation.d.ts +33 -0
- package/dist/src/utils/tokenCalculation.js +145 -0
- package/dist/src/utils/tokenCalculation.js.map +1 -0
- package/dist/src/utils/tokenCalculation.test.d.ts +6 -0
- package/dist/src/utils/tokenCalculation.test.js +184 -0
- package/dist/src/utils/tokenCalculation.test.js.map +1 -0
- package/dist/src/utils/tool-utils.d.ts +28 -0
- package/dist/src/utils/tool-utils.js +96 -0
- package/dist/src/utils/tool-utils.js.map +1 -0
- package/dist/src/utils/tool-utils.test.d.ts +6 -0
- package/dist/src/utils/tool-utils.test.js +84 -0
- package/dist/src/utils/tool-utils.test.js.map +1 -0
- package/dist/src/utils/toolCallContext.d.ts +35 -0
- package/dist/src/utils/toolCallContext.js +29 -0
- package/dist/src/utils/toolCallContext.js.map +1 -0
- package/dist/src/utils/toolCallContext.test.d.ts +6 -0
- package/dist/src/utils/toolCallContext.test.js +68 -0
- package/dist/src/utils/toolCallContext.test.js.map +1 -0
- package/dist/src/utils/userAccountManager.d.ts +20 -0
- package/dist/src/utils/userAccountManager.js +115 -0
- package/dist/src/utils/userAccountManager.js.map +1 -0
- package/dist/src/utils/userAccountManager.test.d.ts +6 -0
- package/dist/src/utils/userAccountManager.test.js +225 -0
- package/dist/src/utils/userAccountManager.test.js.map +1 -0
- package/dist/src/utils/version.d.ts +6 -0
- package/dist/src/utils/version.js +15 -0
- package/dist/src/utils/version.js.map +1 -0
- package/dist/src/utils/version.test.d.ts +6 -0
- package/dist/src/utils/version.test.js +39 -0
- package/dist/src/utils/version.test.js.map +1 -0
- package/dist/src/utils/workspaceContext.d.ts +82 -0
- package/dist/src/utils/workspaceContext.js +192 -0
- package/dist/src/utils/workspaceContext.js.map +1 -0
- package/dist/src/utils/workspaceContext.test.d.ts +6 -0
- package/dist/src/utils/workspaceContext.test.js +374 -0
- package/dist/src/utils/workspaceContext.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1,2654 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
|
|
7
|
+
import { GeminiClient } from './client.js';
|
|
8
|
+
import { AuthType, } from './contentGenerator.js';
|
|
9
|
+
import { GeminiChat } from './geminiChat.js';
|
|
10
|
+
import { CompressionStatus, LlmEventType, Turn, } from './turn.js';
|
|
11
|
+
import { getCoreSystemPrompt } from './prompts.js';
|
|
12
|
+
import { DEFAULT_GEMINI_MODEL_AUTO } from '../config/models.js';
|
|
13
|
+
import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
|
|
14
|
+
import { setSimulate429 } from '../utils/testUtils.js';
|
|
15
|
+
import { tokenLimit } from './tokenLimits.js';
|
|
16
|
+
import { ideContextStore } from '../ide/ideContext.js';
|
|
17
|
+
import { uiTelemetryService } from '../telemetry/uiTelemetry.js';
|
|
18
|
+
import { ChatCompressionService } from '../services/chatCompressionService.js';
|
|
19
|
+
import { createAvailabilityServiceMock } from '../availability/testUtils.js';
|
|
20
|
+
import { ClearcutLogger } from '../telemetry/clearcut-logger/clearcut-logger.js';
|
|
21
|
+
import * as policyCatalog from '../availability/policyCatalog.js';
|
|
22
|
+
import { partToString } from '../utils/partUtils.js';
|
|
23
|
+
import { coreEvents } from '../utils/events.js';
|
|
24
|
+
// Mock fs module to prevent actual file system operations during tests
|
|
25
|
+
const mockFileSystem = new Map();
|
|
26
|
+
vi.mock('node:fs', () => {
|
|
27
|
+
const fsModule = {
|
|
28
|
+
mkdirSync: vi.fn(),
|
|
29
|
+
writeFileSync: vi.fn((path, data) => {
|
|
30
|
+
mockFileSystem.set(path, data);
|
|
31
|
+
}),
|
|
32
|
+
readFileSync: vi.fn((path) => {
|
|
33
|
+
if (mockFileSystem.has(path)) {
|
|
34
|
+
return mockFileSystem.get(path);
|
|
35
|
+
}
|
|
36
|
+
throw Object.assign(new Error('ENOENT: no such file or directory'), {
|
|
37
|
+
code: 'ENOENT',
|
|
38
|
+
});
|
|
39
|
+
}),
|
|
40
|
+
existsSync: vi.fn((path) => mockFileSystem.has(path)),
|
|
41
|
+
createWriteStream: vi.fn(() => ({
|
|
42
|
+
write: vi.fn(),
|
|
43
|
+
on: vi.fn(),
|
|
44
|
+
})),
|
|
45
|
+
};
|
|
46
|
+
return {
|
|
47
|
+
default: fsModule,
|
|
48
|
+
...fsModule,
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
const mockTurnRunFn = vi.fn();
|
|
52
|
+
vi.mock('./turn', async (importOriginal) => {
|
|
53
|
+
const actual = await importOriginal();
|
|
54
|
+
// Define a mock class that has the same shape as the real Turn
|
|
55
|
+
class MockTurn {
|
|
56
|
+
pendingToolCalls = [];
|
|
57
|
+
// The run method is a property that holds our mock function
|
|
58
|
+
run = mockTurnRunFn;
|
|
59
|
+
constructor() {
|
|
60
|
+
// The constructor can be empty or do some mock setup
|
|
61
|
+
}
|
|
62
|
+
getResponseText = vi.fn().mockReturnValue('Mock Response');
|
|
63
|
+
}
|
|
64
|
+
// Export the mock class as 'Turn'
|
|
65
|
+
return {
|
|
66
|
+
...actual,
|
|
67
|
+
Turn: MockTurn,
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
vi.mock('../config/config.js');
|
|
71
|
+
vi.mock('./prompts');
|
|
72
|
+
vi.mock('../utils/getFolderStructure', () => ({
|
|
73
|
+
getFolderStructure: vi.fn().mockResolvedValue('Mock Folder Structure'),
|
|
74
|
+
}));
|
|
75
|
+
vi.mock('../utils/errorReporting', () => ({ reportError: vi.fn() }));
|
|
76
|
+
vi.mock('../utils/nextSpeakerChecker', () => ({
|
|
77
|
+
checkNextSpeaker: vi.fn().mockResolvedValue(null),
|
|
78
|
+
}));
|
|
79
|
+
vi.mock('../utils/generateContentResponseUtilities', () => ({
|
|
80
|
+
getResponseText: (result) => result.candidates?.[0]?.content?.parts?.map((part) => part.text).join('') ||
|
|
81
|
+
undefined,
|
|
82
|
+
}));
|
|
83
|
+
vi.mock('../telemetry/index.js', () => ({
|
|
84
|
+
logApiRequest: vi.fn(),
|
|
85
|
+
logApiResponse: vi.fn(),
|
|
86
|
+
logApiError: vi.fn(),
|
|
87
|
+
}));
|
|
88
|
+
vi.mock('../ide/ideContext.js');
|
|
89
|
+
vi.mock('../telemetry/uiTelemetry.js', () => ({
|
|
90
|
+
uiTelemetryService: {
|
|
91
|
+
setLastPromptTokenCount: vi.fn(),
|
|
92
|
+
getLastPromptTokenCount: vi.fn(),
|
|
93
|
+
},
|
|
94
|
+
}));
|
|
95
|
+
vi.mock('../hooks/hookSystem.js');
|
|
96
|
+
const mockHookSystem = {
|
|
97
|
+
fireBeforeAgentEvent: vi.fn().mockResolvedValue(undefined),
|
|
98
|
+
fireAfterAgentEvent: vi.fn().mockResolvedValue(undefined),
|
|
99
|
+
firePreCompressEvent: vi.fn().mockResolvedValue(undefined),
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Array.fromAsync ponyfill, which will be available in es 2024.
|
|
103
|
+
*
|
|
104
|
+
* Buffers an async generator into an array and returns the result.
|
|
105
|
+
*/
|
|
106
|
+
async function fromAsync(promise) {
|
|
107
|
+
const results = [];
|
|
108
|
+
for await (const result of promise) {
|
|
109
|
+
results.push(result);
|
|
110
|
+
}
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
describe('Gemini Client (client.ts)', () => {
|
|
114
|
+
let mockContentGenerator;
|
|
115
|
+
let mockConfig;
|
|
116
|
+
let client;
|
|
117
|
+
let mockGenerateContentFn;
|
|
118
|
+
let mockRouterService;
|
|
119
|
+
beforeEach(async () => {
|
|
120
|
+
vi.resetAllMocks();
|
|
121
|
+
ClearcutLogger.clearInstance();
|
|
122
|
+
vi.mocked(uiTelemetryService.setLastPromptTokenCount).mockClear();
|
|
123
|
+
mockGenerateContentFn = vi.fn().mockResolvedValue({
|
|
124
|
+
candidates: [{ content: { parts: [{ text: '{"key": "value"}' }] } }],
|
|
125
|
+
});
|
|
126
|
+
// Disable 429 simulation for tests
|
|
127
|
+
setSimulate429(false);
|
|
128
|
+
mockRouterService = {
|
|
129
|
+
route: vi
|
|
130
|
+
.fn()
|
|
131
|
+
.mockResolvedValue({ model: 'default-routed-model', reason: 'test' }),
|
|
132
|
+
};
|
|
133
|
+
mockContentGenerator = {
|
|
134
|
+
generateContent: mockGenerateContentFn,
|
|
135
|
+
generateContentStream: vi.fn(),
|
|
136
|
+
batchEmbedContents: vi.fn(),
|
|
137
|
+
countTokens: vi.fn().mockResolvedValue({ totalTokens: 100 }),
|
|
138
|
+
};
|
|
139
|
+
// Because the GeminiClient constructor kicks off an async process (startChat)
|
|
140
|
+
// that depends on a fully-formed Config object, we need to mock the
|
|
141
|
+
// entire implementation of Config for these tests.
|
|
142
|
+
const mockToolRegistry = {
|
|
143
|
+
getFunctionDeclarations: vi.fn().mockReturnValue([]),
|
|
144
|
+
getTool: vi.fn().mockReturnValue(null),
|
|
145
|
+
};
|
|
146
|
+
const fileService = new FileDiscoveryService('/test/dir');
|
|
147
|
+
const contentGeneratorConfig = {
|
|
148
|
+
apiKey: 'test-key',
|
|
149
|
+
vertexai: false,
|
|
150
|
+
authType: AuthType.USE_GEMINI,
|
|
151
|
+
};
|
|
152
|
+
mockConfig = {
|
|
153
|
+
getContentGeneratorConfig: vi
|
|
154
|
+
.fn()
|
|
155
|
+
.mockReturnValue(contentGeneratorConfig),
|
|
156
|
+
getToolRegistry: vi.fn().mockReturnValue(mockToolRegistry),
|
|
157
|
+
getModel: vi.fn().mockReturnValue('test-model'),
|
|
158
|
+
getUserTier: vi.fn().mockReturnValue(undefined),
|
|
159
|
+
getEmbeddingModel: vi.fn().mockReturnValue('test-embedding-model'),
|
|
160
|
+
getApiKey: vi.fn().mockReturnValue('test-key'),
|
|
161
|
+
getVertexAI: vi.fn().mockReturnValue(false),
|
|
162
|
+
getUserAgent: vi.fn().mockReturnValue('test-agent'),
|
|
163
|
+
getUserMemory: vi.fn().mockReturnValue(''),
|
|
164
|
+
getGlobalMemory: vi.fn().mockReturnValue(''),
|
|
165
|
+
getEnvironmentMemory: vi.fn().mockReturnValue(''),
|
|
166
|
+
isJitContextEnabled: vi.fn().mockReturnValue(false),
|
|
167
|
+
getSessionId: vi.fn().mockReturnValue('test-session-id'),
|
|
168
|
+
getProxy: vi.fn().mockReturnValue(undefined),
|
|
169
|
+
getWorkingDir: vi.fn().mockReturnValue('/test/dir'),
|
|
170
|
+
getFileService: vi.fn().mockReturnValue(fileService),
|
|
171
|
+
getMaxSessionTurns: vi.fn().mockReturnValue(0),
|
|
172
|
+
getQuotaErrorOccurred: vi.fn().mockReturnValue(false),
|
|
173
|
+
setQuotaErrorOccurred: vi.fn(),
|
|
174
|
+
getNoBrowser: vi.fn().mockReturnValue(false),
|
|
175
|
+
getUsageStatisticsEnabled: vi.fn().mockReturnValue(true),
|
|
176
|
+
getIdeModeFeature: vi.fn().mockReturnValue(false),
|
|
177
|
+
getIdeMode: vi.fn().mockReturnValue(true),
|
|
178
|
+
getDebugMode: vi.fn().mockReturnValue(false),
|
|
179
|
+
getPreviewFeatures: vi.fn().mockReturnValue(false),
|
|
180
|
+
getWorkspaceContext: vi.fn().mockReturnValue({
|
|
181
|
+
getDirectories: vi.fn().mockReturnValue(['/test/dir']),
|
|
182
|
+
}),
|
|
183
|
+
getGeminiClient: vi.fn(),
|
|
184
|
+
getModelRouterService: vi
|
|
185
|
+
.fn()
|
|
186
|
+
.mockReturnValue(mockRouterService),
|
|
187
|
+
getMessageBus: vi.fn().mockReturnValue(undefined),
|
|
188
|
+
getEnableHooks: vi.fn().mockReturnValue(false),
|
|
189
|
+
getChatCompression: vi.fn().mockReturnValue(undefined),
|
|
190
|
+
getCompressionThreshold: vi.fn().mockReturnValue(undefined),
|
|
191
|
+
getSkipNextSpeakerCheck: vi.fn().mockReturnValue(false),
|
|
192
|
+
getShowModelInfoInChat: vi.fn().mockReturnValue(false),
|
|
193
|
+
getContinueOnFailedApiCall: vi.fn(),
|
|
194
|
+
getProjectRoot: vi.fn().mockReturnValue('/test/project/root'),
|
|
195
|
+
storage: {
|
|
196
|
+
getProjectTempDir: vi.fn().mockReturnValue('/test/temp'),
|
|
197
|
+
},
|
|
198
|
+
getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator),
|
|
199
|
+
getBaseLlmClient: vi.fn().mockReturnValue({
|
|
200
|
+
generateJson: vi.fn().mockResolvedValue({
|
|
201
|
+
next_speaker: 'user',
|
|
202
|
+
reasoning: 'test',
|
|
203
|
+
}),
|
|
204
|
+
}),
|
|
205
|
+
modelConfigService: {
|
|
206
|
+
getResolvedConfig(modelConfigKey) {
|
|
207
|
+
return {
|
|
208
|
+
model: modelConfigKey.model,
|
|
209
|
+
generateContentConfig: {
|
|
210
|
+
temperature: 0,
|
|
211
|
+
topP: 1,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
isInteractive: vi.fn().mockReturnValue(false),
|
|
217
|
+
getExperiments: () => { },
|
|
218
|
+
getActiveModel: vi.fn().mockReturnValue('test-model'),
|
|
219
|
+
setActiveModel: vi.fn(),
|
|
220
|
+
setModel: vi.fn(),
|
|
221
|
+
resetTurn: vi.fn(),
|
|
222
|
+
getModelAvailabilityService: vi
|
|
223
|
+
.fn()
|
|
224
|
+
.mockReturnValue(createAvailabilityServiceMock()),
|
|
225
|
+
};
|
|
226
|
+
mockConfig.getHookSystem = vi.fn().mockReturnValue(mockHookSystem);
|
|
227
|
+
client = new GeminiClient(mockConfig);
|
|
228
|
+
await client.initialize();
|
|
229
|
+
vi.mocked(mockConfig.getGeminiClient).mockReturnValue(client);
|
|
230
|
+
vi.mocked(uiTelemetryService.setLastPromptTokenCount).mockClear();
|
|
231
|
+
});
|
|
232
|
+
afterEach(() => {
|
|
233
|
+
client.dispose();
|
|
234
|
+
vi.restoreAllMocks();
|
|
235
|
+
});
|
|
236
|
+
describe('addHistory', () => {
|
|
237
|
+
it('should call chat.addHistory with the provided content', async () => {
|
|
238
|
+
const mockChat = {
|
|
239
|
+
addHistory: vi.fn(),
|
|
240
|
+
};
|
|
241
|
+
client['chat'] = mockChat;
|
|
242
|
+
const newContent = {
|
|
243
|
+
role: 'user',
|
|
244
|
+
parts: [{ text: 'New history item' }],
|
|
245
|
+
};
|
|
246
|
+
await client.addHistory(newContent);
|
|
247
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith(newContent);
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
describe('setHistory', () => {
|
|
251
|
+
it('should update telemetry token count when history is set', () => {
|
|
252
|
+
const history = [
|
|
253
|
+
{ role: 'user', parts: [{ text: 'some message' }] },
|
|
254
|
+
];
|
|
255
|
+
client.setHistory(history);
|
|
256
|
+
expect(uiTelemetryService.setLastPromptTokenCount).toHaveBeenCalled();
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
describe('resumeChat', () => {
|
|
260
|
+
it('should update telemetry token count when a chat is resumed', async () => {
|
|
261
|
+
const history = [
|
|
262
|
+
{ role: 'user', parts: [{ text: 'resumed message' }] },
|
|
263
|
+
];
|
|
264
|
+
await client.resumeChat(history);
|
|
265
|
+
expect(uiTelemetryService.setLastPromptTokenCount).toHaveBeenCalled();
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
describe('resetChat', () => {
|
|
269
|
+
it('should create a new chat session, clearing the old history', async () => {
|
|
270
|
+
// 1. Get the initial chat instance and add some history.
|
|
271
|
+
const initialChat = client.getChat();
|
|
272
|
+
const initialHistory = client.getHistory();
|
|
273
|
+
await client.addHistory({
|
|
274
|
+
role: 'user',
|
|
275
|
+
parts: [{ text: 'some old message' }],
|
|
276
|
+
});
|
|
277
|
+
const historyWithOldMessage = client.getHistory();
|
|
278
|
+
expect(historyWithOldMessage.length).toBeGreaterThan(initialHistory.length);
|
|
279
|
+
// 2. Call resetChat.
|
|
280
|
+
await client.resetChat();
|
|
281
|
+
// 3. Get the new chat instance and its history.
|
|
282
|
+
const newChat = client.getChat();
|
|
283
|
+
const newHistory = client.getHistory();
|
|
284
|
+
// 4. Assert that the chat instance is new and the history is reset.
|
|
285
|
+
expect(newChat).not.toBe(initialChat);
|
|
286
|
+
expect(newHistory.length).toBe(initialHistory.length);
|
|
287
|
+
expect(JSON.stringify(newHistory)).not.toContain('some old message');
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
describe('startChat', () => {
|
|
291
|
+
it('should include environment context when resuming a session', async () => {
|
|
292
|
+
const extraHistory = [
|
|
293
|
+
{ role: 'user', parts: [{ text: 'Old message' }] },
|
|
294
|
+
{ role: 'model', parts: [{ text: 'Old response' }] },
|
|
295
|
+
];
|
|
296
|
+
const chat = await client.startChat(extraHistory);
|
|
297
|
+
const history = chat.getHistory();
|
|
298
|
+
// The first message should be the environment context
|
|
299
|
+
expect(history[0].role).toBe('user');
|
|
300
|
+
expect(history[0].parts?.[0]?.text).toContain('This is the Gemini CLI');
|
|
301
|
+
expect(history[0].parts?.[0]?.text).toContain("The project's temporary directory is:");
|
|
302
|
+
// The subsequent messages should be the extra history
|
|
303
|
+
expect(history[1]).toEqual(extraHistory[0]);
|
|
304
|
+
expect(history[2]).toEqual(extraHistory[1]);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
describe('tryCompressChat', () => {
|
|
308
|
+
const mockGetHistory = vi.fn();
|
|
309
|
+
beforeEach(() => {
|
|
310
|
+
vi.mock('./tokenLimits', () => ({
|
|
311
|
+
tokenLimit: vi.fn(),
|
|
312
|
+
}));
|
|
313
|
+
client['chat'] = {
|
|
314
|
+
getHistory: mockGetHistory,
|
|
315
|
+
addHistory: vi.fn(),
|
|
316
|
+
setHistory: vi.fn(),
|
|
317
|
+
getLastPromptTokenCount: vi.fn(),
|
|
318
|
+
};
|
|
319
|
+
});
|
|
320
|
+
function setup({ chatHistory = [
|
|
321
|
+
{ role: 'user', parts: [{ text: 'Long conversation' }] },
|
|
322
|
+
{ role: 'model', parts: [{ text: 'Long response' }] },
|
|
323
|
+
], originalTokenCount = 1000, newTokenCount = 500, compressionStatus = CompressionStatus.COMPRESSED, } = {}) {
|
|
324
|
+
const mockOriginalChat = {
|
|
325
|
+
getHistory: vi.fn((_curated) => chatHistory),
|
|
326
|
+
setHistory: vi.fn(),
|
|
327
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(originalTokenCount),
|
|
328
|
+
getChatRecordingService: vi.fn().mockReturnValue({
|
|
329
|
+
getConversation: vi.fn().mockReturnValue(null),
|
|
330
|
+
getConversationFilePath: vi.fn().mockReturnValue(null),
|
|
331
|
+
}),
|
|
332
|
+
};
|
|
333
|
+
client['chat'] = mockOriginalChat;
|
|
334
|
+
vi.mocked(uiTelemetryService.getLastPromptTokenCount).mockReturnValue(originalTokenCount);
|
|
335
|
+
const newHistory = [
|
|
336
|
+
{ role: 'user', parts: [{ text: 'Summary' }] },
|
|
337
|
+
{ role: 'model', parts: [{ text: 'Got it' }] },
|
|
338
|
+
];
|
|
339
|
+
vi.spyOn(ChatCompressionService.prototype, 'compress').mockResolvedValue({
|
|
340
|
+
newHistory: compressionStatus === CompressionStatus.COMPRESSED
|
|
341
|
+
? newHistory
|
|
342
|
+
: null,
|
|
343
|
+
info: {
|
|
344
|
+
originalTokenCount,
|
|
345
|
+
newTokenCount,
|
|
346
|
+
compressionStatus,
|
|
347
|
+
},
|
|
348
|
+
});
|
|
349
|
+
const mockNewChat = {
|
|
350
|
+
getHistory: vi.fn().mockReturnValue(newHistory),
|
|
351
|
+
setHistory: vi.fn(),
|
|
352
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(newTokenCount),
|
|
353
|
+
};
|
|
354
|
+
client['startChat'] = vi
|
|
355
|
+
.fn()
|
|
356
|
+
.mockResolvedValue(mockNewChat);
|
|
357
|
+
return {
|
|
358
|
+
client,
|
|
359
|
+
mockOriginalChat,
|
|
360
|
+
mockNewChat,
|
|
361
|
+
estimatedNewTokenCount: newTokenCount,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
describe('when compression inflates the token count', () => {
|
|
365
|
+
it('allows compression to be forced/manual after a failure', async () => {
|
|
366
|
+
// Call 1 (Fails): Setup with inflated tokens
|
|
367
|
+
setup({
|
|
368
|
+
originalTokenCount: 100,
|
|
369
|
+
newTokenCount: 200,
|
|
370
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
|
|
371
|
+
});
|
|
372
|
+
await client.tryCompressChat('prompt-id-4', false); // Fails
|
|
373
|
+
// Call 2 (Forced): Re-setup with compressed tokens
|
|
374
|
+
const { estimatedNewTokenCount: compressedTokenCount } = setup({
|
|
375
|
+
originalTokenCount: 100,
|
|
376
|
+
newTokenCount: 50,
|
|
377
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
378
|
+
});
|
|
379
|
+
const result = await client.tryCompressChat('prompt-id-4', true); // Forced
|
|
380
|
+
expect(result).toEqual({
|
|
381
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
382
|
+
newTokenCount: compressedTokenCount,
|
|
383
|
+
originalTokenCount: 100,
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
it('yields the result even if the compression inflated the tokens', async () => {
|
|
387
|
+
const { client, estimatedNewTokenCount } = setup({
|
|
388
|
+
originalTokenCount: 100,
|
|
389
|
+
newTokenCount: 200,
|
|
390
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
|
|
391
|
+
});
|
|
392
|
+
const result = await client.tryCompressChat('prompt-id-4', false);
|
|
393
|
+
expect(result).toEqual({
|
|
394
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
|
|
395
|
+
newTokenCount: estimatedNewTokenCount,
|
|
396
|
+
originalTokenCount: 100,
|
|
397
|
+
});
|
|
398
|
+
// IMPORTANT: The change in client.ts means setLastPromptTokenCount is NOT called on failure
|
|
399
|
+
expect(uiTelemetryService.setLastPromptTokenCount).not.toHaveBeenCalled();
|
|
400
|
+
});
|
|
401
|
+
it('does not manipulate the source chat', async () => {
|
|
402
|
+
const { client, mockOriginalChat } = setup({
|
|
403
|
+
originalTokenCount: 100,
|
|
404
|
+
newTokenCount: 200,
|
|
405
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
|
|
406
|
+
});
|
|
407
|
+
await client.tryCompressChat('prompt-id-4', false);
|
|
408
|
+
// On failure, the chat should NOT be replaced
|
|
409
|
+
expect(client['chat']).toBe(mockOriginalChat);
|
|
410
|
+
});
|
|
411
|
+
it.skip('will not attempt to compress context after a failure', async () => {
|
|
412
|
+
const { client } = setup({
|
|
413
|
+
originalTokenCount: 100,
|
|
414
|
+
newTokenCount: 200,
|
|
415
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
|
|
416
|
+
});
|
|
417
|
+
await client.tryCompressChat('prompt-id-4', false); // This fails and sets hasFailedCompressionAttempt = true
|
|
418
|
+
// Mock the next call to return NOOP
|
|
419
|
+
vi.mocked(ChatCompressionService.prototype.compress).mockResolvedValueOnce({
|
|
420
|
+
newHistory: null,
|
|
421
|
+
info: {
|
|
422
|
+
originalTokenCount: 0,
|
|
423
|
+
newTokenCount: 0,
|
|
424
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
// This call should now be a NOOP
|
|
428
|
+
const result = await client.tryCompressChat('prompt-id-5', false);
|
|
429
|
+
expect(result.compressionStatus).toBe(CompressionStatus.NOOP);
|
|
430
|
+
expect(ChatCompressionService.prototype.compress).toHaveBeenCalledTimes(2);
|
|
431
|
+
expect(ChatCompressionService.prototype.compress).toHaveBeenLastCalledWith(expect.anything(), 'prompt-id-5', false, expect.anything(), expect.anything(), true);
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
it('should correctly latch hasFailedCompressionAttempt flag', async () => {
|
|
435
|
+
// 1. Setup: Call setup() from this test file
|
|
436
|
+
// This helper function mocks the compression service for us.
|
|
437
|
+
const { client } = setup({
|
|
438
|
+
originalTokenCount: 100,
|
|
439
|
+
newTokenCount: 200, // Inflated
|
|
440
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
|
|
441
|
+
});
|
|
442
|
+
// 2. Test Step 1: Trigger a non-forced failure
|
|
443
|
+
await client.tryCompressChat('prompt-1', false); // force = false
|
|
444
|
+
// 3. Assert Step 1: Check that the flag became true
|
|
445
|
+
// 3. Assert Step 1: Check that the flag became true
|
|
446
|
+
expect(client
|
|
447
|
+
.hasFailedCompressionAttempt).toBe(true);
|
|
448
|
+
// 4. Test Step 2: Trigger a forced failure
|
|
449
|
+
await client.tryCompressChat('prompt-2', true); // force = true
|
|
450
|
+
// 5. Assert Step 2: Check that the flag REMAINS true
|
|
451
|
+
// 5. Assert Step 2: Check that the flag REMAINS true
|
|
452
|
+
expect(client
|
|
453
|
+
.hasFailedCompressionAttempt).toBe(true);
|
|
454
|
+
});
|
|
455
|
+
it('should not trigger summarization if token count is below threshold', async () => {
|
|
456
|
+
const MOCKED_TOKEN_LIMIT = 1000;
|
|
457
|
+
const originalTokenCount = MOCKED_TOKEN_LIMIT * 0.699;
|
|
458
|
+
vi.spyOn(ChatCompressionService.prototype, 'compress').mockResolvedValue({
|
|
459
|
+
newHistory: null,
|
|
460
|
+
info: {
|
|
461
|
+
originalTokenCount,
|
|
462
|
+
newTokenCount: originalTokenCount,
|
|
463
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
const initialChat = client.getChat();
|
|
467
|
+
const result = await client.tryCompressChat('prompt-id-2', false);
|
|
468
|
+
const newChat = client.getChat();
|
|
469
|
+
expect(result).toEqual({
|
|
470
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
471
|
+
newTokenCount: originalTokenCount,
|
|
472
|
+
originalTokenCount,
|
|
473
|
+
});
|
|
474
|
+
expect(newChat).toBe(initialChat);
|
|
475
|
+
});
|
|
476
|
+
it('should return NOOP if history is too short to compress', async () => {
|
|
477
|
+
const { client } = setup({
|
|
478
|
+
chatHistory: [{ role: 'user', parts: [{ text: 'hi' }] }],
|
|
479
|
+
originalTokenCount: 50,
|
|
480
|
+
newTokenCount: 50,
|
|
481
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
482
|
+
});
|
|
483
|
+
const result = await client.tryCompressChat('prompt-id-noop', false);
|
|
484
|
+
expect(result).toEqual({
|
|
485
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
486
|
+
originalTokenCount: 50,
|
|
487
|
+
newTokenCount: 50,
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
it('should resume the session file when compression succeeds', async () => {
|
|
491
|
+
const { client, mockOriginalChat } = setup({
|
|
492
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
493
|
+
});
|
|
494
|
+
const mockConversation = { some: 'conversation' };
|
|
495
|
+
const mockFilePath = '/tmp/session.json';
|
|
496
|
+
// Override the mock to return values
|
|
497
|
+
const mockRecordingService = {
|
|
498
|
+
getConversation: vi.fn().mockReturnValue(mockConversation),
|
|
499
|
+
getConversationFilePath: vi.fn().mockReturnValue(mockFilePath),
|
|
500
|
+
};
|
|
501
|
+
vi.mocked(mockOriginalChat.getChatRecordingService).mockReturnValue(mockRecordingService);
|
|
502
|
+
await client.tryCompressChat('prompt-id', false);
|
|
503
|
+
expect(client['startChat']).toHaveBeenCalledWith(expect.anything(), // newHistory
|
|
504
|
+
{
|
|
505
|
+
conversation: mockConversation,
|
|
506
|
+
filePath: mockFilePath,
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
describe('sendMessageStream', () => {
|
|
511
|
+
it('emits a compression event when the context was automatically compressed', async () => {
|
|
512
|
+
// Arrange
|
|
513
|
+
mockTurnRunFn.mockReturnValue((async function* () {
|
|
514
|
+
yield { type: 'content', value: 'Hello' };
|
|
515
|
+
})());
|
|
516
|
+
const compressionInfo = {
|
|
517
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
518
|
+
originalTokenCount: 1000,
|
|
519
|
+
newTokenCount: 500,
|
|
520
|
+
};
|
|
521
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValueOnce(compressionInfo);
|
|
522
|
+
// Act
|
|
523
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-1');
|
|
524
|
+
const events = await fromAsync(stream);
|
|
525
|
+
// Assert
|
|
526
|
+
expect(events).toContainEqual({
|
|
527
|
+
type: LlmEventType.ChatCompressed,
|
|
528
|
+
originalTokens: compressionInfo.originalTokenCount,
|
|
529
|
+
compressedTokens: compressionInfo.newTokenCount,
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
it('does not emit ModelInfo event if signal is aborted', async () => {
|
|
533
|
+
// Arrange
|
|
534
|
+
mockTurnRunFn.mockReturnValue((async function* () {
|
|
535
|
+
yield { type: 'content', value: 'Hello' };
|
|
536
|
+
})());
|
|
537
|
+
const controller = new AbortController();
|
|
538
|
+
controller.abort();
|
|
539
|
+
// Act
|
|
540
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], controller.signal, 'prompt-id-1');
|
|
541
|
+
const events = await fromAsync(stream);
|
|
542
|
+
// Assert
|
|
543
|
+
expect(events).not.toContainEqual(expect.objectContaining({
|
|
544
|
+
type: LlmEventType.ModelInfo,
|
|
545
|
+
}));
|
|
546
|
+
});
|
|
547
|
+
it.each([
|
|
548
|
+
{
|
|
549
|
+
compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
|
|
550
|
+
},
|
|
551
|
+
{ compressionStatus: CompressionStatus.NOOP },
|
|
552
|
+
])('does not emit a compression event when the status is $compressionStatus', async ({ compressionStatus }) => {
|
|
553
|
+
// Arrange
|
|
554
|
+
const mockStream = (async function* () {
|
|
555
|
+
yield { type: 'content', value: 'Hello' };
|
|
556
|
+
})();
|
|
557
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
558
|
+
const compressionInfo = {
|
|
559
|
+
compressionStatus,
|
|
560
|
+
originalTokenCount: 1000,
|
|
561
|
+
newTokenCount: 500,
|
|
562
|
+
};
|
|
563
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValueOnce(compressionInfo);
|
|
564
|
+
// Act
|
|
565
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-1');
|
|
566
|
+
const events = await fromAsync(stream);
|
|
567
|
+
// Assert
|
|
568
|
+
expect(events).not.toContainEqual(expect.objectContaining({
|
|
569
|
+
type: LlmEventType.ChatCompressed,
|
|
570
|
+
}));
|
|
571
|
+
});
|
|
572
|
+
it('should include editor context when ideMode is enabled', async () => {
|
|
573
|
+
// Arrange
|
|
574
|
+
vi.mocked(ideContextStore.get).mockReturnValue({
|
|
575
|
+
workspaceState: {
|
|
576
|
+
openFiles: [
|
|
577
|
+
{
|
|
578
|
+
path: '/path/to/active/file.ts',
|
|
579
|
+
timestamp: Date.now(),
|
|
580
|
+
isActive: true,
|
|
581
|
+
selectedText: 'hello',
|
|
582
|
+
cursor: { line: 5, character: 10 },
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
path: '/path/to/recent/file1.ts',
|
|
586
|
+
timestamp: Date.now(),
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
path: '/path/to/recent/file2.ts',
|
|
590
|
+
timestamp: Date.now(),
|
|
591
|
+
},
|
|
592
|
+
],
|
|
593
|
+
},
|
|
594
|
+
});
|
|
595
|
+
vi.mocked(mockConfig.getIdeMode).mockReturnValue(true);
|
|
596
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
597
|
+
originalTokenCount: 0,
|
|
598
|
+
newTokenCount: 0,
|
|
599
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
600
|
+
});
|
|
601
|
+
mockTurnRunFn.mockReturnValue((async function* () {
|
|
602
|
+
yield { type: 'content', value: 'Hello' };
|
|
603
|
+
})());
|
|
604
|
+
const mockChat = {
|
|
605
|
+
addHistory: vi.fn(),
|
|
606
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
607
|
+
getLastPromptTokenCount: vi.fn(),
|
|
608
|
+
};
|
|
609
|
+
client['chat'] = mockChat;
|
|
610
|
+
const initialRequest = [{ text: 'Hi' }];
|
|
611
|
+
// Act
|
|
612
|
+
const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
|
|
613
|
+
for await (const _ of stream) {
|
|
614
|
+
// consume stream
|
|
615
|
+
}
|
|
616
|
+
// Assert
|
|
617
|
+
expect(ideContextStore.get).toHaveBeenCalled();
|
|
618
|
+
const expectedContext = `
|
|
619
|
+
Here is the user's editor context as a JSON object. This is for your information only.
|
|
620
|
+
\`\`\`json
|
|
621
|
+
${JSON.stringify({
|
|
622
|
+
activeFile: {
|
|
623
|
+
path: '/path/to/active/file.ts',
|
|
624
|
+
cursor: {
|
|
625
|
+
line: 5,
|
|
626
|
+
character: 10,
|
|
627
|
+
},
|
|
628
|
+
selectedText: 'hello',
|
|
629
|
+
},
|
|
630
|
+
otherOpenFiles: ['/path/to/recent/file1.ts', '/path/to/recent/file2.ts'],
|
|
631
|
+
}, null, 2)}
|
|
632
|
+
\`\`\`
|
|
633
|
+
`.trim();
|
|
634
|
+
const expectedRequest = [{ text: expectedContext }];
|
|
635
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith({
|
|
636
|
+
role: 'user',
|
|
637
|
+
parts: expectedRequest,
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
it('should not add context if ideMode is enabled but no open files', async () => {
|
|
641
|
+
// Arrange
|
|
642
|
+
vi.mocked(ideContextStore.get).mockReturnValue({
|
|
643
|
+
workspaceState: {
|
|
644
|
+
openFiles: [],
|
|
645
|
+
},
|
|
646
|
+
});
|
|
647
|
+
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
|
|
648
|
+
const mockStream = (async function* () {
|
|
649
|
+
yield { type: 'content', value: 'Hello' };
|
|
650
|
+
})();
|
|
651
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
652
|
+
const mockChat = {
|
|
653
|
+
addHistory: vi.fn(),
|
|
654
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
655
|
+
getLastPromptTokenCount: vi.fn(),
|
|
656
|
+
};
|
|
657
|
+
client['chat'] = mockChat;
|
|
658
|
+
const initialRequest = [{ text: 'Hi' }];
|
|
659
|
+
// Act
|
|
660
|
+
const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
|
|
661
|
+
for await (const _ of stream) {
|
|
662
|
+
// consume stream
|
|
663
|
+
}
|
|
664
|
+
// Assert
|
|
665
|
+
expect(ideContextStore.get).toHaveBeenCalled();
|
|
666
|
+
expect(mockTurnRunFn).toHaveBeenCalledWith({ model: 'default-routed-model' }, initialRequest, expect.any(AbortSignal));
|
|
667
|
+
});
|
|
668
|
+
it('should add context if ideMode is enabled and there is one active file', async () => {
|
|
669
|
+
// Arrange
|
|
670
|
+
vi.mocked(ideContextStore.get).mockReturnValue({
|
|
671
|
+
workspaceState: {
|
|
672
|
+
openFiles: [
|
|
673
|
+
{
|
|
674
|
+
path: '/path/to/active/file.ts',
|
|
675
|
+
timestamp: Date.now(),
|
|
676
|
+
isActive: true,
|
|
677
|
+
selectedText: 'hello',
|
|
678
|
+
cursor: { line: 5, character: 10 },
|
|
679
|
+
},
|
|
680
|
+
],
|
|
681
|
+
},
|
|
682
|
+
});
|
|
683
|
+
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
|
|
684
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
685
|
+
originalTokenCount: 0,
|
|
686
|
+
newTokenCount: 0,
|
|
687
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
688
|
+
});
|
|
689
|
+
const mockStream = (async function* () {
|
|
690
|
+
yield { type: 'content', value: 'Hello' };
|
|
691
|
+
})();
|
|
692
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
693
|
+
const mockChat = {
|
|
694
|
+
addHistory: vi.fn(),
|
|
695
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
696
|
+
getLastPromptTokenCount: vi.fn(),
|
|
697
|
+
};
|
|
698
|
+
client['chat'] = mockChat;
|
|
699
|
+
const initialRequest = [{ text: 'Hi' }];
|
|
700
|
+
// Act
|
|
701
|
+
const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
|
|
702
|
+
for await (const _ of stream) {
|
|
703
|
+
// consume stream
|
|
704
|
+
}
|
|
705
|
+
// Assert
|
|
706
|
+
expect(ideContextStore.get).toHaveBeenCalled();
|
|
707
|
+
const expectedContext = `
|
|
708
|
+
Here is the user's editor context as a JSON object. This is for your information only.
|
|
709
|
+
\`\`\`json
|
|
710
|
+
${JSON.stringify({
|
|
711
|
+
activeFile: {
|
|
712
|
+
path: '/path/to/active/file.ts',
|
|
713
|
+
cursor: {
|
|
714
|
+
line: 5,
|
|
715
|
+
character: 10,
|
|
716
|
+
},
|
|
717
|
+
selectedText: 'hello',
|
|
718
|
+
},
|
|
719
|
+
}, null, 2)}
|
|
720
|
+
\`\`\`
|
|
721
|
+
`.trim();
|
|
722
|
+
const expectedRequest = [{ text: expectedContext }];
|
|
723
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith({
|
|
724
|
+
role: 'user',
|
|
725
|
+
parts: expectedRequest,
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
it('should add context if ideMode is enabled and there are open files but no active file', async () => {
|
|
729
|
+
// Arrange
|
|
730
|
+
vi.mocked(ideContextStore.get).mockReturnValue({
|
|
731
|
+
workspaceState: {
|
|
732
|
+
openFiles: [
|
|
733
|
+
{
|
|
734
|
+
path: '/path/to/recent/file1.ts',
|
|
735
|
+
timestamp: Date.now(),
|
|
736
|
+
},
|
|
737
|
+
{
|
|
738
|
+
path: '/path/to/recent/file2.ts',
|
|
739
|
+
timestamp: Date.now(),
|
|
740
|
+
},
|
|
741
|
+
],
|
|
742
|
+
},
|
|
743
|
+
});
|
|
744
|
+
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
|
|
745
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
746
|
+
originalTokenCount: 0,
|
|
747
|
+
newTokenCount: 0,
|
|
748
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
749
|
+
});
|
|
750
|
+
const mockStream = (async function* () {
|
|
751
|
+
yield { type: 'content', value: 'Hello' };
|
|
752
|
+
})();
|
|
753
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
754
|
+
const mockChat = {
|
|
755
|
+
addHistory: vi.fn(),
|
|
756
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
757
|
+
getLastPromptTokenCount: vi.fn(),
|
|
758
|
+
};
|
|
759
|
+
client['chat'] = mockChat;
|
|
760
|
+
const initialRequest = [{ text: 'Hi' }];
|
|
761
|
+
// Act
|
|
762
|
+
const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
|
|
763
|
+
for await (const _ of stream) {
|
|
764
|
+
// consume stream
|
|
765
|
+
}
|
|
766
|
+
// Assert
|
|
767
|
+
expect(ideContextStore.get).toHaveBeenCalled();
|
|
768
|
+
const expectedContext = `
|
|
769
|
+
Here is the user's editor context as a JSON object. This is for your information only.
|
|
770
|
+
\`\`\`json
|
|
771
|
+
${JSON.stringify({
|
|
772
|
+
otherOpenFiles: ['/path/to/recent/file1.ts', '/path/to/recent/file2.ts'],
|
|
773
|
+
}, null, 2)}
|
|
774
|
+
\`\`\`
|
|
775
|
+
`.trim();
|
|
776
|
+
const expectedRequest = [{ text: expectedContext }];
|
|
777
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith({
|
|
778
|
+
role: 'user',
|
|
779
|
+
parts: expectedRequest,
|
|
780
|
+
});
|
|
781
|
+
});
|
|
782
|
+
it('should use local estimation for text-only requests and NOT call countTokens', async () => {
|
|
783
|
+
const request = [{ text: 'Hello world' }];
|
|
784
|
+
const generator = client['getContentGeneratorOrFail']();
|
|
785
|
+
const countTokensSpy = vi.spyOn(generator, 'countTokens');
|
|
786
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'test-prompt-id');
|
|
787
|
+
await stream.next(); // Trigger the generator
|
|
788
|
+
expect(countTokensSpy).not.toHaveBeenCalled();
|
|
789
|
+
});
|
|
790
|
+
it('should use countTokens API for requests with non-text parts', async () => {
|
|
791
|
+
const request = [
|
|
792
|
+
{ text: 'Describe this image' },
|
|
793
|
+
{ inlineData: { mimeType: 'image/png', data: 'base64...' } },
|
|
794
|
+
];
|
|
795
|
+
const generator = client['getContentGeneratorOrFail']();
|
|
796
|
+
const countTokensSpy = vi
|
|
797
|
+
.spyOn(generator, 'countTokens')
|
|
798
|
+
.mockResolvedValue({ totalTokens: 123 });
|
|
799
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'test-prompt-id');
|
|
800
|
+
await stream.next(); // Trigger the generator
|
|
801
|
+
expect(countTokensSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
802
|
+
contents: expect.arrayContaining([
|
|
803
|
+
expect.objectContaining({
|
|
804
|
+
parts: expect.arrayContaining([
|
|
805
|
+
{ text: 'Describe this image' },
|
|
806
|
+
{ inlineData: { mimeType: 'image/png', data: 'base64...' } },
|
|
807
|
+
]),
|
|
808
|
+
}),
|
|
809
|
+
]),
|
|
810
|
+
}));
|
|
811
|
+
});
|
|
812
|
+
it('should estimate CJK characters more conservatively (closer to 1 token/char)', async () => {
|
|
813
|
+
const request = [{ text: '你好世界' }]; // 4 chars
|
|
814
|
+
const generator = client['getContentGeneratorOrFail']();
|
|
815
|
+
const countTokensSpy = vi.spyOn(generator, 'countTokens');
|
|
816
|
+
// 4 chars.
|
|
817
|
+
// Old logic: 4/4 = 1.
|
|
818
|
+
// New logic (heuristic): 4 * 1 = 4. (Or at least > 1).
|
|
819
|
+
// Let's assert it's roughly accurate.
|
|
820
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'test-prompt-id');
|
|
821
|
+
await stream.next();
|
|
822
|
+
// Should NOT call countTokens (it's text only)
|
|
823
|
+
expect(countTokensSpy).not.toHaveBeenCalled();
|
|
824
|
+
// The actual token calculation is unit tested in tokenCalculation.test.ts
|
|
825
|
+
});
|
|
826
|
+
it('should return the turn instance after the stream is complete', async () => {
|
|
827
|
+
// Arrange
|
|
828
|
+
const mockStream = (async function* () {
|
|
829
|
+
yield { type: 'content', value: 'Hello' };
|
|
830
|
+
})();
|
|
831
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
832
|
+
const mockChat = {
|
|
833
|
+
addHistory: vi.fn(),
|
|
834
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
835
|
+
getLastPromptTokenCount: vi.fn(),
|
|
836
|
+
};
|
|
837
|
+
client['chat'] = mockChat;
|
|
838
|
+
// Act
|
|
839
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-1');
|
|
840
|
+
// Consume the stream manually to get the final return value.
|
|
841
|
+
let finalResult;
|
|
842
|
+
while (true) {
|
|
843
|
+
const result = await stream.next();
|
|
844
|
+
if (result.done) {
|
|
845
|
+
finalResult = result.value;
|
|
846
|
+
break;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
// Assert
|
|
850
|
+
expect(finalResult).toBeInstanceOf(Turn);
|
|
851
|
+
});
|
|
852
|
+
it('should stop infinite loop after MAX_TURNS when nextSpeaker always returns model', async () => {
|
|
853
|
+
vi.spyOn(client['config'], 'getContinueOnFailedApiCall').mockReturnValue(true);
|
|
854
|
+
// Get the mocked checkNextSpeaker function and configure it to trigger infinite loop
|
|
855
|
+
const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
|
|
856
|
+
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
|
857
|
+
mockCheckNextSpeaker.mockResolvedValue({
|
|
858
|
+
next_speaker: 'model',
|
|
859
|
+
reasoning: 'Test case - always continue',
|
|
860
|
+
});
|
|
861
|
+
// Mock Turn to have no pending tool calls (which would allow nextSpeaker check)
|
|
862
|
+
const mockStream = (async function* () {
|
|
863
|
+
yield { type: 'content', value: 'Continue...' };
|
|
864
|
+
})();
|
|
865
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
866
|
+
const mockChat = {
|
|
867
|
+
addHistory: vi.fn(),
|
|
868
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
869
|
+
getLastPromptTokenCount: vi.fn(),
|
|
870
|
+
};
|
|
871
|
+
client['chat'] = mockChat;
|
|
872
|
+
// Use a signal that never gets aborted
|
|
873
|
+
const abortController = new AbortController();
|
|
874
|
+
const signal = abortController.signal;
|
|
875
|
+
// Act - Start the stream that should loop
|
|
876
|
+
const stream = client.sendMessageStream([{ text: 'Start conversation' }], signal, 'prompt-id-2');
|
|
877
|
+
// Count how many stream events we get
|
|
878
|
+
let eventCount = 0;
|
|
879
|
+
let finalResult;
|
|
880
|
+
// Consume the stream and count iterations
|
|
881
|
+
while (true) {
|
|
882
|
+
const result = await stream.next();
|
|
883
|
+
if (result.done) {
|
|
884
|
+
finalResult = result.value;
|
|
885
|
+
break;
|
|
886
|
+
}
|
|
887
|
+
eventCount++;
|
|
888
|
+
// Safety check to prevent actual infinite loop in test
|
|
889
|
+
if (eventCount > 200) {
|
|
890
|
+
abortController.abort();
|
|
891
|
+
throw new Error('Test exceeded expected event limit - possible actual infinite loop');
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
// Assert
|
|
895
|
+
expect(finalResult).toBeInstanceOf(Turn);
|
|
896
|
+
// If infinite loop protection is working, checkNextSpeaker should be called many times
|
|
897
|
+
// but stop at MAX_TURNS (100). Since each recursive call should trigger checkNextSpeaker,
|
|
898
|
+
// we expect it to be called multiple times before hitting the limit
|
|
899
|
+
expect(mockCheckNextSpeaker).toHaveBeenCalled();
|
|
900
|
+
// The stream should produce events and eventually terminate
|
|
901
|
+
expect(eventCount).toBeGreaterThanOrEqual(1);
|
|
902
|
+
expect(eventCount).toBeLessThan(200); // Should not exceed our safety limit
|
|
903
|
+
});
|
|
904
|
+
it('should yield MaxSessionTurns and stop when session turn limit is reached', async () => {
|
|
905
|
+
// Arrange
|
|
906
|
+
const MAX_SESSION_TURNS = 5;
|
|
907
|
+
vi.spyOn(client['config'], 'getMaxSessionTurns').mockReturnValue(MAX_SESSION_TURNS);
|
|
908
|
+
const mockStream = (async function* () {
|
|
909
|
+
yield { type: 'content', value: 'Hello' };
|
|
910
|
+
})();
|
|
911
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
912
|
+
const mockChat = {
|
|
913
|
+
addHistory: vi.fn(),
|
|
914
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
915
|
+
getLastPromptTokenCount: vi.fn(),
|
|
916
|
+
};
|
|
917
|
+
client['chat'] = mockChat;
|
|
918
|
+
// Act & Assert
|
|
919
|
+
// Run up to the limit
|
|
920
|
+
for (let i = 0; i < MAX_SESSION_TURNS; i++) {
|
|
921
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-4');
|
|
922
|
+
// consume stream
|
|
923
|
+
for await (const _event of stream) {
|
|
924
|
+
// do nothing
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
// This call should exceed the limit
|
|
928
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-5');
|
|
929
|
+
const events = [];
|
|
930
|
+
for await (const event of stream) {
|
|
931
|
+
events.push(event);
|
|
932
|
+
}
|
|
933
|
+
expect(events).toEqual([{ type: LlmEventType.MaxSessionTurns }]);
|
|
934
|
+
expect(mockTurnRunFn).toHaveBeenCalledTimes(MAX_SESSION_TURNS);
|
|
935
|
+
});
|
|
936
|
+
it('should respect MAX_TURNS limit even when turns parameter is set to a large value', async () => {
|
|
937
|
+
// This test verifies that the infinite loop protection works even when
|
|
938
|
+
// someone tries to bypass it by calling with a very large turns value
|
|
939
|
+
// Get the mocked checkNextSpeaker function and configure it to trigger infinite loop
|
|
940
|
+
const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
|
|
941
|
+
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
|
942
|
+
mockCheckNextSpeaker.mockResolvedValue({
|
|
943
|
+
next_speaker: 'model',
|
|
944
|
+
reasoning: 'Test case - always continue',
|
|
945
|
+
});
|
|
946
|
+
// Mock Turn to have no pending tool calls (which would allow nextSpeaker check)
|
|
947
|
+
const mockStream = (async function* () {
|
|
948
|
+
yield { type: 'content', value: 'Continue...' };
|
|
949
|
+
})();
|
|
950
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
951
|
+
const mockChat = {
|
|
952
|
+
addHistory: vi.fn(),
|
|
953
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
954
|
+
getLastPromptTokenCount: vi.fn(),
|
|
955
|
+
};
|
|
956
|
+
client['chat'] = mockChat;
|
|
957
|
+
// Use a signal that never gets aborted
|
|
958
|
+
const abortController = new AbortController();
|
|
959
|
+
const signal = abortController.signal;
|
|
960
|
+
// Act - Start the stream with an extremely high turns value
|
|
961
|
+
// This simulates a case where the turns protection is bypassed
|
|
962
|
+
const stream = client.sendMessageStream([{ text: 'Start conversation' }], signal, 'prompt-id-3', Number.MAX_SAFE_INTEGER);
|
|
963
|
+
// Count how many stream events we get
|
|
964
|
+
let eventCount = 0;
|
|
965
|
+
const maxTestIterations = 1000; // Higher limit to show the loop continues
|
|
966
|
+
// Consume the stream and count iterations
|
|
967
|
+
try {
|
|
968
|
+
while (true) {
|
|
969
|
+
const result = await stream.next();
|
|
970
|
+
if (result.done) {
|
|
971
|
+
break;
|
|
972
|
+
}
|
|
973
|
+
eventCount++;
|
|
974
|
+
// This test should hit this limit, demonstrating the infinite loop
|
|
975
|
+
if (eventCount > maxTestIterations) {
|
|
976
|
+
abortController.abort();
|
|
977
|
+
// This is the expected behavior - we hit the infinite loop
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
catch (_) {
|
|
983
|
+
// If the test framework times out, that also demonstrates the infinite loop
|
|
984
|
+
}
|
|
985
|
+
// Assert that the fix works - the loop should stop at MAX_TURNS
|
|
986
|
+
const callCount = mockCheckNextSpeaker.mock.calls.length;
|
|
987
|
+
// With the fix: even when turns is set to a very high value,
|
|
988
|
+
// the loop should stop at MAX_TURNS (100)
|
|
989
|
+
expect(callCount).toBeLessThanOrEqual(100); // Should not exceed MAX_TURNS
|
|
990
|
+
expect(eventCount).toBeLessThanOrEqual(200); // Should have reasonable number of events
|
|
991
|
+
});
|
|
992
|
+
it('should yield ContextWindowWillOverflow when the context window is about to overflow', async () => {
|
|
993
|
+
// Arrange
|
|
994
|
+
const MOCKED_TOKEN_LIMIT = 1000;
|
|
995
|
+
vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
|
|
996
|
+
// Set last prompt token count
|
|
997
|
+
const lastPromptTokenCount = 900;
|
|
998
|
+
const mockChat = {
|
|
999
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(lastPromptTokenCount),
|
|
1000
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
1001
|
+
};
|
|
1002
|
+
client['chat'] = mockChat;
|
|
1003
|
+
// Remaining = 100.
|
|
1004
|
+
// We need a request > 100 tokens.
|
|
1005
|
+
// A string of length 404 is roughly 101 tokens.
|
|
1006
|
+
const longText = 'a'.repeat(404);
|
|
1007
|
+
const request = [{ text: longText }];
|
|
1008
|
+
// estimateTextOnlyLength counts only text content (400 chars), not JSON structure
|
|
1009
|
+
const estimatedRequestTokenCount = Math.floor(longText.length / 4);
|
|
1010
|
+
const remainingTokenCount = MOCKED_TOKEN_LIMIT - lastPromptTokenCount;
|
|
1011
|
+
// Mock tryCompressChat to not compress
|
|
1012
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
1013
|
+
originalTokenCount: lastPromptTokenCount,
|
|
1014
|
+
newTokenCount: lastPromptTokenCount,
|
|
1015
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
1016
|
+
});
|
|
1017
|
+
// Act
|
|
1018
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'prompt-id-overflow');
|
|
1019
|
+
const events = await fromAsync(stream);
|
|
1020
|
+
// Assert
|
|
1021
|
+
expect(events).toContainEqual({
|
|
1022
|
+
type: LlmEventType.ContextWindowOverflow,
|
|
1023
|
+
currentTokens: estimatedRequestTokenCount,
|
|
1024
|
+
maxTokens: remainingTokenCount,
|
|
1025
|
+
});
|
|
1026
|
+
// Ensure turn.run is not called
|
|
1027
|
+
expect(mockTurnRunFn).not.toHaveBeenCalled();
|
|
1028
|
+
});
|
|
1029
|
+
it("should use the sticky model's token limit for the overflow check", async () => {
|
|
1030
|
+
// Arrange
|
|
1031
|
+
const STICKY_MODEL = 'gemini-1.5-flash';
|
|
1032
|
+
const STICKY_MODEL_LIMIT = 1000;
|
|
1033
|
+
const CONFIG_MODEL_LIMIT = 2000;
|
|
1034
|
+
// Set up token limits
|
|
1035
|
+
vi.mocked(tokenLimit).mockImplementation((model) => {
|
|
1036
|
+
if (model === STICKY_MODEL)
|
|
1037
|
+
return STICKY_MODEL_LIMIT;
|
|
1038
|
+
return CONFIG_MODEL_LIMIT;
|
|
1039
|
+
});
|
|
1040
|
+
// Set the sticky model
|
|
1041
|
+
client['currentSequenceModel'] = STICKY_MODEL;
|
|
1042
|
+
// Set token count
|
|
1043
|
+
const lastPromptTokenCount = 900;
|
|
1044
|
+
const mockChat = {
|
|
1045
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(lastPromptTokenCount),
|
|
1046
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
1047
|
+
};
|
|
1048
|
+
client['chat'] = mockChat;
|
|
1049
|
+
// Remaining (sticky) = 100.
|
|
1050
|
+
// We need a request > 100 tokens.
|
|
1051
|
+
const longText = 'a'.repeat(404);
|
|
1052
|
+
const request = [{ text: longText }];
|
|
1053
|
+
// estimateTextOnlyLength counts only text content (400 chars), not JSON structure
|
|
1054
|
+
const estimatedRequestTokenCount = Math.floor(longText.length / 4);
|
|
1055
|
+
const remainingTokenCount = STICKY_MODEL_LIMIT - lastPromptTokenCount;
|
|
1056
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
1057
|
+
originalTokenCount: lastPromptTokenCount,
|
|
1058
|
+
newTokenCount: lastPromptTokenCount,
|
|
1059
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
1060
|
+
});
|
|
1061
|
+
// Act
|
|
1062
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'test-session-id');
|
|
1063
|
+
const events = await fromAsync(stream);
|
|
1064
|
+
// Assert
|
|
1065
|
+
// Should overflow based on the sticky model's limit
|
|
1066
|
+
expect(events).toContainEqual({
|
|
1067
|
+
type: LlmEventType.ContextWindowOverflow,
|
|
1068
|
+
currentTokens: estimatedRequestTokenCount,
|
|
1069
|
+
maxTokens: remainingTokenCount,
|
|
1070
|
+
});
|
|
1071
|
+
expect(tokenLimit).toHaveBeenCalledWith(STICKY_MODEL);
|
|
1072
|
+
expect(mockTurnRunFn).not.toHaveBeenCalled();
|
|
1073
|
+
});
|
|
1074
|
+
it('should attempt compression before overflow check and proceed if compression frees space', async () => {
|
|
1075
|
+
// Arrange
|
|
1076
|
+
const MOCKED_TOKEN_LIMIT = 1000;
|
|
1077
|
+
vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
|
|
1078
|
+
// Initial state: 950 tokens used, 50 remaining.
|
|
1079
|
+
const initialTokenCount = 950;
|
|
1080
|
+
// Request: 60 tokens. (950 + 60 = 1010 > 1000) -> Would overflow without compression.
|
|
1081
|
+
const longText = 'a'.repeat(240); // 240 / 4 = 60 tokens
|
|
1082
|
+
const request = [{ text: longText }];
|
|
1083
|
+
// Use the real GeminiChat to manage state and token counts more realistically
|
|
1084
|
+
const mockChatCompressed = {
|
|
1085
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(400),
|
|
1086
|
+
getHistory: vi
|
|
1087
|
+
.fn()
|
|
1088
|
+
.mockReturnValue([{ role: 'user', parts: [{ text: 'old' }] }]),
|
|
1089
|
+
addHistory: vi.fn(),
|
|
1090
|
+
getChatRecordingService: vi.fn().mockReturnValue({
|
|
1091
|
+
getConversation: vi.fn(),
|
|
1092
|
+
getConversationFilePath: vi.fn(),
|
|
1093
|
+
}),
|
|
1094
|
+
};
|
|
1095
|
+
const mockChatInitial = {
|
|
1096
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(initialTokenCount),
|
|
1097
|
+
getHistory: vi
|
|
1098
|
+
.fn()
|
|
1099
|
+
.mockReturnValue([{ role: 'user', parts: [{ text: 'old' }] }]),
|
|
1100
|
+
addHistory: vi.fn(),
|
|
1101
|
+
getChatRecordingService: vi.fn().mockReturnValue({
|
|
1102
|
+
getConversation: vi.fn(),
|
|
1103
|
+
getConversationFilePath: vi.fn(),
|
|
1104
|
+
}),
|
|
1105
|
+
};
|
|
1106
|
+
client['chat'] = mockChatInitial;
|
|
1107
|
+
// Mock tryCompressChat to simulate successful compression
|
|
1108
|
+
const tryCompressSpy = vi
|
|
1109
|
+
.spyOn(client, 'tryCompressChat')
|
|
1110
|
+
.mockImplementation(async () => {
|
|
1111
|
+
// In reality, tryCompressChat replaces this.chat
|
|
1112
|
+
client['chat'] = mockChatCompressed;
|
|
1113
|
+
return {
|
|
1114
|
+
originalTokenCount: initialTokenCount,
|
|
1115
|
+
newTokenCount: 400,
|
|
1116
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
1117
|
+
};
|
|
1118
|
+
});
|
|
1119
|
+
// Use a manual spy on Turn.prototype.run since Turn is a real class in this test context
|
|
1120
|
+
// but mocked at the top of the file
|
|
1121
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
1122
|
+
yield { type: 'content', value: 'Success after compression' };
|
|
1123
|
+
});
|
|
1124
|
+
// Act
|
|
1125
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'prompt-id-compression-test');
|
|
1126
|
+
const events = await fromAsync(stream);
|
|
1127
|
+
// Assert
|
|
1128
|
+
// 1. Should NOT contain overflow warning
|
|
1129
|
+
expect(events).not.toContainEqual(expect.objectContaining({
|
|
1130
|
+
type: LlmEventType.ContextWindowOverflow,
|
|
1131
|
+
}));
|
|
1132
|
+
// 2. Should contain compression event
|
|
1133
|
+
expect(events).toContainEqual(expect.objectContaining({
|
|
1134
|
+
type: LlmEventType.ChatCompressed,
|
|
1135
|
+
}));
|
|
1136
|
+
// 3. Should have called tryCompressChat
|
|
1137
|
+
expect(tryCompressSpy).toHaveBeenCalled();
|
|
1138
|
+
// 4. Should have called Turn.run (proceeded with the request)
|
|
1139
|
+
expect(mockTurnRunFn).toHaveBeenCalled();
|
|
1140
|
+
});
|
|
1141
|
+
it('should handle massive function responses by truncating them and then yielding overflow warning', async () => {
|
|
1142
|
+
// Arrange
|
|
1143
|
+
const MOCKED_TOKEN_LIMIT = 1000;
|
|
1144
|
+
vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
|
|
1145
|
+
// History has a large compressible part and a massive function response at the end.
|
|
1146
|
+
const massiveText = 'a'.repeat(200000);
|
|
1147
|
+
const history = [
|
|
1148
|
+
{ role: 'user', parts: [{ text: 'a'.repeat(100000) }] }, // compressible part
|
|
1149
|
+
{ role: 'model', parts: [{ text: 'ok' }] },
|
|
1150
|
+
{
|
|
1151
|
+
role: 'model',
|
|
1152
|
+
parts: [{ functionCall: { name: 'huge_tool', args: {} } }],
|
|
1153
|
+
},
|
|
1154
|
+
{
|
|
1155
|
+
role: 'user',
|
|
1156
|
+
parts: [
|
|
1157
|
+
{
|
|
1158
|
+
functionResponse: {
|
|
1159
|
+
name: 'huge_tool',
|
|
1160
|
+
response: { data: massiveText },
|
|
1161
|
+
},
|
|
1162
|
+
},
|
|
1163
|
+
],
|
|
1164
|
+
},
|
|
1165
|
+
];
|
|
1166
|
+
const realChat = new GeminiChat(mockConfig, '', [], history);
|
|
1167
|
+
client['chat'] = realChat;
|
|
1168
|
+
// Use a realistic mock for compression that simulates the 40k truncation effect.
|
|
1169
|
+
// We spy on the instance directly to ensure it intercepts correctly.
|
|
1170
|
+
const compressSpy = vi
|
|
1171
|
+
.spyOn(client['compressionService'], 'compress')
|
|
1172
|
+
.mockResolvedValue({
|
|
1173
|
+
newHistory: history, // Keep history large for the overflow check
|
|
1174
|
+
info: {
|
|
1175
|
+
originalTokenCount: 50000,
|
|
1176
|
+
newTokenCount: 10000, // Reduced from 50k but still > 1000 limit
|
|
1177
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
1178
|
+
},
|
|
1179
|
+
});
|
|
1180
|
+
// The new request
|
|
1181
|
+
const request = [{ text: 'next question' }];
|
|
1182
|
+
// Act
|
|
1183
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'prompt-id-massive-test');
|
|
1184
|
+
const events = await fromAsync(stream);
|
|
1185
|
+
// Assert
|
|
1186
|
+
// 1. Should have attempted compression
|
|
1187
|
+
expect(compressSpy).toHaveBeenCalled();
|
|
1188
|
+
// 2. Should yield overflow warning because 10000 > 1000 limit.
|
|
1189
|
+
expect(events).toContainEqual(expect.objectContaining({
|
|
1190
|
+
type: LlmEventType.ContextWindowOverflow,
|
|
1191
|
+
currentTokens: expect.any(Number),
|
|
1192
|
+
maxTokens: expect.any(Number),
|
|
1193
|
+
}));
|
|
1194
|
+
});
|
|
1195
|
+
it('should not trigger overflow warning for requests with large binary data (PDFs/images)', async () => {
|
|
1196
|
+
// Arrange
|
|
1197
|
+
const MOCKED_TOKEN_LIMIT = 1000000; // 1M tokens
|
|
1198
|
+
vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
|
|
1199
|
+
const lastPromptTokenCount = 10000;
|
|
1200
|
+
const mockChat = {
|
|
1201
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(lastPromptTokenCount),
|
|
1202
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
1203
|
+
};
|
|
1204
|
+
client['chat'] = mockChat;
|
|
1205
|
+
// Simulate a PDF file with large base64 data (11MB when encoded)
|
|
1206
|
+
// In the old implementation, this would incorrectly estimate ~2.7M tokens
|
|
1207
|
+
// In the new implementation, only the text part is counted
|
|
1208
|
+
const largePdfBase64 = 'A'.repeat(11 * 1024 * 1024);
|
|
1209
|
+
const request = [
|
|
1210
|
+
{ text: 'Please analyze this PDF document' }, // ~35 chars = ~8 tokens
|
|
1211
|
+
{
|
|
1212
|
+
inlineData: {
|
|
1213
|
+
mimeType: 'application/pdf',
|
|
1214
|
+
data: largePdfBase64, // This should be ignored in token estimation
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
];
|
|
1218
|
+
// Mock tryCompressChat to not compress
|
|
1219
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
1220
|
+
originalTokenCount: lastPromptTokenCount,
|
|
1221
|
+
newTokenCount: lastPromptTokenCount,
|
|
1222
|
+
compressionStatus: CompressionStatus.NOOP,
|
|
1223
|
+
});
|
|
1224
|
+
// Mock Turn.run to simulate successful processing
|
|
1225
|
+
const mockStream = (async function* () {
|
|
1226
|
+
yield { type: 'content', value: 'Analysis complete' };
|
|
1227
|
+
})();
|
|
1228
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
1229
|
+
// Act
|
|
1230
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'prompt-id-pdf-test');
|
|
1231
|
+
const events = await fromAsync(stream);
|
|
1232
|
+
// Assert
|
|
1233
|
+
// Should NOT contain overflow warning
|
|
1234
|
+
expect(events).not.toContainEqual(expect.objectContaining({
|
|
1235
|
+
type: LlmEventType.ContextWindowOverflow,
|
|
1236
|
+
}));
|
|
1237
|
+
// Turn.run should be called (processing should continue)
|
|
1238
|
+
expect(mockTurnRunFn).toHaveBeenCalled();
|
|
1239
|
+
});
|
|
1240
|
+
describe('Model Routing', () => {
|
|
1241
|
+
let mockRouterService;
|
|
1242
|
+
beforeEach(() => {
|
|
1243
|
+
mockRouterService = {
|
|
1244
|
+
route: vi
|
|
1245
|
+
.fn()
|
|
1246
|
+
.mockResolvedValue({ model: 'routed-model', reason: 'test' }),
|
|
1247
|
+
};
|
|
1248
|
+
vi.mocked(mockConfig.getModelRouterService).mockReturnValue(mockRouterService);
|
|
1249
|
+
mockTurnRunFn.mockReturnValue((async function* () {
|
|
1250
|
+
yield { type: 'content', value: 'Hello' };
|
|
1251
|
+
})());
|
|
1252
|
+
const mockChat = {
|
|
1253
|
+
addHistory: vi.fn(),
|
|
1254
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
1255
|
+
getLastPromptTokenCount: vi.fn(),
|
|
1256
|
+
};
|
|
1257
|
+
client['chat'] = mockChat;
|
|
1258
|
+
});
|
|
1259
|
+
it('should use the model router service to select a model on the first turn', async () => {
|
|
1260
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-1');
|
|
1261
|
+
await fromAsync(stream); // consume stream
|
|
1262
|
+
expect(mockConfig.getModelRouterService).toHaveBeenCalled();
|
|
1263
|
+
expect(mockRouterService.route).toHaveBeenCalled();
|
|
1264
|
+
expect(mockTurnRunFn).toHaveBeenCalledWith({ model: 'routed-model' }, [{ text: 'Hi' }], expect.any(AbortSignal));
|
|
1265
|
+
});
|
|
1266
|
+
it('should use the same model for subsequent turns in the same prompt (stickiness)', async () => {
|
|
1267
|
+
// First turn
|
|
1268
|
+
let stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-1');
|
|
1269
|
+
await fromAsync(stream);
|
|
1270
|
+
expect(mockRouterService.route).toHaveBeenCalledTimes(1);
|
|
1271
|
+
expect(mockTurnRunFn).toHaveBeenCalledWith({ model: 'routed-model' }, [{ text: 'Hi' }], expect.any(AbortSignal));
|
|
1272
|
+
// Second turn
|
|
1273
|
+
stream = client.sendMessageStream([{ text: 'Continue' }], new AbortController().signal, 'prompt-1');
|
|
1274
|
+
await fromAsync(stream);
|
|
1275
|
+
// Router should not be called again
|
|
1276
|
+
expect(mockRouterService.route).toHaveBeenCalledTimes(1);
|
|
1277
|
+
// Should stick to the first model
|
|
1278
|
+
expect(mockTurnRunFn).toHaveBeenCalledWith({ model: 'routed-model' }, [{ text: 'Continue' }], expect.any(AbortSignal));
|
|
1279
|
+
});
|
|
1280
|
+
it('should reset the sticky model and re-route when the prompt_id changes', async () => {
|
|
1281
|
+
// First prompt
|
|
1282
|
+
let stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-1');
|
|
1283
|
+
await fromAsync(stream);
|
|
1284
|
+
expect(mockRouterService.route).toHaveBeenCalledTimes(1);
|
|
1285
|
+
expect(mockTurnRunFn).toHaveBeenCalledWith({ model: 'routed-model' }, [{ text: 'Hi' }], expect.any(AbortSignal));
|
|
1286
|
+
// New prompt
|
|
1287
|
+
mockRouterService.route.mockResolvedValue({
|
|
1288
|
+
model: 'new-routed-model',
|
|
1289
|
+
reason: 'test',
|
|
1290
|
+
});
|
|
1291
|
+
stream = client.sendMessageStream([{ text: 'A new topic' }], new AbortController().signal, 'prompt-2');
|
|
1292
|
+
await fromAsync(stream);
|
|
1293
|
+
// Router should be called again for the new prompt
|
|
1294
|
+
expect(mockRouterService.route).toHaveBeenCalledTimes(2);
|
|
1295
|
+
// Should use the newly routed model
|
|
1296
|
+
expect(mockTurnRunFn).toHaveBeenCalledWith({ model: 'new-routed-model' }, [{ text: 'A new topic' }], expect.any(AbortSignal));
|
|
1297
|
+
});
|
|
1298
|
+
it('should re-route within the same prompt when the configured model changes', async () => {
|
|
1299
|
+
mockTurnRunFn.mockClear();
|
|
1300
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
1301
|
+
yield { type: 'content', value: 'Hello' };
|
|
1302
|
+
});
|
|
1303
|
+
mockRouterService.route.mockResolvedValueOnce({
|
|
1304
|
+
model: 'original-model',
|
|
1305
|
+
reason: 'test',
|
|
1306
|
+
});
|
|
1307
|
+
let stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-1');
|
|
1308
|
+
await fromAsync(stream);
|
|
1309
|
+
expect(mockRouterService.route).toHaveBeenCalledTimes(1);
|
|
1310
|
+
expect(mockTurnRunFn).toHaveBeenNthCalledWith(1, { model: 'original-model' }, [{ text: 'Hi' }], expect.any(AbortSignal));
|
|
1311
|
+
mockRouterService.route.mockResolvedValue({
|
|
1312
|
+
model: 'fallback-model',
|
|
1313
|
+
reason: 'test',
|
|
1314
|
+
});
|
|
1315
|
+
vi.mocked(mockConfig.getModel).mockReturnValue('gemini-2.5-flash');
|
|
1316
|
+
coreEvents.emitModelChanged('gemini-2.5-flash');
|
|
1317
|
+
stream = client.sendMessageStream([{ text: 'Continue' }], new AbortController().signal, 'prompt-1');
|
|
1318
|
+
await fromAsync(stream);
|
|
1319
|
+
expect(mockRouterService.route).toHaveBeenCalledTimes(2);
|
|
1320
|
+
expect(mockTurnRunFn).toHaveBeenNthCalledWith(2, { model: 'fallback-model' }, [{ text: 'Continue' }], expect.any(AbortSignal));
|
|
1321
|
+
});
|
|
1322
|
+
});
|
|
1323
|
+
it('should use getGlobalMemory for system instruction when JIT is enabled', async () => {
|
|
1324
|
+
vi.mocked(mockConfig.isJitContextEnabled).mockReturnValue(true);
|
|
1325
|
+
vi.mocked(mockConfig.getGlobalMemory).mockReturnValue('Global JIT Memory');
|
|
1326
|
+
vi.mocked(mockConfig.getUserMemory).mockReturnValue('Full JIT Memory');
|
|
1327
|
+
const { getCoreSystemPrompt } = await import('./prompts.js');
|
|
1328
|
+
const mockGetCoreSystemPrompt = vi.mocked(getCoreSystemPrompt);
|
|
1329
|
+
client.updateSystemInstruction();
|
|
1330
|
+
expect(mockGetCoreSystemPrompt).toHaveBeenCalledWith(mockConfig, 'Global JIT Memory');
|
|
1331
|
+
});
|
|
1332
|
+
it('should use getUserMemory for system instruction when JIT is disabled', async () => {
|
|
1333
|
+
vi.mocked(mockConfig.isJitContextEnabled).mockReturnValue(false);
|
|
1334
|
+
vi.mocked(mockConfig.getUserMemory).mockReturnValue('Legacy Memory');
|
|
1335
|
+
const { getCoreSystemPrompt } = await import('./prompts.js');
|
|
1336
|
+
const mockGetCoreSystemPrompt = vi.mocked(getCoreSystemPrompt);
|
|
1337
|
+
client.updateSystemInstruction();
|
|
1338
|
+
expect(mockGetCoreSystemPrompt).toHaveBeenCalledWith(mockConfig, 'Legacy Memory');
|
|
1339
|
+
});
|
|
1340
|
+
it('should recursively call sendMessageStream with "Please continue." when InvalidStream event is received', async () => {
|
|
1341
|
+
vi.spyOn(client['config'], 'getContinueOnFailedApiCall').mockReturnValue(true);
|
|
1342
|
+
// Arrange
|
|
1343
|
+
const mockStream1 = (async function* () {
|
|
1344
|
+
yield { type: LlmEventType.InvalidStream };
|
|
1345
|
+
})();
|
|
1346
|
+
const mockStream2 = (async function* () {
|
|
1347
|
+
yield { type: LlmEventType.TextDelta, text: 'Continued content' };
|
|
1348
|
+
})();
|
|
1349
|
+
mockTurnRunFn
|
|
1350
|
+
.mockReturnValueOnce(mockStream1)
|
|
1351
|
+
.mockReturnValueOnce(mockStream2);
|
|
1352
|
+
const mockChat = {
|
|
1353
|
+
addHistory: vi.fn(),
|
|
1354
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
1355
|
+
getLastPromptTokenCount: vi.fn(),
|
|
1356
|
+
};
|
|
1357
|
+
client['chat'] = mockChat;
|
|
1358
|
+
const initialRequest = [{ text: 'Hi' }];
|
|
1359
|
+
const promptId = 'prompt-id-invalid-stream';
|
|
1360
|
+
const signal = new AbortController().signal;
|
|
1361
|
+
// Act
|
|
1362
|
+
const stream = client.sendMessageStream(initialRequest, signal, promptId);
|
|
1363
|
+
const events = await fromAsync(stream);
|
|
1364
|
+
// Assert
|
|
1365
|
+
expect(events).toEqual([
|
|
1366
|
+
{ type: LlmEventType.ModelInfo, modelName: 'default-routed-model' },
|
|
1367
|
+
{ type: LlmEventType.InvalidStream },
|
|
1368
|
+
{ type: LlmEventType.TextDelta, text: 'Continued content' },
|
|
1369
|
+
]);
|
|
1370
|
+
// Verify that turn.run was called twice
|
|
1371
|
+
expect(mockTurnRunFn).toHaveBeenCalledTimes(2);
|
|
1372
|
+
// First call with original request
|
|
1373
|
+
expect(mockTurnRunFn).toHaveBeenNthCalledWith(1, { model: 'default-routed-model' }, initialRequest, expect.any(AbortSignal));
|
|
1374
|
+
// Second call with "Please continue."
|
|
1375
|
+
expect(mockTurnRunFn).toHaveBeenNthCalledWith(2, { model: 'default-routed-model' }, [{ text: 'System: Please continue.' }], expect.any(AbortSignal));
|
|
1376
|
+
});
|
|
1377
|
+
it('should not recursively call sendMessageStream with "Please continue." when InvalidStream event is received and flag is false', async () => {
|
|
1378
|
+
vi.spyOn(client['config'], 'getContinueOnFailedApiCall').mockReturnValue(false);
|
|
1379
|
+
// Arrange
|
|
1380
|
+
const mockStream1 = (async function* () {
|
|
1381
|
+
yield { type: LlmEventType.InvalidStream };
|
|
1382
|
+
})();
|
|
1383
|
+
mockTurnRunFn.mockReturnValueOnce(mockStream1);
|
|
1384
|
+
const mockChat = {
|
|
1385
|
+
addHistory: vi.fn(),
|
|
1386
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
1387
|
+
getLastPromptTokenCount: vi.fn(),
|
|
1388
|
+
};
|
|
1389
|
+
client['chat'] = mockChat;
|
|
1390
|
+
const initialRequest = [{ text: 'Hi' }];
|
|
1391
|
+
const promptId = 'prompt-id-invalid-stream';
|
|
1392
|
+
const signal = new AbortController().signal;
|
|
1393
|
+
// Act
|
|
1394
|
+
const stream = client.sendMessageStream(initialRequest, signal, promptId);
|
|
1395
|
+
const events = await fromAsync(stream);
|
|
1396
|
+
// Assert
|
|
1397
|
+
expect(events).toEqual([
|
|
1398
|
+
{ type: LlmEventType.ModelInfo, modelName: 'default-routed-model' },
|
|
1399
|
+
{ type: LlmEventType.InvalidStream },
|
|
1400
|
+
]);
|
|
1401
|
+
// Verify that turn.run was called only once
|
|
1402
|
+
expect(mockTurnRunFn).toHaveBeenCalledTimes(1);
|
|
1403
|
+
});
|
|
1404
|
+
it('should stop recursing after one retry when InvalidStream events are repeatedly received', async () => {
|
|
1405
|
+
vi.spyOn(client['config'], 'getContinueOnFailedApiCall').mockReturnValue(true);
|
|
1406
|
+
// Arrange
|
|
1407
|
+
// Always return a new invalid stream
|
|
1408
|
+
mockTurnRunFn.mockImplementation(() => (async function* () {
|
|
1409
|
+
yield { type: LlmEventType.InvalidStream };
|
|
1410
|
+
})());
|
|
1411
|
+
const mockChat = {
|
|
1412
|
+
addHistory: vi.fn(),
|
|
1413
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
1414
|
+
getLastPromptTokenCount: vi.fn(),
|
|
1415
|
+
};
|
|
1416
|
+
client['chat'] = mockChat;
|
|
1417
|
+
const initialRequest = [{ text: 'Hi' }];
|
|
1418
|
+
const promptId = 'prompt-id-infinite-invalid-stream';
|
|
1419
|
+
const signal = new AbortController().signal;
|
|
1420
|
+
// Act
|
|
1421
|
+
const stream = client.sendMessageStream(initialRequest, signal, promptId);
|
|
1422
|
+
const events = await fromAsync(stream);
|
|
1423
|
+
// Assert
|
|
1424
|
+
// We expect 3 events (model_info + original + 1 retry)
|
|
1425
|
+
expect(events.length).toBe(3);
|
|
1426
|
+
expect(events
|
|
1427
|
+
.filter((e) => e.type === LlmEventType.ModelInfo)
|
|
1428
|
+
.map((e) => e.modelName)).toEqual(['default-routed-model']);
|
|
1429
|
+
// Verify that turn.run was called twice
|
|
1430
|
+
expect(mockTurnRunFn).toHaveBeenCalledTimes(2);
|
|
1431
|
+
});
|
|
1432
|
+
describe('Editor context delta', () => {
|
|
1433
|
+
const mockStream = (async function* () {
|
|
1434
|
+
yield { type: 'content', value: 'Hello' };
|
|
1435
|
+
})();
|
|
1436
|
+
beforeEach(() => {
|
|
1437
|
+
client['forceFullIdeContext'] = false; // Reset before each delta test
|
|
1438
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
1439
|
+
originalTokenCount: 0,
|
|
1440
|
+
newTokenCount: 0,
|
|
1441
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
1442
|
+
});
|
|
1443
|
+
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
|
|
1444
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
1445
|
+
const mockChat = {
|
|
1446
|
+
addHistory: vi.fn(),
|
|
1447
|
+
setHistory: vi.fn(),
|
|
1448
|
+
// Assume history is not empty for delta checks
|
|
1449
|
+
getHistory: vi
|
|
1450
|
+
.fn()
|
|
1451
|
+
.mockReturnValue([
|
|
1452
|
+
{ role: 'user', parts: [{ text: 'previous message' }] },
|
|
1453
|
+
]),
|
|
1454
|
+
getLastPromptTokenCount: vi.fn(),
|
|
1455
|
+
};
|
|
1456
|
+
client['chat'] = mockChat;
|
|
1457
|
+
});
|
|
1458
|
+
const testCases = [
|
|
1459
|
+
{
|
|
1460
|
+
description: 'sends delta when active file changes',
|
|
1461
|
+
previousActiveFile: {
|
|
1462
|
+
path: '/path/to/old/file.ts',
|
|
1463
|
+
cursor: { line: 5, character: 10 },
|
|
1464
|
+
selectedText: 'hello',
|
|
1465
|
+
},
|
|
1466
|
+
currentActiveFile: {
|
|
1467
|
+
path: '/path/to/active/file.ts',
|
|
1468
|
+
cursor: { line: 5, character: 10 },
|
|
1469
|
+
selectedText: 'hello',
|
|
1470
|
+
},
|
|
1471
|
+
shouldSendContext: true,
|
|
1472
|
+
},
|
|
1473
|
+
{
|
|
1474
|
+
description: 'sends delta when cursor line changes',
|
|
1475
|
+
previousActiveFile: {
|
|
1476
|
+
path: '/path/to/active/file.ts',
|
|
1477
|
+
cursor: { line: 1, character: 10 },
|
|
1478
|
+
selectedText: 'hello',
|
|
1479
|
+
},
|
|
1480
|
+
currentActiveFile: {
|
|
1481
|
+
path: '/path/to/active/file.ts',
|
|
1482
|
+
cursor: { line: 5, character: 10 },
|
|
1483
|
+
selectedText: 'hello',
|
|
1484
|
+
},
|
|
1485
|
+
shouldSendContext: true,
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
description: 'sends delta when cursor character changes',
|
|
1489
|
+
previousActiveFile: {
|
|
1490
|
+
path: '/path/to/active/file.ts',
|
|
1491
|
+
cursor: { line: 5, character: 1 },
|
|
1492
|
+
selectedText: 'hello',
|
|
1493
|
+
},
|
|
1494
|
+
currentActiveFile: {
|
|
1495
|
+
path: '/path/to/active/file.ts',
|
|
1496
|
+
cursor: { line: 5, character: 10 },
|
|
1497
|
+
selectedText: 'hello',
|
|
1498
|
+
},
|
|
1499
|
+
shouldSendContext: true,
|
|
1500
|
+
},
|
|
1501
|
+
{
|
|
1502
|
+
description: 'sends delta when selected text changes',
|
|
1503
|
+
previousActiveFile: {
|
|
1504
|
+
path: '/path/to/active/file.ts',
|
|
1505
|
+
cursor: { line: 5, character: 10 },
|
|
1506
|
+
selectedText: 'world',
|
|
1507
|
+
},
|
|
1508
|
+
currentActiveFile: {
|
|
1509
|
+
path: '/path/to/active/file.ts',
|
|
1510
|
+
cursor: { line: 5, character: 10 },
|
|
1511
|
+
selectedText: 'hello',
|
|
1512
|
+
},
|
|
1513
|
+
shouldSendContext: true,
|
|
1514
|
+
},
|
|
1515
|
+
{
|
|
1516
|
+
description: 'sends delta when selected text is added',
|
|
1517
|
+
previousActiveFile: {
|
|
1518
|
+
path: '/path/to/active/file.ts',
|
|
1519
|
+
cursor: { line: 5, character: 10 },
|
|
1520
|
+
},
|
|
1521
|
+
currentActiveFile: {
|
|
1522
|
+
path: '/path/to/active/file.ts',
|
|
1523
|
+
cursor: { line: 5, character: 10 },
|
|
1524
|
+
selectedText: 'hello',
|
|
1525
|
+
},
|
|
1526
|
+
shouldSendContext: true,
|
|
1527
|
+
},
|
|
1528
|
+
{
|
|
1529
|
+
description: 'sends delta when selected text is removed',
|
|
1530
|
+
previousActiveFile: {
|
|
1531
|
+
path: '/path/to/active/file.ts',
|
|
1532
|
+
cursor: { line: 5, character: 10 },
|
|
1533
|
+
selectedText: 'hello',
|
|
1534
|
+
},
|
|
1535
|
+
currentActiveFile: {
|
|
1536
|
+
path: '/path/to/active/file.ts',
|
|
1537
|
+
cursor: { line: 5, character: 10 },
|
|
1538
|
+
},
|
|
1539
|
+
shouldSendContext: true,
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
description: 'does not send context when nothing changes',
|
|
1543
|
+
previousActiveFile: {
|
|
1544
|
+
path: '/path/to/active/file.ts',
|
|
1545
|
+
cursor: { line: 5, character: 10 },
|
|
1546
|
+
selectedText: 'hello',
|
|
1547
|
+
},
|
|
1548
|
+
currentActiveFile: {
|
|
1549
|
+
path: '/path/to/active/file.ts',
|
|
1550
|
+
cursor: { line: 5, character: 10 },
|
|
1551
|
+
selectedText: 'hello',
|
|
1552
|
+
},
|
|
1553
|
+
shouldSendContext: false,
|
|
1554
|
+
},
|
|
1555
|
+
];
|
|
1556
|
+
it.each(testCases)('$description', async ({ previousActiveFile, currentActiveFile, shouldSendContext, }) => {
|
|
1557
|
+
// Setup previous context
|
|
1558
|
+
client['lastSentIdeContext'] = {
|
|
1559
|
+
workspaceState: {
|
|
1560
|
+
openFiles: [
|
|
1561
|
+
{
|
|
1562
|
+
path: previousActiveFile.path,
|
|
1563
|
+
cursor: previousActiveFile.cursor,
|
|
1564
|
+
selectedText: previousActiveFile.selectedText,
|
|
1565
|
+
isActive: true,
|
|
1566
|
+
timestamp: Date.now() - 1000,
|
|
1567
|
+
},
|
|
1568
|
+
],
|
|
1569
|
+
},
|
|
1570
|
+
};
|
|
1571
|
+
// Setup current context
|
|
1572
|
+
vi.mocked(ideContextStore.get).mockReturnValue({
|
|
1573
|
+
workspaceState: {
|
|
1574
|
+
openFiles: [
|
|
1575
|
+
{
|
|
1576
|
+
...currentActiveFile,
|
|
1577
|
+
isActive: true,
|
|
1578
|
+
timestamp: Date.now(),
|
|
1579
|
+
},
|
|
1580
|
+
],
|
|
1581
|
+
},
|
|
1582
|
+
});
|
|
1583
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-delta');
|
|
1584
|
+
for await (const _ of stream) {
|
|
1585
|
+
// consume stream
|
|
1586
|
+
}
|
|
1587
|
+
const mockChat = client['chat'];
|
|
1588
|
+
if (shouldSendContext) {
|
|
1589
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({
|
|
1590
|
+
parts: expect.arrayContaining([
|
|
1591
|
+
expect.objectContaining({
|
|
1592
|
+
text: expect.stringContaining("Here is a summary of changes in the user's editor context"),
|
|
1593
|
+
}),
|
|
1594
|
+
]),
|
|
1595
|
+
}));
|
|
1596
|
+
}
|
|
1597
|
+
else {
|
|
1598
|
+
expect(mockChat.addHistory).not.toHaveBeenCalled();
|
|
1599
|
+
}
|
|
1600
|
+
});
|
|
1601
|
+
it('sends full context when history is cleared, even if editor state is unchanged', async () => {
|
|
1602
|
+
const activeFile = {
|
|
1603
|
+
path: '/path/to/active/file.ts',
|
|
1604
|
+
cursor: { line: 5, character: 10 },
|
|
1605
|
+
selectedText: 'hello',
|
|
1606
|
+
};
|
|
1607
|
+
// Setup previous context
|
|
1608
|
+
client['lastSentIdeContext'] = {
|
|
1609
|
+
workspaceState: {
|
|
1610
|
+
openFiles: [
|
|
1611
|
+
{
|
|
1612
|
+
path: activeFile.path,
|
|
1613
|
+
cursor: activeFile.cursor,
|
|
1614
|
+
selectedText: activeFile.selectedText,
|
|
1615
|
+
isActive: true,
|
|
1616
|
+
timestamp: Date.now() - 1000,
|
|
1617
|
+
},
|
|
1618
|
+
],
|
|
1619
|
+
},
|
|
1620
|
+
};
|
|
1621
|
+
// Setup current context (same as previous)
|
|
1622
|
+
vi.mocked(ideContextStore.get).mockReturnValue({
|
|
1623
|
+
workspaceState: {
|
|
1624
|
+
openFiles: [
|
|
1625
|
+
{ ...activeFile, isActive: true, timestamp: Date.now() },
|
|
1626
|
+
],
|
|
1627
|
+
},
|
|
1628
|
+
});
|
|
1629
|
+
// Make history empty
|
|
1630
|
+
const mockChat = client['chat'];
|
|
1631
|
+
mockChat.getHistory.mockReturnValue([]);
|
|
1632
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-history-cleared');
|
|
1633
|
+
for await (const _ of stream) {
|
|
1634
|
+
// consume stream
|
|
1635
|
+
}
|
|
1636
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({
|
|
1637
|
+
parts: expect.arrayContaining([
|
|
1638
|
+
expect.objectContaining({
|
|
1639
|
+
text: expect.stringContaining("Here is the user's editor context"),
|
|
1640
|
+
}),
|
|
1641
|
+
]),
|
|
1642
|
+
}));
|
|
1643
|
+
// Also verify it's the full context, not a delta.
|
|
1644
|
+
const call = mockChat.addHistory.mock.calls[0][0];
|
|
1645
|
+
const contextText = call.parts[0].text;
|
|
1646
|
+
const contextJson = JSON.parse(contextText.match(/```json\n(.*)\n```/s)[1]);
|
|
1647
|
+
expect(contextJson).toHaveProperty('activeFile');
|
|
1648
|
+
expect(contextJson.activeFile.path).toBe('/path/to/active/file.ts');
|
|
1649
|
+
});
|
|
1650
|
+
});
|
|
1651
|
+
describe('Availability Service Integration', () => {
|
|
1652
|
+
let mockAvailabilityService;
|
|
1653
|
+
beforeEach(() => {
|
|
1654
|
+
mockAvailabilityService = createAvailabilityServiceMock();
|
|
1655
|
+
vi.mocked(mockConfig.getModelAvailabilityService).mockReturnValue(mockAvailabilityService);
|
|
1656
|
+
vi.mocked(mockConfig.setActiveModel).mockClear();
|
|
1657
|
+
mockRouterService.route.mockResolvedValue({
|
|
1658
|
+
model: 'model-a',
|
|
1659
|
+
reason: 'test',
|
|
1660
|
+
});
|
|
1661
|
+
vi.mocked(mockConfig.getModelRouterService).mockReturnValue(mockRouterService);
|
|
1662
|
+
vi.spyOn(policyCatalog, 'getModelPolicyChain').mockReturnValue([
|
|
1663
|
+
{
|
|
1664
|
+
model: 'model-a',
|
|
1665
|
+
isLastResort: false,
|
|
1666
|
+
actions: {},
|
|
1667
|
+
stateTransitions: {},
|
|
1668
|
+
},
|
|
1669
|
+
{
|
|
1670
|
+
model: 'model-b',
|
|
1671
|
+
isLastResort: true,
|
|
1672
|
+
actions: {},
|
|
1673
|
+
stateTransitions: {},
|
|
1674
|
+
},
|
|
1675
|
+
]);
|
|
1676
|
+
mockTurnRunFn.mockReturnValue((async function* () {
|
|
1677
|
+
yield { type: 'content', value: 'Hello' };
|
|
1678
|
+
})());
|
|
1679
|
+
});
|
|
1680
|
+
it('should select first available model, set active, and not consume sticky attempt (done lower in chain)', async () => {
|
|
1681
|
+
vi.mocked(mockAvailabilityService.selectFirstAvailable).mockReturnValue({
|
|
1682
|
+
selectedModel: 'model-a',
|
|
1683
|
+
attempts: 1,
|
|
1684
|
+
skipped: [],
|
|
1685
|
+
});
|
|
1686
|
+
vi.mocked(mockConfig.getModel).mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO);
|
|
1687
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-avail');
|
|
1688
|
+
await fromAsync(stream);
|
|
1689
|
+
expect(mockAvailabilityService.selectFirstAvailable).toHaveBeenCalledWith(['model-a', 'model-b']);
|
|
1690
|
+
expect(mockConfig.setActiveModel).toHaveBeenCalledWith('model-a');
|
|
1691
|
+
expect(mockAvailabilityService.consumeStickyAttempt).not.toHaveBeenCalled();
|
|
1692
|
+
// Ensure turn.run used the selected model
|
|
1693
|
+
expect(mockTurnRunFn).toHaveBeenCalledWith(expect.objectContaining({ model: 'model-a' }), expect.anything(), expect.anything());
|
|
1694
|
+
});
|
|
1695
|
+
it('should default to last resort model if selection returns null', async () => {
|
|
1696
|
+
vi.mocked(mockAvailabilityService.selectFirstAvailable).mockReturnValue({
|
|
1697
|
+
selectedModel: null,
|
|
1698
|
+
skipped: [],
|
|
1699
|
+
});
|
|
1700
|
+
vi.mocked(mockConfig.getModel).mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO);
|
|
1701
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-avail-fallback');
|
|
1702
|
+
await fromAsync(stream);
|
|
1703
|
+
expect(mockConfig.setActiveModel).toHaveBeenCalledWith('model-b'); // Last resort
|
|
1704
|
+
expect(mockAvailabilityService.consumeStickyAttempt).not.toHaveBeenCalled();
|
|
1705
|
+
});
|
|
1706
|
+
it('should reset turn on new message stream', async () => {
|
|
1707
|
+
vi.mocked(mockAvailabilityService.selectFirstAvailable).mockReturnValue({
|
|
1708
|
+
selectedModel: 'model-a',
|
|
1709
|
+
skipped: [],
|
|
1710
|
+
});
|
|
1711
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-reset');
|
|
1712
|
+
await fromAsync(stream);
|
|
1713
|
+
expect(mockConfig.resetTurn).toHaveBeenCalled();
|
|
1714
|
+
});
|
|
1715
|
+
it('should NOT reset turn on invalid stream retry', async () => {
|
|
1716
|
+
vi.mocked(mockAvailabilityService.selectFirstAvailable).mockReturnValue({
|
|
1717
|
+
selectedModel: 'model-a',
|
|
1718
|
+
skipped: [],
|
|
1719
|
+
});
|
|
1720
|
+
// We simulate a retry by calling sendMessageStream with isInvalidStreamRetry=true
|
|
1721
|
+
// But the public API doesn't expose that argument directly unless we use the private method or simulate the recursion.
|
|
1722
|
+
// We can simulate recursion by mocking turn run to return invalid stream once.
|
|
1723
|
+
vi.spyOn(client['config'], 'getContinueOnFailedApiCall').mockReturnValue(true);
|
|
1724
|
+
const mockStream1 = (async function* () {
|
|
1725
|
+
yield { type: LlmEventType.InvalidStream };
|
|
1726
|
+
})();
|
|
1727
|
+
const mockStream2 = (async function* () {
|
|
1728
|
+
yield { type: 'content', value: 'ok' };
|
|
1729
|
+
})();
|
|
1730
|
+
mockTurnRunFn
|
|
1731
|
+
.mockReturnValueOnce(mockStream1)
|
|
1732
|
+
.mockReturnValueOnce(mockStream2);
|
|
1733
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-retry');
|
|
1734
|
+
await fromAsync(stream);
|
|
1735
|
+
// resetTurn should be called once (for the initial call) but NOT for the recursive call
|
|
1736
|
+
expect(mockConfig.resetTurn).toHaveBeenCalledTimes(1);
|
|
1737
|
+
});
|
|
1738
|
+
});
|
|
1739
|
+
describe('IDE context with pending tool calls', () => {
|
|
1740
|
+
let mockChat;
|
|
1741
|
+
beforeEach(() => {
|
|
1742
|
+
vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
|
|
1743
|
+
originalTokenCount: 0,
|
|
1744
|
+
newTokenCount: 0,
|
|
1745
|
+
compressionStatus: CompressionStatus.COMPRESSED,
|
|
1746
|
+
});
|
|
1747
|
+
const mockStream = (async function* () {
|
|
1748
|
+
yield { type: 'content', value: 'response' };
|
|
1749
|
+
})();
|
|
1750
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
1751
|
+
mockChat = {
|
|
1752
|
+
addHistory: vi.fn(),
|
|
1753
|
+
getHistory: vi.fn().mockReturnValue([]), // Default empty history
|
|
1754
|
+
setHistory: vi.fn(),
|
|
1755
|
+
getLastPromptTokenCount: vi.fn(),
|
|
1756
|
+
};
|
|
1757
|
+
client['chat'] = mockChat;
|
|
1758
|
+
vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
|
|
1759
|
+
vi.mocked(ideContextStore.get).mockReturnValue({
|
|
1760
|
+
workspaceState: {
|
|
1761
|
+
openFiles: [{ path: '/path/to/file.ts', timestamp: Date.now() }],
|
|
1762
|
+
},
|
|
1763
|
+
});
|
|
1764
|
+
});
|
|
1765
|
+
it('should NOT add IDE context when a tool call is pending', async () => {
|
|
1766
|
+
// Arrange: History ends with a functionCall from the model
|
|
1767
|
+
const historyWithPendingCall = [
|
|
1768
|
+
{ role: 'user', parts: [{ text: 'Please use a tool.' }] },
|
|
1769
|
+
{
|
|
1770
|
+
role: 'model',
|
|
1771
|
+
parts: [{ functionCall: { name: 'some_tool', args: {} } }],
|
|
1772
|
+
},
|
|
1773
|
+
];
|
|
1774
|
+
vi.mocked(mockChat.getHistory).mockReturnValue(historyWithPendingCall);
|
|
1775
|
+
// Act: Simulate sending the tool's response back
|
|
1776
|
+
const stream = client.sendMessageStream([
|
|
1777
|
+
{
|
|
1778
|
+
functionResponse: {
|
|
1779
|
+
name: 'some_tool',
|
|
1780
|
+
response: { success: true },
|
|
1781
|
+
},
|
|
1782
|
+
},
|
|
1783
|
+
], new AbortController().signal, 'prompt-id-tool-response');
|
|
1784
|
+
for await (const _ of stream) {
|
|
1785
|
+
// consume stream to complete the call
|
|
1786
|
+
}
|
|
1787
|
+
// Assert: The IDE context message should NOT have been added to the history.
|
|
1788
|
+
expect(mockChat.addHistory).not.toHaveBeenCalledWith(expect.objectContaining({
|
|
1789
|
+
parts: expect.arrayContaining([
|
|
1790
|
+
expect.objectContaining({
|
|
1791
|
+
text: expect.stringContaining("user's editor context"),
|
|
1792
|
+
}),
|
|
1793
|
+
]),
|
|
1794
|
+
}));
|
|
1795
|
+
});
|
|
1796
|
+
it('should add IDE context when no tool call is pending', async () => {
|
|
1797
|
+
// Arrange: History is normal, no pending calls
|
|
1798
|
+
const normalHistory = [
|
|
1799
|
+
{ role: 'user', parts: [{ text: 'A normal message.' }] },
|
|
1800
|
+
{ role: 'model', parts: [{ text: 'A normal response.' }] },
|
|
1801
|
+
];
|
|
1802
|
+
vi.mocked(mockChat.getHistory).mockReturnValue(normalHistory);
|
|
1803
|
+
// Act
|
|
1804
|
+
const stream = client.sendMessageStream([{ text: 'Another normal message' }], new AbortController().signal, 'prompt-id-normal');
|
|
1805
|
+
for await (const _ of stream) {
|
|
1806
|
+
// consume stream
|
|
1807
|
+
}
|
|
1808
|
+
// Assert: The IDE context message SHOULD have been added.
|
|
1809
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({
|
|
1810
|
+
role: 'user',
|
|
1811
|
+
parts: expect.arrayContaining([
|
|
1812
|
+
expect.objectContaining({
|
|
1813
|
+
text: expect.stringContaining("user's editor context"),
|
|
1814
|
+
}),
|
|
1815
|
+
]),
|
|
1816
|
+
}));
|
|
1817
|
+
});
|
|
1818
|
+
it('should send the latest IDE context on the next message after a skipped context', async () => {
|
|
1819
|
+
// --- Step 1: A tool call is pending, context should be skipped ---
|
|
1820
|
+
// Arrange: History ends with a functionCall
|
|
1821
|
+
const historyWithPendingCall = [
|
|
1822
|
+
{ role: 'user', parts: [{ text: 'Please use a tool.' }] },
|
|
1823
|
+
{
|
|
1824
|
+
role: 'model',
|
|
1825
|
+
parts: [{ functionCall: { name: 'some_tool', args: {} } }],
|
|
1826
|
+
},
|
|
1827
|
+
];
|
|
1828
|
+
vi.mocked(mockChat.getHistory).mockReturnValue(historyWithPendingCall);
|
|
1829
|
+
// Arrange: Set the initial IDE context
|
|
1830
|
+
const initialIdeContext = {
|
|
1831
|
+
workspaceState: {
|
|
1832
|
+
openFiles: [{ path: '/path/to/fileA.ts', timestamp: Date.now() }],
|
|
1833
|
+
},
|
|
1834
|
+
};
|
|
1835
|
+
vi.mocked(ideContextStore.get).mockReturnValue(initialIdeContext);
|
|
1836
|
+
// Act: Send the tool response
|
|
1837
|
+
let stream = client.sendMessageStream([
|
|
1838
|
+
{
|
|
1839
|
+
functionResponse: {
|
|
1840
|
+
name: 'some_tool',
|
|
1841
|
+
response: { success: true },
|
|
1842
|
+
},
|
|
1843
|
+
},
|
|
1844
|
+
], new AbortController().signal, 'prompt-id-tool-response');
|
|
1845
|
+
for await (const _ of stream) {
|
|
1846
|
+
/* consume */
|
|
1847
|
+
}
|
|
1848
|
+
// Assert: The initial context was NOT sent
|
|
1849
|
+
expect(mockChat.addHistory).not.toHaveBeenCalledWith(expect.objectContaining({
|
|
1850
|
+
parts: expect.arrayContaining([
|
|
1851
|
+
expect.objectContaining({
|
|
1852
|
+
text: expect.stringContaining("user's editor context"),
|
|
1853
|
+
}),
|
|
1854
|
+
]),
|
|
1855
|
+
}));
|
|
1856
|
+
// --- Step 2: A new message is sent, latest context should be included ---
|
|
1857
|
+
// Arrange: The model has responded to the tool, and the user is sending a new message.
|
|
1858
|
+
const historyAfterToolResponse = [
|
|
1859
|
+
...historyWithPendingCall,
|
|
1860
|
+
{
|
|
1861
|
+
role: 'user',
|
|
1862
|
+
parts: [
|
|
1863
|
+
{
|
|
1864
|
+
functionResponse: {
|
|
1865
|
+
name: 'some_tool',
|
|
1866
|
+
response: { success: true },
|
|
1867
|
+
},
|
|
1868
|
+
},
|
|
1869
|
+
],
|
|
1870
|
+
},
|
|
1871
|
+
{ role: 'model', parts: [{ text: 'The tool ran successfully.' }] },
|
|
1872
|
+
];
|
|
1873
|
+
vi.mocked(mockChat.getHistory).mockReturnValue(historyAfterToolResponse);
|
|
1874
|
+
vi.mocked(mockChat.addHistory).mockClear(); // Clear previous calls for the next assertion
|
|
1875
|
+
// Arrange: The IDE context has now changed
|
|
1876
|
+
const newIdeContext = {
|
|
1877
|
+
workspaceState: {
|
|
1878
|
+
openFiles: [{ path: '/path/to/fileB.ts', timestamp: Date.now() }],
|
|
1879
|
+
},
|
|
1880
|
+
};
|
|
1881
|
+
vi.mocked(ideContextStore.get).mockReturnValue(newIdeContext);
|
|
1882
|
+
// Act: Send a new, regular user message
|
|
1883
|
+
stream = client.sendMessageStream([{ text: 'Thanks!' }], new AbortController().signal, 'prompt-id-final');
|
|
1884
|
+
for await (const _ of stream) {
|
|
1885
|
+
/* consume */
|
|
1886
|
+
}
|
|
1887
|
+
// Assert: The NEW context was sent as a FULL context because there was no previously sent context.
|
|
1888
|
+
const addHistoryCalls = vi.mocked(mockChat.addHistory).mock.calls;
|
|
1889
|
+
const contextCall = addHistoryCalls.find((call) => JSON.stringify(call[0]).includes("user's editor context"));
|
|
1890
|
+
expect(contextCall).toBeDefined();
|
|
1891
|
+
expect(JSON.stringify(contextCall[0])).toContain("Here is the user's editor context as a JSON object");
|
|
1892
|
+
// Check that the sent context is the new one (fileB.ts)
|
|
1893
|
+
expect(JSON.stringify(contextCall[0])).toContain('fileB.ts');
|
|
1894
|
+
// Check that the sent context is NOT the old one (fileA.ts)
|
|
1895
|
+
expect(JSON.stringify(contextCall[0])).not.toContain('fileA.ts');
|
|
1896
|
+
});
|
|
1897
|
+
it('should send a context DELTA on the next message after a skipped context', async () => {
|
|
1898
|
+
// --- Step 0: Establish an initial context ---
|
|
1899
|
+
vi.mocked(mockChat.getHistory).mockReturnValue([]); // Start with empty history
|
|
1900
|
+
const contextA = {
|
|
1901
|
+
workspaceState: {
|
|
1902
|
+
openFiles: [
|
|
1903
|
+
{
|
|
1904
|
+
path: '/path/to/fileA.ts',
|
|
1905
|
+
isActive: true,
|
|
1906
|
+
timestamp: Date.now(),
|
|
1907
|
+
},
|
|
1908
|
+
],
|
|
1909
|
+
},
|
|
1910
|
+
};
|
|
1911
|
+
vi.mocked(ideContextStore.get).mockReturnValue(contextA);
|
|
1912
|
+
// Act: Send a regular message to establish the initial context
|
|
1913
|
+
let stream = client.sendMessageStream([{ text: 'Initial message' }], new AbortController().signal, 'prompt-id-initial');
|
|
1914
|
+
for await (const _ of stream) {
|
|
1915
|
+
/* consume */
|
|
1916
|
+
}
|
|
1917
|
+
// Assert: Full context for fileA.ts was sent and stored.
|
|
1918
|
+
const initialCall = vi.mocked(mockChat.addHistory).mock.calls[0][0];
|
|
1919
|
+
expect(JSON.stringify(initialCall)).toContain("user's editor context as a JSON object");
|
|
1920
|
+
expect(JSON.stringify(initialCall)).toContain('fileA.ts');
|
|
1921
|
+
// This implicitly tests that `lastSentIdeContext` is now set internally by the client.
|
|
1922
|
+
vi.mocked(mockChat.addHistory).mockClear();
|
|
1923
|
+
// --- Step 1: A tool call is pending, context should be skipped ---
|
|
1924
|
+
const historyWithPendingCall = [
|
|
1925
|
+
{ role: 'user', parts: [{ text: 'Please use a tool.' }] },
|
|
1926
|
+
{
|
|
1927
|
+
role: 'model',
|
|
1928
|
+
parts: [{ functionCall: { name: 'some_tool', args: {} } }],
|
|
1929
|
+
},
|
|
1930
|
+
];
|
|
1931
|
+
vi.mocked(mockChat.getHistory).mockReturnValue(historyWithPendingCall);
|
|
1932
|
+
// Arrange: IDE context changes, but this should be skipped
|
|
1933
|
+
const contextB = {
|
|
1934
|
+
workspaceState: {
|
|
1935
|
+
openFiles: [
|
|
1936
|
+
{
|
|
1937
|
+
path: '/path/to/fileB.ts',
|
|
1938
|
+
isActive: true,
|
|
1939
|
+
timestamp: Date.now(),
|
|
1940
|
+
},
|
|
1941
|
+
],
|
|
1942
|
+
},
|
|
1943
|
+
};
|
|
1944
|
+
vi.mocked(ideContextStore.get).mockReturnValue(contextB);
|
|
1945
|
+
// Act: Send the tool response
|
|
1946
|
+
stream = client.sendMessageStream([
|
|
1947
|
+
{
|
|
1948
|
+
functionResponse: {
|
|
1949
|
+
name: 'some_tool',
|
|
1950
|
+
response: { success: true },
|
|
1951
|
+
},
|
|
1952
|
+
},
|
|
1953
|
+
], new AbortController().signal, 'prompt-id-tool-response');
|
|
1954
|
+
for await (const _ of stream) {
|
|
1955
|
+
/* consume */
|
|
1956
|
+
}
|
|
1957
|
+
// Assert: No context was sent
|
|
1958
|
+
expect(mockChat.addHistory).not.toHaveBeenCalled();
|
|
1959
|
+
// --- Step 2: A new message is sent, latest context DELTA should be included ---
|
|
1960
|
+
const historyAfterToolResponse = [
|
|
1961
|
+
...historyWithPendingCall,
|
|
1962
|
+
{
|
|
1963
|
+
role: 'user',
|
|
1964
|
+
parts: [
|
|
1965
|
+
{
|
|
1966
|
+
functionResponse: {
|
|
1967
|
+
name: 'some_tool',
|
|
1968
|
+
response: { success: true },
|
|
1969
|
+
},
|
|
1970
|
+
},
|
|
1971
|
+
],
|
|
1972
|
+
},
|
|
1973
|
+
{ role: 'model', parts: [{ text: 'The tool ran successfully.' }] },
|
|
1974
|
+
];
|
|
1975
|
+
vi.mocked(mockChat.getHistory).mockReturnValue(historyAfterToolResponse);
|
|
1976
|
+
// Arrange: The IDE context has changed again
|
|
1977
|
+
const contextC = {
|
|
1978
|
+
workspaceState: {
|
|
1979
|
+
openFiles: [
|
|
1980
|
+
// fileA is now closed, fileC is open
|
|
1981
|
+
{
|
|
1982
|
+
path: '/path/to/fileC.ts',
|
|
1983
|
+
isActive: true,
|
|
1984
|
+
timestamp: Date.now(),
|
|
1985
|
+
},
|
|
1986
|
+
],
|
|
1987
|
+
},
|
|
1988
|
+
};
|
|
1989
|
+
vi.mocked(ideContextStore.get).mockReturnValue(contextC);
|
|
1990
|
+
// Act: Send a new, regular user message
|
|
1991
|
+
stream = client.sendMessageStream([{ text: 'Thanks!' }], new AbortController().signal, 'prompt-id-final');
|
|
1992
|
+
for await (const _ of stream) {
|
|
1993
|
+
/* consume */
|
|
1994
|
+
}
|
|
1995
|
+
// Assert: The DELTA context was sent
|
|
1996
|
+
const finalCall = vi.mocked(mockChat.addHistory).mock.calls[0][0];
|
|
1997
|
+
expect(JSON.stringify(finalCall)).toContain('summary of changes');
|
|
1998
|
+
// The delta should reflect fileA being closed and fileC being opened.
|
|
1999
|
+
expect(JSON.stringify(finalCall)).toContain('filesClosed');
|
|
2000
|
+
expect(JSON.stringify(finalCall)).toContain('fileA.ts');
|
|
2001
|
+
expect(JSON.stringify(finalCall)).toContain('activeFileChanged');
|
|
2002
|
+
expect(JSON.stringify(finalCall)).toContain('fileC.ts');
|
|
2003
|
+
});
|
|
2004
|
+
});
|
|
2005
|
+
it('should not call checkNextSpeaker when turn.run() yields an error', async () => {
|
|
2006
|
+
// Arrange
|
|
2007
|
+
const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
|
|
2008
|
+
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
|
2009
|
+
const mockStream = (async function* () {
|
|
2010
|
+
yield {
|
|
2011
|
+
type: LlmEventType.Error,
|
|
2012
|
+
error: 'test error',
|
|
2013
|
+
};
|
|
2014
|
+
})();
|
|
2015
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
2016
|
+
const mockChat = {
|
|
2017
|
+
addHistory: vi.fn(),
|
|
2018
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2019
|
+
getLastPromptTokenCount: vi.fn(),
|
|
2020
|
+
};
|
|
2021
|
+
client['chat'] = mockChat;
|
|
2022
|
+
// Act
|
|
2023
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-error');
|
|
2024
|
+
for await (const _ of stream) {
|
|
2025
|
+
// consume stream
|
|
2026
|
+
}
|
|
2027
|
+
// Assert
|
|
2028
|
+
expect(mockCheckNextSpeaker).not.toHaveBeenCalled();
|
|
2029
|
+
});
|
|
2030
|
+
it('should not call checkNextSpeaker when turn.run() yields a value then an error', async () => {
|
|
2031
|
+
// Arrange
|
|
2032
|
+
const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
|
|
2033
|
+
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
|
2034
|
+
const mockStream = (async function* () {
|
|
2035
|
+
yield { type: LlmEventType.TextDelta, text: 'some content' };
|
|
2036
|
+
yield {
|
|
2037
|
+
type: LlmEventType.Error,
|
|
2038
|
+
error: 'test error',
|
|
2039
|
+
};
|
|
2040
|
+
})();
|
|
2041
|
+
mockTurnRunFn.mockReturnValue(mockStream);
|
|
2042
|
+
const mockChat = {
|
|
2043
|
+
addHistory: vi.fn(),
|
|
2044
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2045
|
+
getLastPromptTokenCount: vi.fn(),
|
|
2046
|
+
};
|
|
2047
|
+
client['chat'] = mockChat;
|
|
2048
|
+
// Act
|
|
2049
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-error');
|
|
2050
|
+
for await (const _ of stream) {
|
|
2051
|
+
// consume stream
|
|
2052
|
+
}
|
|
2053
|
+
// Assert
|
|
2054
|
+
expect(mockCheckNextSpeaker).not.toHaveBeenCalled();
|
|
2055
|
+
});
|
|
2056
|
+
it('should abort linked signal when loop is detected', async () => {
|
|
2057
|
+
// Arrange
|
|
2058
|
+
vi.spyOn(client['loopDetector'], 'turnStarted').mockResolvedValue(false);
|
|
2059
|
+
vi.spyOn(client['loopDetector'], 'addAndCheck')
|
|
2060
|
+
.mockReturnValueOnce(false)
|
|
2061
|
+
.mockReturnValueOnce(true);
|
|
2062
|
+
let capturedSignal;
|
|
2063
|
+
mockTurnRunFn.mockImplementation((_modelConfigKey, _request, signal) => {
|
|
2064
|
+
capturedSignal = signal;
|
|
2065
|
+
return (async function* () {
|
|
2066
|
+
yield { type: LlmEventType.TextDelta, text: 'First event' };
|
|
2067
|
+
yield { type: LlmEventType.TextDelta, text: 'Second event' };
|
|
2068
|
+
})();
|
|
2069
|
+
});
|
|
2070
|
+
const mockChat = {
|
|
2071
|
+
addHistory: vi.fn(),
|
|
2072
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2073
|
+
getLastPromptTokenCount: vi.fn(),
|
|
2074
|
+
};
|
|
2075
|
+
client['chat'] = mockChat;
|
|
2076
|
+
// Act
|
|
2077
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-loop');
|
|
2078
|
+
const events = [];
|
|
2079
|
+
for await (const event of stream) {
|
|
2080
|
+
events.push(event);
|
|
2081
|
+
}
|
|
2082
|
+
// Assert
|
|
2083
|
+
expect(events).toContainEqual({ type: LlmEventType.LoopDetected });
|
|
2084
|
+
expect(capturedSignal.aborted).toBe(true);
|
|
2085
|
+
});
|
|
2086
|
+
});
|
|
2087
|
+
describe('generateContent', () => {
|
|
2088
|
+
it('should call generateContent with the correct parameters', async () => {
|
|
2089
|
+
const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
|
|
2090
|
+
const abortSignal = new AbortController().signal;
|
|
2091
|
+
await client.generateContent({ model: 'test-model' }, contents, abortSignal);
|
|
2092
|
+
expect(mockContentGenerator.generateContent).toHaveBeenCalledWith({
|
|
2093
|
+
model: 'test-model',
|
|
2094
|
+
config: {
|
|
2095
|
+
abortSignal,
|
|
2096
|
+
systemInstruction: getCoreSystemPrompt({}, ''),
|
|
2097
|
+
temperature: 0,
|
|
2098
|
+
topP: 1,
|
|
2099
|
+
},
|
|
2100
|
+
contents,
|
|
2101
|
+
}, 'test-session-id');
|
|
2102
|
+
});
|
|
2103
|
+
it('should use current model from config for content generation', async () => {
|
|
2104
|
+
const initialModel = 'test-model';
|
|
2105
|
+
const contents = [{ role: 'user', parts: [{ text: 'test' }] }];
|
|
2106
|
+
await client.generateContent({ model: initialModel }, contents, new AbortController().signal);
|
|
2107
|
+
expect(mockContentGenerator.generateContent).toHaveBeenCalledWith(expect.objectContaining({
|
|
2108
|
+
model: initialModel,
|
|
2109
|
+
}), 'test-session-id');
|
|
2110
|
+
});
|
|
2111
|
+
describe('Hook System', () => {
|
|
2112
|
+
let mockMessageBus;
|
|
2113
|
+
beforeEach(() => {
|
|
2114
|
+
vi.clearAllMocks();
|
|
2115
|
+
mockMessageBus = { publish: vi.fn(), subscribe: vi.fn() };
|
|
2116
|
+
// Force override config methods on the client instance
|
|
2117
|
+
client['config'].getEnableHooks = vi.fn().mockReturnValue(true);
|
|
2118
|
+
client['config'].getMessageBus = vi
|
|
2119
|
+
.fn()
|
|
2120
|
+
.mockReturnValue(mockMessageBus);
|
|
2121
|
+
});
|
|
2122
|
+
it('should fire BeforeAgent and AfterAgent exactly once for a simple turn', async () => {
|
|
2123
|
+
const promptId = 'test-prompt-hook-1';
|
|
2124
|
+
const request = { text: 'Hello Hooks' };
|
|
2125
|
+
const signal = new AbortController().signal;
|
|
2126
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
2127
|
+
this.getResponseText.mockReturnValue('Hook Response');
|
|
2128
|
+
yield { type: LlmEventType.TextDelta, text: 'Hook Response' };
|
|
2129
|
+
});
|
|
2130
|
+
const stream = client.sendMessageStream(request, signal, promptId);
|
|
2131
|
+
while (!(await stream.next()).done)
|
|
2132
|
+
;
|
|
2133
|
+
expect(mockHookSystem.fireBeforeAgentEvent).toHaveBeenCalledTimes(1);
|
|
2134
|
+
expect(mockHookSystem.fireAfterAgentEvent).toHaveBeenCalledTimes(1);
|
|
2135
|
+
expect(mockHookSystem.fireAfterAgentEvent).toHaveBeenCalledWith(partToString(request), 'Hook Response');
|
|
2136
|
+
// Map should be empty
|
|
2137
|
+
expect(client['hookStateMap'].size).toBe(0);
|
|
2138
|
+
});
|
|
2139
|
+
it('should fire BeforeAgent once and AfterAgent once even with recursion', async () => {
|
|
2140
|
+
const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
|
|
2141
|
+
vi.mocked(checkNextSpeaker)
|
|
2142
|
+
.mockResolvedValueOnce({ next_speaker: 'model', reasoning: 'more' })
|
|
2143
|
+
.mockResolvedValueOnce(null);
|
|
2144
|
+
const promptId = 'test-prompt-hook-recursive';
|
|
2145
|
+
const request = { text: 'Recursion Test' };
|
|
2146
|
+
const signal = new AbortController().signal;
|
|
2147
|
+
let callCount = 0;
|
|
2148
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
2149
|
+
callCount++;
|
|
2150
|
+
const response = `Response ${callCount}`;
|
|
2151
|
+
this.getResponseText.mockReturnValue(response);
|
|
2152
|
+
yield { type: LlmEventType.TextDelta, text: response };
|
|
2153
|
+
});
|
|
2154
|
+
const stream = client.sendMessageStream(request, signal, promptId);
|
|
2155
|
+
while (!(await stream.next()).done)
|
|
2156
|
+
;
|
|
2157
|
+
// BeforeAgent should fire ONLY once despite multiple internal turns
|
|
2158
|
+
expect(mockHookSystem.fireBeforeAgentEvent).toHaveBeenCalledTimes(1);
|
|
2159
|
+
// AfterAgent should fire ONLY when the stack unwinds
|
|
2160
|
+
expect(mockHookSystem.fireAfterAgentEvent).toHaveBeenCalledTimes(1);
|
|
2161
|
+
// Check cumulative response (separated by newline)
|
|
2162
|
+
expect(mockHookSystem.fireAfterAgentEvent).toHaveBeenCalledWith(partToString(request), 'Response 1\nResponse 2');
|
|
2163
|
+
expect(client['hookStateMap'].size).toBe(0);
|
|
2164
|
+
});
|
|
2165
|
+
it('should use original request in AfterAgent hook even when continuation happened', async () => {
|
|
2166
|
+
const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
|
|
2167
|
+
vi.mocked(checkNextSpeaker)
|
|
2168
|
+
.mockResolvedValueOnce({ next_speaker: 'model', reasoning: 'more' })
|
|
2169
|
+
.mockResolvedValueOnce(null);
|
|
2170
|
+
const promptId = 'test-prompt-hook-original-req';
|
|
2171
|
+
const request = { text: 'Do something' };
|
|
2172
|
+
const signal = new AbortController().signal;
|
|
2173
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
2174
|
+
this.getResponseText.mockReturnValue('Ok');
|
|
2175
|
+
yield { type: LlmEventType.TextDelta, text: 'Ok' };
|
|
2176
|
+
});
|
|
2177
|
+
const stream = client.sendMessageStream(request, signal, promptId);
|
|
2178
|
+
while (!(await stream.next()).done)
|
|
2179
|
+
;
|
|
2180
|
+
expect(mockHookSystem.fireAfterAgentEvent).toHaveBeenCalledWith(partToString(request), // Should be 'Do something'
|
|
2181
|
+
expect.stringContaining('Ok'));
|
|
2182
|
+
});
|
|
2183
|
+
it('should cleanup state when prompt_id changes', async () => {
|
|
2184
|
+
const signal = new AbortController().signal;
|
|
2185
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
2186
|
+
this.getResponseText.mockReturnValue('Ok');
|
|
2187
|
+
yield { type: LlmEventType.TextDelta, text: 'Ok' };
|
|
2188
|
+
});
|
|
2189
|
+
client['hookStateMap'].set('old-id', {
|
|
2190
|
+
hasFiredBeforeAgent: true,
|
|
2191
|
+
cumulativeResponse: 'Old',
|
|
2192
|
+
activeCalls: 0,
|
|
2193
|
+
originalRequest: { text: 'Old' },
|
|
2194
|
+
});
|
|
2195
|
+
client['lastPromptId'] = 'old-id';
|
|
2196
|
+
const stream = client.sendMessageStream({ text: 'New' }, signal, 'new-id');
|
|
2197
|
+
await stream.next();
|
|
2198
|
+
expect(client['hookStateMap'].has('old-id')).toBe(false);
|
|
2199
|
+
expect(client['hookStateMap'].has('new-id')).toBe(true);
|
|
2200
|
+
});
|
|
2201
|
+
it('should stop execution in BeforeAgent when hook returns continue: false', async () => {
|
|
2202
|
+
mockHookSystem.fireBeforeAgentEvent.mockResolvedValue({
|
|
2203
|
+
shouldStopExecution: () => true,
|
|
2204
|
+
getEffectiveReason: () => 'Stopped by hook',
|
|
2205
|
+
systemMessage: undefined,
|
|
2206
|
+
});
|
|
2207
|
+
const mockChat = {
|
|
2208
|
+
addHistory: vi.fn(),
|
|
2209
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2210
|
+
getLastPromptTokenCount: vi.fn(),
|
|
2211
|
+
};
|
|
2212
|
+
client['chat'] = mockChat;
|
|
2213
|
+
const request = [{ text: 'Hello' }];
|
|
2214
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'test-prompt');
|
|
2215
|
+
const events = await fromAsync(stream);
|
|
2216
|
+
expect(events).toContainEqual({
|
|
2217
|
+
type: LlmEventType.AgentStopped,
|
|
2218
|
+
reason: 'Stopped by hook',
|
|
2219
|
+
});
|
|
2220
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith({
|
|
2221
|
+
role: 'user',
|
|
2222
|
+
parts: request,
|
|
2223
|
+
});
|
|
2224
|
+
expect(mockTurnRunFn).not.toHaveBeenCalled();
|
|
2225
|
+
});
|
|
2226
|
+
it('should block execution in BeforeAgent when hook returns decision: block', async () => {
|
|
2227
|
+
mockHookSystem.fireBeforeAgentEvent.mockResolvedValue({
|
|
2228
|
+
shouldStopExecution: () => false,
|
|
2229
|
+
isBlockingDecision: () => true,
|
|
2230
|
+
getEffectiveReason: () => 'Blocked by hook',
|
|
2231
|
+
systemMessage: undefined,
|
|
2232
|
+
});
|
|
2233
|
+
const mockChat = {
|
|
2234
|
+
addHistory: vi.fn(),
|
|
2235
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2236
|
+
getLastPromptTokenCount: vi.fn(),
|
|
2237
|
+
};
|
|
2238
|
+
client['chat'] = mockChat;
|
|
2239
|
+
const request = [{ text: 'Hello' }];
|
|
2240
|
+
const stream = client.sendMessageStream(request, new AbortController().signal, 'test-prompt');
|
|
2241
|
+
const events = await fromAsync(stream);
|
|
2242
|
+
expect(events).toContainEqual({
|
|
2243
|
+
type: LlmEventType.AgentBlocked,
|
|
2244
|
+
reason: 'Blocked by hook',
|
|
2245
|
+
});
|
|
2246
|
+
expect(mockChat.addHistory).not.toHaveBeenCalled();
|
|
2247
|
+
expect(mockTurnRunFn).not.toHaveBeenCalled();
|
|
2248
|
+
});
|
|
2249
|
+
it('should stop execution in AfterAgent when hook returns continue: false', async () => {
|
|
2250
|
+
mockHookSystem.fireAfterAgentEvent.mockResolvedValue({
|
|
2251
|
+
shouldStopExecution: () => true,
|
|
2252
|
+
getEffectiveReason: () => 'Stopped after agent',
|
|
2253
|
+
shouldClearContext: () => false,
|
|
2254
|
+
systemMessage: undefined,
|
|
2255
|
+
});
|
|
2256
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
2257
|
+
yield { type: LlmEventType.TextDelta, text: 'Hello' };
|
|
2258
|
+
});
|
|
2259
|
+
const stream = client.sendMessageStream({ text: 'Hi' }, new AbortController().signal, 'test-prompt');
|
|
2260
|
+
const events = await fromAsync(stream);
|
|
2261
|
+
expect(events).toContainEqual(expect.objectContaining({
|
|
2262
|
+
type: LlmEventType.AgentStopped,
|
|
2263
|
+
reason: 'Stopped after agent',
|
|
2264
|
+
}));
|
|
2265
|
+
// sendMessageStream should not recurse
|
|
2266
|
+
expect(mockTurnRunFn).toHaveBeenCalledTimes(1);
|
|
2267
|
+
});
|
|
2268
|
+
it('should yield AgentExecutionBlocked and recurse in AfterAgent when hook returns decision: block', async () => {
|
|
2269
|
+
mockHookSystem.fireAfterAgentEvent
|
|
2270
|
+
.mockResolvedValueOnce({
|
|
2271
|
+
shouldStopExecution: () => false,
|
|
2272
|
+
isBlockingDecision: () => true,
|
|
2273
|
+
getEffectiveReason: () => 'Please explain',
|
|
2274
|
+
shouldClearContext: () => false,
|
|
2275
|
+
systemMessage: undefined,
|
|
2276
|
+
})
|
|
2277
|
+
.mockResolvedValueOnce({
|
|
2278
|
+
shouldStopExecution: () => false,
|
|
2279
|
+
isBlockingDecision: () => false,
|
|
2280
|
+
shouldClearContext: () => false,
|
|
2281
|
+
systemMessage: undefined,
|
|
2282
|
+
});
|
|
2283
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
2284
|
+
yield { type: LlmEventType.TextDelta, text: 'Response' };
|
|
2285
|
+
});
|
|
2286
|
+
const stream = client.sendMessageStream({ text: 'Hi' }, new AbortController().signal, 'test-prompt');
|
|
2287
|
+
const events = await fromAsync(stream);
|
|
2288
|
+
expect(events).toContainEqual(expect.objectContaining({
|
|
2289
|
+
type: LlmEventType.AgentBlocked,
|
|
2290
|
+
reason: 'Please explain',
|
|
2291
|
+
}));
|
|
2292
|
+
// Should have called turn run twice (original + re-prompt)
|
|
2293
|
+
expect(mockTurnRunFn).toHaveBeenCalledTimes(2);
|
|
2294
|
+
expect(mockTurnRunFn).toHaveBeenNthCalledWith(2, expect.anything(), [{ text: 'Please explain' }], expect.anything());
|
|
2295
|
+
});
|
|
2296
|
+
it('should call resetChat when AfterAgent hook returns shouldClearContext: true', async () => {
|
|
2297
|
+
const resetChatSpy = vi
|
|
2298
|
+
.spyOn(client, 'resetChat')
|
|
2299
|
+
.mockResolvedValue(undefined);
|
|
2300
|
+
mockHookSystem.fireAfterAgentEvent
|
|
2301
|
+
.mockResolvedValueOnce({
|
|
2302
|
+
shouldStopExecution: () => false,
|
|
2303
|
+
isBlockingDecision: () => true,
|
|
2304
|
+
getEffectiveReason: () => 'Blocked and clearing context',
|
|
2305
|
+
shouldClearContext: () => true,
|
|
2306
|
+
systemMessage: undefined,
|
|
2307
|
+
})
|
|
2308
|
+
.mockResolvedValueOnce({
|
|
2309
|
+
shouldStopExecution: () => false,
|
|
2310
|
+
isBlockingDecision: () => false,
|
|
2311
|
+
shouldClearContext: () => false,
|
|
2312
|
+
systemMessage: undefined,
|
|
2313
|
+
});
|
|
2314
|
+
mockTurnRunFn.mockImplementation(async function* () {
|
|
2315
|
+
yield { type: LlmEventType.TextDelta, text: 'Response' };
|
|
2316
|
+
});
|
|
2317
|
+
const stream = client.sendMessageStream({ text: 'Hi' }, new AbortController().signal, 'test-prompt');
|
|
2318
|
+
const events = await fromAsync(stream);
|
|
2319
|
+
expect(events).toContainEqual({
|
|
2320
|
+
type: LlmEventType.AgentBlocked,
|
|
2321
|
+
reason: 'Blocked and clearing context',
|
|
2322
|
+
systemMessage: undefined,
|
|
2323
|
+
contextCleared: true,
|
|
2324
|
+
});
|
|
2325
|
+
expect(resetChatSpy).toHaveBeenCalledTimes(1);
|
|
2326
|
+
resetChatSpy.mockRestore();
|
|
2327
|
+
});
|
|
2328
|
+
});
|
|
2329
|
+
});
|
|
2330
|
+
// ============================================================================
|
|
2331
|
+
// processLlmTurn — Non-Gemini provider path
|
|
2332
|
+
// ============================================================================
|
|
2333
|
+
describe('processLlmTurn — non-Gemini provider path', () => {
|
|
2334
|
+
function createNonGeminiGenerator(streamEvents) {
|
|
2335
|
+
return {
|
|
2336
|
+
providerName: 'claude',
|
|
2337
|
+
generateContent: () => {
|
|
2338
|
+
throw new Error('Legacy Gemini API not supported');
|
|
2339
|
+
},
|
|
2340
|
+
generateContentStream: () => {
|
|
2341
|
+
throw new Error('Legacy Gemini API not supported');
|
|
2342
|
+
},
|
|
2343
|
+
countTokens: () => {
|
|
2344
|
+
throw new Error('Legacy Gemini API not supported');
|
|
2345
|
+
},
|
|
2346
|
+
embedContent: () => {
|
|
2347
|
+
throw new Error('Legacy Gemini API not supported');
|
|
2348
|
+
},
|
|
2349
|
+
llmGenerateContent: vi.fn(),
|
|
2350
|
+
llmGenerateContentStream: vi.fn().mockReturnValue((async function* () {
|
|
2351
|
+
for (const event of streamEvents) {
|
|
2352
|
+
yield event;
|
|
2353
|
+
}
|
|
2354
|
+
})()),
|
|
2355
|
+
llmCountTokens: vi.fn(),
|
|
2356
|
+
};
|
|
2357
|
+
}
|
|
2358
|
+
function setupNonGeminiClient(streamEvents) {
|
|
2359
|
+
const generator = createNonGeminiGenerator(streamEvents);
|
|
2360
|
+
vi.mocked(mockConfig.getContentGenerator).mockReturnValue(generator);
|
|
2361
|
+
const mockRecordingService = {
|
|
2362
|
+
recordMessage: vi.fn(),
|
|
2363
|
+
recordMessageTokens: vi.fn(),
|
|
2364
|
+
recordToolCalls: vi.fn(),
|
|
2365
|
+
recordThought: vi.fn(),
|
|
2366
|
+
initialize: vi.fn(),
|
|
2367
|
+
};
|
|
2368
|
+
const mockChat = {
|
|
2369
|
+
addHistory: vi.fn(),
|
|
2370
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2371
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(0),
|
|
2372
|
+
getChatRecordingService: vi.fn().mockReturnValue(mockRecordingService),
|
|
2373
|
+
getSystemInstruction: vi.fn().mockReturnValue('You are helpful.'),
|
|
2374
|
+
getConfiguredTools: vi.fn().mockReturnValue([]),
|
|
2375
|
+
};
|
|
2376
|
+
client['chat'] = mockChat;
|
|
2377
|
+
return { generator, mockChat, mockRecordingService };
|
|
2378
|
+
}
|
|
2379
|
+
it('should yield LlmEvents from non-Gemini provider stream', async () => {
|
|
2380
|
+
const events = [
|
|
2381
|
+
{ type: LlmEventType.TextDelta, text: 'Hello ' },
|
|
2382
|
+
{ type: LlmEventType.TextDelta, text: 'world' },
|
|
2383
|
+
{ type: LlmEventType.Finished, finishReason: 'end_turn' },
|
|
2384
|
+
];
|
|
2385
|
+
setupNonGeminiClient(events);
|
|
2386
|
+
const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-llm-1');
|
|
2387
|
+
const yielded = await fromAsync(stream);
|
|
2388
|
+
// Should contain ModelInfo + the 3 LlmEvents
|
|
2389
|
+
// Note: routing is skipped for non-Gemini, model comes from
|
|
2390
|
+
// resolveProviderModel(config.getModel(), 'claude')
|
|
2391
|
+
expect(yielded).toContainEqual({
|
|
2392
|
+
type: LlmEventType.ModelInfo,
|
|
2393
|
+
modelName: 'test-model',
|
|
2394
|
+
});
|
|
2395
|
+
expect(yielded).toContainEqual({
|
|
2396
|
+
type: LlmEventType.TextDelta,
|
|
2397
|
+
text: 'Hello ',
|
|
2398
|
+
});
|
|
2399
|
+
expect(yielded).toContainEqual({
|
|
2400
|
+
type: LlmEventType.TextDelta,
|
|
2401
|
+
text: 'world',
|
|
2402
|
+
});
|
|
2403
|
+
expect(yielded).toContainEqual({
|
|
2404
|
+
type: LlmEventType.Finished,
|
|
2405
|
+
finishReason: 'end_turn',
|
|
2406
|
+
});
|
|
2407
|
+
});
|
|
2408
|
+
it('should NOT call Turn.run for non-Gemini providers', async () => {
|
|
2409
|
+
setupNonGeminiClient([
|
|
2410
|
+
{ type: LlmEventType.TextDelta, text: 'Hi' },
|
|
2411
|
+
{ type: LlmEventType.Finished, finishReason: 'end_turn' },
|
|
2412
|
+
]);
|
|
2413
|
+
const stream = client.sendMessageStream([{ text: 'test' }], new AbortController().signal, 'prompt-llm-2');
|
|
2414
|
+
await fromAsync(stream);
|
|
2415
|
+
expect(mockTurnRunFn).not.toHaveBeenCalled();
|
|
2416
|
+
});
|
|
2417
|
+
it('should add user request and model response to history', async () => {
|
|
2418
|
+
const { mockChat } = setupNonGeminiClient([
|
|
2419
|
+
{ type: LlmEventType.TextDelta, text: 'Response text' },
|
|
2420
|
+
{ type: LlmEventType.Finished, finishReason: 'end_turn' },
|
|
2421
|
+
]);
|
|
2422
|
+
const stream = client.sendMessageStream([{ text: 'User message' }], new AbortController().signal, 'prompt-llm-3');
|
|
2423
|
+
await fromAsync(stream);
|
|
2424
|
+
// User request added to history
|
|
2425
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({ role: 'user' }));
|
|
2426
|
+
// Model response added to history
|
|
2427
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({
|
|
2428
|
+
role: 'model',
|
|
2429
|
+
parts: expect.arrayContaining([{ text: 'Response text' }]),
|
|
2430
|
+
}));
|
|
2431
|
+
});
|
|
2432
|
+
it('should record user and model messages via chat recording service', async () => {
|
|
2433
|
+
const { mockRecordingService } = setupNonGeminiClient([
|
|
2434
|
+
{ type: LlmEventType.TextDelta, text: 'Bot reply' },
|
|
2435
|
+
{ type: LlmEventType.Finished, finishReason: 'end_turn' },
|
|
2436
|
+
]);
|
|
2437
|
+
const stream = client.sendMessageStream([{ text: 'User msg' }], new AbortController().signal, 'prompt-llm-4');
|
|
2438
|
+
await fromAsync(stream);
|
|
2439
|
+
// User message recorded
|
|
2440
|
+
expect(mockRecordingService.recordMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'user' }));
|
|
2441
|
+
// Model response recorded
|
|
2442
|
+
expect(mockRecordingService.recordMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'gemini', content: 'Bot reply' }));
|
|
2443
|
+
});
|
|
2444
|
+
it('should handle tool call requests in non-Gemini stream', async () => {
|
|
2445
|
+
setupNonGeminiClient([
|
|
2446
|
+
{ type: LlmEventType.TextDelta, text: 'Let me search.' },
|
|
2447
|
+
{
|
|
2448
|
+
type: LlmEventType.ToolCallRequest,
|
|
2449
|
+
callId: 'call-1',
|
|
2450
|
+
name: 'search',
|
|
2451
|
+
args: { query: 'cats' },
|
|
2452
|
+
},
|
|
2453
|
+
{ type: LlmEventType.Finished, finishReason: 'tool_use' },
|
|
2454
|
+
]);
|
|
2455
|
+
const stream = client.sendMessageStream([{ text: 'Find cats' }], new AbortController().signal, 'prompt-llm-5');
|
|
2456
|
+
const yielded = await fromAsync(stream);
|
|
2457
|
+
expect(yielded).toContainEqual(expect.objectContaining({
|
|
2458
|
+
type: LlmEventType.ToolCallRequest,
|
|
2459
|
+
name: 'search',
|
|
2460
|
+
}));
|
|
2461
|
+
});
|
|
2462
|
+
it('should not add model response to history on error', async () => {
|
|
2463
|
+
const { mockChat } = setupNonGeminiClient([
|
|
2464
|
+
{ type: LlmEventType.TextDelta, text: 'partial...' },
|
|
2465
|
+
{
|
|
2466
|
+
type: LlmEventType.Error,
|
|
2467
|
+
error: 'Something went wrong',
|
|
2468
|
+
},
|
|
2469
|
+
]);
|
|
2470
|
+
const stream = client.sendMessageStream([{ text: 'test' }], new AbortController().signal, 'prompt-llm-6');
|
|
2471
|
+
await fromAsync(stream);
|
|
2472
|
+
// User request IS added
|
|
2473
|
+
expect(mockChat.addHistory).toHaveBeenCalledWith(expect.objectContaining({ role: 'user' }));
|
|
2474
|
+
// Model response should NOT be added (error occurred)
|
|
2475
|
+
expect(mockChat.addHistory).not.toHaveBeenCalledWith(expect.objectContaining({ role: 'model' }));
|
|
2476
|
+
});
|
|
2477
|
+
it('should call llmGenerateContentStream with correct request', async () => {
|
|
2478
|
+
const { generator } = setupNonGeminiClient([
|
|
2479
|
+
{ type: LlmEventType.Finished, finishReason: 'end_turn' },
|
|
2480
|
+
]);
|
|
2481
|
+
const stream = client.sendMessageStream([{ text: 'Hello' }], new AbortController().signal, 'prompt-llm-7');
|
|
2482
|
+
await fromAsync(stream);
|
|
2483
|
+
const llmStream = generator.llmGenerateContentStream;
|
|
2484
|
+
expect(llmStream).toHaveBeenCalledWith(expect.objectContaining({
|
|
2485
|
+
model: 'test-model',
|
|
2486
|
+
messages: expect.any(Array),
|
|
2487
|
+
}), 'prompt-llm-7', expect.objectContaining({ signal: expect.any(AbortSignal) }));
|
|
2488
|
+
});
|
|
2489
|
+
it('should skip routing for non-Gemini providers', async () => {
|
|
2490
|
+
setupNonGeminiClient([
|
|
2491
|
+
{ type: LlmEventType.Finished, finishReason: 'end_turn' },
|
|
2492
|
+
]);
|
|
2493
|
+
const stream = client.sendMessageStream([{ text: 'test' }], new AbortController().signal, 'prompt-llm-8');
|
|
2494
|
+
await fromAsync(stream);
|
|
2495
|
+
// Routing should NOT be called — it uses legacy Gemini API
|
|
2496
|
+
expect(mockRouterService.route).not.toHaveBeenCalled();
|
|
2497
|
+
});
|
|
2498
|
+
it('should update config model for status bar display', async () => {
|
|
2499
|
+
setupNonGeminiClient([
|
|
2500
|
+
{ type: LlmEventType.Finished, finishReason: 'end_turn' },
|
|
2501
|
+
]);
|
|
2502
|
+
const stream = client.sendMessageStream([{ text: 'test' }], new AbortController().signal, 'prompt-llm-9');
|
|
2503
|
+
await fromAsync(stream);
|
|
2504
|
+
// config.setModel should be called with resolved provider model
|
|
2505
|
+
expect(mockConfig.setModel).toHaveBeenCalledWith('test-model', true);
|
|
2506
|
+
});
|
|
2507
|
+
it('should yield explicit error when providerName is non-gemini but llm* methods are missing', async () => {
|
|
2508
|
+
const brokenGenerator = {
|
|
2509
|
+
providerName: 'claude',
|
|
2510
|
+
generateContent: () => {
|
|
2511
|
+
throw new Error('legacy path');
|
|
2512
|
+
},
|
|
2513
|
+
generateContentStream: () => {
|
|
2514
|
+
throw new Error('legacy path');
|
|
2515
|
+
},
|
|
2516
|
+
countTokens: () => {
|
|
2517
|
+
throw new Error('legacy path');
|
|
2518
|
+
},
|
|
2519
|
+
embedContent: () => {
|
|
2520
|
+
throw new Error('legacy path');
|
|
2521
|
+
},
|
|
2522
|
+
};
|
|
2523
|
+
vi.mocked(mockConfig.getContentGenerator).mockReturnValue(brokenGenerator);
|
|
2524
|
+
const mockChat = {
|
|
2525
|
+
addHistory: vi.fn(),
|
|
2526
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2527
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(0),
|
|
2528
|
+
getChatRecordingService: vi.fn().mockReturnValue({
|
|
2529
|
+
recordMessage: vi.fn(),
|
|
2530
|
+
recordMessageTokens: vi.fn(),
|
|
2531
|
+
recordToolCalls: vi.fn(),
|
|
2532
|
+
recordThought: vi.fn(),
|
|
2533
|
+
initialize: vi.fn(),
|
|
2534
|
+
}),
|
|
2535
|
+
getSystemInstruction: vi.fn().mockReturnValue('You are helpful.'),
|
|
2536
|
+
getConfiguredTools: vi.fn().mockReturnValue([]),
|
|
2537
|
+
};
|
|
2538
|
+
client['chat'] = mockChat;
|
|
2539
|
+
const stream = client.sendMessageStream([{ text: 'test' }], new AbortController().signal, 'prompt-llm-mismatch');
|
|
2540
|
+
const yielded = await fromAsync(stream);
|
|
2541
|
+
expect(yielded).toContainEqual(expect.objectContaining({
|
|
2542
|
+
type: LlmEventType.Error,
|
|
2543
|
+
code: 'PROVIDER_METHOD_MISMATCH',
|
|
2544
|
+
isRetryable: false,
|
|
2545
|
+
}));
|
|
2546
|
+
expect(mockRouterService.route).not.toHaveBeenCalled();
|
|
2547
|
+
});
|
|
2548
|
+
it('should convert thrown llm stream exception into Error event', async () => {
|
|
2549
|
+
const generator = createNonGeminiGenerator([]);
|
|
2550
|
+
generator.llmGenerateContentStream = vi.fn().mockReturnValue(
|
|
2551
|
+
// eslint-disable-next-line require-yield
|
|
2552
|
+
(async function* () {
|
|
2553
|
+
throw new Error('stream exploded');
|
|
2554
|
+
})());
|
|
2555
|
+
vi.mocked(mockConfig.getContentGenerator).mockReturnValue(generator);
|
|
2556
|
+
const mockChat = {
|
|
2557
|
+
addHistory: vi.fn(),
|
|
2558
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2559
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(0),
|
|
2560
|
+
getChatRecordingService: vi.fn().mockReturnValue({
|
|
2561
|
+
recordMessage: vi.fn(),
|
|
2562
|
+
recordMessageTokens: vi.fn(),
|
|
2563
|
+
recordToolCalls: vi.fn(),
|
|
2564
|
+
recordThought: vi.fn(),
|
|
2565
|
+
initialize: vi.fn(),
|
|
2566
|
+
}),
|
|
2567
|
+
getSystemInstruction: vi.fn().mockReturnValue('You are helpful.'),
|
|
2568
|
+
getConfiguredTools: vi.fn().mockReturnValue([]),
|
|
2569
|
+
};
|
|
2570
|
+
client['chat'] = mockChat;
|
|
2571
|
+
const stream = client.sendMessageStream([{ text: 'test' }], new AbortController().signal, 'prompt-llm-throw');
|
|
2572
|
+
const yielded = await fromAsync(stream);
|
|
2573
|
+
expect(yielded).toContainEqual(expect.objectContaining({
|
|
2574
|
+
type: LlmEventType.ModelInfo,
|
|
2575
|
+
modelName: 'test-model',
|
|
2576
|
+
}));
|
|
2577
|
+
expect(yielded).toContainEqual(expect.objectContaining({
|
|
2578
|
+
type: LlmEventType.Error,
|
|
2579
|
+
code: 'LLM_STREAM_FAILURE',
|
|
2580
|
+
isRetryable: false,
|
|
2581
|
+
}));
|
|
2582
|
+
// Error path should not append model response history.
|
|
2583
|
+
expect(mockChat.addHistory).not.toHaveBeenCalledWith(expect.objectContaining({ role: 'model' }));
|
|
2584
|
+
});
|
|
2585
|
+
it('should yield UserCancelled (not Error) when abort signal triggers stream throw', async () => {
|
|
2586
|
+
const controller = new AbortController();
|
|
2587
|
+
const generator = createNonGeminiGenerator([]);
|
|
2588
|
+
generator.llmGenerateContentStream = vi.fn().mockReturnValue(
|
|
2589
|
+
// eslint-disable-next-line require-yield
|
|
2590
|
+
(async function* () {
|
|
2591
|
+
// Simulate: stream throws after abort signal fires
|
|
2592
|
+
controller.abort();
|
|
2593
|
+
throw new Error('The operation was aborted');
|
|
2594
|
+
})());
|
|
2595
|
+
vi.mocked(mockConfig.getContentGenerator).mockReturnValue(generator);
|
|
2596
|
+
const mockChat = {
|
|
2597
|
+
addHistory: vi.fn(),
|
|
2598
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2599
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(0),
|
|
2600
|
+
getChatRecordingService: vi.fn().mockReturnValue({
|
|
2601
|
+
recordMessage: vi.fn(),
|
|
2602
|
+
recordMessageTokens: vi.fn(),
|
|
2603
|
+
recordToolCalls: vi.fn(),
|
|
2604
|
+
recordThought: vi.fn(),
|
|
2605
|
+
initialize: vi.fn(),
|
|
2606
|
+
}),
|
|
2607
|
+
getSystemInstruction: vi.fn().mockReturnValue('You are helpful.'),
|
|
2608
|
+
getConfiguredTools: vi.fn().mockReturnValue([]),
|
|
2609
|
+
};
|
|
2610
|
+
client['chat'] = mockChat;
|
|
2611
|
+
const stream = client.sendMessageStream([{ text: 'test' }], controller.signal, 'prompt-abort-stream');
|
|
2612
|
+
const yielded = await fromAsync(stream);
|
|
2613
|
+
// Should emit UserCancelled, NOT LLM_STREAM_FAILURE
|
|
2614
|
+
expect(yielded).toContainEqual({
|
|
2615
|
+
type: LlmEventType.UserCancelled,
|
|
2616
|
+
});
|
|
2617
|
+
expect(yielded).not.toContainEqual(expect.objectContaining({ code: 'LLM_STREAM_FAILURE' }));
|
|
2618
|
+
});
|
|
2619
|
+
it('should yield UserCancelled when stream throws AbortError by name', async () => {
|
|
2620
|
+
const generator = createNonGeminiGenerator([]);
|
|
2621
|
+
const abortError = new Error('Aborted');
|
|
2622
|
+
abortError.name = 'AbortError';
|
|
2623
|
+
generator.llmGenerateContentStream = vi.fn().mockReturnValue(
|
|
2624
|
+
// eslint-disable-next-line require-yield
|
|
2625
|
+
(async function* () {
|
|
2626
|
+
throw abortError;
|
|
2627
|
+
})());
|
|
2628
|
+
vi.mocked(mockConfig.getContentGenerator).mockReturnValue(generator);
|
|
2629
|
+
const mockChat = {
|
|
2630
|
+
addHistory: vi.fn(),
|
|
2631
|
+
getHistory: vi.fn().mockReturnValue([]),
|
|
2632
|
+
getLastPromptTokenCount: vi.fn().mockReturnValue(0),
|
|
2633
|
+
getChatRecordingService: vi.fn().mockReturnValue({
|
|
2634
|
+
recordMessage: vi.fn(),
|
|
2635
|
+
recordMessageTokens: vi.fn(),
|
|
2636
|
+
recordToolCalls: vi.fn(),
|
|
2637
|
+
recordThought: vi.fn(),
|
|
2638
|
+
initialize: vi.fn(),
|
|
2639
|
+
}),
|
|
2640
|
+
getSystemInstruction: vi.fn().mockReturnValue('You are helpful.'),
|
|
2641
|
+
getConfiguredTools: vi.fn().mockReturnValue([]),
|
|
2642
|
+
};
|
|
2643
|
+
client['chat'] = mockChat;
|
|
2644
|
+
const stream = client.sendMessageStream([{ text: 'test' }], new AbortController().signal, 'prompt-abort-error');
|
|
2645
|
+
const yielded = await fromAsync(stream);
|
|
2646
|
+
// AbortError by name should also be classified as user cancellation
|
|
2647
|
+
expect(yielded).toContainEqual({
|
|
2648
|
+
type: LlmEventType.UserCancelled,
|
|
2649
|
+
});
|
|
2650
|
+
expect(yielded).not.toContainEqual(expect.objectContaining({ code: 'LLM_STREAM_FAILURE' }));
|
|
2651
|
+
});
|
|
2652
|
+
});
|
|
2653
|
+
});
|
|
2654
|
+
//# sourceMappingURL=client.test.js.map
|