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,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default prompt for generating conversation summaries.
|
|
3
|
+
* Based on OpenCode's PROMPT_COMPACTION.
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_SUMMARY_PROMPT = `You are a helpful assistant that summarizes conversations.
|
|
6
|
+
Given the conversation history, provide a detailed summary that captures:
|
|
7
|
+
1. The main tasks or goals discussed
|
|
8
|
+
2. Key decisions and outcomes
|
|
9
|
+
3. Important context that should be preserved
|
|
10
|
+
4. Any unfinished work or pending items
|
|
11
|
+
|
|
12
|
+
Format the summary as a clear, comprehensive prompt that could be used to continue the conversation.
|
|
13
|
+
Focus on the "what" and "why" rather than the step-by-step "how".`;
|
|
14
|
+
/**
|
|
15
|
+
* Service for managing context compaction in granular history storage.
|
|
16
|
+
*
|
|
17
|
+
* Compaction reduces context size through two mechanisms:
|
|
18
|
+
* 1. Tool output pruning - marks old tool outputs as compacted
|
|
19
|
+
* 2. Compaction boundaries - summarizes old history and creates a boundary
|
|
20
|
+
*
|
|
21
|
+
* Based on OpenCode's compaction patterns:
|
|
22
|
+
* - isOverflow() checks if context exceeds threshold
|
|
23
|
+
* - prune() marks old tool outputs as compacted
|
|
24
|
+
* - insertCompactionBoundary() creates a summary boundary
|
|
25
|
+
*/
|
|
26
|
+
export class CompactionService {
|
|
27
|
+
messageStorage;
|
|
28
|
+
tokenizer;
|
|
29
|
+
config;
|
|
30
|
+
constructor(messageStorage, tokenizer, config) {
|
|
31
|
+
this.messageStorage = messageStorage;
|
|
32
|
+
this.tokenizer = tokenizer;
|
|
33
|
+
this.config = {
|
|
34
|
+
overflowThreshold: config?.overflowThreshold ?? 0.85,
|
|
35
|
+
pruneKeepTokens: config?.pruneKeepTokens ?? 40_000,
|
|
36
|
+
summaryPrompt: config?.summaryPrompt ?? DEFAULT_SUMMARY_PROMPT,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Perform automatic compaction based on current context state.
|
|
41
|
+
* This is a convenience method that checks overflow and takes appropriate action.
|
|
42
|
+
*
|
|
43
|
+
* @returns CompactionResult if action was taken, undefined if no action needed
|
|
44
|
+
*/
|
|
45
|
+
async autoCompact(input) {
|
|
46
|
+
const { contextLimit, currentTokens, sessionId } = input;
|
|
47
|
+
const overflowCheck = this.checkOverflow(currentTokens, contextLimit);
|
|
48
|
+
if (!overflowCheck.isOverflow) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
if (overflowCheck.recommendation === 'prune') {
|
|
52
|
+
return this.pruneToolOutputs(sessionId);
|
|
53
|
+
}
|
|
54
|
+
// For full compaction, we need the caller to generate the summary
|
|
55
|
+
// via the LLM, then call createCompactionBoundary
|
|
56
|
+
// Return a result indicating compaction is needed
|
|
57
|
+
return {
|
|
58
|
+
compactedCount: 0,
|
|
59
|
+
compactionMessageId: undefined,
|
|
60
|
+
tokensSaved: 0,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check if context is overflowing and recommend action.
|
|
65
|
+
*/
|
|
66
|
+
checkOverflow(currentTokens, contextLimit) {
|
|
67
|
+
const threshold = contextLimit * this.config.overflowThreshold;
|
|
68
|
+
const isOverflow = currentTokens > threshold;
|
|
69
|
+
let recommendation = 'none';
|
|
70
|
+
if (isOverflow) {
|
|
71
|
+
// First try pruning tool outputs
|
|
72
|
+
recommendation = 'prune';
|
|
73
|
+
// If we're significantly over, suggest full compaction
|
|
74
|
+
if (currentTokens > contextLimit * 0.95) {
|
|
75
|
+
recommendation = 'compact';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
currentTokens,
|
|
80
|
+
isOverflow,
|
|
81
|
+
maxTokens: contextLimit,
|
|
82
|
+
recommendation,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create a compaction boundary with the given summary.
|
|
87
|
+
* The boundary acts as a marker - history loading stops here.
|
|
88
|
+
*/
|
|
89
|
+
async createCompactionBoundary(sessionId, summary) {
|
|
90
|
+
await this.messageStorage.insertCompactionBoundary(sessionId, summary);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Estimate tokens for a text string.
|
|
94
|
+
* Uses the configured tokenizer.
|
|
95
|
+
*/
|
|
96
|
+
async estimateTokens(text) {
|
|
97
|
+
return this.tokenizer.countTokens(text);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get the current compaction configuration.
|
|
101
|
+
*/
|
|
102
|
+
getConfig() {
|
|
103
|
+
return this.config;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Generate a summary prompt for the LLM to create a compaction summary.
|
|
107
|
+
* This returns the system prompt and user message to send to the LLM.
|
|
108
|
+
*/
|
|
109
|
+
getSummaryPromptParts() {
|
|
110
|
+
return {
|
|
111
|
+
systemPrompt: this.config.summaryPrompt,
|
|
112
|
+
userMessage: 'Based on our conversation so far, provide a detailed summary that captures all important context. ' +
|
|
113
|
+
'This summary will be used to continue the conversation without the full history.',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Prune old tool outputs to reduce context size.
|
|
118
|
+
* Keeps the most recent tool outputs up to the configured token limit.
|
|
119
|
+
*/
|
|
120
|
+
async pruneToolOutputs(sessionId) {
|
|
121
|
+
return this.messageStorage.pruneToolOutputs({
|
|
122
|
+
keepTokens: this.config.pruneKeepTokens,
|
|
123
|
+
sessionId,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Factory function to create CompactionService.
|
|
129
|
+
*/
|
|
130
|
+
export function createCompactionService(messageStorage, tokenizer, config) {
|
|
131
|
+
return new CompactionService(messageStorage, tokenizer, config);
|
|
132
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compaction module for managing context size in granular history storage.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - CompactionService: Main service for overflow detection and compaction
|
|
6
|
+
* - createCompactionService: Factory function
|
|
7
|
+
* - Types: CompactionConfig, OverflowCheckResult, CompactionInput
|
|
8
|
+
*/
|
|
9
|
+
export { type CompactionConfig, type CompactionInput, CompactionService, createCompactionService, type OverflowCheckResult, } from './compaction-service.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compaction module for managing context size in granular history storage.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - CompactionService: Main service for overflow detection and compaction
|
|
6
|
+
* - createCompactionService: Factory function
|
|
7
|
+
* - Types: CompactionConfig, OverflowCheckResult, CompactionInput
|
|
8
|
+
*/
|
|
9
|
+
export { CompactionService, createCompactionService, } from './compaction-service.js';
|
|
@@ -4,6 +4,28 @@ import type { IMessageFormatter } from '../../../../core/interfaces/cipher/i-mes
|
|
|
4
4
|
import type { ITokenizer } from '../../../../core/interfaces/cipher/i-tokenizer.js';
|
|
5
5
|
import type { InternalMessage } from '../../../../core/interfaces/cipher/message-types.js';
|
|
6
6
|
import type { ICompressionStrategy } from './compression/types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for persistence retry behavior.
|
|
9
|
+
*/
|
|
10
|
+
export interface PersistenceRetryConfig {
|
|
11
|
+
/** Base delay between retries in milliseconds (default: 100) */
|
|
12
|
+
baseDelayMs?: number;
|
|
13
|
+
/** Maximum number of retry attempts (default: 3) */
|
|
14
|
+
maxRetries?: number;
|
|
15
|
+
/** Multiplier for exponential backoff (default: 2) */
|
|
16
|
+
multiplier?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Event emitted when persistence fails after all retries.
|
|
20
|
+
*/
|
|
21
|
+
export interface PersistenceFailedEvent {
|
|
22
|
+
/** Number of attempts made */
|
|
23
|
+
attempts: number;
|
|
24
|
+
/** The error that caused the failure */
|
|
25
|
+
error: Error;
|
|
26
|
+
/** Session ID */
|
|
27
|
+
sessionId: string;
|
|
28
|
+
}
|
|
7
29
|
/**
|
|
8
30
|
* Image data for messages
|
|
9
31
|
*/
|
|
@@ -51,6 +73,10 @@ export interface ContextManagerOptions<T> {
|
|
|
51
73
|
historyStorage?: IHistoryStorage;
|
|
52
74
|
logger?: ILogger;
|
|
53
75
|
maxInputTokens: number;
|
|
76
|
+
/** Callback invoked when persistence fails after all retries */
|
|
77
|
+
onPersistenceFailed?: (event: PersistenceFailedEvent) => void;
|
|
78
|
+
/** Configuration for persistence retry behavior */
|
|
79
|
+
persistenceRetry?: PersistenceRetryConfig;
|
|
54
80
|
sessionId: string;
|
|
55
81
|
tokenizer: ITokenizer;
|
|
56
82
|
}
|
|
@@ -79,6 +105,10 @@ export declare class ContextManager<T> {
|
|
|
79
105
|
* Used during parallel tool execution to prevent race conditions.
|
|
80
106
|
*/
|
|
81
107
|
private readonly mutex;
|
|
108
|
+
/** Callback for persistence failure events */
|
|
109
|
+
private readonly onPersistenceFailed?;
|
|
110
|
+
/** Retry configuration for persistence operations */
|
|
111
|
+
private readonly persistenceRetry;
|
|
82
112
|
private readonly sessionId;
|
|
83
113
|
private readonly tokenizer;
|
|
84
114
|
/**
|
|
@@ -91,6 +121,8 @@ export declare class ContextManager<T> {
|
|
|
91
121
|
* @param options.maxInputTokens - Maximum input tokens allowed
|
|
92
122
|
* @param options.historyStorage - Optional history storage for persistence
|
|
93
123
|
* @param options.compressionStrategies - Optional compression strategies (defaults to MiddleRemoval + OldestRemoval)
|
|
124
|
+
* @param options.persistenceRetry - Optional retry configuration for persistence
|
|
125
|
+
* @param options.onPersistenceFailed - Optional callback for persistence failure events
|
|
94
126
|
*/
|
|
95
127
|
constructor(options: ContextManagerOptions<T>);
|
|
96
128
|
/**
|
|
@@ -204,10 +236,17 @@ export declare class ContextManager<T> {
|
|
|
204
236
|
*/
|
|
205
237
|
private isSystemNoise;
|
|
206
238
|
/**
|
|
207
|
-
* Persist current conversation history to storage.
|
|
239
|
+
* Persist current conversation history to storage with retry logic.
|
|
208
240
|
* This is called automatically after each message is added.
|
|
209
241
|
*
|
|
210
|
-
*
|
|
242
|
+
* Uses exponential backoff for retries:
|
|
243
|
+
* - Attempt 1: immediate
|
|
244
|
+
* - Attempt 2: baseDelayMs * multiplier^0 = 100ms
|
|
245
|
+
* - Attempt 3: baseDelayMs * multiplier^1 = 200ms
|
|
246
|
+
*
|
|
247
|
+
* If all retries fail, invokes onPersistenceFailed callback if configured.
|
|
248
|
+
*
|
|
249
|
+
* @returns Promise that resolves when history is persisted (or all retries exhausted)
|
|
211
250
|
*/
|
|
212
251
|
private persistHistory;
|
|
213
252
|
/**
|
|
@@ -218,6 +257,11 @@ export declare class ContextManager<T> {
|
|
|
218
257
|
* @returns Sanitized string representation
|
|
219
258
|
*/
|
|
220
259
|
private sanitizeToolResult;
|
|
260
|
+
/**
|
|
261
|
+
* Sleep for the specified duration.
|
|
262
|
+
* @param ms - Duration in milliseconds
|
|
263
|
+
*/
|
|
264
|
+
private sleep;
|
|
221
265
|
/**
|
|
222
266
|
* Validate a message for API inclusion.
|
|
223
267
|
* Filters out invalid messages that would waste tokens or confuse the LLM.
|
|
@@ -28,6 +28,10 @@ export class ContextManager {
|
|
|
28
28
|
* Used during parallel tool execution to prevent race conditions.
|
|
29
29
|
*/
|
|
30
30
|
mutex = new AsyncMutex();
|
|
31
|
+
/** Callback for persistence failure events */
|
|
32
|
+
onPersistenceFailed;
|
|
33
|
+
/** Retry configuration for persistence operations */
|
|
34
|
+
persistenceRetry;
|
|
31
35
|
sessionId;
|
|
32
36
|
tokenizer;
|
|
33
37
|
/**
|
|
@@ -40,6 +44,8 @@ export class ContextManager {
|
|
|
40
44
|
* @param options.maxInputTokens - Maximum input tokens allowed
|
|
41
45
|
* @param options.historyStorage - Optional history storage for persistence
|
|
42
46
|
* @param options.compressionStrategies - Optional compression strategies (defaults to MiddleRemoval + OldestRemoval)
|
|
47
|
+
* @param options.persistenceRetry - Optional retry configuration for persistence
|
|
48
|
+
* @param options.onPersistenceFailed - Optional callback for persistence failure events
|
|
43
49
|
*/
|
|
44
50
|
constructor(options) {
|
|
45
51
|
this.sessionId = options.sessionId;
|
|
@@ -48,6 +54,13 @@ export class ContextManager {
|
|
|
48
54
|
this.maxInputTokens = options.maxInputTokens;
|
|
49
55
|
this.historyStorage = options.historyStorage;
|
|
50
56
|
this.logger = options.logger ?? new NoOpLogger();
|
|
57
|
+
this.onPersistenceFailed = options.onPersistenceFailed;
|
|
58
|
+
// Initialize persistence retry config with defaults
|
|
59
|
+
this.persistenceRetry = {
|
|
60
|
+
baseDelayMs: options.persistenceRetry?.baseDelayMs ?? 100,
|
|
61
|
+
maxRetries: options.persistenceRetry?.maxRetries ?? 3,
|
|
62
|
+
multiplier: options.persistenceRetry?.multiplier ?? 2,
|
|
63
|
+
};
|
|
51
64
|
// Initialize compression strategies with defaults
|
|
52
65
|
this.compressionStrategies = options.compressionStrategies ?? [
|
|
53
66
|
new MiddleRemovalStrategy({ preserveEnd: 5, preserveStart: 4 }),
|
|
@@ -350,17 +363,59 @@ export class ContextManager {
|
|
|
350
363
|
return content.trim().length === 0;
|
|
351
364
|
}
|
|
352
365
|
/**
|
|
353
|
-
* Persist current conversation history to storage.
|
|
366
|
+
* Persist current conversation history to storage with retry logic.
|
|
354
367
|
* This is called automatically after each message is added.
|
|
355
368
|
*
|
|
356
|
-
*
|
|
369
|
+
* Uses exponential backoff for retries:
|
|
370
|
+
* - Attempt 1: immediate
|
|
371
|
+
* - Attempt 2: baseDelayMs * multiplier^0 = 100ms
|
|
372
|
+
* - Attempt 3: baseDelayMs * multiplier^1 = 200ms
|
|
373
|
+
*
|
|
374
|
+
* If all retries fail, invokes onPersistenceFailed callback if configured.
|
|
375
|
+
*
|
|
376
|
+
* @returns Promise that resolves when history is persisted (or all retries exhausted)
|
|
357
377
|
*/
|
|
358
378
|
async persistHistory() {
|
|
359
379
|
if (!this.historyStorage) {
|
|
360
380
|
return;
|
|
361
381
|
}
|
|
362
|
-
|
|
363
|
-
|
|
382
|
+
const { baseDelayMs, maxRetries, multiplier } = this.persistenceRetry;
|
|
383
|
+
let lastError;
|
|
384
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
385
|
+
try {
|
|
386
|
+
// Store InternalMessage directly (no conversion needed)
|
|
387
|
+
// eslint-disable-next-line no-await-in-loop
|
|
388
|
+
await this.historyStorage.saveHistory(this.sessionId, this.messages);
|
|
389
|
+
return; // Success - exit early
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
393
|
+
if (attempt < maxRetries) {
|
|
394
|
+
// Calculate exponential backoff delay
|
|
395
|
+
const delay = baseDelayMs * multiplier ** (attempt - 1);
|
|
396
|
+
this.logger.warn(`Persistence attempt ${attempt}/${maxRetries} failed, retrying in ${delay}ms`, {
|
|
397
|
+
error: lastError.message,
|
|
398
|
+
sessionId: this.sessionId,
|
|
399
|
+
});
|
|
400
|
+
// Wait before next retry
|
|
401
|
+
// eslint-disable-next-line no-await-in-loop
|
|
402
|
+
await this.sleep(delay);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// All retries exhausted
|
|
407
|
+
this.logger.error(`Persistence failed after ${maxRetries} attempts`, {
|
|
408
|
+
error: lastError?.message,
|
|
409
|
+
sessionId: this.sessionId,
|
|
410
|
+
});
|
|
411
|
+
// Invoke callback if configured
|
|
412
|
+
if (this.onPersistenceFailed && lastError) {
|
|
413
|
+
this.onPersistenceFailed({
|
|
414
|
+
attempts: maxRetries,
|
|
415
|
+
error: lastError,
|
|
416
|
+
sessionId: this.sessionId,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
364
419
|
}
|
|
365
420
|
/**
|
|
366
421
|
* Sanitize tool result for storage.
|
|
@@ -389,6 +444,15 @@ export class ContextManager {
|
|
|
389
444
|
return `[Tool result serialization failed: ${getErrorMessage(error)}]`;
|
|
390
445
|
}
|
|
391
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* Sleep for the specified duration.
|
|
449
|
+
* @param ms - Duration in milliseconds
|
|
450
|
+
*/
|
|
451
|
+
sleep(ms) {
|
|
452
|
+
return new Promise((resolve) => {
|
|
453
|
+
setTimeout(resolve, ms);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
392
456
|
/**
|
|
393
457
|
* Validate a message for API inclusion.
|
|
394
458
|
* Filters out invalid messages that would waste tokens or confuse the LLM.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader-Writer Lock with Disposable pattern support.
|
|
3
|
+
*
|
|
4
|
+
* Provides concurrent read access while ensuring exclusive write access.
|
|
5
|
+
* Multiple readers can hold the lock simultaneously, but writers get
|
|
6
|
+
* exclusive access (no readers or other writers).
|
|
7
|
+
*
|
|
8
|
+
* Follows OpenCode's lock pattern with ES2022 'using' keyword support
|
|
9
|
+
* for automatic release.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Read lock (allows concurrent reads)
|
|
14
|
+
* using _readLock = await RWLock.read('session:123')
|
|
15
|
+
* const data = await storage.get(key)
|
|
16
|
+
*
|
|
17
|
+
* // Write lock (exclusive access)
|
|
18
|
+
* using _writeLock = await RWLock.write('session:123')
|
|
19
|
+
* await storage.set(key, value)
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Global lock manager for coordinating concurrent access.
|
|
24
|
+
* Uses per-target locks to allow independent locking of different resources.
|
|
25
|
+
*/
|
|
26
|
+
declare class RWLockManager {
|
|
27
|
+
private readonly locks;
|
|
28
|
+
/**
|
|
29
|
+
* Get current lock statistics for debugging.
|
|
30
|
+
*/
|
|
31
|
+
getStats(): {
|
|
32
|
+
activeLocks: number;
|
|
33
|
+
targets: string[];
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Acquire a read lock.
|
|
37
|
+
* Multiple readers can hold the lock simultaneously.
|
|
38
|
+
* Will wait if a writer holds the lock or is waiting.
|
|
39
|
+
*
|
|
40
|
+
* @param target - Resource identifier to lock
|
|
41
|
+
* @returns Disposable that releases the lock when disposed
|
|
42
|
+
*/
|
|
43
|
+
read(target: string): Promise<Disposable>;
|
|
44
|
+
/**
|
|
45
|
+
* Acquire a write lock.
|
|
46
|
+
* Writers get exclusive access - no readers or other writers.
|
|
47
|
+
* Writers have priority over readers to prevent writer starvation.
|
|
48
|
+
*
|
|
49
|
+
* @param target - Resource identifier to lock
|
|
50
|
+
* @returns Disposable that releases the lock when disposed
|
|
51
|
+
*/
|
|
52
|
+
write(target: string): Promise<Disposable>;
|
|
53
|
+
/**
|
|
54
|
+
* Clean up lock state if no longer needed.
|
|
55
|
+
*/
|
|
56
|
+
private cleanupIfEmpty;
|
|
57
|
+
/**
|
|
58
|
+
* Get or create lock state for a target.
|
|
59
|
+
*/
|
|
60
|
+
private getLockState;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Global RWLock instance for coordinating storage access.
|
|
64
|
+
* Use this for all storage operations to prevent race conditions.
|
|
65
|
+
*/
|
|
66
|
+
export declare const RWLock: RWLockManager;
|
|
67
|
+
/**
|
|
68
|
+
* Helper function to create a lock key from a storage key.
|
|
69
|
+
* Converts ["message", "session123", "msg456"] to "message:session123:msg456"
|
|
70
|
+
*/
|
|
71
|
+
export declare function lockKeyFromStorageKey(storageKey: readonly string[]): string;
|
|
72
|
+
export {};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reader-Writer Lock with Disposable pattern support.
|
|
3
|
+
*
|
|
4
|
+
* Provides concurrent read access while ensuring exclusive write access.
|
|
5
|
+
* Multiple readers can hold the lock simultaneously, but writers get
|
|
6
|
+
* exclusive access (no readers or other writers).
|
|
7
|
+
*
|
|
8
|
+
* Follows OpenCode's lock pattern with ES2022 'using' keyword support
|
|
9
|
+
* for automatic release.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Read lock (allows concurrent reads)
|
|
14
|
+
* using _readLock = await RWLock.read('session:123')
|
|
15
|
+
* const data = await storage.get(key)
|
|
16
|
+
*
|
|
17
|
+
* // Write lock (exclusive access)
|
|
18
|
+
* using _writeLock = await RWLock.write('session:123')
|
|
19
|
+
* await storage.set(key, value)
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Global lock manager for coordinating concurrent access.
|
|
24
|
+
* Uses per-target locks to allow independent locking of different resources.
|
|
25
|
+
*/
|
|
26
|
+
class RWLockManager {
|
|
27
|
+
locks = new Map();
|
|
28
|
+
/**
|
|
29
|
+
* Get current lock statistics for debugging.
|
|
30
|
+
*/
|
|
31
|
+
getStats() {
|
|
32
|
+
return {
|
|
33
|
+
activeLocks: this.locks.size,
|
|
34
|
+
targets: [...this.locks.keys()],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Acquire a read lock.
|
|
39
|
+
* Multiple readers can hold the lock simultaneously.
|
|
40
|
+
* Will wait if a writer holds the lock or is waiting.
|
|
41
|
+
*
|
|
42
|
+
* @param target - Resource identifier to lock
|
|
43
|
+
* @returns Disposable that releases the lock when disposed
|
|
44
|
+
*/
|
|
45
|
+
async read(target) {
|
|
46
|
+
const state = this.getLockState(target);
|
|
47
|
+
// Wait for any pending/active writer (writers have priority to prevent starvation)
|
|
48
|
+
while (state.writer || state.waitingWriters.length > 0) {
|
|
49
|
+
// eslint-disable-next-line no-await-in-loop
|
|
50
|
+
await new Promise((resolve) => {
|
|
51
|
+
state.waitingReaders.push(resolve);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
state.readers++;
|
|
55
|
+
return {
|
|
56
|
+
[Symbol.dispose]: () => {
|
|
57
|
+
state.readers--;
|
|
58
|
+
// If no more readers and writers are waiting, wake a writer
|
|
59
|
+
if (state.readers === 0 && state.waitingWriters.length > 0) {
|
|
60
|
+
const next = state.waitingWriters.shift();
|
|
61
|
+
next?.();
|
|
62
|
+
}
|
|
63
|
+
this.cleanupIfEmpty(target);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Acquire a write lock.
|
|
69
|
+
* Writers get exclusive access - no readers or other writers.
|
|
70
|
+
* Writers have priority over readers to prevent writer starvation.
|
|
71
|
+
*
|
|
72
|
+
* @param target - Resource identifier to lock
|
|
73
|
+
* @returns Disposable that releases the lock when disposed
|
|
74
|
+
*/
|
|
75
|
+
async write(target) {
|
|
76
|
+
const state = this.getLockState(target);
|
|
77
|
+
// Wait for all readers and any active writer
|
|
78
|
+
while (state.writer || state.readers > 0) {
|
|
79
|
+
// eslint-disable-next-line no-await-in-loop
|
|
80
|
+
await new Promise((resolve) => {
|
|
81
|
+
state.waitingWriters.push(resolve);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
state.writer = true;
|
|
85
|
+
return {
|
|
86
|
+
[Symbol.dispose]: () => {
|
|
87
|
+
state.writer = false;
|
|
88
|
+
// Prefer writers over readers to prevent writer starvation
|
|
89
|
+
if (state.waitingWriters.length > 0) {
|
|
90
|
+
const next = state.waitingWriters.shift();
|
|
91
|
+
next?.();
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
// Wake all pending readers at once
|
|
95
|
+
while (state.waitingReaders.length > 0) {
|
|
96
|
+
const next = state.waitingReaders.shift();
|
|
97
|
+
next?.();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
this.cleanupIfEmpty(target);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Clean up lock state if no longer needed.
|
|
106
|
+
*/
|
|
107
|
+
cleanupIfEmpty(target) {
|
|
108
|
+
const state = this.locks.get(target);
|
|
109
|
+
if (state &&
|
|
110
|
+
state.readers === 0 &&
|
|
111
|
+
!state.writer &&
|
|
112
|
+
state.waitingReaders.length === 0 &&
|
|
113
|
+
state.waitingWriters.length === 0) {
|
|
114
|
+
this.locks.delete(target);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get or create lock state for a target.
|
|
119
|
+
*/
|
|
120
|
+
getLockState(target) {
|
|
121
|
+
let state = this.locks.get(target);
|
|
122
|
+
if (!state) {
|
|
123
|
+
state = {
|
|
124
|
+
readers: 0,
|
|
125
|
+
waitingReaders: [],
|
|
126
|
+
waitingWriters: [],
|
|
127
|
+
writer: false,
|
|
128
|
+
};
|
|
129
|
+
this.locks.set(target, state);
|
|
130
|
+
}
|
|
131
|
+
return state;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Global RWLock instance for coordinating storage access.
|
|
136
|
+
* Use this for all storage operations to prevent race conditions.
|
|
137
|
+
*/
|
|
138
|
+
export const RWLock = new RWLockManager();
|
|
139
|
+
/**
|
|
140
|
+
* Helper function to create a lock key from a storage key.
|
|
141
|
+
* Converts ["message", "session123", "msg456"] to "message:session123:msg456"
|
|
142
|
+
*/
|
|
143
|
+
export function lockKeyFromStorageKey(storageKey) {
|
|
144
|
+
return storageKey.join(':');
|
|
145
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ByteRover Content Generator.
|
|
3
3
|
*
|
|
4
|
-
* Implements IContentGenerator using ByteRover
|
|
5
|
-
* Supports both Claude and Gemini models through the unified
|
|
4
|
+
* Implements IContentGenerator using ByteRover HTTP service.
|
|
5
|
+
* Supports both Claude and Gemini models through the unified HTTP interface.
|
|
6
6
|
*/
|
|
7
7
|
import type { GenerateContentChunk, GenerateContentRequest, GenerateContentResponse, IContentGenerator } from '../../../../core/interfaces/cipher/i-content-generator.js';
|
|
8
|
-
import type {
|
|
8
|
+
import type { ByteRoverLlmHttpService } from '../../http/internal-llm-http-service.js';
|
|
9
9
|
import { type ThinkingConfig } from '../thought-parser.js';
|
|
10
10
|
/**
|
|
11
11
|
* Configuration for ByteRover Content Generator.
|
|
@@ -23,7 +23,7 @@ export interface ByteRoverContentGeneratorConfig {
|
|
|
23
23
|
/**
|
|
24
24
|
* ByteRover Content Generator.
|
|
25
25
|
*
|
|
26
|
-
* Wraps
|
|
26
|
+
* Wraps ByteRoverLlmHttpService and implements IContentGenerator.
|
|
27
27
|
* Handles:
|
|
28
28
|
* - Provider detection (Claude vs Gemini)
|
|
29
29
|
* - Message formatting via provider-specific formatters
|
|
@@ -33,16 +33,16 @@ export interface ByteRoverContentGeneratorConfig {
|
|
|
33
33
|
export declare class ByteRoverContentGenerator implements IContentGenerator {
|
|
34
34
|
private readonly config;
|
|
35
35
|
private readonly formatter;
|
|
36
|
-
private readonly
|
|
36
|
+
private readonly httpService;
|
|
37
37
|
private readonly providerType;
|
|
38
38
|
private readonly tokenizer;
|
|
39
39
|
/**
|
|
40
40
|
* Create a new ByteRover Content Generator.
|
|
41
41
|
*
|
|
42
|
-
* @param
|
|
42
|
+
* @param httpService - Configured HTTP service for LLM API calls
|
|
43
43
|
* @param config - Generator configuration
|
|
44
44
|
*/
|
|
45
|
-
constructor(
|
|
45
|
+
constructor(httpService: ByteRoverLlmHttpService, config: ByteRoverContentGeneratorConfig);
|
|
46
46
|
/**
|
|
47
47
|
* Estimate tokens synchronously using character-based approximation.
|
|
48
48
|
*
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ByteRover Content Generator.
|
|
3
3
|
*
|
|
4
|
-
* Implements IContentGenerator using ByteRover
|
|
5
|
-
* Supports both Claude and Gemini models through the unified
|
|
4
|
+
* Implements IContentGenerator using ByteRover HTTP service.
|
|
5
|
+
* Supports both Claude and Gemini models through the unified HTTP interface.
|
|
6
6
|
*/
|
|
7
7
|
import { FunctionCallingConfigMode } from '@google/genai';
|
|
8
8
|
import { ClaudeMessageFormatter } from '../formatters/claude-formatter.js';
|
|
@@ -13,7 +13,7 @@ import { GeminiTokenizer } from '../tokenizers/gemini-tokenizer.js';
|
|
|
13
13
|
/**
|
|
14
14
|
* ByteRover Content Generator.
|
|
15
15
|
*
|
|
16
|
-
* Wraps
|
|
16
|
+
* Wraps ByteRoverLlmHttpService and implements IContentGenerator.
|
|
17
17
|
* Handles:
|
|
18
18
|
* - Provider detection (Claude vs Gemini)
|
|
19
19
|
* - Message formatting via provider-specific formatters
|
|
@@ -23,17 +23,17 @@ import { GeminiTokenizer } from '../tokenizers/gemini-tokenizer.js';
|
|
|
23
23
|
export class ByteRoverContentGenerator {
|
|
24
24
|
config;
|
|
25
25
|
formatter;
|
|
26
|
-
|
|
26
|
+
httpService;
|
|
27
27
|
providerType;
|
|
28
28
|
tokenizer;
|
|
29
29
|
/**
|
|
30
30
|
* Create a new ByteRover Content Generator.
|
|
31
31
|
*
|
|
32
|
-
* @param
|
|
32
|
+
* @param httpService - Configured HTTP service for LLM API calls
|
|
33
33
|
* @param config - Generator configuration
|
|
34
34
|
*/
|
|
35
|
-
constructor(
|
|
36
|
-
this.
|
|
35
|
+
constructor(httpService, config) {
|
|
36
|
+
this.httpService = httpService;
|
|
37
37
|
this.config = {
|
|
38
38
|
maxTokens: config.maxTokens ?? 8192,
|
|
39
39
|
model: config.model,
|
|
@@ -81,7 +81,7 @@ export class ByteRoverContentGenerator {
|
|
|
81
81
|
...(request.mode && { mode: request.mode }),
|
|
82
82
|
...(request.executionContext && { executionContext: request.executionContext }),
|
|
83
83
|
};
|
|
84
|
-
const rawResponse = await this.
|
|
84
|
+
const rawResponse = await this.httpService.generateContent(contents, config, this.config.model, executionMetadata);
|
|
85
85
|
// Parse response to internal format
|
|
86
86
|
const messages = this.formatter.parseResponse(rawResponse);
|
|
87
87
|
const lastMessage = messages.at(-1);
|
|
@@ -390,6 +390,7 @@ export class ByteRoverLLMService {
|
|
|
390
390
|
availableTools,
|
|
391
391
|
commandType: executionContext?.commandType,
|
|
392
392
|
conversationMetadata: executionContext?.conversationMetadata,
|
|
393
|
+
fileReferenceInstructions: executionContext?.fileReferenceInstructions,
|
|
393
394
|
memoryManager: this.memoryManager,
|
|
394
395
|
mode,
|
|
395
396
|
});
|
|
@@ -498,6 +499,7 @@ export class ByteRoverLLMService {
|
|
|
498
499
|
// Emit tool result event with success/error info
|
|
499
500
|
this.sessionEventBus.emit('llmservice:toolResult', {
|
|
500
501
|
callId: toolCall.id,
|
|
502
|
+
error: result.errorMessage,
|
|
501
503
|
errorType: result.errorType,
|
|
502
504
|
metadata: {
|
|
503
505
|
...result.metadata,
|