@renxqoo/renx-code 0.0.8 → 0.0.10
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 +114 -40
- package/bin/renx.cjs +79 -42
- package/bin/renx.exe +0 -0
- package/package.json +10 -28
- package/src/App.tsx +0 -297
- package/src/agent/runtime/event-format.ts +0 -258
- package/src/agent/runtime/model-types.ts +0 -13
- package/src/agent/runtime/runtime.context-usage.test.ts +0 -192
- package/src/agent/runtime/runtime.error-handling.test.ts +0 -235
- package/src/agent/runtime/runtime.simple.test.ts +0 -16
- package/src/agent/runtime/runtime.test.ts +0 -296
- package/src/agent/runtime/runtime.ts +0 -875
- package/src/agent/runtime/runtime.usage-forwarding.test.ts +0 -228
- package/src/agent/runtime/source-modules.test.ts +0 -38
- package/src/agent/runtime/source-modules.ts +0 -370
- package/src/agent/runtime/tool-call-buffer.test.ts +0 -65
- package/src/agent/runtime/tool-call-buffer.ts +0 -60
- package/src/agent/runtime/tool-confirmation.test.ts +0 -56
- package/src/agent/runtime/tool-confirmation.ts +0 -15
- package/src/agent/runtime/types.ts +0 -99
- package/src/commands/slash-commands.test.ts +0 -216
- package/src/commands/slash-commands.ts +0 -64
- package/src/components/chat/assistant-reply.test.tsx +0 -47
- package/src/components/chat/assistant-reply.tsx +0 -136
- package/src/components/chat/assistant-segment.test.ts +0 -99
- package/src/components/chat/assistant-segment.tsx +0 -125
- package/src/components/chat/assistant-tool-group.tsx +0 -900
- package/src/components/chat/code-block.test.tsx +0 -206
- package/src/components/chat/code-block.tsx +0 -313
- package/src/components/chat/prompt-card.tsx +0 -81
- package/src/components/chat/segment-groups.test.ts +0 -52
- package/src/components/chat/segment-groups.ts +0 -106
- package/src/components/chat/turn-item.tsx +0 -39
- package/src/components/conversation-panel.tsx +0 -43
- package/src/components/file-mention-menu.tsx +0 -77
- package/src/components/file-picker-dialog.tsx +0 -206
- package/src/components/footer-hints.tsx +0 -75
- package/src/components/model-picker-dialog.tsx +0 -248
- package/src/components/prompt.tsx +0 -233
- package/src/components/slash-command-menu.tsx +0 -65
- package/src/components/tool-confirm-dialog-content.test.ts +0 -103
- package/src/components/tool-confirm-dialog-content.ts +0 -186
- package/src/components/tool-confirm-dialog.tsx +0 -187
- package/src/components/tool-display-config.ts +0 -119
- package/src/context-usage-regressions.test.ts +0 -26
- package/src/files/attachment-capabilities.test.ts +0 -30
- package/src/files/attachment-capabilities.ts +0 -50
- package/src/files/attachment-content.ts +0 -153
- package/src/files/file-mention-query.test.ts +0 -34
- package/src/files/file-mention-query.ts +0 -32
- package/src/files/prompt-display.ts +0 -13
- package/src/files/types.ts +0 -5
- package/src/files/workspace-files.ts +0 -61
- package/src/hooks/agent-event-handlers.test.ts +0 -207
- package/src/hooks/agent-event-handlers.ts +0 -196
- package/src/hooks/chat-local-replies.fixed.test.ts +0 -119
- package/src/hooks/chat-local-replies.test.ts +0 -153
- package/src/hooks/chat-local-replies.ts +0 -63
- package/src/hooks/turn-updater.test.ts +0 -70
- package/src/hooks/turn-updater.ts +0 -166
- package/src/hooks/use-agent-chat.context.test.ts +0 -10
- package/src/hooks/use-agent-chat.status.test.ts +0 -14
- package/src/hooks/use-agent-chat.test.ts +0 -80
- package/src/hooks/use-agent-chat.ts +0 -621
- package/src/hooks/use-file-mention-menu.ts +0 -196
- package/src/hooks/use-file-picker.ts +0 -185
- package/src/hooks/use-model-picker.ts +0 -196
- package/src/hooks/use-slash-command-menu.ts +0 -154
- package/src/index.tsx +0 -55
- package/src/runtime/clipboard.test.ts +0 -43
- package/src/runtime/clipboard.ts +0 -89
- package/src/runtime/exit.test.ts +0 -177
- package/src/runtime/exit.ts +0 -98
- package/src/runtime/runtime-support.test.ts +0 -31
- package/src/runtime/terminal-theme.test.ts +0 -55
- package/src/runtime/terminal-theme.ts +0 -196
- package/src/types/chat.ts +0 -32
- package/src/types/message-content.ts +0 -48
- package/src/ui/open-code-theme.ts +0 -176
- package/src/ui/opencode-markdown.ts +0 -211
- package/src/ui/theme.simple.test.ts +0 -52
- package/src/ui/theme.test.ts +0 -151
- package/src/ui/theme.ts +0 -152
- package/src/utils/time.test.ts +0 -144
- package/src/utils/time.ts +0 -7
- package/tsconfig.json +0 -30
- package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +0 -95
- package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +0 -1345
- package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +0 -1353
- package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +0 -60
- package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +0 -278
- package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +0 -72
- package/vendor/agent-root/src/agent/__test__/types.test.ts +0 -137
- package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +0 -83
- package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +0 -34
- package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +0 -323
- package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +0 -290
- package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +0 -377
- package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +0 -212
- package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +0 -295
- package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +0 -3607
- package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +0 -35
- package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +0 -517
- package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +0 -97
- package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +0 -479
- package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +0 -80
- package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +0 -76
- package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +0 -173
- package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +0 -109
- package/vendor/agent-root/src/agent/agent/abort-runtime.ts +0 -71
- package/vendor/agent-root/src/agent/agent/callback-safety.ts +0 -33
- package/vendor/agent-root/src/agent/agent/compaction.ts +0 -291
- package/vendor/agent-root/src/agent/agent/concurrency.ts +0 -103
- package/vendor/agent-root/src/agent/agent/error-normalizer.ts +0 -190
- package/vendor/agent-root/src/agent/agent/error.ts +0 -198
- package/vendor/agent-root/src/agent/agent/index.ts +0 -1772
- package/vendor/agent-root/src/agent/agent/logger.ts +0 -65
- package/vendor/agent-root/src/agent/agent/message-utils.ts +0 -101
- package/vendor/agent-root/src/agent/agent/stream-events.ts +0 -61
- package/vendor/agent-root/src/agent/agent/telemetry.ts +0 -123
- package/vendor/agent-root/src/agent/agent/timeout-budget.ts +0 -227
- package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +0 -111
- package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +0 -164
- package/vendor/agent-root/src/agent/agent/write-buffer.ts +0 -188
- package/vendor/agent-root/src/agent/agent/write-file-session.ts +0 -238
- package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +0 -1053
- package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +0 -158
- package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +0 -437
- package/vendor/agent-root/src/agent/app/agent-app-service.ts +0 -748
- package/vendor/agent-root/src/agent/app/contracts.ts +0 -109
- package/vendor/agent-root/src/agent/app/index.ts +0 -5
- package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +0 -151
- package/vendor/agent-root/src/agent/app/ports.ts +0 -72
- package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +0 -1182
- package/vendor/agent-root/src/agent/app/sqlite-client.ts +0 -177
- package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +0 -36
- package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +0 -33
- package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +0 -40
- package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +0 -91
- package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +0 -116
- package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +0 -52
- package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +0 -53
- package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +0 -52
- package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +0 -40
- package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +0 -19
- package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +0 -28
- package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +0 -26
- package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +0 -30
- package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +0 -567
- package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +0 -583
- package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +0 -972
- package/vendor/agent-root/src/agent/error-contract.ts +0 -154
- package/vendor/agent-root/src/agent/prompts/system.ts +0 -246
- package/vendor/agent-root/src/agent/prompts/system1.ts +0 -208
- package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +0 -98
- package/vendor/agent-root/src/agent/storage/file-history-store.ts +0 -313
- package/vendor/agent-root/src/agent/storage/file-storage-config.ts +0 -94
- package/vendor/agent-root/src/agent/storage/file-system.ts +0 -31
- package/vendor/agent-root/src/agent/storage/file-write-service.ts +0 -21
- package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +0 -413
- package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +0 -356
- package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +0 -375
- package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +0 -372
- package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +0 -108
- package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +0 -258
- package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +0 -121
- package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +0 -210
- package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +0 -139
- package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +0 -456
- package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +0 -192
- package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +0 -300
- package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +0 -214
- package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +0 -336
- package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +0 -494
- package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +0 -543
- package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +0 -172
- package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +0 -116
- package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +0 -267
- package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +0 -519
- package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +0 -225
- package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +0 -223
- package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +0 -184
- package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +0 -287
- package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +0 -190
- package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +0 -352
- package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +0 -395
- package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +0 -391
- package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +0 -176
- package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +0 -68
- package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +0 -630
- package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +0 -732
- package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +0 -494
- package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +0 -175
- package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +0 -505
- package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +0 -55
- package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +0 -244
- package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +0 -290
- package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +0 -368
- package/vendor/agent-root/src/agent/tool/base-tool.ts +0 -345
- package/vendor/agent-root/src/agent/tool/bash-policy.ts +0 -636
- package/vendor/agent-root/src/agent/tool/bash.ts +0 -688
- package/vendor/agent-root/src/agent/tool/error.ts +0 -131
- package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +0 -264
- package/vendor/agent-root/src/agent/tool/file-history-list.ts +0 -103
- package/vendor/agent-root/src/agent/tool/file-history-restore.ts +0 -149
- package/vendor/agent-root/src/agent/tool/file-read-tool.ts +0 -211
- package/vendor/agent-root/src/agent/tool/glob.ts +0 -171
- package/vendor/agent-root/src/agent/tool/grep.ts +0 -496
- package/vendor/agent-root/src/agent/tool/lsp.ts +0 -481
- package/vendor/agent-root/src/agent/tool/path-security.ts +0 -117
- package/vendor/agent-root/src/agent/tool/search/common.ts +0 -153
- package/vendor/agent-root/src/agent/tool/skill/index.ts +0 -13
- package/vendor/agent-root/src/agent/tool/skill/loader.ts +0 -229
- package/vendor/agent-root/src/agent/tool/skill/parser.ts +0 -124
- package/vendor/agent-root/src/agent/tool/skill/types.ts +0 -27
- package/vendor/agent-root/src/agent/tool/skill-tool.ts +0 -143
- package/vendor/agent-root/src/agent/tool/task-create.ts +0 -186
- package/vendor/agent-root/src/agent/tool/task-errors.ts +0 -42
- package/vendor/agent-root/src/agent/tool/task-get.ts +0 -116
- package/vendor/agent-root/src/agent/tool/task-graph.ts +0 -78
- package/vendor/agent-root/src/agent/tool/task-list.ts +0 -141
- package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +0 -232
- package/vendor/agent-root/src/agent/tool/task-output.ts +0 -223
- package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +0 -115
- package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +0 -336
- package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +0 -55
- package/vendor/agent-root/src/agent/tool/task-stop.ts +0 -187
- package/vendor/agent-root/src/agent/tool/task-store.ts +0 -217
- package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +0 -149
- package/vendor/agent-root/src/agent/tool/task-types.ts +0 -264
- package/vendor/agent-root/src/agent/tool/task-update.ts +0 -315
- package/vendor/agent-root/src/agent/tool/task.ts +0 -209
- package/vendor/agent-root/src/agent/tool/tool-manager.ts +0 -361
- package/vendor/agent-root/src/agent/tool/tool-prompts.ts +0 -242
- package/vendor/agent-root/src/agent/tool/types.ts +0 -116
- package/vendor/agent-root/src/agent/tool/web-fetch.ts +0 -227
- package/vendor/agent-root/src/agent/tool/web-search.ts +0 -208
- package/vendor/agent-root/src/agent/tool/write-file.ts +0 -497
- package/vendor/agent-root/src/agent/types.ts +0 -232
- package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +0 -18
- package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +0 -610
- package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +0 -223
- package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +0 -42
- package/vendor/agent-root/src/agent/utils/index.ts +0 -16
- package/vendor/agent-root/src/agent/utils/message.ts +0 -171
- package/vendor/agent-root/src/agent/utils/token.ts +0 -28
- package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +0 -238
- package/vendor/agent-root/src/config/__tests__/loader.test.ts +0 -361
- package/vendor/agent-root/src/config/__tests__/runtime.test.ts +0 -88
- package/vendor/agent-root/src/config/index.ts +0 -55
- package/vendor/agent-root/src/config/loader.ts +0 -494
- package/vendor/agent-root/src/config/paths.ts +0 -30
- package/vendor/agent-root/src/config/runtime.ts +0 -163
- package/vendor/agent-root/src/config/types.ts +0 -96
- package/vendor/agent-root/src/logger/index.ts +0 -57
- package/vendor/agent-root/src/logger/logger.ts +0 -819
- package/vendor/agent-root/src/logger/types.ts +0 -150
- package/vendor/agent-root/src/providers/__tests__/errors.test.ts +0 -441
- package/vendor/agent-root/src/providers/__tests__/index.test.ts +0 -16
- package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +0 -318
- package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +0 -600
- package/vendor/agent-root/src/providers/__tests__/registry.test.ts +0 -523
- package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +0 -298
- package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +0 -354
- package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +0 -58
- package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +0 -261
- package/vendor/agent-root/src/providers/adapters/anthropic.ts +0 -572
- package/vendor/agent-root/src/providers/adapters/base.ts +0 -131
- package/vendor/agent-root/src/providers/adapters/kimi.ts +0 -48
- package/vendor/agent-root/src/providers/adapters/responses.ts +0 -732
- package/vendor/agent-root/src/providers/adapters/standard.ts +0 -120
- package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +0 -313
- package/vendor/agent-root/src/providers/http/client.ts +0 -289
- package/vendor/agent-root/src/providers/http/stream-parser.ts +0 -109
- package/vendor/agent-root/src/providers/index.ts +0 -76
- package/vendor/agent-root/src/providers/kimi-headers.ts +0 -177
- package/vendor/agent-root/src/providers/openai-compatible.ts +0 -387
- package/vendor/agent-root/src/providers/registry/model-config.ts +0 -477
- package/vendor/agent-root/src/providers/registry/provider-factory.ts +0 -127
- package/vendor/agent-root/src/providers/registry.ts +0 -135
- package/vendor/agent-root/src/providers/types/api.ts +0 -284
- package/vendor/agent-root/src/providers/types/config.ts +0 -58
- package/vendor/agent-root/src/providers/types/errors.ts +0 -323
- package/vendor/agent-root/src/providers/types/index.ts +0 -72
- package/vendor/agent-root/src/providers/types/provider.ts +0 -45
- package/vendor/agent-root/src/providers/types/registry.ts +0 -68
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
import * as os from 'node:os';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import { promises as fs } from 'node:fs';
|
|
4
|
-
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
-
import {
|
|
6
|
-
abortWriteBufferSession,
|
|
7
|
-
appendContent,
|
|
8
|
-
appendRawArgs,
|
|
9
|
-
cleanupWriteBufferSessionFiles,
|
|
10
|
-
createWriteBufferSession,
|
|
11
|
-
finalizeWriteBufferSession,
|
|
12
|
-
loadWriteBufferSession,
|
|
13
|
-
resolveBufferId,
|
|
14
|
-
} from '../write-buffer';
|
|
15
|
-
import { createConfiguredFileHistoryStore } from '../../storage/file-history-store';
|
|
16
|
-
|
|
17
|
-
const tempDirs: string[] = [];
|
|
18
|
-
|
|
19
|
-
async function createTempDir(): Promise<string> {
|
|
20
|
-
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'renx-write-buffer-'));
|
|
21
|
-
tempDirs.push(dir);
|
|
22
|
-
return dir;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
afterEach(async () => {
|
|
26
|
-
await Promise.all(tempDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })));
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
describe('write-buffer', () => {
|
|
30
|
-
it('uses toolCallId as bufferId when provided', async () => {
|
|
31
|
-
const baseDir = await createTempDir();
|
|
32
|
-
const session = await createWriteBufferSession({
|
|
33
|
-
messageId: 'msg_1',
|
|
34
|
-
toolCallId: 'tool_call_1',
|
|
35
|
-
baseDir,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
expect(session.bufferId).toBe('tool_call_1');
|
|
39
|
-
expect(session.status).toBe('active');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('creates generated bufferId when toolCallId is missing', async () => {
|
|
43
|
-
const generated = resolveBufferId(undefined);
|
|
44
|
-
expect(generated.startsWith('buffer_')).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('appends raw args and content with byte counters', async () => {
|
|
48
|
-
const baseDir = await createTempDir();
|
|
49
|
-
const session = await createWriteBufferSession({
|
|
50
|
-
messageId: 'msg_append',
|
|
51
|
-
toolCallId: 'tool_append',
|
|
52
|
-
baseDir,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const raw = await appendRawArgs(session, '{"path":"a.txt"');
|
|
56
|
-
const content = await appendContent(session, 'hello');
|
|
57
|
-
|
|
58
|
-
expect(raw.bytesWritten).toBeGreaterThan(0);
|
|
59
|
-
expect(raw.totalBytes).toBe(raw.bytesWritten);
|
|
60
|
-
expect(content.bytesWritten).toBe(5);
|
|
61
|
-
expect(content.totalBytes).toBe(5);
|
|
62
|
-
|
|
63
|
-
const loaded = await loadWriteBufferSession(session.metaPath);
|
|
64
|
-
expect(loaded.rawArgsBytes).toBe(raw.totalBytes);
|
|
65
|
-
expect(loaded.contentBytes).toBe(content.totalBytes);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('finalizes buffered content to target path', async () => {
|
|
69
|
-
const baseDir = await createTempDir();
|
|
70
|
-
const outputDir = await createTempDir();
|
|
71
|
-
const targetPath = path.join(outputDir, 'out.txt');
|
|
72
|
-
|
|
73
|
-
const session = await createWriteBufferSession({
|
|
74
|
-
messageId: 'msg_final',
|
|
75
|
-
toolCallId: 'tool_final',
|
|
76
|
-
targetPath,
|
|
77
|
-
baseDir,
|
|
78
|
-
});
|
|
79
|
-
await appendContent(session, 'part1');
|
|
80
|
-
await appendContent(session, 'part2');
|
|
81
|
-
|
|
82
|
-
const finalized = await finalizeWriteBufferSession(session);
|
|
83
|
-
const content = await fs.readFile(targetPath, 'utf8');
|
|
84
|
-
|
|
85
|
-
expect(content).toBe('part1part2');
|
|
86
|
-
expect(finalized.status).toBe('finalized');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('uses the env-configured write buffer directory by default', async () => {
|
|
90
|
-
const renxHome = await createTempDir();
|
|
91
|
-
const previousRenxHome = process.env.RENX_HOME;
|
|
92
|
-
|
|
93
|
-
process.env.RENX_HOME = renxHome;
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const session = await createWriteBufferSession({
|
|
97
|
-
messageId: 'msg_env_default',
|
|
98
|
-
toolCallId: 'tool_env_default',
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
expect(session.baseDir).toBe(path.join(renxHome, 'storage', 'cache', 'write-buffer'));
|
|
102
|
-
} finally {
|
|
103
|
-
if (previousRenxHome === undefined) {
|
|
104
|
-
delete process.env.RENX_HOME;
|
|
105
|
-
} else {
|
|
106
|
-
process.env.RENX_HOME = previousRenxHome;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('stores a historical snapshot before finalize overwrites an existing file', async () => {
|
|
112
|
-
const renxHome = await createTempDir();
|
|
113
|
-
const outputDir = await createTempDir();
|
|
114
|
-
const targetPath = path.join(outputDir, 'history.txt');
|
|
115
|
-
const previousRenxHome = process.env.RENX_HOME;
|
|
116
|
-
const previousHistoryEnabled = process.env.AGENT_FILE_HISTORY_ENABLED;
|
|
117
|
-
|
|
118
|
-
process.env.RENX_HOME = renxHome;
|
|
119
|
-
process.env.AGENT_FILE_HISTORY_ENABLED = 'true';
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
await fs.writeFile(targetPath, 'old-version', 'utf8');
|
|
123
|
-
const session = await createWriteBufferSession({
|
|
124
|
-
messageId: 'msg_history',
|
|
125
|
-
toolCallId: 'tool_history',
|
|
126
|
-
targetPath,
|
|
127
|
-
baseDir: path.join(renxHome, 'storage', 'cache'),
|
|
128
|
-
});
|
|
129
|
-
await appendContent(session, 'new-version');
|
|
130
|
-
|
|
131
|
-
await finalizeWriteBufferSession(session);
|
|
132
|
-
|
|
133
|
-
const store = createConfiguredFileHistoryStore();
|
|
134
|
-
const versions = await store.listVersions(targetPath);
|
|
135
|
-
|
|
136
|
-
expect(await fs.readFile(targetPath, 'utf8')).toBe('new-version');
|
|
137
|
-
expect(versions).toHaveLength(1);
|
|
138
|
-
|
|
139
|
-
const restored = await store.restoreVersion(targetPath, versions[0].versionId);
|
|
140
|
-
expect(restored).toBe(true);
|
|
141
|
-
expect(await fs.readFile(targetPath, 'utf8')).toBe('old-version');
|
|
142
|
-
} finally {
|
|
143
|
-
if (previousRenxHome === undefined) {
|
|
144
|
-
delete process.env.RENX_HOME;
|
|
145
|
-
} else {
|
|
146
|
-
process.env.RENX_HOME = previousRenxHome;
|
|
147
|
-
}
|
|
148
|
-
if (previousHistoryEnabled === undefined) {
|
|
149
|
-
delete process.env.AGENT_FILE_HISTORY_ENABLED;
|
|
150
|
-
} else {
|
|
151
|
-
process.env.AGENT_FILE_HISTORY_ENABLED = previousHistoryEnabled;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('marks session aborted and supports cleanup', async () => {
|
|
157
|
-
const baseDir = await createTempDir();
|
|
158
|
-
const session = await createWriteBufferSession({
|
|
159
|
-
messageId: 'msg_abort',
|
|
160
|
-
toolCallId: 'tool_abort',
|
|
161
|
-
baseDir,
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
await abortWriteBufferSession(session);
|
|
165
|
-
const aborted = await loadWriteBufferSession(session.metaPath);
|
|
166
|
-
expect(aborted.status).toBe('aborted');
|
|
167
|
-
|
|
168
|
-
await cleanupWriteBufferSessionFiles(session);
|
|
169
|
-
await expect(fs.stat(session.rawArgsPath)).rejects.toThrow();
|
|
170
|
-
await expect(fs.stat(session.contentPath)).rejects.toThrow();
|
|
171
|
-
await expect(fs.stat(session.metaPath)).rejects.toThrow();
|
|
172
|
-
});
|
|
173
|
-
});
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { ToolCall } from '../../../providers';
|
|
3
|
-
import {
|
|
4
|
-
bufferWriteFileToolCallChunk,
|
|
5
|
-
buildWriteFileSessionKey,
|
|
6
|
-
cleanupWriteFileBufferIfNeeded,
|
|
7
|
-
enrichWriteFileToolError,
|
|
8
|
-
type WriteBufferRuntime,
|
|
9
|
-
} from '../write-file-session';
|
|
10
|
-
|
|
11
|
-
function createWriteFileToolCall(id: string, content: string): ToolCall {
|
|
12
|
-
return {
|
|
13
|
-
id,
|
|
14
|
-
type: 'function',
|
|
15
|
-
index: 0,
|
|
16
|
-
function: {
|
|
17
|
-
name: 'write_file',
|
|
18
|
-
arguments: JSON.stringify({
|
|
19
|
-
path: 'a.txt',
|
|
20
|
-
content,
|
|
21
|
-
}),
|
|
22
|
-
},
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
describe('write-file-session', () => {
|
|
27
|
-
it('buildWriteFileSessionKey isolates by execution and step', () => {
|
|
28
|
-
const keyA = buildWriteFileSessionKey({
|
|
29
|
-
executionId: 'exec_a',
|
|
30
|
-
stepIndex: 1,
|
|
31
|
-
toolCallId: 'tool_1',
|
|
32
|
-
});
|
|
33
|
-
const keyB = buildWriteFileSessionKey({
|
|
34
|
-
executionId: 'exec_b',
|
|
35
|
-
stepIndex: 1,
|
|
36
|
-
toolCallId: 'tool_1',
|
|
37
|
-
});
|
|
38
|
-
const keyC = buildWriteFileSessionKey({
|
|
39
|
-
executionId: 'exec_a',
|
|
40
|
-
stepIndex: 2,
|
|
41
|
-
toolCallId: 'tool_1',
|
|
42
|
-
});
|
|
43
|
-
expect(keyA).not.toBe(keyB);
|
|
44
|
-
expect(keyA).not.toBe(keyC);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('keeps write buffer runtimes isolated for same toolCallId under different session keys', async () => {
|
|
48
|
-
const toolCall = createWriteFileToolCall('wf_same_id', 'partial-content');
|
|
49
|
-
const sessions = new Map<string, WriteBufferRuntime>();
|
|
50
|
-
const sessionKeyA = buildWriteFileSessionKey({
|
|
51
|
-
executionId: 'exec_A',
|
|
52
|
-
stepIndex: 1,
|
|
53
|
-
toolCallId: toolCall.id,
|
|
54
|
-
});
|
|
55
|
-
const sessionKeyB = buildWriteFileSessionKey({
|
|
56
|
-
executionId: 'exec_B',
|
|
57
|
-
stepIndex: 1,
|
|
58
|
-
toolCallId: toolCall.id,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
await bufferWriteFileToolCallChunk({
|
|
63
|
-
toolCall,
|
|
64
|
-
argumentsChunk: '{"path":"a.txt","content":"partial-content"}',
|
|
65
|
-
messageId: 'msg_A',
|
|
66
|
-
sessionKey: sessionKeyA,
|
|
67
|
-
sessions,
|
|
68
|
-
});
|
|
69
|
-
await bufferWriteFileToolCallChunk({
|
|
70
|
-
toolCall,
|
|
71
|
-
argumentsChunk: '{"path":"a.txt","content":"partial-content"}',
|
|
72
|
-
messageId: 'msg_B',
|
|
73
|
-
sessionKey: sessionKeyB,
|
|
74
|
-
sessions,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(sessions.size).toBe(2);
|
|
78
|
-
const sessionA = sessions.get(sessionKeyA);
|
|
79
|
-
const sessionB = sessions.get(sessionKeyB);
|
|
80
|
-
expect(sessionA).toBeDefined();
|
|
81
|
-
expect(sessionB).toBeDefined();
|
|
82
|
-
expect(sessionA?.session.metaPath).not.toBe(sessionB?.session.metaPath);
|
|
83
|
-
|
|
84
|
-
await cleanupWriteFileBufferIfNeeded(toolCall, sessions, sessionKeyA);
|
|
85
|
-
expect(sessions.size).toBe(1);
|
|
86
|
-
|
|
87
|
-
const payloadText = await enrichWriteFileToolError(
|
|
88
|
-
toolCall,
|
|
89
|
-
'invalid args',
|
|
90
|
-
sessions,
|
|
91
|
-
sessionKeyB
|
|
92
|
-
);
|
|
93
|
-
const payload = JSON.parse(payloadText) as {
|
|
94
|
-
code: string;
|
|
95
|
-
buffer?: { bufferedBytes: number };
|
|
96
|
-
};
|
|
97
|
-
expect(payload.code).toBe('WRITE_FILE_PARTIAL_BUFFERED');
|
|
98
|
-
expect(payload.buffer?.bufferedBytes).toBeGreaterThan(0);
|
|
99
|
-
|
|
100
|
-
await cleanupWriteFileBufferIfNeeded(toolCall, sessions, sessionKeyB);
|
|
101
|
-
expect(sessions.size).toBe(0);
|
|
102
|
-
} finally {
|
|
103
|
-
const remaining = [...sessions.entries()];
|
|
104
|
-
for (const [key] of remaining) {
|
|
105
|
-
await cleanupWriteFileBufferIfNeeded(toolCall, sessions, key);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { TimeoutBudgetExceededError } from './error';
|
|
2
|
-
import { timeoutBudgetReasonFromSignal } from './timeout-budget';
|
|
3
|
-
|
|
4
|
-
export function timeoutBudgetErrorFromSignal(
|
|
5
|
-
signal: AbortSignal | undefined
|
|
6
|
-
): TimeoutBudgetExceededError | undefined {
|
|
7
|
-
const reason = timeoutBudgetReasonFromSignal(signal);
|
|
8
|
-
if (!reason) {
|
|
9
|
-
return undefined;
|
|
10
|
-
}
|
|
11
|
-
return new TimeoutBudgetExceededError(reason.message);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function normalizeTimeoutBudgetError(
|
|
15
|
-
error: unknown,
|
|
16
|
-
signal: AbortSignal | undefined
|
|
17
|
-
): TimeoutBudgetExceededError | undefined {
|
|
18
|
-
if (error instanceof TimeoutBudgetExceededError) {
|
|
19
|
-
return error;
|
|
20
|
-
}
|
|
21
|
-
return timeoutBudgetErrorFromSignal(signal);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function throwIfAborted(signal: AbortSignal | undefined, abortedMessage: string): void {
|
|
25
|
-
if (!signal?.aborted) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const timeoutError = timeoutBudgetErrorFromSignal(signal);
|
|
29
|
-
if (timeoutError) {
|
|
30
|
-
throw timeoutError;
|
|
31
|
-
}
|
|
32
|
-
const error = new Error(abortedMessage);
|
|
33
|
-
error.name = 'AbortError';
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function sleepWithAbort(
|
|
38
|
-
ms: number,
|
|
39
|
-
signal?: AbortSignal,
|
|
40
|
-
abortedMessage = 'Operation aborted'
|
|
41
|
-
): Promise<void> {
|
|
42
|
-
if (ms <= 0) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
await new Promise<void>((resolve, reject) => {
|
|
46
|
-
const onAbort = () => {
|
|
47
|
-
cleanup();
|
|
48
|
-
clearTimeout(timer);
|
|
49
|
-
const err = new Error(abortedMessage);
|
|
50
|
-
err.name = 'AbortError';
|
|
51
|
-
reject(err);
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const cleanup = () => {
|
|
55
|
-
signal?.removeEventListener('abort', onAbort);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const timer = setTimeout(() => {
|
|
59
|
-
cleanup();
|
|
60
|
-
resolve();
|
|
61
|
-
}, ms);
|
|
62
|
-
|
|
63
|
-
if (signal) {
|
|
64
|
-
if (signal.aborted) {
|
|
65
|
-
onAbort();
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
signal.addEventListener('abort', onAbort, { once: true });
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { ErrorDecision } from '../types';
|
|
2
|
-
|
|
3
|
-
export async function safeCallback<T>(
|
|
4
|
-
callback: ((arg: T) => void | Promise<void>) | undefined,
|
|
5
|
-
arg: T,
|
|
6
|
-
onError?: (error: unknown) => void
|
|
7
|
-
): Promise<void> {
|
|
8
|
-
if (!callback) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
try {
|
|
12
|
-
await callback(arg);
|
|
13
|
-
} catch (error) {
|
|
14
|
-
onError?.(error);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export async function safeErrorCallback(
|
|
19
|
-
callback: ((error: Error) => ErrorDecision | void | Promise<ErrorDecision | void>) | undefined,
|
|
20
|
-
error: Error,
|
|
21
|
-
onError?: (error: unknown) => void
|
|
22
|
-
): Promise<ErrorDecision | undefined> {
|
|
23
|
-
if (!callback) {
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
try {
|
|
27
|
-
const result = await callback(error);
|
|
28
|
-
return result as ErrorDecision | undefined;
|
|
29
|
-
} catch (err) {
|
|
30
|
-
onError?.(err);
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 涓婁笅鏂囧帇缂╂ā鍧? *
|
|
3
|
-
* 浣跨敤 LLM 鐢熸垚鎽樿鏉ュ帇缂╁璇濆巻鍙诧紝鍑忓皯 token 娑堣€? */
|
|
4
|
-
|
|
5
|
-
import { getEncoding } from 'js-tiktoken';
|
|
6
|
-
import type { LLMProvider, LLMResponse } from '../../providers';
|
|
7
|
-
import type { Message } from '../types';
|
|
8
|
-
import type { AgentLogger } from './logger';
|
|
9
|
-
import {
|
|
10
|
-
contentToText,
|
|
11
|
-
splitMessages,
|
|
12
|
-
processToolCallPairs,
|
|
13
|
-
rebuildMessages,
|
|
14
|
-
} from '../utils/message';
|
|
15
|
-
import { LLMTool } from '../tool/types';
|
|
16
|
-
|
|
17
|
-
// =============================================================================
|
|
18
|
-
// 绫诲瀷瀹氫箟
|
|
19
|
-
// =============================================================================
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 鍘嬬缉閫夐」
|
|
23
|
-
*/
|
|
24
|
-
export interface CompactOptions {
|
|
25
|
-
/** LLM Provider锛堢敤浜庣敓鎴愭憳瑕侊級 */
|
|
26
|
-
provider: LLMProvider;
|
|
27
|
-
/** 淇濈暀鏈€杩戞秷鎭暟 */
|
|
28
|
-
keepMessagesNum: number;
|
|
29
|
-
/** 鏃ュ織鍣紙鍙€夛級 */
|
|
30
|
-
logger?: AgentLogger;
|
|
31
|
-
/** 鎽樿璇█锛堥粯璁?'English'锛?*/
|
|
32
|
-
language?: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 鍘嬬缉缁撴灉
|
|
37
|
-
*/
|
|
38
|
-
export interface CompactResult {
|
|
39
|
-
/** 鍘嬬缉鍚庣殑娑堟伅鍒楄〃 */
|
|
40
|
-
messages: Message[];
|
|
41
|
-
/** 鎽樿娑堟伅 */
|
|
42
|
-
summaryMessage: Message | null;
|
|
43
|
-
/** 琚涪寮冪殑娑堟伅 ID 鍒楄〃 */
|
|
44
|
-
removedMessageIds: string[];
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// =============================================================================
|
|
48
|
-
// Token 浼扮畻宸ュ叿鍑芥暟
|
|
49
|
-
// =============================================================================
|
|
50
|
-
|
|
51
|
-
// 浣跨敤 cl100k_base 缂栫爜锛圙PT-3.5/GPT-4 浣跨敤鐨勭紪鐮侊級
|
|
52
|
-
const encoder = getEncoding('cl100k_base');
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* 浼扮畻鏂囨湰 Token 鏁帮紙浣跨敤 js-tiktoken 绮剧‘璁$畻锛? *
|
|
56
|
-
* 浣跨敤 OpenAI 鐨?cl100k_base 缂栫爜杩涜绮剧‘ Token 璁$畻銆? * 鐩告瘮鍚彂寮忕畻娉曪紝杩欒兘鎻愪緵鍑嗙‘鐨?Token 璁℃暟锛岄伩鍏嶄笂涓嬫枃婧㈠嚭銆? *
|
|
57
|
-
* @param text 瑕佷及绠楃殑鏂囨湰
|
|
58
|
-
* @returns 瀹為檯 token 鏁? */
|
|
59
|
-
export function estimateTokens(text: string): number {
|
|
60
|
-
if (!text) return 0;
|
|
61
|
-
try {
|
|
62
|
-
return encoder.encode(text).length;
|
|
63
|
-
} catch (error) {
|
|
64
|
-
// 闄嶇骇绛栫暐锛氬鏋滅紪鐮佸け璐ワ紝浣跨敤淇濆畧鐨勫惎鍙戝紡浼扮畻
|
|
65
|
-
// 姹夊瓧 x2锛屽叾浠?x1.3
|
|
66
|
-
console.warn('[TokenEstimation] Failed to encode text, using heuristic fallback', error);
|
|
67
|
-
const chineseMatch = text.match(/[\u4e00-\u9fa5]/g);
|
|
68
|
-
const chineseCount = chineseMatch ? chineseMatch.length : 0;
|
|
69
|
-
const otherCount = text.length - chineseCount;
|
|
70
|
-
return Math.ceil(chineseCount * 2 + otherCount * 0.4);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* 浼扮畻娑堟伅鍒楄〃鐨?Token 鏁? *
|
|
76
|
-
* 閬靛惊 OpenAI 鑱婂ぉ鏍煎紡鐨勮璐硅鍒欙細
|
|
77
|
-
* - 姣忔潯娑堟伅鏈?3 tokens 鐨勫浐瀹氬紑閿€ (<|start|>{role}<|end|>)
|
|
78
|
-
* - name 瀛楁棰濆 1 token
|
|
79
|
-
* - role 鍜?content 璁″叆 token
|
|
80
|
-
* - 鍥炲寮曞璇?3 tokens
|
|
81
|
-
*/
|
|
82
|
-
export function estimateMessagesTokens(messages: Message[], tools?: LLMTool[]): number {
|
|
83
|
-
let total = 0;
|
|
84
|
-
|
|
85
|
-
for (const m of messages) {
|
|
86
|
-
// Per-message protocol overhead.
|
|
87
|
-
total += 3;
|
|
88
|
-
|
|
89
|
-
if (m.role) {
|
|
90
|
-
total += estimateTokens(m.role);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const name = (m as unknown as Record<string, unknown>).name as string | undefined;
|
|
94
|
-
if (name) {
|
|
95
|
-
// Name field has an additional overhead token.
|
|
96
|
-
total += estimateTokens(name) + 1;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (typeof m.content === 'string') {
|
|
100
|
-
total += estimateTokens(m.content);
|
|
101
|
-
} else if (Array.isArray(m.content)) {
|
|
102
|
-
for (const part of m.content) {
|
|
103
|
-
if (part.type === 'text' && part.text) {
|
|
104
|
-
total += estimateTokens(part.text);
|
|
105
|
-
continue;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (part.type === 'image_url') {
|
|
109
|
-
const detail = part.image_url.detail || 'auto';
|
|
110
|
-
if (detail === 'low') {
|
|
111
|
-
total += 85;
|
|
112
|
-
} else {
|
|
113
|
-
// Conservative estimate for high/auto detail images.
|
|
114
|
-
total += 765;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const toolCalls = m.tool_calls as unknown[];
|
|
121
|
-
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
122
|
-
total += estimateTokens(JSON.stringify(toolCalls));
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const toolCallId = m.tool_call_id as string | undefined;
|
|
126
|
-
if (toolCallId) {
|
|
127
|
-
total += estimateTokens(toolCallId);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (tools && tools.length > 0) {
|
|
132
|
-
total += estimateTokens(JSON.stringify(tools));
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Assistant priming tokens.
|
|
136
|
-
total += 3;
|
|
137
|
-
return total;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export type CompactionLogger = AgentLogger;
|
|
141
|
-
|
|
142
|
-
// =============================================================================
|
|
143
|
-
// 鍐呴儴杈呭姪鍑芥暟
|
|
144
|
-
// =============================================================================
|
|
145
|
-
|
|
146
|
-
function isSummaryMessage(message: Message): boolean {
|
|
147
|
-
const text = contentToText(message.content);
|
|
148
|
-
return text.startsWith('[Conversation Summary]') || text.startsWith('[瀵硅瘽鎽樿]');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function buildSummaryPrompt(): string {
|
|
152
|
-
return `You are an expert AI conversation compressor. Compress the conversation history into a structured memory summary with the following sections: 1. Primary Request and Intent 2. Key Technical Concepts 3. Files and Code Sections (preserve exact file paths) 4. Errors and Fixes (include exact error messages) 5. Problem Solving Process 6. Important User Instructions and Constraints 7. Pending Tasks 8. Current Work State Requirements: - Preserve critical technical details - Keep exact file paths and commands - Remove redundant or conversational text - Maintain task continuity for future steps - Keep the summary concise but information-dense`;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// =============================================================================
|
|
156
|
-
// 鏍稿績鍘嬬缉鍑芥暟
|
|
157
|
-
// =============================================================================
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* 鍘嬬缉瀵硅瘽鍘嗗彶
|
|
161
|
-
*
|
|
162
|
-
* @param messages 鍘熷娑堟伅鍒楄〃
|
|
163
|
-
* @param options 鍘嬬缉閫夐」
|
|
164
|
-
* @returns 鍘嬬缉缁撴灉
|
|
165
|
-
*/
|
|
166
|
-
export async function compact(
|
|
167
|
-
messages: Message[],
|
|
168
|
-
options: CompactOptions
|
|
169
|
-
): Promise<CompactResult> {
|
|
170
|
-
const { provider, keepMessagesNum, logger } = options;
|
|
171
|
-
// 鍒嗙娑堟伅鍖哄煙
|
|
172
|
-
const { systemMessage, pending, active } = splitMessages(messages, keepMessagesNum);
|
|
173
|
-
// 澶勭悊宸ュ叿璋冪敤閰嶅
|
|
174
|
-
const { pending: finalPending, active: finalActive } = processToolCallPairs(pending, active);
|
|
175
|
-
// 鏀堕泦琚涪寮冪殑娑堟伅 ID
|
|
176
|
-
const removedMessageIds = collectRemovedMessageIds(messages, new Set(finalActive), systemMessage);
|
|
177
|
-
// 鐢熸垚鎽樿
|
|
178
|
-
const summaryContent = await generateSummary({
|
|
179
|
-
provider,
|
|
180
|
-
pendingMessages: finalPending,
|
|
181
|
-
sourceMessages: messages,
|
|
182
|
-
logger,
|
|
183
|
-
});
|
|
184
|
-
const summaryMessage = summaryContent
|
|
185
|
-
? {
|
|
186
|
-
messageId: crypto.randomUUID(),
|
|
187
|
-
role: 'assistant' as const,
|
|
188
|
-
type: 'summary' as const,
|
|
189
|
-
content: `[Conversation Summary]\n${summaryContent}`,
|
|
190
|
-
timestamp: Date.now(),
|
|
191
|
-
}
|
|
192
|
-
: null;
|
|
193
|
-
// 閲嶇粍娑堟伅
|
|
194
|
-
const newMessages = rebuildMessages(systemMessage, summaryMessage, finalActive);
|
|
195
|
-
logger?.info?.(`[Compaction] Completed. messages=${messages.length}->${newMessages.length}`);
|
|
196
|
-
return { messages: newMessages, summaryMessage, removedMessageIds };
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* 鏀堕泦琚涪寮冪殑娑堟伅 ID
|
|
201
|
-
*/
|
|
202
|
-
function collectRemovedMessageIds(
|
|
203
|
-
allMessages: Message[],
|
|
204
|
-
keptMessages: Set<Message>,
|
|
205
|
-
systemMessage?: Message
|
|
206
|
-
): string[] {
|
|
207
|
-
const removedIds: string[] = [];
|
|
208
|
-
for (const msg of allMessages) {
|
|
209
|
-
// 璺宠繃 system 娑堟伅
|
|
210
|
-
if (msg === systemMessage) continue;
|
|
211
|
-
// 濡傛灉娑堟伅涓嶅湪淇濈暀闆嗗悎涓紝鏀堕泦鍏?ID
|
|
212
|
-
if (!keptMessages.has(msg)) {
|
|
213
|
-
if (msg.messageId) {
|
|
214
|
-
removedIds.push(msg.messageId);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return removedIds;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// =============================================================================
|
|
222
|
-
// 鍐呴儴瀹炵幇
|
|
223
|
-
// =============================================================================
|
|
224
|
-
|
|
225
|
-
async function generateSummary(input: {
|
|
226
|
-
provider: LLMProvider;
|
|
227
|
-
pendingMessages: Message[];
|
|
228
|
-
sourceMessages: Message[];
|
|
229
|
-
logger?: AgentLogger;
|
|
230
|
-
}): Promise<string> {
|
|
231
|
-
const { provider, pendingMessages, sourceMessages, logger } = input;
|
|
232
|
-
|
|
233
|
-
if (pendingMessages.length === 0) {
|
|
234
|
-
return '';
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
let previousSummary = '';
|
|
238
|
-
if (isSummaryMessage(pendingMessages[0])) {
|
|
239
|
-
previousSummary = contentToText(pendingMessages[0].content);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const summaryPrompt = buildSummaryPrompt();
|
|
243
|
-
const previousSummaryBlock = previousSummary
|
|
244
|
-
? `\n<previous_summary>\n${previousSummary}\n</previous_summary>\n`
|
|
245
|
-
: '';
|
|
246
|
-
|
|
247
|
-
const compactionMessage = `<compaction-message>
|
|
248
|
-
${sourceMessages.map((m) => `${m.role}: ${contentToText(m.content)}`).join('\n')}
|
|
249
|
-
</compaction-message>`;
|
|
250
|
-
|
|
251
|
-
const requestMessages = [
|
|
252
|
-
{ role: 'system' as const, content: summaryPrompt },
|
|
253
|
-
{ role: 'user' as const, content: `${compactionMessage}\n${previousSummaryBlock}` },
|
|
254
|
-
];
|
|
255
|
-
|
|
256
|
-
const options: { max_tokens: number; model?: string; abortSignal?: AbortSignal } = {
|
|
257
|
-
max_tokens: 1024,
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const configuredModel = provider.config?.model;
|
|
261
|
-
if (typeof configuredModel === 'string' && configuredModel.trim().length > 0) {
|
|
262
|
-
options.model = configuredModel;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// 璁剧疆瓒呮椂
|
|
266
|
-
const timeoutMs = provider.getTimeTimeout();
|
|
267
|
-
if (timeoutMs && Number.isFinite(timeoutMs) && timeoutMs > 0) {
|
|
268
|
-
try {
|
|
269
|
-
options.abortSignal = AbortSignal.timeout(timeoutMs);
|
|
270
|
-
} catch {
|
|
271
|
-
// ignore
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
const response = await provider.generate(requestMessages, options);
|
|
277
|
-
|
|
278
|
-
if (!response || typeof response !== 'object' || !('choices' in response)) {
|
|
279
|
-
logger?.warn?.('[Compaction] Summary generation returned invalid response');
|
|
280
|
-
return '';
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const choice = (response as LLMResponse).choices?.[0];
|
|
284
|
-
|
|
285
|
-
const content = contentToText(choice?.message?.content || '').trim();
|
|
286
|
-
return content || '';
|
|
287
|
-
} catch (error) {
|
|
288
|
-
logger?.warn?.('[Compaction] Summary generation failed:', { error: String(error) });
|
|
289
|
-
return '';
|
|
290
|
-
}
|
|
291
|
-
}
|