byterover-cli 0.3.5 → 0.4.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/README.md +119 -63
- package/bin/dev.js +8 -1
- package/bin/run.js +7 -0
- package/dist/commands/cipher-agent/run.d.ts +30 -0
- package/dist/commands/cipher-agent/run.js +123 -61
- package/dist/commands/cipher-agent/set-prompt.d.ts +2 -0
- package/dist/commands/cipher-agent/set-prompt.js +13 -8
- package/dist/commands/cipher-agent/show-prompt.d.ts +2 -0
- package/dist/commands/cipher-agent/show-prompt.js +17 -12
- package/dist/commands/curate.d.ts +3 -60
- package/dist/commands/curate.js +45 -341
- package/dist/commands/foo.d.ts +4 -2
- package/dist/commands/foo.js +21 -16
- package/dist/commands/main.d.ts +9 -0
- package/dist/commands/main.js +34 -0
- package/dist/commands/query.d.ts +2 -48
- package/dist/commands/query.js +19 -287
- package/dist/commands/status.d.ts +2 -13
- package/dist/commands/status.js +12 -91
- package/dist/commands/watch.d.ts +2 -0
- package/dist/commands/watch.js +23 -19
- package/dist/config/environment.d.ts +1 -1
- package/dist/config/environment.js +2 -2
- package/dist/constants.d.ts +4 -5
- package/dist/constants.js +5 -5
- package/dist/core/domain/cipher/errors/storage-error.d.ts +89 -0
- package/dist/core/domain/cipher/errors/storage-error.js +130 -0
- package/dist/core/domain/cipher/queue/types.d.ts +71 -0
- package/dist/core/domain/cipher/queue/types.js +9 -0
- package/dist/core/domain/cipher/storage/message-storage-types.d.ts +218 -0
- package/dist/core/domain/cipher/storage/message-storage-types.js +18 -0
- package/dist/core/domain/cipher/tools/constants.d.ts +1 -0
- package/dist/core/domain/cipher/tools/constants.js +1 -0
- package/dist/core/domain/entities/event.d.ts +1 -1
- package/dist/core/domain/entities/event.js +5 -0
- package/dist/core/domain/entities/global-config.d.ts +36 -0
- package/dist/core/domain/entities/global-config.js +66 -0
- package/dist/core/domain/knowledge/directory-manager.d.ts +10 -0
- package/dist/core/domain/knowledge/directory-manager.js +18 -0
- package/dist/core/domain/knowledge/markdown-writer.d.ts +9 -0
- package/dist/core/domain/knowledge/markdown-writer.js +51 -1
- package/dist/core/interfaces/cipher/i-agent-storage.d.ts +152 -0
- package/dist/core/interfaces/cipher/i-agent-storage.js +1 -0
- package/dist/core/interfaces/cipher/i-cipher-agent.d.ts +2 -0
- package/dist/core/interfaces/cipher/i-key-storage.d.ts +91 -0
- package/dist/core/interfaces/cipher/i-key-storage.js +1 -0
- package/dist/core/interfaces/i-global-config-store.d.ts +34 -0
- package/dist/core/interfaces/i-global-config-store.js +1 -0
- package/dist/core/interfaces/i-onboarding-preference-store.d.ts +20 -0
- package/dist/core/interfaces/i-onboarding-preference-store.js +1 -0
- package/dist/core/interfaces/i-terminal.d.ts +146 -0
- package/dist/core/interfaces/i-terminal.js +1 -0
- package/dist/core/interfaces/i-workspace-detector-service.d.ts +8 -0
- package/dist/core/interfaces/i-workspace-detector-service.js +1 -0
- package/dist/core/interfaces/usecase/i-clear-use-case.d.ts +6 -0
- package/dist/core/interfaces/usecase/i-clear-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-curate-use-case.d.ts +10 -0
- package/dist/core/interfaces/usecase/i-curate-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-generate-rules-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-generate-rules-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-init-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-init-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-login-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-login-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-logout-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-logout-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-pull-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-pull-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-push-use-case.d.ts +6 -0
- package/dist/core/interfaces/usecase/i-push-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-query-use-case.d.ts +9 -0
- package/dist/core/interfaces/usecase/i-query-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-space-list-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-space-list-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-space-switch-use-case.d.ts +3 -0
- package/dist/core/interfaces/usecase/i-space-switch-use-case.js +1 -0
- package/dist/core/interfaces/usecase/i-status-use-case.d.ts +5 -0
- package/dist/core/interfaces/usecase/i-status-use-case.js +1 -0
- package/dist/hooks/init/welcome.js +1 -2
- package/dist/infra/cipher/agent-service-factory.d.ts +13 -6
- package/dist/infra/cipher/agent-service-factory.js +40 -16
- package/dist/infra/cipher/cipher-agent.js +4 -4
- package/dist/infra/cipher/consumer/consumer-lock.d.ts +20 -0
- package/dist/infra/cipher/consumer/consumer-lock.js +40 -0
- package/dist/infra/cipher/consumer/consumer-service.d.ts +99 -0
- package/dist/infra/cipher/consumer/consumer-service.js +165 -0
- package/dist/infra/cipher/consumer/execution-consumer.d.ts +121 -0
- package/dist/infra/cipher/consumer/execution-consumer.js +523 -0
- package/dist/infra/cipher/consumer/index.d.ts +33 -0
- package/dist/infra/cipher/consumer/index.js +33 -0
- package/dist/infra/cipher/consumer/queue-polling-service.d.ts +120 -0
- package/dist/infra/cipher/consumer/queue-polling-service.js +248 -0
- package/dist/infra/cipher/http/internal-llm-http-service.d.ts +94 -0
- package/dist/infra/cipher/http/internal-llm-http-service.js +118 -0
- package/dist/infra/cipher/llm/context/compaction/compaction-service.d.ts +106 -0
- package/dist/infra/cipher/llm/context/compaction/compaction-service.js +132 -0
- package/dist/infra/cipher/llm/context/compaction/index.d.ts +9 -0
- package/dist/infra/cipher/llm/context/compaction/index.js +9 -0
- package/dist/infra/cipher/llm/context/context-manager.d.ts +46 -2
- package/dist/infra/cipher/llm/context/context-manager.js +68 -4
- package/dist/infra/cipher/llm/context/rw-lock.d.ts +72 -0
- package/dist/infra/cipher/llm/context/rw-lock.js +145 -0
- package/dist/infra/cipher/llm/generators/byterover-content-generator.d.ts +7 -7
- package/dist/infra/cipher/llm/generators/byterover-content-generator.js +8 -8
- package/dist/infra/cipher/llm/internal-llm-service.js +2 -0
- package/dist/infra/cipher/session/session-manager.d.ts +4 -4
- package/dist/infra/cipher/session/session-manager.js +5 -5
- package/dist/infra/cipher/storage/agent-storage.d.ts +246 -0
- package/dist/infra/cipher/storage/agent-storage.js +956 -0
- package/dist/infra/cipher/storage/dual-format-history-storage.d.ts +77 -0
- package/dist/infra/cipher/storage/dual-format-history-storage.js +149 -0
- package/dist/infra/cipher/storage/granular-history-storage.d.ts +65 -0
- package/dist/infra/cipher/storage/granular-history-storage.js +118 -0
- package/dist/infra/cipher/storage/message-storage-service.d.ts +108 -0
- package/dist/infra/cipher/storage/message-storage-service.js +529 -0
- package/dist/infra/cipher/storage/process-utils.d.ts +16 -0
- package/dist/infra/cipher/storage/process-utils.js +43 -0
- package/dist/infra/cipher/storage/sqlite-key-storage.d.ts +105 -0
- package/dist/infra/cipher/storage/sqlite-key-storage.js +404 -0
- package/dist/infra/cipher/system-prompt/simple-prompt-factory.d.ts +1 -0
- package/dist/infra/cipher/system-prompt/simple-prompt-factory.js +7 -0
- package/dist/infra/cipher/tools/default-policy-rules.js +1 -1
- package/dist/infra/cipher/tools/implementations/curate-tool.d.ts +10 -0
- package/dist/infra/cipher/tools/implementations/curate-tool.js +371 -0
- package/dist/infra/cipher/tools/implementations/find-knowledge-topics-tool.js +11 -8
- package/dist/infra/cipher/tools/tool-manager.d.ts +8 -2
- package/dist/infra/cipher/tools/tool-manager.js +29 -2
- package/dist/infra/cipher/tools/tool-registry.js +7 -0
- package/dist/infra/http/authenticated-http-client.d.ts +21 -0
- package/dist/infra/http/authenticated-http-client.js +38 -0
- package/dist/infra/repl/commands/arg-parser.d.ts +97 -0
- package/dist/infra/repl/commands/arg-parser.js +129 -0
- package/dist/infra/repl/commands/clear-command.d.ts +5 -0
- package/dist/infra/repl/commands/clear-command.js +61 -0
- package/dist/infra/repl/commands/curate-command.d.ts +9 -0
- package/dist/infra/repl/commands/curate-command.js +88 -0
- package/dist/infra/repl/commands/gen-rules-command.d.ts +7 -0
- package/dist/infra/repl/commands/gen-rules-command.js +38 -0
- package/dist/infra/repl/commands/index.d.ts +8 -0
- package/dist/infra/repl/commands/index.js +36 -0
- package/dist/infra/repl/commands/init-command.d.ts +7 -0
- package/dist/infra/repl/commands/init-command.js +83 -0
- package/dist/infra/repl/commands/login-command.d.ts +7 -0
- package/dist/infra/repl/commands/login-command.js +50 -0
- package/dist/infra/repl/commands/logout-command.d.ts +5 -0
- package/dist/infra/repl/commands/logout-command.js +48 -0
- package/dist/infra/repl/commands/pull-command.d.ts +5 -0
- package/dist/infra/repl/commands/pull-command.js +61 -0
- package/dist/infra/repl/commands/push-command.d.ts +5 -0
- package/dist/infra/repl/commands/push-command.js +66 -0
- package/dist/infra/repl/commands/query-command.d.ts +5 -0
- package/dist/infra/repl/commands/query-command.js +66 -0
- package/dist/infra/repl/commands/space/index.d.ts +5 -0
- package/dist/infra/repl/commands/space/index.js +14 -0
- package/dist/infra/repl/commands/space/list-command.d.ts +5 -0
- package/dist/infra/repl/commands/space/list-command.js +70 -0
- package/dist/infra/repl/commands/space/switch-command.d.ts +5 -0
- package/dist/infra/repl/commands/space/switch-command.js +37 -0
- package/dist/infra/repl/commands/status-command.d.ts +5 -0
- package/dist/infra/repl/commands/status-command.js +39 -0
- package/dist/infra/repl/repl-startup.d.ts +18 -0
- package/dist/infra/repl/repl-startup.js +26 -0
- package/dist/infra/storage/file-global-config-store.d.ts +22 -0
- package/dist/infra/storage/file-global-config-store.js +65 -0
- package/dist/infra/storage/file-onboarding-preference-store.d.ts +10 -0
- package/dist/infra/storage/file-onboarding-preference-store.js +46 -0
- package/dist/infra/terminal/oclif-terminal.d.ts +19 -0
- package/dist/infra/terminal/oclif-terminal.js +60 -0
- package/dist/infra/terminal/repl-terminal.d.ts +31 -0
- package/dist/infra/terminal/repl-terminal.js +116 -0
- package/dist/infra/tracking/mixpanel-tracking-service.d.ts +11 -1
- package/dist/infra/tracking/mixpanel-tracking-service.js +18 -13
- package/dist/infra/usecase/clear-use-case.d.ts +20 -0
- package/dist/infra/usecase/clear-use-case.js +58 -0
- package/dist/infra/usecase/curate-use-case.d.ts +66 -0
- package/dist/infra/usecase/curate-use-case.js +283 -0
- package/dist/{commands/gen-rules.d.ts → infra/usecase/generate-rules-use-case.d.ts} +14 -20
- package/dist/{commands/gen-rules.js → infra/usecase/generate-rules-use-case.js} +59 -78
- package/dist/infra/usecase/init-use-case.d.ts +139 -0
- package/dist/{commands/init.js → infra/usecase/init-use-case.js} +184 -230
- package/dist/infra/usecase/login-use-case.d.ts +28 -0
- package/dist/infra/usecase/login-use-case.js +88 -0
- package/dist/infra/usecase/logout-use-case.d.ts +22 -0
- package/dist/infra/usecase/logout-use-case.js +51 -0
- package/dist/infra/usecase/pull-use-case.d.ts +35 -0
- package/dist/infra/usecase/pull-use-case.js +89 -0
- package/dist/infra/usecase/push-use-case.d.ts +37 -0
- package/dist/infra/usecase/push-use-case.js +124 -0
- package/dist/infra/usecase/query-use-case.d.ts +78 -0
- package/dist/infra/usecase/query-use-case.js +401 -0
- package/dist/infra/usecase/space-list-use-case.d.ts +27 -0
- package/dist/infra/usecase/space-list-use-case.js +64 -0
- package/dist/infra/usecase/space-switch-use-case.d.ts +36 -0
- package/dist/infra/usecase/space-switch-use-case.js +140 -0
- package/dist/infra/usecase/status-use-case.d.ts +27 -0
- package/dist/infra/usecase/status-use-case.js +97 -0
- package/dist/infra/workspace/workspace-detector-service.d.ts +3 -6
- package/dist/resources/prompts/curate-context-tree-curation.yml +23 -11
- package/dist/resources/prompts/query-context-tree-retrieval.yml +3 -4
- package/dist/resources/prompts/system-prompt.yml +1 -1
- package/dist/resources/prompts/tool-outputs.yml +4 -3
- package/dist/templates/sections/command-reference.md +12 -0
- package/dist/templates/sections/workflow.md +10 -1
- package/dist/tui/app.d.ts +9 -0
- package/dist/tui/app.js +26 -0
- package/dist/tui/components/enter-prompt.d.ts +13 -0
- package/dist/tui/components/enter-prompt.js +15 -0
- package/dist/tui/components/execution/execution-changes.d.ts +14 -0
- package/dist/tui/components/execution/execution-changes.js +15 -0
- package/dist/tui/components/execution/execution-content.d.ts +25 -0
- package/dist/tui/components/execution/execution-content.js +67 -0
- package/dist/tui/components/execution/execution-input.d.ts +12 -0
- package/dist/tui/components/execution/execution-input.js +16 -0
- package/dist/tui/components/execution/execution-progress.d.ts +21 -0
- package/dist/tui/components/execution/execution-progress.js +21 -0
- package/dist/tui/components/execution/execution-status.d.ts +13 -0
- package/dist/tui/components/execution/execution-status.js +19 -0
- package/dist/tui/components/execution/index.d.ts +11 -0
- package/dist/tui/components/execution/index.js +11 -0
- package/dist/tui/components/execution/log-item.d.ts +17 -0
- package/dist/tui/components/execution/log-item.js +25 -0
- package/dist/tui/components/footer.d.ts +5 -0
- package/dist/tui/components/footer.js +12 -0
- package/dist/tui/components/header.d.ts +18 -0
- package/dist/tui/components/header.js +18 -0
- package/dist/tui/components/index.d.ts +17 -0
- package/dist/tui/components/index.js +14 -0
- package/dist/tui/components/inline-prompts/index.d.ts +15 -0
- package/dist/tui/components/inline-prompts/index.js +10 -0
- package/dist/tui/components/inline-prompts/inline-confirm.d.ts +17 -0
- package/dist/tui/components/inline-prompts/inline-confirm.js +32 -0
- package/dist/tui/components/inline-prompts/inline-file-selector.d.ts +43 -0
- package/dist/tui/components/inline-prompts/inline-file-selector.js +185 -0
- package/dist/tui/components/inline-prompts/inline-input.d.ts +19 -0
- package/dist/tui/components/inline-prompts/inline-input.js +32 -0
- package/dist/tui/components/inline-prompts/inline-search.d.ts +20 -0
- package/dist/tui/components/inline-prompts/inline-search.js +50 -0
- package/dist/tui/components/inline-prompts/inline-select.d.ts +20 -0
- package/dist/tui/components/inline-prompts/inline-select.js +34 -0
- package/dist/tui/components/logo.d.ts +43 -0
- package/dist/tui/components/logo.js +103 -0
- package/dist/tui/components/message-item.d.ts +12 -0
- package/dist/tui/components/message-item.js +12 -0
- package/dist/tui/components/onboarding/copyable-prompt.d.ts +15 -0
- package/dist/tui/components/onboarding/copyable-prompt.js +65 -0
- package/dist/tui/components/onboarding/index.d.ts +7 -0
- package/dist/tui/components/onboarding/index.js +6 -0
- package/dist/tui/components/onboarding/onboarding-flow.d.ts +13 -0
- package/dist/tui/components/onboarding/onboarding-flow.js +304 -0
- package/dist/tui/components/onboarding/onboarding-step.d.ts +23 -0
- package/dist/tui/components/onboarding/onboarding-step.js +12 -0
- package/dist/tui/components/output-log.d.ts +14 -0
- package/dist/tui/components/output-log.js +13 -0
- package/dist/tui/components/scrollable-list.d.ts +30 -0
- package/dist/tui/components/scrollable-list.js +121 -0
- package/dist/tui/components/suggestions.d.ts +16 -0
- package/dist/tui/components/suggestions.js +162 -0
- package/dist/tui/components/tab-bar.d.ts +10 -0
- package/dist/tui/components/tab-bar.js +12 -0
- package/dist/tui/constants.d.ts +11 -0
- package/dist/tui/constants.js +13 -0
- package/dist/tui/contexts/auth-context.d.ts +30 -0
- package/dist/tui/contexts/auth-context.js +153 -0
- package/dist/tui/contexts/consumer.d.ts +31 -0
- package/dist/tui/contexts/consumer.js +56 -0
- package/dist/tui/contexts/index.d.ts +6 -0
- package/dist/tui/contexts/index.js +6 -0
- package/dist/tui/contexts/onboarding-context.d.ts +43 -0
- package/dist/tui/contexts/onboarding-context.js +181 -0
- package/dist/tui/contexts/services-context.d.ts +29 -0
- package/dist/tui/contexts/services-context.js +20 -0
- package/dist/tui/contexts/use-commands.d.ts +29 -0
- package/dist/tui/contexts/use-commands.js +53 -0
- package/dist/tui/contexts/use-mode.d.ts +43 -0
- package/dist/tui/contexts/use-mode.js +76 -0
- package/dist/tui/contexts/use-theme.d.ts +53 -0
- package/dist/tui/contexts/use-theme.js +60 -0
- package/dist/tui/hooks/index.d.ts +17 -0
- package/dist/tui/hooks/index.js +14 -0
- package/dist/tui/hooks/use-activity-logs.d.ts +26 -0
- package/dist/tui/hooks/use-activity-logs.js +90 -0
- package/dist/tui/hooks/use-consumer.d.ts +12 -0
- package/dist/tui/hooks/use-consumer.js +50 -0
- package/dist/tui/hooks/use-onboarding.d.ts +7 -0
- package/dist/tui/hooks/use-onboarding.js +6 -0
- package/dist/tui/hooks/use-queue-polling.d.ts +31 -0
- package/dist/tui/hooks/use-queue-polling.js +90 -0
- package/dist/tui/hooks/use-slash-command-processor.d.ts +16 -0
- package/dist/tui/hooks/use-slash-command-processor.js +132 -0
- package/dist/tui/hooks/use-slash-completion.d.ts +30 -0
- package/dist/tui/hooks/use-slash-completion.js +230 -0
- package/dist/tui/hooks/use-tab-navigation.d.ts +10 -0
- package/dist/tui/hooks/use-tab-navigation.js +35 -0
- package/dist/tui/hooks/use-visible-window.d.ts +22 -0
- package/dist/tui/hooks/use-visible-window.js +37 -0
- package/dist/tui/index.d.ts +1 -0
- package/dist/tui/index.js +1 -0
- package/dist/tui/providers/app-providers.d.ts +25 -0
- package/dist/tui/providers/app-providers.js +9 -0
- package/dist/tui/types/commands.d.ts +252 -0
- package/dist/tui/types/commands.js +16 -0
- package/dist/tui/types/dialogs.d.ts +37 -0
- package/dist/tui/types/dialogs.js +4 -0
- package/dist/tui/types/index.d.ts +11 -0
- package/dist/tui/types/index.js +7 -0
- package/dist/tui/types/messages.d.ts +55 -0
- package/dist/tui/types/messages.js +4 -0
- package/dist/tui/types/prompts.d.ts +100 -0
- package/dist/tui/types/prompts.js +4 -0
- package/dist/tui/types/ui.d.ts +14 -0
- package/dist/tui/types/ui.js +4 -0
- package/dist/tui/types.d.ts +1 -0
- package/dist/tui/types.js +1 -0
- package/dist/tui/views/command-view.d.ts +12 -0
- package/dist/tui/views/command-view.js +451 -0
- package/dist/tui/views/index.d.ts +6 -0
- package/dist/tui/views/index.js +6 -0
- package/dist/tui/views/login-view.d.ts +10 -0
- package/dist/tui/views/login-view.js +30 -0
- package/dist/tui/views/logs-view.d.ts +11 -0
- package/dist/tui/views/logs-view.js +73 -0
- package/dist/utils/file-validator.d.ts +16 -0
- package/dist/utils/file-validator.js +81 -0
- package/dist/utils/global-config-path.d.ts +15 -0
- package/dist/utils/global-config-path.js +38 -0
- package/oclif.manifest.json +29 -315
- package/package.json +11 -4
- package/dist/commands/clear.d.ts +0 -19
- package/dist/commands/clear.js +0 -78
- package/dist/commands/init.d.ts +0 -130
- package/dist/commands/login.d.ts +0 -22
- package/dist/commands/login.js +0 -108
- package/dist/commands/logout.d.ts +0 -16
- package/dist/commands/logout.js +0 -61
- package/dist/commands/pull.d.ts +0 -33
- package/dist/commands/pull.js +0 -115
- package/dist/commands/push.d.ts +0 -35
- package/dist/commands/push.js +0 -160
- package/dist/commands/space/list.d.ts +0 -25
- package/dist/commands/space/list.js +0 -114
- package/dist/commands/space/switch.d.ts +0 -36
- package/dist/commands/space/switch.js +0 -160
- package/dist/infra/cipher/grpc/internal-llm-grpc-service.d.ts +0 -149
- package/dist/infra/cipher/grpc/internal-llm-grpc-service.js +0 -364
- package/dist/infra/cipher/grpc/internal-llm-grpc.proto +0 -94
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { Execution, ToolCall } from '../storage/agent-storage.js';
|
|
3
|
+
export interface QueueStats {
|
|
4
|
+
completed: number;
|
|
5
|
+
failed: number;
|
|
6
|
+
queued: number;
|
|
7
|
+
running: number;
|
|
8
|
+
total: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ExecutionWithToolCalls {
|
|
11
|
+
execution: Execution;
|
|
12
|
+
toolCalls: ToolCall[];
|
|
13
|
+
}
|
|
14
|
+
export interface QueueSnapshot {
|
|
15
|
+
/** All executions for the current session (with tool calls) - ordered by created_at ASC */
|
|
16
|
+
sessionExecutions: ExecutionWithToolCalls[];
|
|
17
|
+
stats: QueueStats;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
}
|
|
20
|
+
export type QueueEventType = 'error' | 'execution:completed' | 'execution:failed' | 'execution:started' | 'reconnected' | 'snapshot' | 'stats:updated' | 'stopped';
|
|
21
|
+
export interface QueueEvents {
|
|
22
|
+
error: (error: Error) => void;
|
|
23
|
+
'execution:completed': (execution: Execution) => void;
|
|
24
|
+
'execution:failed': (execution: Execution) => void;
|
|
25
|
+
'execution:started': (execution: Execution) => void;
|
|
26
|
+
reconnected: () => void;
|
|
27
|
+
snapshot: (snapshot: QueueSnapshot) => void;
|
|
28
|
+
'stats:updated': (stats: QueueStats) => void;
|
|
29
|
+
stopped: () => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* QueuePollingService - Singleton service that polls agent.db and emits events
|
|
33
|
+
*
|
|
34
|
+
* Architecture:
|
|
35
|
+
* - Polls database at configurable interval (default 500ms)
|
|
36
|
+
* - Compares snapshots to detect changes
|
|
37
|
+
* - Emits granular events for UI updates
|
|
38
|
+
* - Singleton pattern prevents memory leaks from multiple instances
|
|
39
|
+
*
|
|
40
|
+
* Events:
|
|
41
|
+
* - 'snapshot': Full queue snapshot (for initial render)
|
|
42
|
+
* - 'stats:updated': Queue statistics changed
|
|
43
|
+
* - 'execution:started': New execution started
|
|
44
|
+
* - 'execution:completed': Execution completed successfully
|
|
45
|
+
* - 'execution:failed': Execution failed
|
|
46
|
+
* - 'error': Polling error occurred
|
|
47
|
+
* - 'stopped': Service stopped
|
|
48
|
+
*/
|
|
49
|
+
export declare class QueuePollingService extends EventEmitter {
|
|
50
|
+
private consumerId?;
|
|
51
|
+
private initialized;
|
|
52
|
+
private lastSnapshot;
|
|
53
|
+
private pollInterval;
|
|
54
|
+
private pollTimer;
|
|
55
|
+
private running;
|
|
56
|
+
private seenExecutionIds;
|
|
57
|
+
constructor(options?: {
|
|
58
|
+
consumerId?: string;
|
|
59
|
+
pollInterval?: number;
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* Get current snapshot without polling
|
|
63
|
+
*/
|
|
64
|
+
getCurrentSnapshot(): null | QueueSnapshot;
|
|
65
|
+
/**
|
|
66
|
+
* Check if service is running
|
|
67
|
+
*/
|
|
68
|
+
isRunning(): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Set consumer ID for session-based execution history
|
|
71
|
+
* Takes effect on next poll cycle
|
|
72
|
+
*/
|
|
73
|
+
setConsumerId(consumerId: string | undefined): void;
|
|
74
|
+
/**
|
|
75
|
+
* Set poll interval (takes effect on next poll)
|
|
76
|
+
*/
|
|
77
|
+
setPollInterval(ms: number): void;
|
|
78
|
+
/**
|
|
79
|
+
* Start polling
|
|
80
|
+
*/
|
|
81
|
+
start(): Promise<void>;
|
|
82
|
+
/**
|
|
83
|
+
* Stop polling
|
|
84
|
+
*/
|
|
85
|
+
stop(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Build current snapshot from database
|
|
88
|
+
*/
|
|
89
|
+
private buildSnapshot;
|
|
90
|
+
/**
|
|
91
|
+
* Detect changes and emit appropriate events
|
|
92
|
+
*/
|
|
93
|
+
private detectChangesAndEmit;
|
|
94
|
+
/**
|
|
95
|
+
* Single poll iteration
|
|
96
|
+
*/
|
|
97
|
+
private poll;
|
|
98
|
+
/**
|
|
99
|
+
* Schedule next poll
|
|
100
|
+
*/
|
|
101
|
+
private schedulePoll;
|
|
102
|
+
/**
|
|
103
|
+
* Compare two stats objects for equality
|
|
104
|
+
*/
|
|
105
|
+
private statsEqual;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get singleton QueuePollingService instance
|
|
109
|
+
* @param options - Configuration options
|
|
110
|
+
* @param options.consumerId - Optional consumer identifier
|
|
111
|
+
* @param options.pollInterval - Optional poll interval in milliseconds
|
|
112
|
+
*/
|
|
113
|
+
export declare function getQueuePollingService(options?: {
|
|
114
|
+
consumerId?: string;
|
|
115
|
+
pollInterval?: number;
|
|
116
|
+
}): QueuePollingService;
|
|
117
|
+
/**
|
|
118
|
+
* Stop and clear singleton instance
|
|
119
|
+
*/
|
|
120
|
+
export declare function stopQueuePollingService(): void;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { closeAgentStorage, getAgentStorage, getAgentStorageSync } from '../storage/agent-storage.js';
|
|
3
|
+
// ==================== SERVICE ====================
|
|
4
|
+
/**
|
|
5
|
+
* QueuePollingService - Singleton service that polls agent.db and emits events
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - Polls database at configurable interval (default 500ms)
|
|
9
|
+
* - Compares snapshots to detect changes
|
|
10
|
+
* - Emits granular events for UI updates
|
|
11
|
+
* - Singleton pattern prevents memory leaks from multiple instances
|
|
12
|
+
*
|
|
13
|
+
* Events:
|
|
14
|
+
* - 'snapshot': Full queue snapshot (for initial render)
|
|
15
|
+
* - 'stats:updated': Queue statistics changed
|
|
16
|
+
* - 'execution:started': New execution started
|
|
17
|
+
* - 'execution:completed': Execution completed successfully
|
|
18
|
+
* - 'execution:failed': Execution failed
|
|
19
|
+
* - 'error': Polling error occurred
|
|
20
|
+
* - 'stopped': Service stopped
|
|
21
|
+
*/
|
|
22
|
+
// eslint-disable-next-line unicorn/prefer-event-target -- EventEmitter better for Node.js typed events
|
|
23
|
+
export class QueuePollingService extends EventEmitter {
|
|
24
|
+
consumerId;
|
|
25
|
+
initialized = false;
|
|
26
|
+
lastSnapshot = null;
|
|
27
|
+
pollInterval;
|
|
28
|
+
pollTimer = null;
|
|
29
|
+
running = false;
|
|
30
|
+
seenExecutionIds = new Set();
|
|
31
|
+
constructor(options) {
|
|
32
|
+
super();
|
|
33
|
+
this.consumerId = options?.consumerId;
|
|
34
|
+
this.pollInterval = options?.pollInterval ?? 500;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get current snapshot without polling
|
|
38
|
+
*/
|
|
39
|
+
getCurrentSnapshot() {
|
|
40
|
+
return this.lastSnapshot;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if service is running
|
|
44
|
+
*/
|
|
45
|
+
isRunning() {
|
|
46
|
+
return this.running;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Set consumer ID for session-based execution history
|
|
50
|
+
* Takes effect on next poll cycle
|
|
51
|
+
*/
|
|
52
|
+
setConsumerId(consumerId) {
|
|
53
|
+
this.consumerId = consumerId;
|
|
54
|
+
// Clear last snapshot to force fresh data with new consumer
|
|
55
|
+
this.lastSnapshot = null;
|
|
56
|
+
this.seenExecutionIds.clear();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Set poll interval (takes effect on next poll)
|
|
60
|
+
*/
|
|
61
|
+
setPollInterval(ms) {
|
|
62
|
+
this.pollInterval = ms;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Start polling
|
|
66
|
+
*/
|
|
67
|
+
async start() {
|
|
68
|
+
if (this.running)
|
|
69
|
+
return;
|
|
70
|
+
try {
|
|
71
|
+
// Initialize storage (auto-detects .brv/blobs from cwd)
|
|
72
|
+
await getAgentStorage();
|
|
73
|
+
this.initialized = true;
|
|
74
|
+
this.running = true;
|
|
75
|
+
// Initial poll
|
|
76
|
+
await this.poll();
|
|
77
|
+
// Start poll loop
|
|
78
|
+
this.schedulePoll();
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
this.emit('error', error instanceof Error ? error : new Error(String(error)));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Stop polling
|
|
86
|
+
*/
|
|
87
|
+
stop() {
|
|
88
|
+
this.running = false;
|
|
89
|
+
if (this.pollTimer) {
|
|
90
|
+
clearTimeout(this.pollTimer);
|
|
91
|
+
this.pollTimer = null;
|
|
92
|
+
}
|
|
93
|
+
if (this.initialized) {
|
|
94
|
+
closeAgentStorage();
|
|
95
|
+
this.initialized = false;
|
|
96
|
+
}
|
|
97
|
+
this.emit('stopped');
|
|
98
|
+
}
|
|
99
|
+
// ==================== PRIVATE ====================
|
|
100
|
+
/**
|
|
101
|
+
* Build current snapshot from database
|
|
102
|
+
*/
|
|
103
|
+
buildSnapshot() {
|
|
104
|
+
const storage = getAgentStorageSync();
|
|
105
|
+
// Get session executions with tool calls (if consumerId is set)
|
|
106
|
+
let sessionExecutions = [];
|
|
107
|
+
if (this.consumerId) {
|
|
108
|
+
const sessionExecs = storage.getSessionExecutions(this.consumerId);
|
|
109
|
+
sessionExecutions = sessionExecs.map((exec) => ({
|
|
110
|
+
execution: exec,
|
|
111
|
+
toolCalls: storage.getToolCalls(exec.id),
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
// Get stats directly from DB (accurate counts)
|
|
115
|
+
const stats = storage.getStats();
|
|
116
|
+
return {
|
|
117
|
+
sessionExecutions,
|
|
118
|
+
stats,
|
|
119
|
+
timestamp: Date.now(),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Detect changes and emit appropriate events
|
|
124
|
+
*/
|
|
125
|
+
detectChangesAndEmit(oldSnapshot, newSnapshot) {
|
|
126
|
+
// Always emit snapshot for subscribers that want full state
|
|
127
|
+
this.emit('snapshot', newSnapshot);
|
|
128
|
+
// Detect stats changes
|
|
129
|
+
if (!oldSnapshot || !this.statsEqual(oldSnapshot.stats, newSnapshot.stats)) {
|
|
130
|
+
this.emit('stats:updated', newSnapshot.stats);
|
|
131
|
+
}
|
|
132
|
+
// Detect execution state changes
|
|
133
|
+
const executions = newSnapshot.sessionExecutions.map((e) => e.execution);
|
|
134
|
+
for (const exec of executions) {
|
|
135
|
+
const wasSeenBefore = this.seenExecutionIds.has(exec.id);
|
|
136
|
+
if (wasSeenBefore) {
|
|
137
|
+
// Check if status changed
|
|
138
|
+
const oldExecs = oldSnapshot?.sessionExecutions.map((e) => e.execution) ?? [];
|
|
139
|
+
const oldExec = oldExecs.find((e) => e.id === exec.id);
|
|
140
|
+
if (oldExec && oldExec.status !== exec.status) {
|
|
141
|
+
if (exec.status === 'completed') {
|
|
142
|
+
this.emit('execution:completed', exec);
|
|
143
|
+
}
|
|
144
|
+
else if (exec.status === 'failed') {
|
|
145
|
+
this.emit('execution:failed', exec);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this.seenExecutionIds.add(exec.id);
|
|
151
|
+
if (exec.status === 'running') {
|
|
152
|
+
this.emit('execution:started', exec);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Limit seen IDs to prevent memory growth
|
|
157
|
+
if (this.seenExecutionIds.size > 1000) {
|
|
158
|
+
const idsToKeep = new Set(executions.map((e) => e.id));
|
|
159
|
+
this.seenExecutionIds = idsToKeep;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Single poll iteration
|
|
164
|
+
*/
|
|
165
|
+
async poll() {
|
|
166
|
+
if (!this.running || !this.initialized)
|
|
167
|
+
return;
|
|
168
|
+
try {
|
|
169
|
+
// Check if DB file was replaced (e.g., by brv init in another terminal)
|
|
170
|
+
const storage = getAgentStorageSync();
|
|
171
|
+
if (storage.isDbFileChanged()) {
|
|
172
|
+
// DB file was replaced - reconnect
|
|
173
|
+
await storage.reconnect();
|
|
174
|
+
// Clear seen IDs since DB was reset
|
|
175
|
+
this.seenExecutionIds.clear();
|
|
176
|
+
this.lastSnapshot = null;
|
|
177
|
+
this.emit('reconnected');
|
|
178
|
+
}
|
|
179
|
+
const newSnapshot = this.buildSnapshot();
|
|
180
|
+
this.detectChangesAndEmit(this.lastSnapshot, newSnapshot);
|
|
181
|
+
this.lastSnapshot = newSnapshot;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
// If stop() was called during poll, silently exit - this is expected during shutdown
|
|
185
|
+
if (!this.running)
|
|
186
|
+
return;
|
|
187
|
+
// Try to recover from errors (connection lost, storage closed, etc.)
|
|
188
|
+
try {
|
|
189
|
+
// Use getAgentStorage() which auto-reinitializes if singleton was closed
|
|
190
|
+
const storage = await getAgentStorage();
|
|
191
|
+
await storage.reconnect();
|
|
192
|
+
this.seenExecutionIds.clear();
|
|
193
|
+
this.lastSnapshot = null;
|
|
194
|
+
this.emit('reconnected');
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Reconnect failed - only emit error if still running (not during intentional shutdown)
|
|
198
|
+
if (this.running) {
|
|
199
|
+
this.emit('error', error instanceof Error ? error : new Error(String(error)));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Schedule next poll
|
|
206
|
+
*/
|
|
207
|
+
schedulePoll() {
|
|
208
|
+
if (!this.running)
|
|
209
|
+
return;
|
|
210
|
+
this.pollTimer = setTimeout(async () => {
|
|
211
|
+
await this.poll();
|
|
212
|
+
this.schedulePoll();
|
|
213
|
+
}, this.pollInterval);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Compare two stats objects for equality
|
|
217
|
+
*/
|
|
218
|
+
statsEqual(a, b) {
|
|
219
|
+
return (a.queued === b.queued &&
|
|
220
|
+
a.running === b.running &&
|
|
221
|
+
a.completed === b.completed &&
|
|
222
|
+
a.failed === b.failed &&
|
|
223
|
+
a.total === b.total);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// ==================== SINGLETON ====================
|
|
227
|
+
let instance = null;
|
|
228
|
+
/**
|
|
229
|
+
* Get singleton QueuePollingService instance
|
|
230
|
+
* @param options - Configuration options
|
|
231
|
+
* @param options.consumerId - Optional consumer identifier
|
|
232
|
+
* @param options.pollInterval - Optional poll interval in milliseconds
|
|
233
|
+
*/
|
|
234
|
+
export function getQueuePollingService(options) {
|
|
235
|
+
if (!instance) {
|
|
236
|
+
instance = new QueuePollingService(options);
|
|
237
|
+
}
|
|
238
|
+
return instance;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Stop and clear singleton instance
|
|
242
|
+
*/
|
|
243
|
+
export function stopQueuePollingService() {
|
|
244
|
+
if (instance) {
|
|
245
|
+
instance.stop();
|
|
246
|
+
instance = null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { RequestOptions } from '@anthropic-ai/sdk/internal/request-options';
|
|
2
|
+
import type { MessageCreateParamsNonStreaming } from '@anthropic-ai/sdk/resources/messages.js';
|
|
3
|
+
import type { Content, GenerateContentConfig, GenerateContentResponse } from '@google/genai';
|
|
4
|
+
/**
|
|
5
|
+
* ByteRover HTTP LLM provider configuration.
|
|
6
|
+
*/
|
|
7
|
+
export interface ByteRoverHttpConfig {
|
|
8
|
+
accessToken: string;
|
|
9
|
+
apiBaseUrl: string;
|
|
10
|
+
projectId?: string;
|
|
11
|
+
region?: string;
|
|
12
|
+
sessionKey: string;
|
|
13
|
+
spaceId: string;
|
|
14
|
+
teamId: string;
|
|
15
|
+
timeout?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* ByteRover HTTP LLM API client.
|
|
19
|
+
*
|
|
20
|
+
* Simple wrapper around ByteRover REST LLM service.
|
|
21
|
+
* Delegates prompt building and formatting to service layer.
|
|
22
|
+
*
|
|
23
|
+
* Responsibilities:
|
|
24
|
+
* - Call the remote REST API
|
|
25
|
+
* - Handle HTTP responses
|
|
26
|
+
* - Convert to GenerateContentResponse format
|
|
27
|
+
*
|
|
28
|
+
* Does NOT:
|
|
29
|
+
* - Build prompts or format inputs
|
|
30
|
+
* - Parse or manipulate response content
|
|
31
|
+
* - Handle tool call parsing from text
|
|
32
|
+
*/
|
|
33
|
+
export declare class ByteRoverLlmHttpService {
|
|
34
|
+
private readonly config;
|
|
35
|
+
/**
|
|
36
|
+
* Initialize a new ByteRover HTTP LLM service client.
|
|
37
|
+
*
|
|
38
|
+
* Sets up configuration with sensible defaults:
|
|
39
|
+
* - projectId defaults to 'byterover'
|
|
40
|
+
* - region defaults to 'us-east1' (can be overridden per request)
|
|
41
|
+
* - timeout defaults to 60 seconds
|
|
42
|
+
*
|
|
43
|
+
* @param config - HTTP client configuration (accessToken, apiBaseUrl, sessionKey, optional: projectId, region, timeout)
|
|
44
|
+
*/
|
|
45
|
+
constructor(config: ByteRoverHttpConfig);
|
|
46
|
+
/**
|
|
47
|
+
* Call ByteRover REST LLM service to generate content.
|
|
48
|
+
*
|
|
49
|
+
* Simple forward to remote REST API - delegates all formatting to backend.
|
|
50
|
+
* Supports both Gemini and Claude formats - the correct format is determined
|
|
51
|
+
* automatically based on the model name.
|
|
52
|
+
*
|
|
53
|
+
* Parameter structure differs by provider:
|
|
54
|
+
* - Gemini: contents = Content[], config = GenerateContentConfig
|
|
55
|
+
* - Claude: contents = MessageCreateParamsNonStreaming (complete body), config = RequestOptions (HTTP options)
|
|
56
|
+
*
|
|
57
|
+
* @param contents - For Gemini: Content[]. For Claude: MessageCreateParamsNonStreaming (complete body)
|
|
58
|
+
* @param config - For Gemini: GenerateContentConfig. For Claude: RequestOptions (optional HTTP options)
|
|
59
|
+
* @param model - Model to use (detects provider from model name)
|
|
60
|
+
* @param executionMetadata - Optional execution metadata (mode, executionContext)
|
|
61
|
+
* @returns Response in GenerateContentResponse format
|
|
62
|
+
*/
|
|
63
|
+
generateContent(contents: Content[] | MessageCreateParamsNonStreaming, config: GenerateContentConfig | RequestOptions, model: string, executionMetadata?: Record<string, unknown>): Promise<GenerateContentResponse>;
|
|
64
|
+
/**
|
|
65
|
+
* Call the ByteRover REST Generate endpoint.
|
|
66
|
+
*
|
|
67
|
+
* Handles authentication headers and error handling.
|
|
68
|
+
*
|
|
69
|
+
* @param request - The REST generate request with model, provider, region, and params
|
|
70
|
+
* @returns Promise resolving to the complete LLM response
|
|
71
|
+
* @throws Error if the request fails
|
|
72
|
+
*/
|
|
73
|
+
private callHttpGenerate;
|
|
74
|
+
/**
|
|
75
|
+
* Detect LLM provider from model identifier.
|
|
76
|
+
*
|
|
77
|
+
* Determines which provider (Claude or Gemini) to use based on the model name.
|
|
78
|
+
* Defaults to Gemini if the model doesn't match Claude patterns.
|
|
79
|
+
*
|
|
80
|
+
* @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
|
|
81
|
+
* @returns Provider name: 'claude' or 'gemini'
|
|
82
|
+
*/
|
|
83
|
+
private detectProviderFromModel;
|
|
84
|
+
/**
|
|
85
|
+
* Detect appropriate GCP region from model identifier.
|
|
86
|
+
*
|
|
87
|
+
* Routes Claude models to us-east5 and Gemini models to global.
|
|
88
|
+
* This ensures compatibility with the provider's available regions on Vertex AI.
|
|
89
|
+
*
|
|
90
|
+
* @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
|
|
91
|
+
* @returns GCP region identifier ('us-east5' or 'global')
|
|
92
|
+
*/
|
|
93
|
+
private detectRegionFromModel;
|
|
94
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { AuthenticatedHttpClient } from '../../http/authenticated-http-client.js';
|
|
2
|
+
/**
|
|
3
|
+
* ByteRover HTTP LLM API client.
|
|
4
|
+
*
|
|
5
|
+
* Simple wrapper around ByteRover REST LLM service.
|
|
6
|
+
* Delegates prompt building and formatting to service layer.
|
|
7
|
+
*
|
|
8
|
+
* Responsibilities:
|
|
9
|
+
* - Call the remote REST API
|
|
10
|
+
* - Handle HTTP responses
|
|
11
|
+
* - Convert to GenerateContentResponse format
|
|
12
|
+
*
|
|
13
|
+
* Does NOT:
|
|
14
|
+
* - Build prompts or format inputs
|
|
15
|
+
* - Parse or manipulate response content
|
|
16
|
+
* - Handle tool call parsing from text
|
|
17
|
+
*/
|
|
18
|
+
export class ByteRoverLlmHttpService {
|
|
19
|
+
config;
|
|
20
|
+
/**
|
|
21
|
+
* Initialize a new ByteRover HTTP LLM service client.
|
|
22
|
+
*
|
|
23
|
+
* Sets up configuration with sensible defaults:
|
|
24
|
+
* - projectId defaults to 'byterover'
|
|
25
|
+
* - region defaults to 'us-east1' (can be overridden per request)
|
|
26
|
+
* - timeout defaults to 60 seconds
|
|
27
|
+
*
|
|
28
|
+
* @param config - HTTP client configuration (accessToken, apiBaseUrl, sessionKey, optional: projectId, region, timeout)
|
|
29
|
+
*/
|
|
30
|
+
constructor(config) {
|
|
31
|
+
this.config = {
|
|
32
|
+
accessToken: config.accessToken,
|
|
33
|
+
apiBaseUrl: config.apiBaseUrl,
|
|
34
|
+
projectId: config.projectId ?? 'byterover',
|
|
35
|
+
region: config.region ?? 'us-east1',
|
|
36
|
+
sessionKey: config.sessionKey,
|
|
37
|
+
spaceId: config.spaceId,
|
|
38
|
+
teamId: config.teamId,
|
|
39
|
+
timeout: config.timeout ?? 60_000,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Call ByteRover REST LLM service to generate content.
|
|
44
|
+
*
|
|
45
|
+
* Simple forward to remote REST API - delegates all formatting to backend.
|
|
46
|
+
* Supports both Gemini and Claude formats - the correct format is determined
|
|
47
|
+
* automatically based on the model name.
|
|
48
|
+
*
|
|
49
|
+
* Parameter structure differs by provider:
|
|
50
|
+
* - Gemini: contents = Content[], config = GenerateContentConfig
|
|
51
|
+
* - Claude: contents = MessageCreateParamsNonStreaming (complete body), config = RequestOptions (HTTP options)
|
|
52
|
+
*
|
|
53
|
+
* @param contents - For Gemini: Content[]. For Claude: MessageCreateParamsNonStreaming (complete body)
|
|
54
|
+
* @param config - For Gemini: GenerateContentConfig. For Claude: RequestOptions (optional HTTP options)
|
|
55
|
+
* @param model - Model to use (detects provider from model name)
|
|
56
|
+
* @param executionMetadata - Optional execution metadata (mode, executionContext)
|
|
57
|
+
* @returns Response in GenerateContentResponse format
|
|
58
|
+
*/
|
|
59
|
+
async generateContent(contents, config, model, executionMetadata) {
|
|
60
|
+
const request = {
|
|
61
|
+
executionMetadata: JSON.stringify(executionMetadata ?? {}),
|
|
62
|
+
params: {
|
|
63
|
+
config: JSON.stringify(config),
|
|
64
|
+
contents: JSON.stringify(contents),
|
|
65
|
+
model,
|
|
66
|
+
},
|
|
67
|
+
project_id: this.config.projectId,
|
|
68
|
+
provider: this.detectProviderFromModel(model),
|
|
69
|
+
region: this.detectRegionFromModel(model),
|
|
70
|
+
spaceId: this.config.spaceId,
|
|
71
|
+
teamId: this.config.teamId,
|
|
72
|
+
};
|
|
73
|
+
return this.callHttpGenerate(request);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Call the ByteRover REST Generate endpoint.
|
|
77
|
+
*
|
|
78
|
+
* Handles authentication headers and error handling.
|
|
79
|
+
*
|
|
80
|
+
* @param request - The REST generate request with model, provider, region, and params
|
|
81
|
+
* @returns Promise resolving to the complete LLM response
|
|
82
|
+
* @throws Error if the request fails
|
|
83
|
+
*/
|
|
84
|
+
async callHttpGenerate(request) {
|
|
85
|
+
const url = `${this.config.apiBaseUrl}/api/llm/generate`;
|
|
86
|
+
const httpClient = new AuthenticatedHttpClient(this.config.accessToken, this.config.sessionKey);
|
|
87
|
+
const response = await httpClient.post(url, request, {
|
|
88
|
+
timeout: this.config.timeout,
|
|
89
|
+
});
|
|
90
|
+
// Parse the JSON string response
|
|
91
|
+
const content = JSON.parse(response.data);
|
|
92
|
+
return content;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Detect LLM provider from model identifier.
|
|
96
|
+
*
|
|
97
|
+
* Determines which provider (Claude or Gemini) to use based on the model name.
|
|
98
|
+
* Defaults to Gemini if the model doesn't match Claude patterns.
|
|
99
|
+
*
|
|
100
|
+
* @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
|
|
101
|
+
* @returns Provider name: 'claude' or 'gemini'
|
|
102
|
+
*/
|
|
103
|
+
detectProviderFromModel(model) {
|
|
104
|
+
return model.toLowerCase().startsWith('claude') ? 'claude' : 'gemini';
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Detect appropriate GCP region from model identifier.
|
|
108
|
+
*
|
|
109
|
+
* Routes Claude models to us-east5 and Gemini models to global.
|
|
110
|
+
* This ensures compatibility with the provider's available regions on Vertex AI.
|
|
111
|
+
*
|
|
112
|
+
* @param model - Model identifier (e.g., 'claude-3-5-sonnet', 'gemini-2.5-flash')
|
|
113
|
+
* @returns GCP region identifier ('us-east5' or 'global')
|
|
114
|
+
*/
|
|
115
|
+
detectRegionFromModel(model) {
|
|
116
|
+
return model.toLowerCase().startsWith('claude') ? 'us-east5' : 'global';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { CompactionResult } from '../../../../../core/domain/cipher/storage/message-storage-types.js';
|
|
2
|
+
import type { ITokenizer } from '../../../../../core/interfaces/cipher/i-tokenizer.js';
|
|
3
|
+
import type { MessageStorageService } from '../../../storage/message-storage-service.js';
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for compaction behavior.
|
|
6
|
+
*/
|
|
7
|
+
export interface CompactionConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Percentage of context tokens that triggers compaction (0.0 - 1.0).
|
|
10
|
+
* Default: 0.85 (85%)
|
|
11
|
+
*/
|
|
12
|
+
overflowThreshold?: number;
|
|
13
|
+
/**
|
|
14
|
+
* Number of tokens to keep in tool outputs after pruning.
|
|
15
|
+
* Default: 40000
|
|
16
|
+
*/
|
|
17
|
+
pruneKeepTokens?: number;
|
|
18
|
+
/**
|
|
19
|
+
* System prompt for generating compaction summaries.
|
|
20
|
+
*/
|
|
21
|
+
summaryPrompt?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Result of checking for context overflow.
|
|
25
|
+
*/
|
|
26
|
+
export interface OverflowCheckResult {
|
|
27
|
+
/** Current token count */
|
|
28
|
+
currentTokens: number;
|
|
29
|
+
/** Whether overflow threshold is exceeded */
|
|
30
|
+
isOverflow: boolean;
|
|
31
|
+
/** Maximum allowed tokens */
|
|
32
|
+
maxTokens: number;
|
|
33
|
+
/** Recommended action */
|
|
34
|
+
recommendation: 'compact' | 'none' | 'prune';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Input for compaction operations.
|
|
38
|
+
*/
|
|
39
|
+
export interface CompactionInput {
|
|
40
|
+
/** Maximum context tokens allowed */
|
|
41
|
+
contextLimit: number;
|
|
42
|
+
/** Current token count (including all messages) */
|
|
43
|
+
currentTokens: number;
|
|
44
|
+
/** Session ID to compact */
|
|
45
|
+
sessionId: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Service for managing context compaction in granular history storage.
|
|
49
|
+
*
|
|
50
|
+
* Compaction reduces context size through two mechanisms:
|
|
51
|
+
* 1. Tool output pruning - marks old tool outputs as compacted
|
|
52
|
+
* 2. Compaction boundaries - summarizes old history and creates a boundary
|
|
53
|
+
*
|
|
54
|
+
* Based on OpenCode's compaction patterns:
|
|
55
|
+
* - isOverflow() checks if context exceeds threshold
|
|
56
|
+
* - prune() marks old tool outputs as compacted
|
|
57
|
+
* - insertCompactionBoundary() creates a summary boundary
|
|
58
|
+
*/
|
|
59
|
+
export declare class CompactionService {
|
|
60
|
+
private readonly messageStorage;
|
|
61
|
+
private readonly tokenizer;
|
|
62
|
+
private readonly config;
|
|
63
|
+
constructor(messageStorage: MessageStorageService, tokenizer: ITokenizer, config?: CompactionConfig);
|
|
64
|
+
/**
|
|
65
|
+
* Perform automatic compaction based on current context state.
|
|
66
|
+
* This is a convenience method that checks overflow and takes appropriate action.
|
|
67
|
+
*
|
|
68
|
+
* @returns CompactionResult if action was taken, undefined if no action needed
|
|
69
|
+
*/
|
|
70
|
+
autoCompact(input: CompactionInput): Promise<CompactionResult | undefined>;
|
|
71
|
+
/**
|
|
72
|
+
* Check if context is overflowing and recommend action.
|
|
73
|
+
*/
|
|
74
|
+
checkOverflow(currentTokens: number, contextLimit: number): OverflowCheckResult;
|
|
75
|
+
/**
|
|
76
|
+
* Create a compaction boundary with the given summary.
|
|
77
|
+
* The boundary acts as a marker - history loading stops here.
|
|
78
|
+
*/
|
|
79
|
+
createCompactionBoundary(sessionId: string, summary: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Estimate tokens for a text string.
|
|
82
|
+
* Uses the configured tokenizer.
|
|
83
|
+
*/
|
|
84
|
+
estimateTokens(text: string): Promise<number>;
|
|
85
|
+
/**
|
|
86
|
+
* Get the current compaction configuration.
|
|
87
|
+
*/
|
|
88
|
+
getConfig(): Readonly<Required<CompactionConfig>>;
|
|
89
|
+
/**
|
|
90
|
+
* Generate a summary prompt for the LLM to create a compaction summary.
|
|
91
|
+
* This returns the system prompt and user message to send to the LLM.
|
|
92
|
+
*/
|
|
93
|
+
getSummaryPromptParts(): {
|
|
94
|
+
systemPrompt: string;
|
|
95
|
+
userMessage: string;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Prune old tool outputs to reduce context size.
|
|
99
|
+
* Keeps the most recent tool outputs up to the configured token limit.
|
|
100
|
+
*/
|
|
101
|
+
pruneToolOutputs(sessionId: string): Promise<CompactionResult>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Factory function to create CompactionService.
|
|
105
|
+
*/
|
|
106
|
+
export declare function createCompactionService(messageStorage: MessageStorageService, tokenizer: ITokenizer, config?: CompactionConfig): CompactionService;
|