onbuzz 3.3.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/LICENSE +267 -0
- package/README.md +425 -0
- package/bin/cli.js +556 -0
- package/bin/loxia-terminal-v2.js +162 -0
- package/bin/loxia-terminal.js +90 -0
- package/bin/start-with-terminal.js +200 -0
- package/node_modules/@isaacs/balanced-match/LICENSE.md +23 -0
- package/node_modules/@isaacs/balanced-match/README.md +60 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.d.ts +9 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.js +59 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/index.js.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/commonjs/package.json +3 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.d.ts +9 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.d.ts.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.js +54 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/index.js.map +1 -0
- package/node_modules/@isaacs/balanced-match/dist/esm/package.json +3 -0
- package/node_modules/@isaacs/balanced-match/package.json +79 -0
- package/node_modules/@isaacs/brace-expansion/LICENSE +23 -0
- package/node_modules/@isaacs/brace-expansion/README.md +97 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.d.ts +6 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js +199 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/commonjs/package.json +3 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.d.ts +6 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.d.ts.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.js +195 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +1 -0
- package/node_modules/@isaacs/brace-expansion/dist/esm/package.json +3 -0
- package/node_modules/@isaacs/brace-expansion/package.json +60 -0
- package/node_modules/glob/LICENSE.md +63 -0
- package/node_modules/glob/README.md +1177 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts +388 -0
- package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/glob.js +247 -0
- package/node_modules/glob/dist/commonjs/glob.js.map +1 -0
- package/node_modules/glob/dist/commonjs/has-magic.d.ts +14 -0
- package/node_modules/glob/dist/commonjs/has-magic.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/has-magic.js +27 -0
- package/node_modules/glob/dist/commonjs/has-magic.js.map +1 -0
- package/node_modules/glob/dist/commonjs/ignore.d.ts +24 -0
- package/node_modules/glob/dist/commonjs/ignore.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/ignore.js +119 -0
- package/node_modules/glob/dist/commonjs/ignore.js.map +1 -0
- package/node_modules/glob/dist/commonjs/index.d.ts +97 -0
- package/node_modules/glob/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/index.js +68 -0
- package/node_modules/glob/dist/commonjs/index.js.map +1 -0
- package/node_modules/glob/dist/commonjs/index.min.js +4 -0
- package/node_modules/glob/dist/commonjs/index.min.js.map +7 -0
- package/node_modules/glob/dist/commonjs/package.json +3 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts +76 -0
- package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/pattern.js +219 -0
- package/node_modules/glob/dist/commonjs/pattern.js.map +1 -0
- package/node_modules/glob/dist/commonjs/processor.d.ts +59 -0
- package/node_modules/glob/dist/commonjs/processor.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/processor.js +301 -0
- package/node_modules/glob/dist/commonjs/processor.js.map +1 -0
- package/node_modules/glob/dist/commonjs/walker.d.ts +97 -0
- package/node_modules/glob/dist/commonjs/walker.d.ts.map +1 -0
- package/node_modules/glob/dist/commonjs/walker.js +387 -0
- package/node_modules/glob/dist/commonjs/walker.js.map +1 -0
- package/node_modules/glob/dist/esm/glob.d.ts +388 -0
- package/node_modules/glob/dist/esm/glob.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/glob.js +243 -0
- package/node_modules/glob/dist/esm/glob.js.map +1 -0
- package/node_modules/glob/dist/esm/has-magic.d.ts +14 -0
- package/node_modules/glob/dist/esm/has-magic.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/has-magic.js +23 -0
- package/node_modules/glob/dist/esm/has-magic.js.map +1 -0
- package/node_modules/glob/dist/esm/ignore.d.ts +24 -0
- package/node_modules/glob/dist/esm/ignore.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/ignore.js +115 -0
- package/node_modules/glob/dist/esm/ignore.js.map +1 -0
- package/node_modules/glob/dist/esm/index.d.ts +97 -0
- package/node_modules/glob/dist/esm/index.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/index.js +55 -0
- package/node_modules/glob/dist/esm/index.js.map +1 -0
- package/node_modules/glob/dist/esm/index.min.js +4 -0
- package/node_modules/glob/dist/esm/index.min.js.map +7 -0
- package/node_modules/glob/dist/esm/package.json +3 -0
- package/node_modules/glob/dist/esm/pattern.d.ts +76 -0
- package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/pattern.js +215 -0
- package/node_modules/glob/dist/esm/pattern.js.map +1 -0
- package/node_modules/glob/dist/esm/processor.d.ts +59 -0
- package/node_modules/glob/dist/esm/processor.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/processor.js +294 -0
- package/node_modules/glob/dist/esm/processor.js.map +1 -0
- package/node_modules/glob/dist/esm/walker.d.ts +97 -0
- package/node_modules/glob/dist/esm/walker.d.ts.map +1 -0
- package/node_modules/glob/dist/esm/walker.js +381 -0
- package/node_modules/glob/dist/esm/walker.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/LICENSE.md +55 -0
- package/node_modules/glob/node_modules/minimatch/README.md +453 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +2 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js +14 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +20 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +591 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts +8 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +152 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +15 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +30 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +94 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +1029 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/package.json +3 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +22 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +38 -0
- package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +2 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js +10 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +20 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +587 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts +8 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +148 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +15 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +26 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +94 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +1016 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/package.json +3 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +22 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +34 -0
- package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -0
- package/node_modules/glob/node_modules/minimatch/package.json +67 -0
- package/node_modules/glob/package.json +101 -0
- package/node_modules/minipass/LICENSE +15 -0
- package/node_modules/minipass/README.md +825 -0
- package/node_modules/minipass/dist/commonjs/index.d.ts +549 -0
- package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/minipass/dist/commonjs/index.js +1028 -0
- package/node_modules/minipass/dist/commonjs/index.js.map +1 -0
- package/node_modules/minipass/dist/commonjs/package.json +3 -0
- package/node_modules/minipass/dist/esm/index.d.ts +549 -0
- package/node_modules/minipass/dist/esm/index.d.ts.map +1 -0
- package/node_modules/minipass/dist/esm/index.js +1018 -0
- package/node_modules/minipass/dist/esm/index.js.map +1 -0
- package/node_modules/minipass/dist/esm/package.json +3 -0
- package/node_modules/minipass/package.json +82 -0
- package/node_modules/package-json-from-dist/LICENSE.md +63 -0
- package/node_modules/package-json-from-dist/README.md +110 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts +89 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.js +134 -0
- package/node_modules/package-json-from-dist/dist/commonjs/index.js.map +1 -0
- package/node_modules/package-json-from-dist/dist/commonjs/package.json +3 -0
- package/node_modules/package-json-from-dist/dist/esm/index.d.ts +89 -0
- package/node_modules/package-json-from-dist/dist/esm/index.d.ts.map +1 -0
- package/node_modules/package-json-from-dist/dist/esm/index.js +129 -0
- package/node_modules/package-json-from-dist/dist/esm/index.js.map +1 -0
- package/node_modules/package-json-from-dist/dist/esm/package.json +3 -0
- package/node_modules/package-json-from-dist/package.json +68 -0
- package/node_modules/path-scurry/LICENSE.md +55 -0
- package/node_modules/path-scurry/README.md +636 -0
- package/node_modules/path-scurry/dist/commonjs/index.d.ts +1115 -0
- package/node_modules/path-scurry/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/path-scurry/dist/commonjs/index.js +2018 -0
- package/node_modules/path-scurry/dist/commonjs/index.js.map +1 -0
- package/node_modules/path-scurry/dist/commonjs/package.json +3 -0
- package/node_modules/path-scurry/dist/esm/index.d.ts +1115 -0
- package/node_modules/path-scurry/dist/esm/index.d.ts.map +1 -0
- package/node_modules/path-scurry/dist/esm/index.js +1983 -0
- package/node_modules/path-scurry/dist/esm/index.js.map +1 -0
- package/node_modules/path-scurry/dist/esm/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/LICENSE.md +55 -0
- package/node_modules/path-scurry/node_modules/lru-cache/README.md +383 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +1323 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +1589 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +1323 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +1585 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +2 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +7 -0
- package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/package.json +3 -0
- package/node_modules/path-scurry/node_modules/lru-cache/package.json +101 -0
- package/node_modules/path-scurry/package.json +88 -0
- package/node_modules/rimraf/LICENSE.md +55 -0
- package/node_modules/rimraf/README.md +226 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.js +58 -0
- package/node_modules/rimraf/dist/commonjs/default-tmp.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/error.d.ts +6 -0
- package/node_modules/rimraf/dist/commonjs/error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/error.js +10 -0
- package/node_modules/rimraf/dist/commonjs/error.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.js +38 -0
- package/node_modules/rimraf/dist/commonjs/fix-eperm.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fs.d.ts +15 -0
- package/node_modules/rimraf/dist/commonjs/fs.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/fs.js +33 -0
- package/node_modules/rimraf/dist/commonjs/fs.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.js +24 -0
- package/node_modules/rimraf/dist/commonjs/ignore-enoent.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/index.d.ts +50 -0
- package/node_modules/rimraf/dist/commonjs/index.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/index.js +78 -0
- package/node_modules/rimraf/dist/commonjs/index.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.d.ts +34 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.js +53 -0
- package/node_modules/rimraf/dist/commonjs/opt-arg.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/package.json +3 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.js +48 -0
- package/node_modules/rimraf/dist/commonjs/path-arg.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.js +19 -0
- package/node_modules/rimraf/dist/commonjs/readdir-or-error.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.d.ts +8 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.js +65 -0
- package/node_modules/rimraf/dist/commonjs/retry-busy.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.d.ts +3 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.js +8 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-manual.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.js +138 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-move-remove.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.js +24 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-native.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.js +103 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-posix.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.js +159 -0
- package/node_modules/rimraf/dist/commonjs/rimraf-windows.js.map +1 -0
- package/node_modules/rimraf/dist/commonjs/use-native.d.ts +4 -0
- package/node_modules/rimraf/dist/commonjs/use-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/commonjs/use-native.js +18 -0
- package/node_modules/rimraf/dist/commonjs/use-native.js.map +1 -0
- package/node_modules/rimraf/dist/esm/bin.d.mts +3 -0
- package/node_modules/rimraf/dist/esm/bin.d.mts.map +1 -0
- package/node_modules/rimraf/dist/esm/bin.mjs +250 -0
- package/node_modules/rimraf/dist/esm/bin.mjs.map +1 -0
- package/node_modules/rimraf/dist/esm/default-tmp.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/default-tmp.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/default-tmp.js +55 -0
- package/node_modules/rimraf/dist/esm/default-tmp.js.map +1 -0
- package/node_modules/rimraf/dist/esm/error.d.ts +6 -0
- package/node_modules/rimraf/dist/esm/error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/error.js +5 -0
- package/node_modules/rimraf/dist/esm/error.js.map +1 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.js +33 -0
- package/node_modules/rimraf/dist/esm/fix-eperm.js.map +1 -0
- package/node_modules/rimraf/dist/esm/fs.d.ts +15 -0
- package/node_modules/rimraf/dist/esm/fs.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/fs.js +18 -0
- package/node_modules/rimraf/dist/esm/fs.js.map +1 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.js +19 -0
- package/node_modules/rimraf/dist/esm/ignore-enoent.js.map +1 -0
- package/node_modules/rimraf/dist/esm/index.d.ts +50 -0
- package/node_modules/rimraf/dist/esm/index.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/index.js +70 -0
- package/node_modules/rimraf/dist/esm/index.js.map +1 -0
- package/node_modules/rimraf/dist/esm/opt-arg.d.ts +34 -0
- package/node_modules/rimraf/dist/esm/opt-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/opt-arg.js +46 -0
- package/node_modules/rimraf/dist/esm/opt-arg.js.map +1 -0
- package/node_modules/rimraf/dist/esm/package.json +3 -0
- package/node_modules/rimraf/dist/esm/path-arg.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/path-arg.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/path-arg.js +46 -0
- package/node_modules/rimraf/dist/esm/path-arg.js.map +1 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.js +14 -0
- package/node_modules/rimraf/dist/esm/readdir-or-error.js.map +1 -0
- package/node_modules/rimraf/dist/esm/retry-busy.d.ts +8 -0
- package/node_modules/rimraf/dist/esm/retry-busy.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/retry-busy.js +60 -0
- package/node_modules/rimraf/dist/esm/retry-busy.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.d.ts +3 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.js +5 -0
- package/node_modules/rimraf/dist/esm/rimraf-manual.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.js +133 -0
- package/node_modules/rimraf/dist/esm/rimraf-move-remove.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.js +19 -0
- package/node_modules/rimraf/dist/esm/rimraf-native.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.js +98 -0
- package/node_modules/rimraf/dist/esm/rimraf-posix.js.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.js +154 -0
- package/node_modules/rimraf/dist/esm/rimraf-windows.js.map +1 -0
- package/node_modules/rimraf/dist/esm/use-native.d.ts +4 -0
- package/node_modules/rimraf/dist/esm/use-native.d.ts.map +1 -0
- package/node_modules/rimraf/dist/esm/use-native.js +15 -0
- package/node_modules/rimraf/dist/esm/use-native.js.map +1 -0
- package/node_modules/rimraf/package.json +92 -0
- package/package.json +152 -0
- package/scripts/install-scanners.js +258 -0
- package/scripts/watchdog.js +147 -0
- package/src/analyzers/CSSAnalyzer.js +297 -0
- package/src/analyzers/ConfigValidator.js +690 -0
- package/src/analyzers/ESLintAnalyzer.js +320 -0
- package/src/analyzers/JavaScriptAnalyzer.js +261 -0
- package/src/analyzers/PrettierFormatter.js +247 -0
- package/src/analyzers/PythonAnalyzer.js +283 -0
- package/src/analyzers/SecurityAnalyzer.js +729 -0
- package/src/analyzers/SparrowAnalyzer.js +341 -0
- package/src/analyzers/TypeScriptAnalyzer.js +247 -0
- package/src/analyzers/codeCloneDetector/analyzer.js +344 -0
- package/src/analyzers/codeCloneDetector/detector.js +250 -0
- package/src/analyzers/codeCloneDetector/index.js +192 -0
- package/src/analyzers/codeCloneDetector/parser.js +199 -0
- package/src/analyzers/codeCloneDetector/reporter.js +148 -0
- package/src/analyzers/codeCloneDetector/scanner.js +88 -0
- package/src/core/agentPool.js +1957 -0
- package/src/core/agentScheduler.js +3212 -0
- package/src/core/contextManager.js +709 -0
- package/src/core/flowExecutor.js +928 -0
- package/src/core/messageProcessor.js +808 -0
- package/src/core/orchestrator.js +584 -0
- package/src/core/stateManager.js +1500 -0
- package/src/index.js +972 -0
- package/src/interfaces/cli.js +553 -0
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +208 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +236 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +138 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +137 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +350 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +332 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +256 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +388 -0
- package/src/interfaces/terminal/api/apiClient.js +299 -0
- package/src/interfaces/terminal/api/messageRouter.js +262 -0
- package/src/interfaces/terminal/api/session.js +266 -0
- package/src/interfaces/terminal/api/websocket.js +497 -0
- package/src/interfaces/terminal/components/AgentCreator.js +705 -0
- package/src/interfaces/terminal/components/AgentEditor.js +678 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +330 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +92 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +264 -0
- package/src/interfaces/terminal/components/Header.js +28 -0
- package/src/interfaces/terminal/components/HelpPanel.js +231 -0
- package/src/interfaces/terminal/components/InputBox.js +118 -0
- package/src/interfaces/terminal/components/Layout.js +603 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +71 -0
- package/src/interfaces/terminal/components/MessageList.js +281 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +251 -0
- package/src/interfaces/terminal/components/SearchPanel.js +265 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +415 -0
- package/src/interfaces/terminal/components/StatusBar.js +65 -0
- package/src/interfaces/terminal/components/TextInput.js +127 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +227 -0
- package/src/interfaces/terminal/config/constants.js +393 -0
- package/src/interfaces/terminal/index.js +168 -0
- package/src/interfaces/terminal/state/useAgentControl.js +496 -0
- package/src/interfaces/terminal/state/useAgents.js +537 -0
- package/src/interfaces/terminal/state/useConnection.js +444 -0
- package/src/interfaces/terminal/state/useMessages.js +630 -0
- package/src/interfaces/terminal/state/useTools.js +554 -0
- package/src/interfaces/terminal/utils/debugLogger.js +44 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +232 -0
- package/src/interfaces/terminal/utils/theme.js +85 -0
- package/src/interfaces/webServer.js +5457 -0
- package/src/modules/fileExplorer/controller.js +413 -0
- package/src/modules/fileExplorer/index.js +37 -0
- package/src/modules/fileExplorer/middleware.js +92 -0
- package/src/modules/fileExplorer/routes.js +158 -0
- package/src/modules/fileExplorer/types.js +44 -0
- package/src/services/agentActivityService.js +399 -0
- package/src/services/aiService.js +2618 -0
- package/src/services/apiKeyManager.js +334 -0
- package/src/services/benchmarkService.js +196 -0
- package/src/services/budgetService.js +565 -0
- package/src/services/contextInjectionService.js +268 -0
- package/src/services/conversationCompactionService.js +1103 -0
- package/src/services/credentialVault.js +685 -0
- package/src/services/errorHandler.js +810 -0
- package/src/services/fileAttachmentService.js +547 -0
- package/src/services/flowContextService.js +189 -0
- package/src/services/memoryService.js +521 -0
- package/src/services/modelRouterService.js +365 -0
- package/src/services/modelsService.js +323 -0
- package/src/services/ollamaService.js +452 -0
- package/src/services/portRegistry.js +336 -0
- package/src/services/portTracker.js +223 -0
- package/src/services/projectDetector.js +404 -0
- package/src/services/promptService.js +372 -0
- package/src/services/qualityInspector.js +796 -0
- package/src/services/scheduleService.js +725 -0
- package/src/services/serviceRegistry.js +386 -0
- package/src/services/skillsService.js +486 -0
- package/src/services/telegramService.js +920 -0
- package/src/services/tokenCountingService.js +316 -0
- package/src/services/visualEditorBridge.js +1033 -0
- package/src/services/visualEditorServer.js +1727 -0
- package/src/services/whatsappService.js +663 -0
- package/src/tools/__tests__/webTool.e2e.test.js +569 -0
- package/src/tools/__tests__/webTool.unit.test.js +195 -0
- package/src/tools/agentCommunicationTool.js +1343 -0
- package/src/tools/agentDelayTool.js +498 -0
- package/src/tools/asyncToolManager.js +604 -0
- package/src/tools/baseTool.js +887 -0
- package/src/tools/browserTool.js +897 -0
- package/src/tools/cloneDetectionTool.js +581 -0
- package/src/tools/codeMapTool.js +857 -0
- package/src/tools/dependencyResolverTool.js +1212 -0
- package/src/tools/docxTool.js +623 -0
- package/src/tools/excelTool.js +636 -0
- package/src/tools/fileContentReplaceTool.js +840 -0
- package/src/tools/fileTreeTool.js +833 -0
- package/src/tools/filesystemTool.js +1217 -0
- package/src/tools/helpTool.js +198 -0
- package/src/tools/imageTool.js +1034 -0
- package/src/tools/importAnalyzerTool.js +1056 -0
- package/src/tools/jobDoneTool.js +388 -0
- package/src/tools/memoryTool.js +554 -0
- package/src/tools/pdfTool.js +627 -0
- package/src/tools/seekTool.js +883 -0
- package/src/tools/skillsTool.js +276 -0
- package/src/tools/staticAnalysisTool.js +2146 -0
- package/src/tools/taskManagerTool.js +2836 -0
- package/src/tools/terminalTool.js +2486 -0
- package/src/tools/userPromptTool.js +474 -0
- package/src/tools/videoTool.js +1139 -0
- package/src/tools/visionTool.js +507 -0
- package/src/tools/visualEditorTool.js +1175 -0
- package/src/tools/webTool.js +3114 -0
- package/src/tools/whatsappTool.js +457 -0
- package/src/types/agent.js +519 -0
- package/src/types/contextReference.js +972 -0
- package/src/types/conversation.js +730 -0
- package/src/types/toolCommand.js +747 -0
- package/src/utilities/attachmentValidator.js +288 -0
- package/src/utilities/browserStealth.js +630 -0
- package/src/utilities/configManager.js +618 -0
- package/src/utilities/constants.js +870 -0
- package/src/utilities/directoryAccessManager.js +566 -0
- package/src/utilities/fileProcessor.js +307 -0
- package/src/utilities/humanBehavior.js +453 -0
- package/src/utilities/jsonRepair.js +242 -0
- package/src/utilities/logger.js +436 -0
- package/src/utilities/platformUtils.js +255 -0
- package/src/utilities/platformUtils.test.js +98 -0
- package/src/utilities/stealthConstants.js +377 -0
- package/src/utilities/structuredFileValidator.js +699 -0
- package/src/utilities/tagParser.js +878 -0
- package/src/utilities/toolConstants.js +415 -0
- package/src/utilities/userDataDir.js +300 -0
- package/web-ui/build/brands/autopilot/favicon.svg +1 -0
- package/web-ui/build/brands/autopilot/logo.webp +0 -0
- package/web-ui/build/brands/onbuzz/favicon.svg +1 -0
- package/web-ui/build/brands/onbuzz/logo-text.webp +0 -0
- package/web-ui/build/brands/onbuzz/logo.webp +0 -0
- package/web-ui/build/index.html +15 -0
- package/web-ui/build/logo.png +0 -0
- package/web-ui/build/logo2.png +0 -0
- package/web-ui/build/static/index-SmQFfvBs.js +746 -0
- package/web-ui/build/static/index-V2ySwjHp.css +1 -0
|
@@ -0,0 +1,1103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConversationCompactionService - Intelligent conversation compactization
|
|
3
|
+
*
|
|
4
|
+
* Purpose:
|
|
5
|
+
* - Compress long conversations while preserving critical information
|
|
6
|
+
* - AI-based summarization with sandwich approach (beginning + summary + end)
|
|
7
|
+
* - Multi-pass compaction (up to 3 passes) when a single pass isn't enough
|
|
8
|
+
* - Model switching support via best-existing-conversation selection
|
|
9
|
+
* - Compaction model validation against live model catalog
|
|
10
|
+
*
|
|
11
|
+
* Strategy:
|
|
12
|
+
* - Summarization only (sandwich approach):
|
|
13
|
+
* Keep beginning messages + AI summary of middle + end messages
|
|
14
|
+
* Middle segment always >= 50% of total messages
|
|
15
|
+
* Multi-pass: if result is still too large, re-summarize up to MAX_COMPACTION_PASSES times
|
|
16
|
+
*
|
|
17
|
+
* Model Switch Behavior:
|
|
18
|
+
* - Instead of truncation, find the best existing compacted conversation
|
|
19
|
+
* from another model and summarize that for the target model
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
COMPACTION_CONFIG,
|
|
24
|
+
COMPACTION_STRATEGIES,
|
|
25
|
+
} from '../utilities/constants.js';
|
|
26
|
+
|
|
27
|
+
class ConversationCompactionService {
|
|
28
|
+
constructor(tokenCountingService, aiService, logger) {
|
|
29
|
+
this.tokenCountingService = tokenCountingService;
|
|
30
|
+
this.aiService = aiService;
|
|
31
|
+
this.logger = logger;
|
|
32
|
+
|
|
33
|
+
// Models service for runtime validation (injected after construction)
|
|
34
|
+
this.modelsService = null;
|
|
35
|
+
|
|
36
|
+
// Round-robin index for compaction model selection
|
|
37
|
+
this.compactionModelIndex = 0;
|
|
38
|
+
|
|
39
|
+
// Summary generation prompt template
|
|
40
|
+
this.summaryPromptTemplate = this._createSummaryPromptTemplate();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Inject models service for runtime model validation
|
|
45
|
+
* @param {ModelsService} modelsService - Models service instance
|
|
46
|
+
*/
|
|
47
|
+
setModelsService(modelsService) {
|
|
48
|
+
this.modelsService = modelsService;
|
|
49
|
+
this.logger.info('ModelsService injected into compaction service');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Get validated compaction models — filters COMPACTION_MODELS against live catalog
|
|
54
|
+
* @returns {string[]} Array of model names that are both recommended and available
|
|
55
|
+
* @private
|
|
56
|
+
*/
|
|
57
|
+
_getValidatedCompactionModels() {
|
|
58
|
+
const recommendedModels = COMPACTION_CONFIG.COMPACTION_MODELS || [];
|
|
59
|
+
|
|
60
|
+
if (!this.modelsService) {
|
|
61
|
+
this.logger.debug('No modelsService available, using all recommended compaction models');
|
|
62
|
+
return recommendedModels;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const availableNames = this.modelsService.getAvailableModelNames();
|
|
67
|
+
if (!availableNames || availableNames.length === 0) {
|
|
68
|
+
this.logger.warn('ModelsService returned no models, using all recommended compaction models');
|
|
69
|
+
return recommendedModels;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const availableSet = new Set(availableNames);
|
|
73
|
+
const validated = recommendedModels.filter(m => availableSet.has(m));
|
|
74
|
+
|
|
75
|
+
if (validated.length > 0) {
|
|
76
|
+
this.logger.debug('Compaction models validated against live catalog', {
|
|
77
|
+
recommended: recommendedModels.length,
|
|
78
|
+
available: validated.length,
|
|
79
|
+
validated
|
|
80
|
+
});
|
|
81
|
+
return validated;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// No recommended models match — pick the available model with the largest context window
|
|
85
|
+
this.logger.warn('No recommended compaction models found in catalog, selecting largest-context available model');
|
|
86
|
+
const models = this.modelsService.getModels();
|
|
87
|
+
const chatModels = models.filter(m => m.type === 'chat' || !m.type);
|
|
88
|
+
|
|
89
|
+
if (chatModels.length === 0) {
|
|
90
|
+
this.logger.error('No chat models available at all, falling back to recommended list');
|
|
91
|
+
return recommendedModels;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Sort by context window descending
|
|
95
|
+
chatModels.sort((a, b) => (b.contextWindow || 0) - (a.contextWindow || 0));
|
|
96
|
+
const fallbackModel = chatModels[0].name;
|
|
97
|
+
|
|
98
|
+
this.logger.info('Using fallback compaction model from catalog', {
|
|
99
|
+
model: fallbackModel,
|
|
100
|
+
contextWindow: chatModels[0].contextWindow
|
|
101
|
+
});
|
|
102
|
+
return [fallbackModel];
|
|
103
|
+
|
|
104
|
+
} catch (error) {
|
|
105
|
+
this.logger.warn('Failed to validate compaction models against catalog', {
|
|
106
|
+
error: error.message
|
|
107
|
+
});
|
|
108
|
+
return recommendedModels;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get next compaction model using round-robin from validated models
|
|
114
|
+
* @param {string[]} models - Validated model list
|
|
115
|
+
* @param {number} offset - Offset from current index
|
|
116
|
+
* @returns {string} Model name
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
_getNextCompactionModel(models, offset = 0) {
|
|
120
|
+
if (!models || models.length === 0) {
|
|
121
|
+
throw new Error('No compaction models available');
|
|
122
|
+
}
|
|
123
|
+
const index = (this.compactionModelIndex + offset) % models.length;
|
|
124
|
+
return models[index];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Advance the round-robin index
|
|
129
|
+
* @private
|
|
130
|
+
*/
|
|
131
|
+
_advanceCompactionModelIndex() {
|
|
132
|
+
const models = COMPACTION_CONFIG.COMPACTION_MODELS || [];
|
|
133
|
+
if (models.length > 0) {
|
|
134
|
+
this.compactionModelIndex = (this.compactionModelIndex + 1) % models.length;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Main compaction entry point
|
|
140
|
+
* @param {Array} messages - Original messages array
|
|
141
|
+
* @param {string} currentModel - Current model being used
|
|
142
|
+
* @param {string} targetModel - Target model (may differ if switching)
|
|
143
|
+
* @param {Object} options - Compaction options
|
|
144
|
+
* @param {Map} [options.compactedConversations] - Map of modelId → compactedMessages (for model switch)
|
|
145
|
+
* @returns {Promise<Object>} Compaction result with messages and metadata
|
|
146
|
+
*/
|
|
147
|
+
async compactConversation(messages, currentModel, targetModel, options = {}) {
|
|
148
|
+
const startTime = Date.now();
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
// Validate inputs
|
|
152
|
+
if (!Array.isArray(messages) || messages.length === 0) {
|
|
153
|
+
throw new Error('Messages array is required and cannot be empty');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Split oversized messages into smaller chunks before compaction.
|
|
157
|
+
// This increases message count so the sandwich strategy can push
|
|
158
|
+
// oversized content into the summarizable middle segment.
|
|
159
|
+
const splitResult = this._splitOversizedMessages(messages);
|
|
160
|
+
let wasSplit = splitResult.wasSplit;
|
|
161
|
+
|
|
162
|
+
const minMessages = options.emergency ? 4 : COMPACTION_CONFIG.MIN_MESSAGES_FOR_COMPACTION;
|
|
163
|
+
|
|
164
|
+
if (splitResult.messages.length < minMessages) {
|
|
165
|
+
this.logger.warn('Too few messages for compaction', {
|
|
166
|
+
messageCount: splitResult.messages.length,
|
|
167
|
+
originalCount: messages.length,
|
|
168
|
+
minimum: minMessages,
|
|
169
|
+
emergency: !!options.emergency
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
compactedMessages: messages,
|
|
174
|
+
strategy: 'none',
|
|
175
|
+
originalTokenCount: 0,
|
|
176
|
+
compactedTokenCount: 0,
|
|
177
|
+
reductionPercent: 0,
|
|
178
|
+
skipped: true,
|
|
179
|
+
reason: 'Too few messages'
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Determine if model switch and pick best starting conversation
|
|
184
|
+
const isModelSwitch = currentModel !== targetModel;
|
|
185
|
+
let messagesToCompact = splitResult.messages;
|
|
186
|
+
|
|
187
|
+
if (isModelSwitch && options.compactedConversations) {
|
|
188
|
+
const bestConversation = this._findBestConversationForModelSwitch(
|
|
189
|
+
options.compactedConversations,
|
|
190
|
+
targetModel
|
|
191
|
+
);
|
|
192
|
+
if (bestConversation) {
|
|
193
|
+
// Split the best conversation too (it may contain oversized messages)
|
|
194
|
+
const bestSplit = this._splitOversizedMessages(bestConversation);
|
|
195
|
+
messagesToCompact = bestSplit.messages;
|
|
196
|
+
wasSplit = wasSplit || bestSplit.wasSplit;
|
|
197
|
+
this.logger.info('Using best existing conversation for model switch', {
|
|
198
|
+
originalMessages: messages.length,
|
|
199
|
+
bestConversationMessages: bestConversation.length,
|
|
200
|
+
currentModel,
|
|
201
|
+
targetModel
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
this.logger.info('Starting conversation compaction', {
|
|
207
|
+
messageCount: messagesToCompact.length,
|
|
208
|
+
currentModel,
|
|
209
|
+
targetModel,
|
|
210
|
+
strategy: COMPACTION_STRATEGIES.SUMMARIZATION,
|
|
211
|
+
isModelSwitch
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Execute multi-pass summarization
|
|
215
|
+
const result = await this._compactWithMultiPassSummarization(
|
|
216
|
+
messagesToCompact,
|
|
217
|
+
targetModel,
|
|
218
|
+
{ ...options, wasSplit }
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
// Add execution metadata
|
|
222
|
+
const executionTime = Date.now() - startTime;
|
|
223
|
+
result.executionTime = executionTime;
|
|
224
|
+
result.timestamp = new Date().toISOString();
|
|
225
|
+
|
|
226
|
+
this.logger.info('Compaction completed successfully', {
|
|
227
|
+
strategy: result.strategy,
|
|
228
|
+
originalMessages: messagesToCompact.length,
|
|
229
|
+
compactedMessages: result.compactedMessages.length,
|
|
230
|
+
originalTokens: result.originalTokenCount,
|
|
231
|
+
compactedTokens: result.compactedTokenCount,
|
|
232
|
+
reductionPercent: result.reductionPercent.toFixed(2),
|
|
233
|
+
passes: result.passes,
|
|
234
|
+
executionTime: `${executionTime}ms`
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
return result;
|
|
238
|
+
|
|
239
|
+
} catch (error) {
|
|
240
|
+
const executionTime = Date.now() - startTime;
|
|
241
|
+
|
|
242
|
+
this.logger.error('Compaction failed', {
|
|
243
|
+
error: error.message,
|
|
244
|
+
messageCount: messages.length,
|
|
245
|
+
currentModel,
|
|
246
|
+
targetModel,
|
|
247
|
+
executionTime: `${executionTime}ms`
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Find the best existing compacted conversation for model switching.
|
|
256
|
+
* Prefers the conversation from a model whose context window is the largest
|
|
257
|
+
* C where C < targetModel's context window.
|
|
258
|
+
* Falls back to the shortest compacted conversation.
|
|
259
|
+
*
|
|
260
|
+
* @param {Map} compactedConversations - Map of modelId → compactedMessages
|
|
261
|
+
* @param {string} targetModel - Target model name
|
|
262
|
+
* @returns {Array|null} Best conversation messages, or null
|
|
263
|
+
* @private
|
|
264
|
+
*/
|
|
265
|
+
_findBestConversationForModelSwitch(compactedConversations, targetModel) {
|
|
266
|
+
if (!compactedConversations || compactedConversations.size === 0) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const targetContextWindow = this.tokenCountingService.getModelContextWindow(targetModel);
|
|
271
|
+
|
|
272
|
+
// Collect candidates: conversations that have messages
|
|
273
|
+
const candidates = [];
|
|
274
|
+
for (const [modelId, msgs] of compactedConversations) {
|
|
275
|
+
if (Array.isArray(msgs) && msgs.length > 0) {
|
|
276
|
+
const contextWindow = this.tokenCountingService.getModelContextWindow(modelId);
|
|
277
|
+
candidates.push({ modelId, messages: msgs, contextWindow });
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (candidates.length === 0) {
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Prefer: largest context window that is < targetModel's context window
|
|
286
|
+
// (these conversations were already compacted to fit a smaller window, so they'll fit the target)
|
|
287
|
+
const smallerCandidates = candidates
|
|
288
|
+
.filter(c => c.contextWindow < targetContextWindow)
|
|
289
|
+
.sort((a, b) => b.contextWindow - a.contextWindow);
|
|
290
|
+
|
|
291
|
+
if (smallerCandidates.length > 0) {
|
|
292
|
+
const best = smallerCandidates[0];
|
|
293
|
+
this.logger.debug('Best conversation for model switch: largest smaller context', {
|
|
294
|
+
selectedModel: best.modelId,
|
|
295
|
+
selectedContextWindow: best.contextWindow,
|
|
296
|
+
targetContextWindow,
|
|
297
|
+
messageCount: best.messages.length
|
|
298
|
+
});
|
|
299
|
+
return best.messages;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Fallback: shortest conversation (fewest messages)
|
|
303
|
+
candidates.sort((a, b) => a.messages.length - b.messages.length);
|
|
304
|
+
const shortest = candidates[0];
|
|
305
|
+
this.logger.debug('Best conversation for model switch: shortest', {
|
|
306
|
+
selectedModel: shortest.modelId,
|
|
307
|
+
messageCount: shortest.messages.length
|
|
308
|
+
});
|
|
309
|
+
return shortest.messages;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Multi-pass summarization: runs up to MAX_COMPACTION_PASSES passes.
|
|
314
|
+
* After each pass, checks if the result fits within the compaction threshold.
|
|
315
|
+
* If it fits, returns immediately; otherwise re-compacts the compacted result.
|
|
316
|
+
*
|
|
317
|
+
* @param {Array} messages - Messages to compact
|
|
318
|
+
* @param {string} model - Target model name
|
|
319
|
+
* @param {Object} options - Compaction options
|
|
320
|
+
* @returns {Promise<Object>} Compaction result
|
|
321
|
+
* @private
|
|
322
|
+
*/
|
|
323
|
+
async _compactWithMultiPassSummarization(messages, model, options) {
|
|
324
|
+
const maxPasses = COMPACTION_CONFIG.MAX_COMPACTION_PASSES;
|
|
325
|
+
const contextWindow = this.tokenCountingService.getModelContextWindow(model);
|
|
326
|
+
const maxOutputTokens = this.tokenCountingService.getModelMaxOutputTokens(model);
|
|
327
|
+
const threshold = COMPACTION_CONFIG.DEFAULT_THRESHOLD;
|
|
328
|
+
const wasSplit = options.wasSplit || false;
|
|
329
|
+
|
|
330
|
+
let currentMessages = messages;
|
|
331
|
+
let result = null;
|
|
332
|
+
|
|
333
|
+
for (let pass = 1; pass <= maxPasses; pass++) {
|
|
334
|
+
this.logger.info(`Compaction pass ${pass}/${maxPasses}`, {
|
|
335
|
+
inputMessages: currentMessages.length,
|
|
336
|
+
model,
|
|
337
|
+
contextWindow,
|
|
338
|
+
wasSplit
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
result = await this._executeSingleSummarizationPass(currentMessages, model, options, pass);
|
|
342
|
+
|
|
343
|
+
// Check if result fits within threshold
|
|
344
|
+
const compactedTokens = this.tokenCountingService.getConversationTokenCount(
|
|
345
|
+
result.compactedMessages,
|
|
346
|
+
model
|
|
347
|
+
);
|
|
348
|
+
result.compactedTokenCount = compactedTokens;
|
|
349
|
+
|
|
350
|
+
const fitsWithinThreshold = !this.tokenCountingService.shouldTriggerCompaction(
|
|
351
|
+
compactedTokens,
|
|
352
|
+
maxOutputTokens,
|
|
353
|
+
contextWindow,
|
|
354
|
+
threshold
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
this.logger.info(`Compaction pass ${pass} result`, {
|
|
358
|
+
compactedMessages: result.compactedMessages.length,
|
|
359
|
+
compactedTokens,
|
|
360
|
+
fitsWithinThreshold,
|
|
361
|
+
contextWindow,
|
|
362
|
+
threshold
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
if (fitsWithinThreshold) {
|
|
366
|
+
result.passes = pass;
|
|
367
|
+
return result;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// If not the last pass, use compacted result as input for next pass
|
|
371
|
+
// Split any oversized messages that survived compaction
|
|
372
|
+
if (pass < maxPasses) {
|
|
373
|
+
const reSplit = this._splitOversizedMessages(result.compactedMessages);
|
|
374
|
+
currentMessages = reSplit.messages;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Best effort after all passes
|
|
379
|
+
this.logger.warn('Compaction did not fit within threshold after all passes', {
|
|
380
|
+
passes: maxPasses,
|
|
381
|
+
finalTokens: result.compactedTokenCount,
|
|
382
|
+
contextWindow,
|
|
383
|
+
threshold
|
|
384
|
+
});
|
|
385
|
+
result.passes = maxPasses;
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Execute a single summarization pass (sandwich approach).
|
|
391
|
+
* Preserves beginning + AI summary of middle + end.
|
|
392
|
+
*
|
|
393
|
+
* @param {Array} messages - Messages to compact
|
|
394
|
+
* @param {string} model - Target model name
|
|
395
|
+
* @param {Object} options - Compaction options
|
|
396
|
+
* @param {number} passNumber - Current pass number (1-based)
|
|
397
|
+
* @returns {Promise<Object>} Compaction result
|
|
398
|
+
* @private
|
|
399
|
+
*/
|
|
400
|
+
async _executeSingleSummarizationPass(messages, model, options, passNumber) {
|
|
401
|
+
const strategy = COMPACTION_STRATEGIES.SUMMARIZATION;
|
|
402
|
+
|
|
403
|
+
// Estimate original token count
|
|
404
|
+
const originalTokenCount = this.tokenCountingService.getConversationTokenCount(
|
|
405
|
+
messages,
|
|
406
|
+
model
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
// Identify segments (message-count-based)
|
|
410
|
+
// When oversized messages were split, use a small end segment so
|
|
411
|
+
// most chunks land in the middle for summarization
|
|
412
|
+
const segments = this._identifySegments(messages, { wasSplit: options.wasSplit });
|
|
413
|
+
|
|
414
|
+
this.logger.info(`Pass ${passNumber}: segments identified`, {
|
|
415
|
+
summarizedMessages: segments.middle.length,
|
|
416
|
+
keptMessages: segments.end.length,
|
|
417
|
+
totalMessages: messages.length
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Generate summary of middle segment
|
|
421
|
+
let summary;
|
|
422
|
+
try {
|
|
423
|
+
summary = await this._generateSummary(
|
|
424
|
+
segments.middle,
|
|
425
|
+
model,
|
|
426
|
+
{
|
|
427
|
+
...options,
|
|
428
|
+
middleStartIndex: segments.middleStartIndex,
|
|
429
|
+
middleEndIndex: segments.middleEndIndex,
|
|
430
|
+
passNumber
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
if (error.code === 'ALL_MODELS_EXHAUSTED') {
|
|
435
|
+
// All AI models failed — use structural fallback
|
|
436
|
+
this.logger.warn('All summarization models exhausted, using structural fallback compaction');
|
|
437
|
+
const fallbackResult = this._performFallbackCompaction(messages);
|
|
438
|
+
|
|
439
|
+
const compactedTokenCount = this.tokenCountingService.getConversationTokenCount(
|
|
440
|
+
fallbackResult.compactedMessages,
|
|
441
|
+
model
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
const reductionPercent = originalTokenCount > 0
|
|
445
|
+
? ((originalTokenCount - compactedTokenCount) / originalTokenCount) * 100
|
|
446
|
+
: 0;
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
compactedMessages: fallbackResult.compactedMessages,
|
|
450
|
+
strategy: 'structural_fallback',
|
|
451
|
+
originalTokenCount,
|
|
452
|
+
compactedTokenCount,
|
|
453
|
+
reductionPercent,
|
|
454
|
+
segments: {
|
|
455
|
+
beginningCount: segments.beginning.length,
|
|
456
|
+
middleCount: segments.middle.length,
|
|
457
|
+
endCount: segments.end.length,
|
|
458
|
+
summaryInserted: true,
|
|
459
|
+
fallback: true
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
throw error;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Construct compacted conversation
|
|
467
|
+
const compactedMessages = [
|
|
468
|
+
...segments.beginning,
|
|
469
|
+
summary,
|
|
470
|
+
...segments.end
|
|
471
|
+
];
|
|
472
|
+
|
|
473
|
+
// Count tokens in compacted conversation
|
|
474
|
+
const compactedTokenCount = this.tokenCountingService.getConversationTokenCount(
|
|
475
|
+
compactedMessages,
|
|
476
|
+
model
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
// Calculate reduction
|
|
480
|
+
const reductionPercent = originalTokenCount > 0
|
|
481
|
+
? ((originalTokenCount - compactedTokenCount) / originalTokenCount) * 100
|
|
482
|
+
: 0;
|
|
483
|
+
|
|
484
|
+
return {
|
|
485
|
+
compactedMessages,
|
|
486
|
+
strategy,
|
|
487
|
+
originalTokenCount,
|
|
488
|
+
compactedTokenCount,
|
|
489
|
+
reductionPercent,
|
|
490
|
+
segments: {
|
|
491
|
+
beginningCount: segments.beginning.length,
|
|
492
|
+
middleCount: segments.middle.length,
|
|
493
|
+
endCount: segments.end.length,
|
|
494
|
+
summaryInserted: true
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Calculate the maximum characters the summarizer can handle in a single call.
|
|
501
|
+
* Uses the largest available compaction model's context window minus overhead.
|
|
502
|
+
*
|
|
503
|
+
* @returns {number} Maximum characters per summarization call
|
|
504
|
+
* @private
|
|
505
|
+
*/
|
|
506
|
+
_calculateSummarizerCapacity() {
|
|
507
|
+
const models = this._getValidatedCompactionModels();
|
|
508
|
+
const contextWindows = { ...(COMPACTION_CONFIG.MODEL_CONTEXT_WINDOWS || {}) };
|
|
509
|
+
|
|
510
|
+
// Augment with live data from modelsService if available
|
|
511
|
+
if (this.modelsService) {
|
|
512
|
+
try {
|
|
513
|
+
const allModels = this.modelsService.getModels();
|
|
514
|
+
for (const m of allModels) {
|
|
515
|
+
if (m.contextWindow) {
|
|
516
|
+
contextWindows[m.name] = m.contextWindow;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
} catch (e) { /* use static fallback */ }
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const largestContext = Math.max(...models.map(m => contextWindows[m] || 128000));
|
|
523
|
+
|
|
524
|
+
const usableTokens = largestContext
|
|
525
|
+
- (COMPACTION_CONFIG.SUMMARIZER_SYSTEM_PROMPT_OVERHEAD || 500)
|
|
526
|
+
- (COMPACTION_CONFIG.SUMMARIZER_TEMPLATE_OVERHEAD || 800)
|
|
527
|
+
- (COMPACTION_CONFIG.MAX_SUMMARY_TOKENS || 8000)
|
|
528
|
+
- (COMPACTION_CONFIG.SUMMARIZER_SAFETY_MARGIN || 5000);
|
|
529
|
+
|
|
530
|
+
const effectiveTokens = Math.max(10000, usableTokens);
|
|
531
|
+
return effectiveTokens * (COMPACTION_CONFIG.CHARS_PER_TOKEN_ESTIMATE || 3);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Identify conversation segments using token-budget sizing.
|
|
536
|
+
* The middle segment starts at the 15% char mark and extends forward
|
|
537
|
+
* until hitting either the summarizer's capacity or 35% of total chars.
|
|
538
|
+
* This guarantees the middle always fits within the summarizer's context window.
|
|
539
|
+
*
|
|
540
|
+
* @param {Array} messages - Messages array
|
|
541
|
+
* @param {Object} [options] - Segmentation options
|
|
542
|
+
* @param {boolean} [options.wasSplit] - Whether oversized messages were split (unused in new logic)
|
|
543
|
+
* @returns {Object} { beginning, middle, end, middleStartIndex, middleEndIndex }
|
|
544
|
+
* @private
|
|
545
|
+
*/
|
|
546
|
+
_identifySegments(messages, options = {}) {
|
|
547
|
+
const totalMessages = messages.length;
|
|
548
|
+
|
|
549
|
+
// Edge case: very small conversations — summarize all but last message
|
|
550
|
+
if (totalMessages <= 4) {
|
|
551
|
+
return {
|
|
552
|
+
beginning: [],
|
|
553
|
+
middle: messages.slice(0, Math.max(1, totalMessages - 1)),
|
|
554
|
+
end: messages.slice(-1),
|
|
555
|
+
middleStartIndex: 0,
|
|
556
|
+
middleEndIndex: Math.max(0, totalMessages - 2)
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Calculate char length of each message
|
|
561
|
+
const msgChars = messages.map(m => {
|
|
562
|
+
const content = typeof m.content === 'string' ? m.content : JSON.stringify(m.content || '');
|
|
563
|
+
return content.length;
|
|
564
|
+
});
|
|
565
|
+
const totalChars = msgChars.reduce((sum, c) => sum + c, 0);
|
|
566
|
+
|
|
567
|
+
// Get summarizer capacity (max chars it can handle in one call)
|
|
568
|
+
const summarizerCapacity = this._calculateSummarizerCapacity();
|
|
569
|
+
|
|
570
|
+
// Walk BACKWARD from end to determine tail (kept verbatim)
|
|
571
|
+
// Recent messages are more relevant for continuation than old ones
|
|
572
|
+
const tailBudget = totalChars * COMPACTION_CONFIG.TAIL_PRESERVE_PERCENTAGE;
|
|
573
|
+
let tailChars = 0;
|
|
574
|
+
let keepStartIdx = totalMessages;
|
|
575
|
+
for (let i = totalMessages - 1; i >= 0; i--) {
|
|
576
|
+
if (tailChars + msgChars[i] > tailBudget && i < totalMessages - 1) {
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
tailChars += msgChars[i];
|
|
580
|
+
keepStartIdx = i;
|
|
581
|
+
}
|
|
582
|
+
// Ensure at least 1 message in the summarize segment
|
|
583
|
+
keepStartIdx = Math.max(1, keepStartIdx);
|
|
584
|
+
|
|
585
|
+
// Old segment: M[0..keepStartIdx-1] — to be summarized
|
|
586
|
+
// Cap by summarizer capacity (if too large, only summarize what fits this pass)
|
|
587
|
+
let oldChars = 0;
|
|
588
|
+
let summarizeEndIdx = keepStartIdx;
|
|
589
|
+
for (let i = 0; i < keepStartIdx; i++) {
|
|
590
|
+
if (oldChars + msgChars[i] > summarizerCapacity && i > 0) {
|
|
591
|
+
summarizeEndIdx = i;
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
oldChars += msgChars[i];
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const middle = messages.slice(0, summarizeEndIdx); // summarized
|
|
598
|
+
const end = messages.slice(summarizeEndIdx); // kept verbatim
|
|
599
|
+
|
|
600
|
+
this.logger.info('Segment identification (tail-preserving)', {
|
|
601
|
+
totalMessages,
|
|
602
|
+
totalChars,
|
|
603
|
+
summarizerCapacity,
|
|
604
|
+
middleCount: middle.length,
|
|
605
|
+
middleChars: oldChars,
|
|
606
|
+
endCount: end.length,
|
|
607
|
+
tailBudget,
|
|
608
|
+
keepStartIdx,
|
|
609
|
+
summarizeEndIdx
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
return {
|
|
613
|
+
beginning: [],
|
|
614
|
+
middle: middle.length > 0 ? middle : [messages[0]],
|
|
615
|
+
end: end.length > 0 ? end : [messages[messages.length - 1]],
|
|
616
|
+
middleStartIndex: 0,
|
|
617
|
+
middleEndIndex: summarizeEndIdx - 1
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Generate AI summary of middle segment using validated compaction models
|
|
623
|
+
* @private
|
|
624
|
+
*/
|
|
625
|
+
async _generateSummary(middleMessages, model, options = {}) {
|
|
626
|
+
if (middleMessages.length === 0) {
|
|
627
|
+
return {
|
|
628
|
+
role: 'system',
|
|
629
|
+
content: `${COMPACTION_CONFIG.COMPACTION_SUMMARY_PREFIX} No messages to summarize.`,
|
|
630
|
+
type: 'summary',
|
|
631
|
+
timestamp: new Date().toISOString()
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Format middle messages for summarization
|
|
636
|
+
let middleContent = middleMessages
|
|
637
|
+
.map(msg => `${msg.role}: ${typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content)}`)
|
|
638
|
+
.join('\n\n');
|
|
639
|
+
|
|
640
|
+
// Estimate input tokens
|
|
641
|
+
const estimatedInputTokens = Math.ceil(middleContent.length / COMPACTION_CONFIG.CHARS_PER_TOKEN_ESTIMATE);
|
|
642
|
+
|
|
643
|
+
// Get validated compaction models
|
|
644
|
+
const models = this._getValidatedCompactionModels();
|
|
645
|
+
|
|
646
|
+
// Get context windows for smart selection
|
|
647
|
+
const contextWindows = COMPACTION_CONFIG.MODEL_CONTEXT_WINDOWS || {};
|
|
648
|
+
|
|
649
|
+
// If modelsService available, augment context windows with live data
|
|
650
|
+
if (this.modelsService) {
|
|
651
|
+
try {
|
|
652
|
+
const allModels = this.modelsService.getModels();
|
|
653
|
+
for (const m of allModels) {
|
|
654
|
+
if (m.contextWindow) {
|
|
655
|
+
contextWindows[m.name] = m.contextWindow;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
} catch (e) {
|
|
659
|
+
// Ignore — use static fallback
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// Find the largest context window available among compaction models
|
|
664
|
+
const largestContextWindow = Math.max(
|
|
665
|
+
...models.map(m => contextWindows[m] || 128000)
|
|
666
|
+
);
|
|
667
|
+
const maxInputTokens = largestContextWindow - 10000;
|
|
668
|
+
|
|
669
|
+
// Middle is now sized by _identifySegments to fit within the summarizer's capacity.
|
|
670
|
+
// No truncation needed — the segment is guaranteed to be within budget.
|
|
671
|
+
if (estimatedInputTokens > maxInputTokens) {
|
|
672
|
+
this.logger.info('Middle segment exceeds single model but sized to fit summarizer capacity', {
|
|
673
|
+
estimatedInputTokens,
|
|
674
|
+
maxInputTokens,
|
|
675
|
+
largestContextWindow,
|
|
676
|
+
middleChars: middleContent.length
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Build summary prompt
|
|
681
|
+
const summaryPrompt = this.summaryPromptTemplate
|
|
682
|
+
.replace('{middle_segment}', middleContent);
|
|
683
|
+
|
|
684
|
+
// Estimate tokens for model selection
|
|
685
|
+
const finalEstimatedTokens = Math.ceil(middleContent.length / COMPACTION_CONFIG.CHARS_PER_TOKEN_ESTIMATE);
|
|
686
|
+
|
|
687
|
+
// Filter to models with sufficient context
|
|
688
|
+
const requiredContext = finalEstimatedTokens + 10000;
|
|
689
|
+
const capableModels = models.filter(m => {
|
|
690
|
+
const modelContext = contextWindows[m] || 128000;
|
|
691
|
+
return modelContext >= requiredContext;
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
const selectedModels = capableModels.length > 0 ? capableModels : models;
|
|
695
|
+
|
|
696
|
+
this.logger.info('Compaction model selection', {
|
|
697
|
+
finalEstimatedTokens,
|
|
698
|
+
requiredContext,
|
|
699
|
+
validatedModelsCount: models.length,
|
|
700
|
+
capableModelsCount: capableModels.length,
|
|
701
|
+
selectedModels
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
const modelsAttempted = [];
|
|
705
|
+
let lastError = null;
|
|
706
|
+
|
|
707
|
+
for (let attempt = 0; attempt < selectedModels.length; attempt++) {
|
|
708
|
+
const compactionModel = selectedModels[attempt];
|
|
709
|
+
modelsAttempted.push(compactionModel);
|
|
710
|
+
|
|
711
|
+
try {
|
|
712
|
+
this.logger.info('Generating summary', {
|
|
713
|
+
compactionModel,
|
|
714
|
+
attempt: attempt + 1,
|
|
715
|
+
totalModels: selectedModels.length,
|
|
716
|
+
middleMessageCount: middleMessages.length,
|
|
717
|
+
passNumber: options.passNumber || 1
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
// Call AI service (skipCircuitBreaker prevents compaction failures from blocking the agent)
|
|
721
|
+
const response = await this.aiService.sendMessage(
|
|
722
|
+
compactionModel,
|
|
723
|
+
summaryPrompt,
|
|
724
|
+
{
|
|
725
|
+
systemPrompt: 'You are a conversation summarization expert. Your goal is to compress conversations while preserving critical information for continued interaction.',
|
|
726
|
+
maxTokens: COMPACTION_CONFIG.MAX_SUMMARY_TOKENS,
|
|
727
|
+
temperature: 0.3,
|
|
728
|
+
sessionId: options.sessionId,
|
|
729
|
+
platformProvided: true,
|
|
730
|
+
skipCircuitBreaker: true
|
|
731
|
+
}
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
const summaryContent = response.content.trim();
|
|
735
|
+
|
|
736
|
+
// Build index range string
|
|
737
|
+
const indexRange = (options.middleStartIndex !== undefined && options.middleEndIndex !== undefined)
|
|
738
|
+
? `original messages ${options.middleStartIndex}-${options.middleEndIndex}`
|
|
739
|
+
: `${middleMessages.length} messages`;
|
|
740
|
+
|
|
741
|
+
this.logger.info('Summary generated successfully', {
|
|
742
|
+
compactionModel,
|
|
743
|
+
attempt: attempt + 1,
|
|
744
|
+
originalLength: middleContent.length,
|
|
745
|
+
summaryLength: summaryContent.length,
|
|
746
|
+
compressionRatio: (summaryContent.length / middleContent.length * 100).toFixed(2) + '%',
|
|
747
|
+
indexRange,
|
|
748
|
+
passNumber: options.passNumber || 1
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
// Advance round-robin index
|
|
752
|
+
this._advanceCompactionModelIndex();
|
|
753
|
+
|
|
754
|
+
return {
|
|
755
|
+
role: 'system',
|
|
756
|
+
content: `${COMPACTION_CONFIG.COMPACTION_SUMMARY_PREFIX} - ${indexRange}]\n\n${summaryContent}\n\n${COMPACTION_CONFIG.COMPACTION_SUMMARY_SUFFIX}`,
|
|
757
|
+
type: 'summary',
|
|
758
|
+
timestamp: new Date().toISOString(),
|
|
759
|
+
metadata: {
|
|
760
|
+
originalMessageCount: middleMessages.length,
|
|
761
|
+
originalStartIndex: options.middleStartIndex,
|
|
762
|
+
originalEndIndex: options.middleEndIndex,
|
|
763
|
+
compactionModel,
|
|
764
|
+
passNumber: options.passNumber || 1
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
} catch (error) {
|
|
769
|
+
lastError = error;
|
|
770
|
+
const isRateLimit = error.message?.includes('429') || error.message?.includes('rate limit');
|
|
771
|
+
|
|
772
|
+
this.logger.warn('Summary generation failed, trying next model', {
|
|
773
|
+
compactionModel,
|
|
774
|
+
attempt: attempt + 1,
|
|
775
|
+
remainingModels: selectedModels.length - attempt - 1,
|
|
776
|
+
isRateLimit,
|
|
777
|
+
error: error.message
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// All models exhausted
|
|
783
|
+
const errorDetails = {
|
|
784
|
+
modelsAttempted,
|
|
785
|
+
lastError: lastError?.message,
|
|
786
|
+
middleMessageCount: middleMessages.length,
|
|
787
|
+
isRateLimitIssue: lastError?.message?.includes('429') || lastError?.message?.includes('rate limit')
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
this.logger.error('All compaction models exhausted', errorDetails);
|
|
791
|
+
|
|
792
|
+
if (options.onAllModelsExhausted) {
|
|
793
|
+
options.onAllModelsExhausted({
|
|
794
|
+
type: 'compaction_models_exhausted',
|
|
795
|
+
message: `Conversation compaction failed: All ${selectedModels.length} models are currently unavailable. ${errorDetails.isRateLimitIssue ? 'Rate limits may be in effect.' : ''} Using structural fallback compaction.`,
|
|
796
|
+
models: modelsAttempted,
|
|
797
|
+
error: lastError?.message
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
this._advanceCompactionModelIndex();
|
|
802
|
+
|
|
803
|
+
const exhaustedError = new Error('ALL_MODELS_EXHAUSTED');
|
|
804
|
+
exhaustedError.code = 'ALL_MODELS_EXHAUSTED';
|
|
805
|
+
exhaustedError.details = errorDetails;
|
|
806
|
+
throw exhaustedError;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Perform structural fallback compaction when all AI models are unavailable.
|
|
811
|
+
* No AI call required - pure structural transformation:
|
|
812
|
+
* 1. Remove all system messages (except the first/main one)
|
|
813
|
+
* 2. Remove tool results
|
|
814
|
+
* 3. Keep beginning + end of remaining messages
|
|
815
|
+
* 4. Replace middle with a short paragraph
|
|
816
|
+
* @param {Array} allMessages - The full original messages array
|
|
817
|
+
* @returns {Object} { compactedMessages, metadata }
|
|
818
|
+
* @private
|
|
819
|
+
*/
|
|
820
|
+
_performFallbackCompaction(allMessages) {
|
|
821
|
+
// 1. Identify the main system message
|
|
822
|
+
const mainSystemMsg = allMessages.find(m => m.role === 'system' && m.type !== 'summary');
|
|
823
|
+
|
|
824
|
+
// 2. Filter out system messages (except main) and tool results
|
|
825
|
+
const filteredMessages = allMessages.filter(m => {
|
|
826
|
+
if (m === mainSystemMsg) return true;
|
|
827
|
+
if (m.role === 'system') return false;
|
|
828
|
+
if (m.type === 'tool_result' || m.role === 'tool') return false;
|
|
829
|
+
return true;
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
const removedSystemCount = allMessages.filter(m => m.role === 'system' && m !== mainSystemMsg).length;
|
|
833
|
+
const removedToolCount = allMessages.filter(m => m.type === 'tool_result' || m.role === 'tool').length;
|
|
834
|
+
|
|
835
|
+
// 3. Apply sandwich using segment identification
|
|
836
|
+
const segments = this._identifySegments(filteredMessages);
|
|
837
|
+
|
|
838
|
+
// 4. Build replacement paragraph for middle section
|
|
839
|
+
const middleSummary = this._buildFallbackMiddleParagraph(segments.middle, {
|
|
840
|
+
removedSystemCount,
|
|
841
|
+
removedToolCount,
|
|
842
|
+
totalOriginalMessages: allMessages.length
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// 5. Create the summary message
|
|
846
|
+
const summaryMessage = {
|
|
847
|
+
role: 'system',
|
|
848
|
+
content: `${COMPACTION_CONFIG.COMPACTION_SUMMARY_PREFIX} - structural fallback]\n\n${middleSummary}\n\n${COMPACTION_CONFIG.COMPACTION_SUMMARY_SUFFIX}`,
|
|
849
|
+
type: 'summary',
|
|
850
|
+
timestamp: new Date().toISOString(),
|
|
851
|
+
metadata: {
|
|
852
|
+
fallback: true,
|
|
853
|
+
structural: true,
|
|
854
|
+
removedSystemMessages: removedSystemCount,
|
|
855
|
+
removedToolResults: removedToolCount,
|
|
856
|
+
middleMessagesCompacted: segments.middle.length
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
// 6. Reconstruct conversation
|
|
861
|
+
const compactedMessages = [
|
|
862
|
+
...segments.beginning,
|
|
863
|
+
summaryMessage,
|
|
864
|
+
...segments.end
|
|
865
|
+
];
|
|
866
|
+
|
|
867
|
+
this.logger.info('Structural fallback compaction performed', {
|
|
868
|
+
originalMessages: allMessages.length,
|
|
869
|
+
afterFiltering: filteredMessages.length,
|
|
870
|
+
removedSystemMessages: removedSystemCount,
|
|
871
|
+
removedToolResults: removedToolCount,
|
|
872
|
+
beginningKept: segments.beginning.length,
|
|
873
|
+
middleCompacted: segments.middle.length,
|
|
874
|
+
endKept: segments.end.length,
|
|
875
|
+
finalMessages: compactedMessages.length
|
|
876
|
+
});
|
|
877
|
+
|
|
878
|
+
return {
|
|
879
|
+
compactedMessages,
|
|
880
|
+
metadata: {
|
|
881
|
+
strategy: 'structural_fallback',
|
|
882
|
+
removedSystemMessages: removedSystemCount,
|
|
883
|
+
removedToolResults: removedToolCount,
|
|
884
|
+
middleMessagesCompacted: segments.middle.length
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/**
|
|
890
|
+
* Build a short paragraph summarizing the middle section for fallback compaction
|
|
891
|
+
* @private
|
|
892
|
+
*/
|
|
893
|
+
_buildFallbackMiddleParagraph(middleMessages, stats) {
|
|
894
|
+
const userMsgs = middleMessages.filter(m => m.role === 'user');
|
|
895
|
+
const assistantMsgs = middleMessages.filter(m => m.role === 'assistant');
|
|
896
|
+
|
|
897
|
+
// Extract file paths mentioned in messages
|
|
898
|
+
const filePathRegex = /(?:\/[\w.-]+)+\.\w+|(?:[A-Za-z]:)?(?:\\[\w.-]+)+\.\w+|(?:src|lib|test|config|public|dist|build|node_modules)\/[\w./\-]+/g;
|
|
899
|
+
const filePaths = new Set();
|
|
900
|
+
for (const msg of middleMessages) {
|
|
901
|
+
const content = typeof msg.content === 'string' ? msg.content : '';
|
|
902
|
+
const matches = content.match(filePathRegex);
|
|
903
|
+
if (matches) {
|
|
904
|
+
matches.forEach(p => filePaths.add(p));
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
const parts = [];
|
|
909
|
+
parts.push(`[${middleMessages.length} messages compacted (${userMsgs.length} user, ${assistantMsgs.length} assistant).`);
|
|
910
|
+
|
|
911
|
+
if (stats.removedSystemCount > 0 || stats.removedToolCount > 0) {
|
|
912
|
+
parts.push(`Additionally removed: ${stats.removedSystemCount} system messages, ${stats.removedToolCount} tool results.`);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
if (filePaths.size > 0) {
|
|
916
|
+
const fileList = Array.from(filePaths).slice(0, 20).join(', ');
|
|
917
|
+
parts.push(`Files referenced: ${fileList}${filePaths.size > 20 ? ` and ${filePaths.size - 20} more` : ''}.`);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
parts.push('Summary generation was unavailable - content structurally compacted for context management.]');
|
|
921
|
+
|
|
922
|
+
return parts.join(' ');
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* Split oversized messages into smaller chunks for effective compaction.
|
|
927
|
+
* When a single message exceeds OVERSIZED_MESSAGE_THRESHOLD, it gets split
|
|
928
|
+
* into chunks of MAX_CHUNK_SIZE, increasing message count so the sandwich
|
|
929
|
+
* strategy can push the content into the summarizable middle segment.
|
|
930
|
+
*
|
|
931
|
+
* @param {Array} messages - Messages array
|
|
932
|
+
* @returns {Array} Messages with oversized ones split into chunks
|
|
933
|
+
* @private
|
|
934
|
+
*/
|
|
935
|
+
_splitOversizedMessages(messages) {
|
|
936
|
+
const threshold = COMPACTION_CONFIG.OVERSIZED_MESSAGE_THRESHOLD;
|
|
937
|
+
const maxChunk = COMPACTION_CONFIG.MAX_CHUNK_SIZE;
|
|
938
|
+
|
|
939
|
+
let splitCount = 0;
|
|
940
|
+
const result = [];
|
|
941
|
+
|
|
942
|
+
for (const msg of messages) {
|
|
943
|
+
const content = typeof msg.content === 'string' ? msg.content : '';
|
|
944
|
+
|
|
945
|
+
if (content.length <= threshold) {
|
|
946
|
+
result.push(msg);
|
|
947
|
+
continue;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// Split this message
|
|
951
|
+
splitCount++;
|
|
952
|
+
const chunks = this._splitContentIntoChunks(content, maxChunk);
|
|
953
|
+
|
|
954
|
+
this.logger.info('Splitting oversized message for compaction', {
|
|
955
|
+
role: msg.role,
|
|
956
|
+
type: msg.type || 'none',
|
|
957
|
+
originalChars: content.length,
|
|
958
|
+
chunks: chunks.length
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
962
|
+
const chunkMsg = {
|
|
963
|
+
...msg,
|
|
964
|
+
content: `[Part ${i + 1}/${chunks.length}${i === 0 ? ' — oversized message split for compaction' : ' — continued'}]\n${chunks[i]}`,
|
|
965
|
+
_splitMetadata: {
|
|
966
|
+
originalLength: content.length,
|
|
967
|
+
chunkIndex: i,
|
|
968
|
+
totalChunks: chunks.length
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
// Give each chunk a unique ID to avoid conflicts
|
|
972
|
+
if (msg.id) {
|
|
973
|
+
chunkMsg.id = `${msg.id}-chunk-${i + 1}`;
|
|
974
|
+
}
|
|
975
|
+
result.push(chunkMsg);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
if (splitCount > 0) {
|
|
980
|
+
this.logger.info('Oversized message splitting complete', {
|
|
981
|
+
originalCount: messages.length,
|
|
982
|
+
newCount: result.length,
|
|
983
|
+
added: result.length - messages.length,
|
|
984
|
+
messagesSplit: splitCount
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
return { messages: result, wasSplit: splitCount > 0 };
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Split content into chunks, respecting natural boundaries.
|
|
993
|
+
* Priority: double newlines > single newlines > hard cut at maxChunk.
|
|
994
|
+
*
|
|
995
|
+
* @param {string} content - Content to split
|
|
996
|
+
* @param {number} maxChunk - Maximum chunk size in chars
|
|
997
|
+
* @returns {string[]} Array of content chunks
|
|
998
|
+
* @private
|
|
999
|
+
*/
|
|
1000
|
+
_splitContentIntoChunks(content, maxChunk) {
|
|
1001
|
+
if (content.length <= maxChunk) return [content];
|
|
1002
|
+
|
|
1003
|
+
const chunks = [];
|
|
1004
|
+
let remaining = content;
|
|
1005
|
+
|
|
1006
|
+
while (remaining.length > maxChunk) {
|
|
1007
|
+
let splitAt = -1;
|
|
1008
|
+
|
|
1009
|
+
// Try double newline within the chunk range
|
|
1010
|
+
const searchRange = remaining.substring(0, maxChunk);
|
|
1011
|
+
const lastDoubleNL = searchRange.lastIndexOf('\n\n');
|
|
1012
|
+
if (lastDoubleNL > maxChunk * 0.3) {
|
|
1013
|
+
splitAt = lastDoubleNL + 2;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Fallback: single newline
|
|
1017
|
+
if (splitAt === -1) {
|
|
1018
|
+
const lastNL = searchRange.lastIndexOf('\n');
|
|
1019
|
+
if (lastNL > maxChunk * 0.3) {
|
|
1020
|
+
splitAt = lastNL + 1;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Fallback: sentence boundary (". " — common in prose, rare in code)
|
|
1025
|
+
if (splitAt === -1) {
|
|
1026
|
+
const lastSentence = searchRange.lastIndexOf('. ');
|
|
1027
|
+
if (lastSentence > maxChunk * 0.3) {
|
|
1028
|
+
splitAt = lastSentence + 2;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
// Fallback: hard cut (e.g. minified code with no newlines)
|
|
1033
|
+
// TODO: Consider splitting at last space or semicolon before maxChunk
|
|
1034
|
+
// to avoid breaking mid-token/mid-word in minified code
|
|
1035
|
+
if (splitAt === -1) {
|
|
1036
|
+
splitAt = maxChunk;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
chunks.push(remaining.substring(0, splitAt));
|
|
1040
|
+
remaining = remaining.substring(splitAt);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
if (remaining.length > 0) {
|
|
1044
|
+
chunks.push(remaining);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
return chunks;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
/**
|
|
1051
|
+
* Create summary prompt template with preservation guidelines
|
|
1052
|
+
* @private
|
|
1053
|
+
*/
|
|
1054
|
+
_createSummaryPromptTemplate() {
|
|
1055
|
+
return `You are compacting a conversation to preserve critical information while reducing token count.
|
|
1056
|
+
|
|
1057
|
+
CONTEXT: You are summarizing the EARLIEST portion of a conversation. The most recent messages are preserved separately. Your summary should capture what was accomplished, key decisions, and any information still relevant for continuation. Focus on outcomes over process.
|
|
1058
|
+
|
|
1059
|
+
PRESERVATION GUIDELINES:
|
|
1060
|
+
|
|
1061
|
+
HIGH PRIORITY (Always Preserve):
|
|
1062
|
+
- User requests and goals: What the user asked for, their stated preferences, and desired outcomes — these drive all ongoing work
|
|
1063
|
+
- Current task and next steps: What the agent is actively working on and what remains to be done
|
|
1064
|
+
- Recent achievements and current status: What was accomplished, what state the work is in now
|
|
1065
|
+
- Files created or modified successfully: Full file paths that were written, created, or changed
|
|
1066
|
+
- Meaningful tool invocations and their outcomes: Tool calls that produced important results or side effects
|
|
1067
|
+
- Future reference value: Information likely to be referenced again
|
|
1068
|
+
- Decisions and reasoning: WHY things were decided, not just what
|
|
1069
|
+
- API signatures and interfaces: Function definitions, method calls
|
|
1070
|
+
- Active dependencies: Information that ongoing work relies on
|
|
1071
|
+
- Error patterns and solutions: What failed and how it was fixed
|
|
1072
|
+
- Key facts and data: Specific numbers, names, configurations
|
|
1073
|
+
|
|
1074
|
+
MEDIUM PRIORITY (Compress Intelligently):
|
|
1075
|
+
- Code blocks: Keep function signatures + brief description, compress implementation details
|
|
1076
|
+
- Working solutions: Essence and outcome, not every implementation step
|
|
1077
|
+
- Failed attempts: Brief mention of what didn't work and why, skip detailed troubleshooting
|
|
1078
|
+
- Repetitive content: Consolidate similar examples or explanations
|
|
1079
|
+
|
|
1080
|
+
LOW PRIORITY (Heavily Compress/Remove):
|
|
1081
|
+
- Completed calculations: Keep results, skip intermediate steps
|
|
1082
|
+
- Verbose explanations: Summarize well-known concepts
|
|
1083
|
+
- Debug output: Skip terminal logs and error messages that served their purpose
|
|
1084
|
+
- Trial-and-error sequences: Skip multiple failed attempts with no lasting value
|
|
1085
|
+
- Acknowledgments and pleasantries: Skip "thank you", "sure", "okay" type exchanges
|
|
1086
|
+
|
|
1087
|
+
CONVERSATION SEGMENT TO SUMMARIZE:
|
|
1088
|
+
{middle_segment}
|
|
1089
|
+
|
|
1090
|
+
TASK: Create a concise summary that preserves logical flow and critical information. Focus on:
|
|
1091
|
+
1. Key decisions and their reasoning
|
|
1092
|
+
2. Important facts, data, and configurations
|
|
1093
|
+
3. Active context needed for continuation
|
|
1094
|
+
4. Problem-solving outcomes (skip the debugging process)
|
|
1095
|
+
5. Dependencies and interfaces that code/work relies on
|
|
1096
|
+
|
|
1097
|
+
Someone reading this should understand the conversation progression and have all information needed for effective continuation.
|
|
1098
|
+
|
|
1099
|
+
OUTPUT: Provide ONLY the summary text without preamble, explanation, or meta-commentary.`;
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
export default ConversationCompactionService;
|