@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,119 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
extractErrorMessage,
|
|
5
|
-
buildHelpSegments,
|
|
6
|
-
buildUnsupportedSegments,
|
|
7
|
-
} from './chat-local-replies';
|
|
8
|
-
|
|
9
|
-
describe('chat-local-replies', () => {
|
|
10
|
-
describe('extractErrorMessage', () => {
|
|
11
|
-
it('should extract message from Error object', () => {
|
|
12
|
-
const error = new Error('Test error message');
|
|
13
|
-
const result = extractErrorMessage(error);
|
|
14
|
-
|
|
15
|
-
expect(result).toBe('Error: Test error message');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should extract message from Error with custom name', () => {
|
|
19
|
-
const error = new TypeError('Type error occurred');
|
|
20
|
-
const result = extractErrorMessage(error);
|
|
21
|
-
|
|
22
|
-
expect(result).toBe('TypeError: Type error occurred');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should handle non-Error values', () => {
|
|
26
|
-
expect(extractErrorMessage('string error')).toBe('string error');
|
|
27
|
-
expect(extractErrorMessage(123)).toBe('123');
|
|
28
|
-
expect(extractErrorMessage(null)).toBe('null');
|
|
29
|
-
expect(extractErrorMessage(undefined)).toBe('undefined');
|
|
30
|
-
expect(extractErrorMessage({ toString: () => 'custom object' })).toBe('custom object');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should handle edge cases gracefully', () => {
|
|
34
|
-
// 测试函数不会抛出错误
|
|
35
|
-
expect(() => extractErrorMessage({})).not.toThrow();
|
|
36
|
-
expect(() => extractErrorMessage([])).not.toThrow();
|
|
37
|
-
expect(() => extractErrorMessage(() => {})).not.toThrow();
|
|
38
|
-
|
|
39
|
-
// 结果应该是字符串
|
|
40
|
-
expect(typeof extractErrorMessage({})).toBe('string');
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('buildHelpSegments', () => {
|
|
45
|
-
it('should build help segments with correct structure', () => {
|
|
46
|
-
const turnId = 1;
|
|
47
|
-
const segments = buildHelpSegments(turnId);
|
|
48
|
-
|
|
49
|
-
expect(segments).toBeArray();
|
|
50
|
-
expect(segments).toHaveLength(2);
|
|
51
|
-
|
|
52
|
-
// 检查第一个segment(thinking)
|
|
53
|
-
const thinkingSegment = segments[0]!;
|
|
54
|
-
expect(thinkingSegment.id).toBe(`${turnId}:thinking`);
|
|
55
|
-
expect(thinkingSegment.type).toBe('thinking');
|
|
56
|
-
expect(thinkingSegment.content).toBeString();
|
|
57
|
-
expect(thinkingSegment.content).toContain('OpenTUI Agent CLI');
|
|
58
|
-
|
|
59
|
-
// 检查第二个segment(text)
|
|
60
|
-
const textSegment = segments[1]!;
|
|
61
|
-
expect(textSegment.id).toBe(`${turnId}:text`);
|
|
62
|
-
expect(textSegment.type).toBe('text');
|
|
63
|
-
expect(textSegment.content).toBeString();
|
|
64
|
-
expect(textSegment.content).toContain('Available commands:');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should generate unique IDs for different turn IDs', () => {
|
|
68
|
-
const segments1 = buildHelpSegments(1);
|
|
69
|
-
const segments2 = buildHelpSegments(2);
|
|
70
|
-
|
|
71
|
-
expect(segments1[0]!.id).toBe('1:thinking');
|
|
72
|
-
expect(segments1[1]!.id).toBe('1:text');
|
|
73
|
-
expect(segments2[0]!.id).toBe('2:thinking');
|
|
74
|
-
expect(segments2[1]!.id).toBe('2:text');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should include all command information', () => {
|
|
78
|
-
const segments = buildHelpSegments(1);
|
|
79
|
-
const textContent = segments[1]!.content;
|
|
80
|
-
|
|
81
|
-
expect(textContent).toContain('/help (/commands) - show help');
|
|
82
|
-
expect(textContent).toContain('/clear (/new) - clear all turns');
|
|
83
|
-
expect(textContent).toContain('/exit (/quit /q) - exit app');
|
|
84
|
-
expect(textContent).toContain('/models (/model) - open model selector');
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe('buildUnsupportedSegments', () => {
|
|
89
|
-
it('should build unsupported segments with command name', () => {
|
|
90
|
-
const turnId = 1;
|
|
91
|
-
const commandName = 'export';
|
|
92
|
-
const segments = buildUnsupportedSegments(turnId, commandName);
|
|
93
|
-
|
|
94
|
-
expect(segments).toBeArray();
|
|
95
|
-
expect(segments).toHaveLength(2);
|
|
96
|
-
|
|
97
|
-
const thinkingSegment = segments[0]!;
|
|
98
|
-
expect(thinkingSegment.id).toBe(`${turnId}:thinking`);
|
|
99
|
-
expect(thinkingSegment.type).toBe('thinking');
|
|
100
|
-
expect(thinkingSegment.content).toContain(commandName);
|
|
101
|
-
|
|
102
|
-
const textSegment = segments[1]!;
|
|
103
|
-
expect(textSegment.id).toBe(`${turnId}:text`);
|
|
104
|
-
expect(textSegment.type).toBe('text');
|
|
105
|
-
expect(textSegment.content).toContain(`/${commandName}`);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should handle different command names', () => {
|
|
109
|
-
const testCases = ['fork', 'init', 'sessions', 'review'];
|
|
110
|
-
|
|
111
|
-
for (const command of testCases) {
|
|
112
|
-
const segments = buildUnsupportedSegments(1, command);
|
|
113
|
-
const textContent = segments[1]!.content;
|
|
114
|
-
|
|
115
|
-
expect(textContent).toContain(`/${command}`);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
});
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'bun:test';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
extractErrorMessage,
|
|
5
|
-
buildHelpSegments,
|
|
6
|
-
buildUnsupportedSegments,
|
|
7
|
-
} from './chat-local-replies';
|
|
8
|
-
|
|
9
|
-
describe('chat-local-replies', () => {
|
|
10
|
-
describe('extractErrorMessage', () => {
|
|
11
|
-
it('should extract message from Error object', () => {
|
|
12
|
-
const error = new Error('Test error message');
|
|
13
|
-
const result = extractErrorMessage(error);
|
|
14
|
-
|
|
15
|
-
expect(result).toBe('Error: Test error message');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should extract message from Error with custom name', () => {
|
|
19
|
-
const error = new TypeError('Type error occurred');
|
|
20
|
-
const result = extractErrorMessage(error);
|
|
21
|
-
|
|
22
|
-
expect(result).toBe('TypeError: Type error occurred');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should handle non-Error values', () => {
|
|
26
|
-
expect(extractErrorMessage('string error')).toBe('string error');
|
|
27
|
-
expect(extractErrorMessage(123)).toBe('123');
|
|
28
|
-
expect(extractErrorMessage(null)).toBe('null');
|
|
29
|
-
expect(extractErrorMessage(undefined)).toBe('undefined');
|
|
30
|
-
expect(extractErrorMessage({ toString: () => 'custom object' })).toBe('custom object');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should handle objects without toString', () => {
|
|
34
|
-
const obj = Object.create(null);
|
|
35
|
-
const result = extractErrorMessage(obj);
|
|
36
|
-
|
|
37
|
-
expect(result).toBe('[object Object]');
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
describe('buildHelpSegments', () => {
|
|
42
|
-
it('should build help segments with correct structure', () => {
|
|
43
|
-
const turnId = 1;
|
|
44
|
-
const segments = buildHelpSegments(turnId);
|
|
45
|
-
|
|
46
|
-
expect(segments).toBeArray();
|
|
47
|
-
expect(segments).toHaveLength(2);
|
|
48
|
-
|
|
49
|
-
// 检查第一个segment(thinking)
|
|
50
|
-
const thinkingSegment = segments[0]!;
|
|
51
|
-
expect(thinkingSegment.id).toBe(`${turnId}:thinking`);
|
|
52
|
-
expect(thinkingSegment.type).toBe('thinking');
|
|
53
|
-
expect(thinkingSegment.content).toBeString();
|
|
54
|
-
expect(thinkingSegment.content).toContain('OpenTUI Agent CLI');
|
|
55
|
-
|
|
56
|
-
// 检查第二个segment(text)
|
|
57
|
-
const textSegment = segments[1]!;
|
|
58
|
-
expect(textSegment.id).toBe(`${turnId}:text`);
|
|
59
|
-
expect(textSegment.type).toBe('text');
|
|
60
|
-
expect(textSegment.content).toBeString();
|
|
61
|
-
expect(textSegment.content).toContain('Available commands:');
|
|
62
|
-
expect(textSegment.content).toContain('/help');
|
|
63
|
-
expect(textSegment.content).toContain('/clear');
|
|
64
|
-
expect(textSegment.content).toContain('/exit');
|
|
65
|
-
expect(textSegment.content).toContain('/models');
|
|
66
|
-
expect(textSegment.content).toContain('/files');
|
|
67
|
-
expect(textSegment.content).toContain('Keyboard shortcuts:');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should generate unique IDs for different turn IDs', () => {
|
|
71
|
-
const segments1 = buildHelpSegments(1);
|
|
72
|
-
const segments2 = buildHelpSegments(2);
|
|
73
|
-
|
|
74
|
-
expect(segments1[0]!.id).toBe('1:thinking');
|
|
75
|
-
expect(segments1[1]!.id).toBe('1:text');
|
|
76
|
-
expect(segments2[0]!.id).toBe('2:thinking');
|
|
77
|
-
expect(segments2[1]!.id).toBe('2:text');
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('should include all command information', () => {
|
|
81
|
-
const segments = buildHelpSegments(1);
|
|
82
|
-
const textContent = segments[1]!.content;
|
|
83
|
-
|
|
84
|
-
expect(textContent).toContain('/help (/commands) - show help');
|
|
85
|
-
expect(textContent).toContain('/clear (/new) - clear all turns');
|
|
86
|
-
expect(textContent).toContain('/exit (/quit /q) - exit app');
|
|
87
|
-
expect(textContent).toContain('/models (/model) - open model selector');
|
|
88
|
-
expect(textContent).toContain('/files (/file) - attach workspace files');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should include keyboard shortcuts', () => {
|
|
92
|
-
const segments = buildHelpSegments(1);
|
|
93
|
-
const textContent = segments[1]!.content;
|
|
94
|
-
|
|
95
|
-
expect(textContent).toContain('Esc - stop current response when the agent is thinking');
|
|
96
|
-
expect(textContent).toContain('Ctrl+L - clear conversation panel');
|
|
97
|
-
expect(textContent).toContain('Use /files to attach local workspace files');
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe('buildUnsupportedSegments', () => {
|
|
102
|
-
it('should build unsupported segments with command name', () => {
|
|
103
|
-
const turnId = 1;
|
|
104
|
-
const commandName = 'export';
|
|
105
|
-
const segments = buildUnsupportedSegments(turnId, commandName);
|
|
106
|
-
|
|
107
|
-
expect(segments).toBeArray();
|
|
108
|
-
expect(segments).toHaveLength(2);
|
|
109
|
-
|
|
110
|
-
// 检查thinking segment
|
|
111
|
-
const thinkingSegment = segments[0]!;
|
|
112
|
-
expect(thinkingSegment.id).toBe(`${turnId}:thinking`);
|
|
113
|
-
expect(thinkingSegment.type).toBe('thinking');
|
|
114
|
-
expect(thinkingSegment.content).toBeString();
|
|
115
|
-
expect(thinkingSegment.content).toContain(commandName);
|
|
116
|
-
expect(thinkingSegment.content).toContain('not implemented');
|
|
117
|
-
|
|
118
|
-
// 检查text segment
|
|
119
|
-
const textSegment = segments[1]!;
|
|
120
|
-
expect(textSegment.id).toBe(`${turnId}:text`);
|
|
121
|
-
expect(textSegment.type).toBe('text');
|
|
122
|
-
expect(textSegment.content).toBeString();
|
|
123
|
-
expect(textSegment.content).toContain(`/${commandName}`);
|
|
124
|
-
expect(textSegment.content).toContain('not implemented yet');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should handle different command names', () => {
|
|
128
|
-
const testCases = [
|
|
129
|
-
{ command: 'fork', expected: 'fork' },
|
|
130
|
-
{ command: 'init', expected: 'init' },
|
|
131
|
-
{ command: 'sessions', expected: 'sessions' },
|
|
132
|
-
{ command: 'review', expected: 'review' },
|
|
133
|
-
];
|
|
134
|
-
|
|
135
|
-
for (const testCase of testCases) {
|
|
136
|
-
const segments = buildUnsupportedSegments(1, testCase.command);
|
|
137
|
-
const textContent = segments[1]!.content;
|
|
138
|
-
|
|
139
|
-
expect(textContent).toContain(`/${testCase.command}`);
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should generate unique IDs for different turn IDs', () => {
|
|
144
|
-
const segments1 = buildUnsupportedSegments(1, 'export');
|
|
145
|
-
const segments2 = buildUnsupportedSegments(2, 'export');
|
|
146
|
-
|
|
147
|
-
expect(segments1[0]!.id).toBe('1:thinking');
|
|
148
|
-
expect(segments1[1]!.id).toBe('1:text');
|
|
149
|
-
expect(segments2[0]!.id).toBe('2:thinking');
|
|
150
|
-
expect(segments2[1]!.id).toBe('2:text');
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export type LocalReplySegment = {
|
|
2
|
-
id: string;
|
|
3
|
-
type: 'thinking' | 'text';
|
|
4
|
-
content: string;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const extractErrorMessage = (error: unknown): string => {
|
|
8
|
-
if (error instanceof Error) {
|
|
9
|
-
return `${error.name}: ${error.message}`;
|
|
10
|
-
}
|
|
11
|
-
try {
|
|
12
|
-
return String(error);
|
|
13
|
-
} catch {
|
|
14
|
-
return Object.prototype.toString.call(error);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const buildHelpSegments = (turnId: number): LocalReplySegment[] => {
|
|
19
|
-
return [
|
|
20
|
-
{
|
|
21
|
-
id: `${turnId}:thinking`,
|
|
22
|
-
type: 'thinking',
|
|
23
|
-
content: 'This is the command help for OpenTUI Agent CLI.',
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
id: `${turnId}:text`,
|
|
27
|
-
type: 'text',
|
|
28
|
-
content: [
|
|
29
|
-
'Available commands:',
|
|
30
|
-
'/help (/commands) - show help',
|
|
31
|
-
'/clear (/new) - clear all turns',
|
|
32
|
-
'/exit (/quit /q) - exit app',
|
|
33
|
-
'/models (/model) - open model selector',
|
|
34
|
-
'/files (/file) - attach workspace files',
|
|
35
|
-
'Type @/ to attach workspace files inline',
|
|
36
|
-
'',
|
|
37
|
-
'Keyboard shortcuts:',
|
|
38
|
-
'Esc - stop current response when the agent is thinking',
|
|
39
|
-
'Ctrl+L - clear conversation panel',
|
|
40
|
-
'Use /files to attach local workspace files',
|
|
41
|
-
'Use @/path to search and attach files inline',
|
|
42
|
-
].join('\n'),
|
|
43
|
-
},
|
|
44
|
-
];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const buildUnsupportedSegments = (
|
|
48
|
-
turnId: number,
|
|
49
|
-
commandName: string
|
|
50
|
-
): LocalReplySegment[] => {
|
|
51
|
-
return [
|
|
52
|
-
{
|
|
53
|
-
id: `${turnId}:thinking`,
|
|
54
|
-
type: 'thinking',
|
|
55
|
-
content: `The user selected /${commandName}. This command is not implemented in current demo.`,
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
id: `${turnId}:text`,
|
|
59
|
-
type: 'text',
|
|
60
|
-
content: `Command /${commandName} is not implemented yet in this CLI demo.`,
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { createStreamingReply, orderReplySegments } from './turn-updater';
|
|
4
|
-
import type { ReplySegment } from '../types/chat';
|
|
5
|
-
|
|
6
|
-
describe('createStreamingReply', () => {
|
|
7
|
-
it('initializes startedAtMs for realtime duration display', () => {
|
|
8
|
-
const before = Date.now();
|
|
9
|
-
const reply = createStreamingReply('glm-5');
|
|
10
|
-
const after = Date.now();
|
|
11
|
-
|
|
12
|
-
expect(typeof reply.startedAtMs).toBe('number');
|
|
13
|
-
expect((reply.startedAtMs as number) >= before).toBe(true);
|
|
14
|
-
expect((reply.startedAtMs as number) <= after).toBe(true);
|
|
15
|
-
expect(reply.status).toBe('streaming');
|
|
16
|
-
expect(reply.durationSeconds).toBe(0);
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('orderReplySegments', () => {
|
|
21
|
-
it('keeps each tool-result adjacent to its tool-use for concurrent multi-tool calls', () => {
|
|
22
|
-
const input: ReplySegment[] = [
|
|
23
|
-
{ id: '1:thinking:1', type: 'thinking', content: '先并发调用4个工具。' },
|
|
24
|
-
{ id: '1:tool-use:call_a', type: 'code', content: '# Tool A\n' },
|
|
25
|
-
{ id: '1:tool-use:call_b', type: 'code', content: '# Tool B\n' },
|
|
26
|
-
{ id: '1:tool-use:call_c', type: 'code', content: '# Tool C\n' },
|
|
27
|
-
{ id: '1:tool-use:call_d', type: 'code', content: '# Tool D\n' },
|
|
28
|
-
{ id: '1:tool-result:call_c', type: 'code', content: '# Result C\n' },
|
|
29
|
-
{ id: '1:tool-result:call_a', type: 'code', content: '# Result A\n' },
|
|
30
|
-
{ id: '1:tool-result:call_d', type: 'code', content: '# Result D\n' },
|
|
31
|
-
{ id: '1:tool-result:call_b', type: 'code', content: '# Result B\n' },
|
|
32
|
-
{ id: '1:text:2', type: 'text', content: '工具执行结束。' },
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
const ordered = orderReplySegments(input);
|
|
36
|
-
expect(ordered.map(segment => segment.id)).toEqual([
|
|
37
|
-
'1:thinking:1',
|
|
38
|
-
'1:tool-use:call_a',
|
|
39
|
-
'1:tool-result:call_a',
|
|
40
|
-
'1:tool-use:call_b',
|
|
41
|
-
'1:tool-result:call_b',
|
|
42
|
-
'1:tool-use:call_c',
|
|
43
|
-
'1:tool-result:call_c',
|
|
44
|
-
'1:tool-use:call_d',
|
|
45
|
-
'1:tool-result:call_d',
|
|
46
|
-
'1:text:2',
|
|
47
|
-
]);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('keeps stream output between its tool-use and tool-result', () => {
|
|
51
|
-
const input: ReplySegment[] = [
|
|
52
|
-
{ id: '1:tool-use:call_1', type: 'code', content: '# Tool 1\n' },
|
|
53
|
-
{ id: '1:tool-use:call_2', type: 'code', content: '# Tool 2\n' },
|
|
54
|
-
{ id: '1:tool:call_2:stdout', type: 'code', content: 'line2\n' },
|
|
55
|
-
{ id: '1:tool:call_1:stdout', type: 'code', content: 'line1\n' },
|
|
56
|
-
{ id: '1:tool-result:call_2', type: 'code', content: '# Result 2\n' },
|
|
57
|
-
{ id: '1:tool-result:call_1', type: 'code', content: '# Result 1\n' },
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
const ordered = orderReplySegments(input);
|
|
61
|
-
expect(ordered.map(segment => segment.id)).toEqual([
|
|
62
|
-
'1:tool-use:call_1',
|
|
63
|
-
'1:tool:call_1:stdout',
|
|
64
|
-
'1:tool-result:call_1',
|
|
65
|
-
'1:tool-use:call_2',
|
|
66
|
-
'1:tool:call_2:stdout',
|
|
67
|
-
'1:tool-result:call_2',
|
|
68
|
-
]);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AssistantReply,
|
|
3
|
-
ChatTurn,
|
|
4
|
-
ReplySegment,
|
|
5
|
-
ReplySegmentType,
|
|
6
|
-
ReplyStatus,
|
|
7
|
-
} from '../types/chat';
|
|
8
|
-
|
|
9
|
-
const DEFAULT_AGENT_LABEL = '';
|
|
10
|
-
|
|
11
|
-
export const createStreamingReply = (modelLabel: string): AssistantReply => ({
|
|
12
|
-
agentLabel: DEFAULT_AGENT_LABEL,
|
|
13
|
-
modelLabel,
|
|
14
|
-
startedAtMs: Date.now(),
|
|
15
|
-
durationSeconds: 0,
|
|
16
|
-
segments: [],
|
|
17
|
-
status: 'streaming',
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
export const patchTurn = (
|
|
21
|
-
turns: ChatTurn[],
|
|
22
|
-
turnId: number,
|
|
23
|
-
patch: (turn: ChatTurn) => ChatTurn
|
|
24
|
-
): ChatTurn[] => {
|
|
25
|
-
return turns.map(turn => (turn.id === turnId ? patch(turn) : turn));
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const ensureSegment = (
|
|
29
|
-
segments: ReplySegment[],
|
|
30
|
-
segmentId: string,
|
|
31
|
-
type: ReplySegmentType,
|
|
32
|
-
data?: unknown
|
|
33
|
-
): ReplySegment[] => {
|
|
34
|
-
if (segments.some(segment => segment.id === segmentId)) {
|
|
35
|
-
return segments;
|
|
36
|
-
}
|
|
37
|
-
return [
|
|
38
|
-
...segments,
|
|
39
|
-
{ id: segmentId, type, content: '', ...(data !== undefined ? { data } : {}) },
|
|
40
|
-
];
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const appendToSegment = (
|
|
44
|
-
segments: ReplySegment[],
|
|
45
|
-
segmentId: string,
|
|
46
|
-
type: ReplySegmentType,
|
|
47
|
-
chunk: string,
|
|
48
|
-
data?: unknown
|
|
49
|
-
): ReplySegment[] => {
|
|
50
|
-
const base = ensureSegment(segments, segmentId, type, data);
|
|
51
|
-
return base.map(segment =>
|
|
52
|
-
segment.id === segmentId
|
|
53
|
-
? {
|
|
54
|
-
...segment,
|
|
55
|
-
content: `${segment.content}${chunk}`,
|
|
56
|
-
...(data !== undefined ? { data } : {}),
|
|
57
|
-
}
|
|
58
|
-
: segment
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
type ToolSegmentKind = 'use' | 'stream' | 'result';
|
|
63
|
-
|
|
64
|
-
const parseToolSegment = (
|
|
65
|
-
segmentId: string
|
|
66
|
-
): {
|
|
67
|
-
toolCallId: string;
|
|
68
|
-
kind: ToolSegmentKind;
|
|
69
|
-
} | null => {
|
|
70
|
-
const toolUseMatch = segmentId.match(/^\d+:tool-use:(.+)$/);
|
|
71
|
-
if (toolUseMatch && toolUseMatch[1]) {
|
|
72
|
-
return { toolCallId: toolUseMatch[1], kind: 'use' };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const toolResultMatch = segmentId.match(/^\d+:tool-result:(.+)$/);
|
|
76
|
-
if (toolResultMatch && toolResultMatch[1]) {
|
|
77
|
-
return { toolCallId: toolResultMatch[1], kind: 'result' };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const toolStreamMatch = segmentId.match(/^\d+:tool:([^:]+):/);
|
|
81
|
-
if (toolStreamMatch && toolStreamMatch[1]) {
|
|
82
|
-
return { toolCallId: toolStreamMatch[1], kind: 'stream' };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return null;
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export const orderReplySegments = (segments: ReplySegment[]): ReplySegment[] => {
|
|
89
|
-
type ToolGroup = {
|
|
90
|
-
use: ReplySegment[];
|
|
91
|
-
stream: ReplySegment[];
|
|
92
|
-
result: ReplySegment[];
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
const groups = new Map<string, ToolGroup>();
|
|
96
|
-
const emittedGroupIds = new Set<string>();
|
|
97
|
-
const ordered: Array<ReplySegment | { groupId: string }> = [];
|
|
98
|
-
|
|
99
|
-
for (const segment of segments) {
|
|
100
|
-
const parsed = parseToolSegment(segment.id);
|
|
101
|
-
if (!parsed) {
|
|
102
|
-
ordered.push(segment);
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const existing = groups.get(parsed.toolCallId) ?? {
|
|
107
|
-
use: [],
|
|
108
|
-
stream: [],
|
|
109
|
-
result: [],
|
|
110
|
-
};
|
|
111
|
-
existing[parsed.kind].push(segment);
|
|
112
|
-
groups.set(parsed.toolCallId, existing);
|
|
113
|
-
|
|
114
|
-
if (!emittedGroupIds.has(parsed.toolCallId)) {
|
|
115
|
-
emittedGroupIds.add(parsed.toolCallId);
|
|
116
|
-
ordered.push({ groupId: parsed.toolCallId });
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const normalized: ReplySegment[] = [];
|
|
121
|
-
for (const item of ordered) {
|
|
122
|
-
if ('id' in item) {
|
|
123
|
-
normalized.push(item);
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const group = groups.get(item.groupId);
|
|
128
|
-
if (!group) {
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
normalized.push(...group.use, ...group.stream, ...group.result);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return normalized;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
export const appendNoteLine = (
|
|
138
|
-
segments: ReplySegment[],
|
|
139
|
-
segmentId: string,
|
|
140
|
-
text: string
|
|
141
|
-
): ReplySegment[] => {
|
|
142
|
-
const line = text.endsWith('\n') ? text : `${text}\n`;
|
|
143
|
-
return appendToSegment(segments, segmentId, 'note', line);
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
export const setReplyStatus = (
|
|
147
|
-
turns: ChatTurn[],
|
|
148
|
-
turnId: number,
|
|
149
|
-
status: ReplyStatus,
|
|
150
|
-
extras?: Partial<AssistantReply>
|
|
151
|
-
): ChatTurn[] => {
|
|
152
|
-
return patchTurn(turns, turnId, turn => {
|
|
153
|
-
const reply = turn.reply;
|
|
154
|
-
if (!reply) {
|
|
155
|
-
return turn;
|
|
156
|
-
}
|
|
157
|
-
return {
|
|
158
|
-
...turn,
|
|
159
|
-
reply: {
|
|
160
|
-
...reply,
|
|
161
|
-
...extras,
|
|
162
|
-
status,
|
|
163
|
-
},
|
|
164
|
-
};
|
|
165
|
-
});
|
|
166
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { describe, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
describe('useAgentChat context behavior', () => {
|
|
4
|
-
it.todo(
|
|
5
|
-
'keeps the previous context usage visible when a resend starts until the first fresh context update arrives'
|
|
6
|
-
);
|
|
7
|
-
it.todo(
|
|
8
|
-
'updates context usage from realtime onContextUsage before the final usage event is emitted'
|
|
9
|
-
);
|
|
10
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { resolveReplyStatus } from './use-agent-chat';
|
|
4
|
-
|
|
5
|
-
describe('resolveReplyStatus', () => {
|
|
6
|
-
it('maps server-side error completions to reply error state', () => {
|
|
7
|
-
expect(resolveReplyStatus('error')).toBe('error');
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it('keeps non-error completions as done state', () => {
|
|
11
|
-
expect(resolveReplyStatus('stop')).toBe('done');
|
|
12
|
-
expect(resolveReplyStatus('cancelled')).toBe('done');
|
|
13
|
-
});
|
|
14
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { act, renderHook, waitFor } from '@testing-library/react';
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
|
|
4
|
-
vi.mock('../commands/slash-commands', () => ({
|
|
5
|
-
resolveSlashCommand: vi.fn(),
|
|
6
|
-
}));
|
|
7
|
-
|
|
8
|
-
vi.mock('../agent/runtime/runtime', () => ({
|
|
9
|
-
getAgentModelAttachmentCapabilities: vi.fn(),
|
|
10
|
-
getAgentModelLabel: vi.fn(),
|
|
11
|
-
runAgentPrompt: vi.fn(),
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
|
-
vi.mock('../runtime/exit', () => ({
|
|
15
|
-
requestExit: vi.fn(),
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
import * as runtime from '../agent/runtime/runtime';
|
|
19
|
-
import { useAgentChat } from './use-agent-chat';
|
|
20
|
-
|
|
21
|
-
describe('useAgentChat', () => {
|
|
22
|
-
const mockGetAgentModelLabel = runtime.getAgentModelLabel as unknown as ReturnType<typeof vi.fn>;
|
|
23
|
-
const mockGetAgentModelAttachmentCapabilities =
|
|
24
|
-
runtime.getAgentModelAttachmentCapabilities as unknown as ReturnType<typeof vi.fn>;
|
|
25
|
-
const mockRunAgentPrompt = runtime.runAgentPrompt as unknown as ReturnType<typeof vi.fn>;
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
vi.clearAllMocks();
|
|
29
|
-
mockGetAgentModelLabel.mockResolvedValue('glm-5');
|
|
30
|
-
mockGetAgentModelAttachmentCapabilities.mockResolvedValue({
|
|
31
|
-
image: false,
|
|
32
|
-
audio: false,
|
|
33
|
-
video: false,
|
|
34
|
-
});
|
|
35
|
-
mockRunAgentPrompt.mockResolvedValue({ success: true });
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
afterEach(() => {
|
|
39
|
-
vi.restoreAllMocks();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('initializes with default state and resolves the model label', async () => {
|
|
43
|
-
const { result } = renderHook(() => useAgentChat());
|
|
44
|
-
|
|
45
|
-
expect(result.current.turns).toEqual([]);
|
|
46
|
-
expect(result.current.inputValue).toBe('');
|
|
47
|
-
expect(result.current.isThinking).toBe(false);
|
|
48
|
-
expect(result.current.contextUsagePercent).toBe(null);
|
|
49
|
-
expect(result.current.pendingToolConfirm).toBe(null);
|
|
50
|
-
|
|
51
|
-
await waitFor(() => {
|
|
52
|
-
expect(result.current.modelLabel).toBe('glm-5');
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('updates input value', () => {
|
|
57
|
-
const { result } = renderHook(() => useAgentChat());
|
|
58
|
-
|
|
59
|
-
act(() => {
|
|
60
|
-
result.current.setInputValue('test input');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
expect(result.current.inputValue).toBe('test input');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('clears input', () => {
|
|
67
|
-
const { result } = renderHook(() => useAgentChat());
|
|
68
|
-
|
|
69
|
-
act(() => {
|
|
70
|
-
result.current.setInputValue('test input');
|
|
71
|
-
});
|
|
72
|
-
expect(result.current.inputValue).toBe('test input');
|
|
73
|
-
|
|
74
|
-
act(() => {
|
|
75
|
-
result.current.clearInput();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
expect(result.current.inputValue).toBe('');
|
|
79
|
-
});
|
|
80
|
-
});
|