@renxqoo/renx-code 0.0.9 → 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 +14 -0
- 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,479 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
createTimeoutBudgetState,
|
|
4
|
-
createExecutionAbortScope,
|
|
5
|
-
createStageAbortScope,
|
|
6
|
-
combineAbortSignals,
|
|
7
|
-
getAbortReason,
|
|
8
|
-
getTotalRemainingBudgetMs,
|
|
9
|
-
consumeStageBudget,
|
|
10
|
-
createTimeoutBudgetReason,
|
|
11
|
-
isTimeoutBudgetReason,
|
|
12
|
-
timeoutBudgetReasonFromSignal,
|
|
13
|
-
} from '../timeout-budget';
|
|
14
|
-
|
|
15
|
-
describe('createTimeoutBudgetState', () => {
|
|
16
|
-
it('returns undefined when no valid timeout is provided', () => {
|
|
17
|
-
const result = createTimeoutBudgetState({
|
|
18
|
-
inputTimeoutBudgetMs: undefined,
|
|
19
|
-
configTimeoutBudgetMs: undefined,
|
|
20
|
-
inputLlmTimeoutRatio: 0.5,
|
|
21
|
-
configLlmTimeoutRatio: 0.7,
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
expect(result).toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('returns undefined when timeout is zero or negative', () => {
|
|
28
|
-
// When inputTimeoutBudgetMs is 0, it should use configTimeoutBudgetMs
|
|
29
|
-
const result1 = createTimeoutBudgetState({
|
|
30
|
-
inputTimeoutBudgetMs: 0,
|
|
31
|
-
configTimeoutBudgetMs: 1000,
|
|
32
|
-
inputLlmTimeoutRatio: 0.5,
|
|
33
|
-
configLlmTimeoutRatio: 0.7,
|
|
34
|
-
});
|
|
35
|
-
expect(result1).toBeDefined();
|
|
36
|
-
expect(result1!.totalMs).toBe(1000);
|
|
37
|
-
|
|
38
|
-
// When inputTimeoutBudgetMs is negative, it should use configTimeoutBudgetMs
|
|
39
|
-
const result2 = createTimeoutBudgetState({
|
|
40
|
-
inputTimeoutBudgetMs: -100,
|
|
41
|
-
configTimeoutBudgetMs: 1000,
|
|
42
|
-
inputLlmTimeoutRatio: 0.5,
|
|
43
|
-
configLlmTimeoutRatio: 0.7,
|
|
44
|
-
});
|
|
45
|
-
expect(result2).toBeDefined();
|
|
46
|
-
expect(result2!.totalMs).toBe(1000);
|
|
47
|
-
|
|
48
|
-
// When both are invalid, return undefined
|
|
49
|
-
expect(
|
|
50
|
-
createTimeoutBudgetState({
|
|
51
|
-
inputTimeoutBudgetMs: 0,
|
|
52
|
-
configTimeoutBudgetMs: 0,
|
|
53
|
-
inputLlmTimeoutRatio: 0.5,
|
|
54
|
-
configLlmTimeoutRatio: 0.7,
|
|
55
|
-
})
|
|
56
|
-
).toBeUndefined();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('uses input timeout when provided', () => {
|
|
60
|
-
const result = createTimeoutBudgetState({
|
|
61
|
-
inputTimeoutBudgetMs: 5000,
|
|
62
|
-
configTimeoutBudgetMs: 10000,
|
|
63
|
-
inputLlmTimeoutRatio: 0.6,
|
|
64
|
-
configLlmTimeoutRatio: 0.7,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
expect(result).toBeDefined();
|
|
68
|
-
expect(result!.totalMs).toBe(5000);
|
|
69
|
-
expect(result!.llmRemainingMs).toBe(3000); // 5000 * 0.6
|
|
70
|
-
expect(result!.toolRemainingMs).toBe(2000); // 5000 - 3000
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('uses config timeout when input is invalid', () => {
|
|
74
|
-
const result = createTimeoutBudgetState({
|
|
75
|
-
inputTimeoutBudgetMs: NaN,
|
|
76
|
-
configTimeoutBudgetMs: 10000,
|
|
77
|
-
inputLlmTimeoutRatio: NaN,
|
|
78
|
-
configLlmTimeoutRatio: 0.7,
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
expect(result).toBeDefined();
|
|
82
|
-
expect(result!.totalMs).toBe(10000);
|
|
83
|
-
// When inputLlmTimeoutRatio is NaN, it should use configLlmTimeoutRatio (0.7)
|
|
84
|
-
expect(result!.llmRemainingMs).toBe(7000); // 10000 * 0.7
|
|
85
|
-
expect(result!.toolRemainingMs).toBe(3000); // 10000 - 7000
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('clamps ratio between 0.05 and 0.95', () => {
|
|
89
|
-
const result1 = createTimeoutBudgetState({
|
|
90
|
-
inputTimeoutBudgetMs: 10000,
|
|
91
|
-
configTimeoutBudgetMs: 10000,
|
|
92
|
-
inputLlmTimeoutRatio: 0.01, // below minimum
|
|
93
|
-
configLlmTimeoutRatio: 0.7,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
expect(result1!.llmRemainingMs).toBe(500); // 10000 * 0.05 (clamped)
|
|
97
|
-
|
|
98
|
-
const result2 = createTimeoutBudgetState({
|
|
99
|
-
inputTimeoutBudgetMs: 10000,
|
|
100
|
-
configTimeoutBudgetMs: 10000,
|
|
101
|
-
inputLlmTimeoutRatio: 0.99, // above maximum
|
|
102
|
-
configLlmTimeoutRatio: 0.7,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
expect(result2!.llmRemainingMs).toBe(9500); // 10000 * 0.95 (clamped)
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('uses config ratio when input ratio is invalid', () => {
|
|
109
|
-
const result = createTimeoutBudgetState({
|
|
110
|
-
inputTimeoutBudgetMs: 10000,
|
|
111
|
-
configTimeoutBudgetMs: 10000,
|
|
112
|
-
inputLlmTimeoutRatio: NaN,
|
|
113
|
-
configLlmTimeoutRatio: 0.8,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
expect(result!.llmRemainingMs).toBe(8000); // 10000 * 0.8
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('ensures minimum llm remaining of 1ms', () => {
|
|
120
|
-
const result = createTimeoutBudgetState({
|
|
121
|
-
inputTimeoutBudgetMs: 10,
|
|
122
|
-
configTimeoutBudgetMs: 10,
|
|
123
|
-
inputLlmTimeoutRatio: 0.05,
|
|
124
|
-
configLlmTimeoutRatio: 0.7,
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
expect(result!.llmRemainingMs).toBe(1); // minimum 1ms
|
|
128
|
-
expect(result!.toolRemainingMs).toBe(9); // 10 - 1
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe('getTotalRemainingBudgetMs', () => {
|
|
133
|
-
it('returns remaining time correctly', () => {
|
|
134
|
-
const budget = {
|
|
135
|
-
totalMs: 10000,
|
|
136
|
-
startedAt: Date.now() - 2000, // 2 seconds ago
|
|
137
|
-
llmRemainingMs: 7000,
|
|
138
|
-
toolRemainingMs: 3000,
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const remaining = getTotalRemainingBudgetMs(budget);
|
|
142
|
-
expect(remaining).toBeLessThanOrEqual(8000);
|
|
143
|
-
expect(remaining).toBeGreaterThan(7900);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('returns 0 when budget is exhausted', () => {
|
|
147
|
-
const budget = {
|
|
148
|
-
totalMs: 1000,
|
|
149
|
-
startedAt: Date.now() - 2000, // 2 seconds ago
|
|
150
|
-
llmRemainingMs: 700,
|
|
151
|
-
toolRemainingMs: 300,
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const remaining = getTotalRemainingBudgetMs(budget);
|
|
155
|
-
expect(remaining).toBe(0);
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
describe('consumeStageBudget', () => {
|
|
160
|
-
it('consumes llm budget correctly', () => {
|
|
161
|
-
const budget = {
|
|
162
|
-
totalMs: 10000,
|
|
163
|
-
startedAt: Date.now(),
|
|
164
|
-
llmRemainingMs: 5000,
|
|
165
|
-
toolRemainingMs: 5000,
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
consumeStageBudget(budget, 'llm', 1000);
|
|
169
|
-
expect(budget.llmRemainingMs).toBe(4000);
|
|
170
|
-
expect(budget.toolRemainingMs).toBe(5000);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('consumes tool budget correctly', () => {
|
|
174
|
-
const budget = {
|
|
175
|
-
totalMs: 10000,
|
|
176
|
-
startedAt: Date.now(),
|
|
177
|
-
llmRemainingMs: 5000,
|
|
178
|
-
toolRemainingMs: 5000,
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
consumeStageBudget(budget, 'tool', 2000);
|
|
182
|
-
expect(budget.llmRemainingMs).toBe(5000);
|
|
183
|
-
expect(budget.toolRemainingMs).toBe(3000);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('does not go below zero', () => {
|
|
187
|
-
const budget = {
|
|
188
|
-
totalMs: 10000,
|
|
189
|
-
startedAt: Date.now(),
|
|
190
|
-
llmRemainingMs: 1000,
|
|
191
|
-
toolRemainingMs: 1000,
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
consumeStageBudget(budget, 'llm', 2000);
|
|
195
|
-
expect(budget.llmRemainingMs).toBe(0);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it('handles negative elapsed time', () => {
|
|
199
|
-
const budget = {
|
|
200
|
-
totalMs: 10000,
|
|
201
|
-
startedAt: Date.now(),
|
|
202
|
-
llmRemainingMs: 5000,
|
|
203
|
-
toolRemainingMs: 5000,
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
consumeStageBudget(budget, 'llm', -1000);
|
|
207
|
-
expect(budget.llmRemainingMs).toBe(5000); // no change
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
describe('createTimeoutBudgetReason', () => {
|
|
212
|
-
it('creates reason for total stage', () => {
|
|
213
|
-
const reason = createTimeoutBudgetReason('total', 5000);
|
|
214
|
-
|
|
215
|
-
expect(reason.type).toBe('agent-timeout-budget');
|
|
216
|
-
expect(reason.stage).toBe('total');
|
|
217
|
-
expect(reason.message).toContain('execution');
|
|
218
|
-
expect(reason.message).toContain('5000');
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it('creates reason for llm stage', () => {
|
|
222
|
-
const reason = createTimeoutBudgetReason('llm', 3000);
|
|
223
|
-
|
|
224
|
-
expect(reason.type).toBe('agent-timeout-budget');
|
|
225
|
-
expect(reason.stage).toBe('llm');
|
|
226
|
-
expect(reason.message).toContain('llm');
|
|
227
|
-
expect(reason.message).toContain('3000');
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('creates reason for tool stage', () => {
|
|
231
|
-
const reason = createTimeoutBudgetReason('tool', 2000);
|
|
232
|
-
|
|
233
|
-
expect(reason.type).toBe('agent-timeout-budget');
|
|
234
|
-
expect(reason.stage).toBe('tool');
|
|
235
|
-
expect(reason.message).toContain('tool');
|
|
236
|
-
expect(reason.message).toContain('2000');
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
describe('isTimeoutBudgetReason', () => {
|
|
241
|
-
it('returns true for valid timeout budget reason', () => {
|
|
242
|
-
const reason = {
|
|
243
|
-
type: 'agent-timeout-budget',
|
|
244
|
-
stage: 'total',
|
|
245
|
-
message: 'Timeout budget exceeded',
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
expect(isTimeoutBudgetReason(reason)).toBe(true);
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
it('returns false for invalid objects', () => {
|
|
252
|
-
expect(isTimeoutBudgetReason(null)).toBe(false);
|
|
253
|
-
expect(isTimeoutBudgetReason(undefined)).toBe(false);
|
|
254
|
-
expect(isTimeoutBudgetReason('string')).toBe(false);
|
|
255
|
-
expect(isTimeoutBudgetReason(123)).toBe(false);
|
|
256
|
-
expect(isTimeoutBudgetReason({})).toBe(false);
|
|
257
|
-
expect(isTimeoutBudgetReason({ type: 'other' })).toBe(false);
|
|
258
|
-
expect(isTimeoutBudgetReason({ type: 'agent-timeout-budget' })).toBe(false);
|
|
259
|
-
expect(isTimeoutBudgetReason({ type: 'agent-timeout-budget', stage: 123 })).toBe(false);
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
describe('getAbortReason', () => {
|
|
264
|
-
it('returns reason from aborted signal', () => {
|
|
265
|
-
const controller = new AbortController();
|
|
266
|
-
const reason = { custom: 'reason' };
|
|
267
|
-
controller.abort(reason);
|
|
268
|
-
|
|
269
|
-
expect(getAbortReason(controller.signal)).toBe(reason);
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('returns undefined for non-aborted signal', () => {
|
|
273
|
-
const controller = new AbortController();
|
|
274
|
-
expect(getAbortReason(controller.signal)).toBeUndefined();
|
|
275
|
-
});
|
|
276
|
-
});
|
|
277
|
-
|
|
278
|
-
describe('combineAbortSignals', () => {
|
|
279
|
-
it('returns undefined signal when both are undefined', () => {
|
|
280
|
-
const scope = combineAbortSignals(undefined, undefined);
|
|
281
|
-
expect(scope.signal).toBeUndefined();
|
|
282
|
-
expect(typeof scope.release).toBe('function');
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
it('returns primary signal when secondary is undefined', () => {
|
|
286
|
-
const controller = new AbortController();
|
|
287
|
-
const scope = combineAbortSignals(controller.signal, undefined);
|
|
288
|
-
|
|
289
|
-
expect(scope.signal).toBe(controller.signal);
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
it('returns secondary signal when primary is undefined', () => {
|
|
293
|
-
const controller = new AbortController();
|
|
294
|
-
const scope = combineAbortSignals(undefined, controller.signal);
|
|
295
|
-
|
|
296
|
-
expect(scope.signal).toBe(controller.signal);
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
it('combines two signals correctly', () => {
|
|
300
|
-
const controller1 = new AbortController();
|
|
301
|
-
const controller2 = new AbortController();
|
|
302
|
-
const scope = combineAbortSignals(controller1.signal, controller2.signal);
|
|
303
|
-
|
|
304
|
-
expect(scope.signal).toBeDefined();
|
|
305
|
-
expect(scope.signal!.aborted).toBe(false);
|
|
306
|
-
|
|
307
|
-
controller1.abort();
|
|
308
|
-
expect(scope.signal!.aborted).toBe(true);
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
it('handles already aborted primary signal', () => {
|
|
312
|
-
const controller1 = new AbortController();
|
|
313
|
-
const controller2 = new AbortController();
|
|
314
|
-
controller1.abort();
|
|
315
|
-
|
|
316
|
-
const scope = combineAbortSignals(controller1.signal, controller2.signal);
|
|
317
|
-
expect(scope.signal!.aborted).toBe(true);
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
it('handles already aborted secondary signal', () => {
|
|
321
|
-
const controller1 = new AbortController();
|
|
322
|
-
const controller2 = new AbortController();
|
|
323
|
-
controller2.abort();
|
|
324
|
-
|
|
325
|
-
const scope = combineAbortSignals(controller1.signal, controller2.signal);
|
|
326
|
-
expect(scope.signal!.aborted).toBe(true);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
it('release function removes event listeners', () => {
|
|
330
|
-
const controller1 = new AbortController();
|
|
331
|
-
const controller2 = new AbortController();
|
|
332
|
-
const scope = combineAbortSignals(controller1.signal, controller2.signal);
|
|
333
|
-
|
|
334
|
-
// Should not throw
|
|
335
|
-
expect(() => scope.release()).not.toThrow();
|
|
336
|
-
});
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
describe('timeoutBudgetReasonFromSignal', () => {
|
|
340
|
-
it('returns reason for aborted signal with timeout budget reason', () => {
|
|
341
|
-
const controller = new AbortController();
|
|
342
|
-
const reason = createTimeoutBudgetReason('total', 5000);
|
|
343
|
-
controller.abort(reason);
|
|
344
|
-
|
|
345
|
-
const result = timeoutBudgetReasonFromSignal(controller.signal);
|
|
346
|
-
expect(result).toBe(reason);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it('returns undefined for non-aborted signal', () => {
|
|
350
|
-
const controller = new AbortController();
|
|
351
|
-
expect(timeoutBudgetReasonFromSignal(controller.signal)).toBeUndefined();
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
it('returns undefined for aborted signal with non-timeout reason', () => {
|
|
355
|
-
const controller = new AbortController();
|
|
356
|
-
controller.abort('custom reason');
|
|
357
|
-
|
|
358
|
-
expect(timeoutBudgetReasonFromSignal(controller.signal)).toBeUndefined();
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
it('returns undefined for undefined signal', () => {
|
|
362
|
-
expect(timeoutBudgetReasonFromSignal(undefined)).toBeUndefined();
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
describe('createExecutionAbortScope', () => {
|
|
367
|
-
it('returns input signal when no timeout budget', () => {
|
|
368
|
-
const controller = new AbortController();
|
|
369
|
-
const scope = createExecutionAbortScope(controller.signal, undefined);
|
|
370
|
-
|
|
371
|
-
expect(scope.signal).toBe(controller.signal);
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
it('creates combined scope with timeout budget', () => {
|
|
375
|
-
const budget = {
|
|
376
|
-
totalMs: 1000,
|
|
377
|
-
startedAt: Date.now(),
|
|
378
|
-
llmRemainingMs: 700,
|
|
379
|
-
toolRemainingMs: 300,
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
const scope = createExecutionAbortScope(undefined, budget);
|
|
383
|
-
|
|
384
|
-
expect(scope.signal).toBeDefined();
|
|
385
|
-
expect(scope.signal!.aborted).toBe(false);
|
|
386
|
-
|
|
387
|
-
// Should abort after timeout
|
|
388
|
-
return new Promise<void>((resolve) => {
|
|
389
|
-
setTimeout(() => {
|
|
390
|
-
expect(scope.signal!.aborted).toBe(true);
|
|
391
|
-
scope.release();
|
|
392
|
-
resolve();
|
|
393
|
-
}, 1100);
|
|
394
|
-
});
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
it('combines input signal with timeout', () => {
|
|
398
|
-
const controller = new AbortController();
|
|
399
|
-
const budget = {
|
|
400
|
-
totalMs: 1000,
|
|
401
|
-
startedAt: Date.now(),
|
|
402
|
-
llmRemainingMs: 700,
|
|
403
|
-
toolRemainingMs: 300,
|
|
404
|
-
};
|
|
405
|
-
|
|
406
|
-
const scope = createExecutionAbortScope(controller.signal, budget);
|
|
407
|
-
|
|
408
|
-
expect(scope.signal).toBeDefined();
|
|
409
|
-
|
|
410
|
-
// Abort via input signal
|
|
411
|
-
controller.abort();
|
|
412
|
-
expect(scope.signal!.aborted).toBe(true);
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
describe('createStageAbortScope', () => {
|
|
417
|
-
it('returns base signal when no timeout budget', () => {
|
|
418
|
-
const controller = new AbortController();
|
|
419
|
-
const scope = createStageAbortScope(controller.signal, undefined, 'llm');
|
|
420
|
-
|
|
421
|
-
expect(scope.signal).toBe(controller.signal);
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
it('creates scope for llm stage', () => {
|
|
425
|
-
const budget = {
|
|
426
|
-
totalMs: 10000,
|
|
427
|
-
startedAt: Date.now(),
|
|
428
|
-
llmRemainingMs: 5000,
|
|
429
|
-
toolRemainingMs: 5000,
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
const scope = createStageAbortScope(undefined, budget, 'llm');
|
|
433
|
-
|
|
434
|
-
expect(scope.signal).toBeDefined();
|
|
435
|
-
expect(scope.signal!.aborted).toBe(false);
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it('creates scope for tool stage', () => {
|
|
439
|
-
const budget = {
|
|
440
|
-
totalMs: 10000,
|
|
441
|
-
startedAt: Date.now(),
|
|
442
|
-
llmRemainingMs: 5000,
|
|
443
|
-
toolRemainingMs: 5000,
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
const scope = createStageAbortScope(undefined, budget, 'tool');
|
|
447
|
-
|
|
448
|
-
expect(scope.signal).toBeDefined();
|
|
449
|
-
expect(scope.signal!.aborted).toBe(false);
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
it('handles exhausted stage budget', () => {
|
|
453
|
-
const budget = {
|
|
454
|
-
totalMs: 10000,
|
|
455
|
-
startedAt: Date.now(),
|
|
456
|
-
llmRemainingMs: 0,
|
|
457
|
-
toolRemainingMs: 5000,
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
const scope = createStageAbortScope(undefined, budget, 'llm');
|
|
461
|
-
|
|
462
|
-
expect(scope.signal).toBeDefined();
|
|
463
|
-
expect(scope.signal!.aborted).toBe(true);
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
it('uses minimum of stage and total remaining', () => {
|
|
467
|
-
const budget = {
|
|
468
|
-
totalMs: 10000,
|
|
469
|
-
startedAt: Date.now() - 8000, // 8 seconds ago
|
|
470
|
-
llmRemainingMs: 5000,
|
|
471
|
-
toolRemainingMs: 5000,
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
const scope = createStageAbortScope(undefined, budget, 'llm');
|
|
475
|
-
|
|
476
|
-
expect(scope.signal).toBeDefined();
|
|
477
|
-
// Should use total remaining (2000ms) instead of stage remaining (5000ms)
|
|
478
|
-
});
|
|
479
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import type { ToolCall } from '../../../providers';
|
|
3
|
-
import { mergeToolCalls } from '../tool-call-merge';
|
|
4
|
-
|
|
5
|
-
describe('tool-call-merge', () => {
|
|
6
|
-
it('merges fragmented tool call arguments and keeps stable ordering', async () => {
|
|
7
|
-
const existing: ToolCall[] = [
|
|
8
|
-
{
|
|
9
|
-
id: 'a',
|
|
10
|
-
type: 'function',
|
|
11
|
-
index: 0,
|
|
12
|
-
function: { name: '', arguments: '{"x":' },
|
|
13
|
-
},
|
|
14
|
-
];
|
|
15
|
-
const incoming: ToolCall[] = [
|
|
16
|
-
{
|
|
17
|
-
id: 'a',
|
|
18
|
-
type: 'function',
|
|
19
|
-
index: 0,
|
|
20
|
-
function: { name: 'bash', arguments: '1}' },
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
id: 'b',
|
|
24
|
-
type: 'function',
|
|
25
|
-
index: 1,
|
|
26
|
-
function: { name: 'write_file', arguments: '{}' },
|
|
27
|
-
},
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const onArgumentsChunk = vi.fn(async () => undefined);
|
|
31
|
-
const merged = await mergeToolCalls({
|
|
32
|
-
existing,
|
|
33
|
-
incoming,
|
|
34
|
-
messageId: 'm1',
|
|
35
|
-
onArgumentsChunk,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
expect(merged).toHaveLength(2);
|
|
39
|
-
expect(merged[0]).toMatchObject({
|
|
40
|
-
id: 'a',
|
|
41
|
-
function: { name: 'bash', arguments: '{"x":1}' },
|
|
42
|
-
});
|
|
43
|
-
expect(merged[1]).toMatchObject({ id: 'b' });
|
|
44
|
-
expect(onArgumentsChunk).toHaveBeenCalledTimes(2);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('merges follow-up fragments by index when id/name are omitted', async () => {
|
|
48
|
-
const existing: ToolCall[] = [
|
|
49
|
-
{
|
|
50
|
-
id: 'call_1',
|
|
51
|
-
type: 'function',
|
|
52
|
-
index: 0,
|
|
53
|
-
function: { name: 'bash', arguments: '{' },
|
|
54
|
-
},
|
|
55
|
-
];
|
|
56
|
-
const incoming = [
|
|
57
|
-
{
|
|
58
|
-
function: { arguments: '"command":"ls -la"}' },
|
|
59
|
-
index: 0,
|
|
60
|
-
},
|
|
61
|
-
] as unknown as ToolCall[];
|
|
62
|
-
|
|
63
|
-
const onArgumentsChunk = vi.fn(async () => undefined);
|
|
64
|
-
const merged = await mergeToolCalls({
|
|
65
|
-
existing,
|
|
66
|
-
incoming,
|
|
67
|
-
messageId: 'm2',
|
|
68
|
-
onArgumentsChunk,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
expect(merged).toHaveLength(1);
|
|
72
|
-
expect(merged[0]).toMatchObject({
|
|
73
|
-
id: 'call_1',
|
|
74
|
-
type: 'function',
|
|
75
|
-
index: 0,
|
|
76
|
-
function: { name: 'bash', arguments: '{"command":"ls -la"}' },
|
|
77
|
-
});
|
|
78
|
-
expect(onArgumentsChunk).toHaveBeenCalledTimes(1);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
InMemoryToolExecutionLedger,
|
|
4
|
-
NoopToolExecutionLedger,
|
|
5
|
-
executeToolCallWithLedger,
|
|
6
|
-
type ToolExecutionLedgerRecord,
|
|
7
|
-
} from '../tool-execution-ledger';
|
|
8
|
-
|
|
9
|
-
function makeRecord(output: string): ToolExecutionLedgerRecord {
|
|
10
|
-
return {
|
|
11
|
-
success: true,
|
|
12
|
-
output,
|
|
13
|
-
summary: output || 'no output',
|
|
14
|
-
recordedAt: Date.now(),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
describe('tool-execution-ledger', () => {
|
|
19
|
-
it('InMemoryToolExecutionLedger executeOnce deduplicates concurrent execution', async () => {
|
|
20
|
-
const ledger = new InMemoryToolExecutionLedger();
|
|
21
|
-
let executionCount = 0;
|
|
22
|
-
|
|
23
|
-
const run = () =>
|
|
24
|
-
ledger.executeOnce('exec_1', 'tool_1', async () => {
|
|
25
|
-
executionCount += 1;
|
|
26
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
27
|
-
return makeRecord('ok');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const [resultA, resultB] = await Promise.all([run(), run()]);
|
|
31
|
-
expect(resultA.record.output).toBe('ok');
|
|
32
|
-
expect(resultB.record.output).toBe('ok');
|
|
33
|
-
expect(executionCount).toBe(1);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('NoopToolExecutionLedger executeOnce never caches', async () => {
|
|
37
|
-
const ledger = new NoopToolExecutionLedger();
|
|
38
|
-
let executionCount = 0;
|
|
39
|
-
|
|
40
|
-
const run = async () =>
|
|
41
|
-
ledger.executeOnce('exec_2', 'tool_2', async () => {
|
|
42
|
-
executionCount += 1;
|
|
43
|
-
return makeRecord(`ok_${executionCount}`);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const first = await run();
|
|
47
|
-
const second = await run();
|
|
48
|
-
expect(first.fromCache).toBe(false);
|
|
49
|
-
expect(second.fromCache).toBe(false);
|
|
50
|
-
expect(first.record.output).toBe('ok_1');
|
|
51
|
-
expect(second.record.output).toBe('ok_2');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('executeToolCallWithLedger bypasses cache when executionId is empty', async () => {
|
|
55
|
-
const ledger = new InMemoryToolExecutionLedger();
|
|
56
|
-
let executionCount = 0;
|
|
57
|
-
|
|
58
|
-
const run = async () =>
|
|
59
|
-
executeToolCallWithLedger({
|
|
60
|
-
ledger,
|
|
61
|
-
executionId: '',
|
|
62
|
-
toolCallId: 'tool_3',
|
|
63
|
-
execute: async () => {
|
|
64
|
-
executionCount += 1;
|
|
65
|
-
return makeRecord(`result_${executionCount}`);
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const first = await run();
|
|
70
|
-
const second = await run();
|
|
71
|
-
expect(first.fromCache).toBe(false);
|
|
72
|
-
expect(second.fromCache).toBe(false);
|
|
73
|
-
expect(first.record.output).toBe('result_1');
|
|
74
|
-
expect(second.record.output).toBe('result_2');
|
|
75
|
-
});
|
|
76
|
-
});
|