@yeshwanthyk/coding-agent 0.3.0 → 0.3.2
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 +8 -6
- package/dist/adapters/acp/index.d.ts +10 -0
- package/dist/adapters/acp/index.d.ts.map +1 -0
- package/dist/adapters/acp/index.js +250 -0
- package/dist/adapters/acp/index.js.map +1 -0
- package/dist/adapters/acp/protocol.d.ts +171 -0
- package/dist/adapters/acp/protocol.d.ts.map +1 -0
- package/dist/adapters/acp/protocol.js +25 -0
- package/dist/adapters/acp/protocol.js.map +1 -0
- package/dist/adapters/acp/session.d.ts +33 -0
- package/dist/adapters/acp/session.d.ts.map +1 -0
- package/dist/adapters/acp/session.js +216 -0
- package/dist/adapters/acp/session.js.map +1 -0
- package/dist/adapters/acp/updates.d.ts +17 -0
- package/dist/adapters/acp/updates.d.ts.map +1 -0
- package/dist/adapters/acp/updates.js +62 -0
- package/dist/adapters/acp/updates.js.map +1 -0
- package/dist/adapters/cli/headless.d.ts +7 -0
- package/dist/adapters/cli/headless.d.ts.map +1 -0
- package/dist/adapters/cli/headless.js +93 -0
- package/dist/adapters/cli/headless.js.map +1 -0
- package/dist/adapters/cli/validate.d.ts +3 -0
- package/dist/adapters/cli/validate.d.ts.map +1 -0
- package/dist/adapters/cli/validate.js +40 -0
- package/dist/adapters/cli/validate.js.map +1 -0
- package/dist/adapters/tui/app.d.ts +8 -0
- package/dist/adapters/tui/app.d.ts.map +1 -0
- package/dist/adapters/tui/app.jsx +25 -0
- package/dist/adapters/tui/app.jsx.map +1 -0
- package/dist/agent-events.d.ts +63 -0
- package/dist/agent-events.d.ts.map +1 -0
- package/dist/agent-events.js +510 -0
- package/dist/agent-events.js.map +1 -0
- package/dist/args.d.ts +18 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +87 -0
- package/dist/args.js.map +1 -0
- package/dist/autocomplete-commands.d.ts +26 -0
- package/dist/autocomplete-commands.d.ts.map +1 -0
- package/dist/autocomplete-commands.js +82 -0
- package/dist/autocomplete-commands.js.map +1 -0
- package/dist/commands.d.ts +10 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +17 -0
- package/dist/commands.js.map +1 -0
- package/dist/compact-handler.d.ts +42 -0
- package/dist/compact-handler.d.ts.map +1 -0
- package/dist/compact-handler.js +211 -0
- package/dist/compact-handler.js.map +1 -0
- package/dist/components/Footer.d.ts +9 -0
- package/dist/components/Footer.d.ts.map +1 -0
- package/dist/components/Footer.jsx +36 -0
- package/dist/components/Footer.jsx.map +1 -0
- package/dist/components/Header.d.ts +23 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.jsx +174 -0
- package/dist/components/Header.jsx.map +1 -0
- package/dist/components/MessageList.d.ts +19 -0
- package/dist/components/MessageList.d.ts.map +1 -0
- package/dist/components/MessageList.jsx +237 -0
- package/dist/components/MessageList.jsx.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -0
- package/dist/domain/commands/builtin/clear.d.ts +3 -0
- package/dist/domain/commands/builtin/clear.d.ts.map +1 -0
- package/dist/domain/commands/builtin/clear.js +13 -0
- package/dist/domain/commands/builtin/clear.js.map +1 -0
- package/dist/domain/commands/builtin/compact.d.ts +3 -0
- package/dist/domain/commands/builtin/compact.d.ts.map +1 -0
- package/dist/domain/commands/builtin/compact.js +84 -0
- package/dist/domain/commands/builtin/compact.js.map +1 -0
- package/dist/domain/commands/builtin/conceal.d.ts +3 -0
- package/dist/domain/commands/builtin/conceal.d.ts.map +1 -0
- package/dist/domain/commands/builtin/conceal.js +8 -0
- package/dist/domain/commands/builtin/conceal.js.map +1 -0
- package/dist/domain/commands/builtin/diffwrap.d.ts +3 -0
- package/dist/domain/commands/builtin/diffwrap.d.ts.map +1 -0
- package/dist/domain/commands/builtin/diffwrap.js +8 -0
- package/dist/domain/commands/builtin/diffwrap.js.map +1 -0
- package/dist/domain/commands/builtin/editor.d.ts +3 -0
- package/dist/domain/commands/builtin/editor.d.ts.map +1 -0
- package/dist/domain/commands/builtin/editor.js +22 -0
- package/dist/domain/commands/builtin/editor.js.map +1 -0
- package/dist/domain/commands/builtin/exit.d.ts +3 -0
- package/dist/domain/commands/builtin/exit.d.ts.map +1 -0
- package/dist/domain/commands/builtin/exit.js +14 -0
- package/dist/domain/commands/builtin/exit.js.map +1 -0
- package/dist/domain/commands/builtin/followup.d.ts +3 -0
- package/dist/domain/commands/builtin/followup.d.ts.map +1 -0
- package/dist/domain/commands/builtin/followup.js +20 -0
- package/dist/domain/commands/builtin/followup.js.map +1 -0
- package/dist/domain/commands/builtin/index.d.ts +2 -0
- package/dist/domain/commands/builtin/index.d.ts.map +1 -0
- package/dist/domain/commands/builtin/index.js +29 -0
- package/dist/domain/commands/builtin/index.js.map +1 -0
- package/dist/domain/commands/builtin/login.d.ts +3 -0
- package/dist/domain/commands/builtin/login.d.ts.map +1 -0
- package/dist/domain/commands/builtin/login.js +92 -0
- package/dist/domain/commands/builtin/login.js.map +1 -0
- package/dist/domain/commands/builtin/model.d.ts +3 -0
- package/dist/domain/commands/builtin/model.d.ts.map +1 -0
- package/dist/domain/commands/builtin/model.js +53 -0
- package/dist/domain/commands/builtin/model.js.map +1 -0
- package/dist/domain/commands/builtin/status.d.ts +3 -0
- package/dist/domain/commands/builtin/status.d.ts.map +1 -0
- package/dist/domain/commands/builtin/status.js +30 -0
- package/dist/domain/commands/builtin/status.js.map +1 -0
- package/dist/domain/commands/builtin/steer.d.ts +3 -0
- package/dist/domain/commands/builtin/steer.d.ts.map +1 -0
- package/dist/domain/commands/builtin/steer.js +20 -0
- package/dist/domain/commands/builtin/steer.js.map +1 -0
- package/dist/domain/commands/builtin/theme.d.ts +3 -0
- package/dist/domain/commands/builtin/theme.d.ts.map +1 -0
- package/dist/domain/commands/builtin/theme.js +19 -0
- package/dist/domain/commands/builtin/theme.js.map +1 -0
- package/dist/domain/commands/builtin/thinking.d.ts +3 -0
- package/dist/domain/commands/builtin/thinking.d.ts.map +1 -0
- package/dist/domain/commands/builtin/thinking.js +16 -0
- package/dist/domain/commands/builtin/thinking.js.map +1 -0
- package/dist/domain/commands/helpers.d.ts +7 -0
- package/dist/domain/commands/helpers.d.ts.map +1 -0
- package/dist/domain/commands/helpers.js +34 -0
- package/dist/domain/commands/helpers.js.map +1 -0
- package/dist/domain/commands/registry.d.ts +10 -0
- package/dist/domain/commands/registry.d.ts.map +1 -0
- package/dist/domain/commands/registry.js +36 -0
- package/dist/domain/commands/registry.js.map +1 -0
- package/dist/domain/commands/types.d.ts +62 -0
- package/dist/domain/commands/types.d.ts.map +1 -0
- package/dist/domain/commands/types.js +2 -0
- package/dist/domain/commands/types.js.map +1 -0
- package/dist/domain/messaging/content.d.ts +37 -0
- package/dist/domain/messaging/content.d.ts.map +1 -0
- package/dist/domain/messaging/content.js +103 -0
- package/dist/domain/messaging/content.js.map +1 -0
- package/dist/editor.d.ts +26 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +81 -0
- package/dist/editor.js.map +1 -0
- package/dist/extensibility/schema.d.ts +2 -0
- package/dist/extensibility/schema.d.ts.map +1 -0
- package/{src/extensibility/schema.ts → dist/extensibility/schema.js} +2 -1
- package/dist/extensibility/schema.js.map +1 -0
- package/dist/extensibility/validation.d.ts +2 -0
- package/dist/extensibility/validation.d.ts.map +1 -0
- package/{src/extensibility/validation.ts → dist/extensibility/validation.js} +2 -1
- package/dist/extensibility/validation.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useAgentEvents.d.ts +8 -0
- package/dist/hooks/useAgentEvents.d.ts.map +1 -0
- package/dist/hooks/useAgentEvents.js +22 -0
- package/dist/hooks/useAgentEvents.js.map +1 -0
- package/dist/hooks/useEditorBridge.d.ts +20 -0
- package/dist/hooks/useEditorBridge.d.ts.map +1 -0
- package/dist/hooks/useEditorBridge.js +80 -0
- package/dist/hooks/useEditorBridge.js.map +1 -0
- package/dist/hooks/useGitStatus.d.ts +2 -0
- package/dist/hooks/useGitStatus.d.ts.map +1 -0
- package/dist/hooks/useGitStatus.js +26 -0
- package/dist/hooks/useGitStatus.js.map +1 -0
- package/dist/hooks/usePromptQueue.d.ts +2 -0
- package/dist/hooks/usePromptQueue.d.ts.map +1 -0
- package/dist/hooks/usePromptQueue.js +2 -0
- package/dist/hooks/usePromptQueue.js.map +1 -0
- package/dist/hooks/useSessionController.d.ts +2 -0
- package/dist/hooks/useSessionController.d.ts.map +1 -0
- package/dist/hooks/useSessionController.js +2 -0
- package/dist/hooks/useSessionController.js.map +1 -0
- package/dist/hooks/useSpinner.d.ts +4 -0
- package/dist/hooks/useSpinner.d.ts.map +1 -0
- package/dist/hooks/useSpinner.js +25 -0
- package/dist/hooks/useSpinner.js.map +1 -0
- package/dist/hooks/useToastManager.d.ts +6 -0
- package/dist/hooks/useToastManager.d.ts.map +1 -0
- package/dist/hooks/useToastManager.js +22 -0
- package/dist/hooks/useToastManager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +156 -0
- package/dist/index.js.map +1 -0
- package/dist/keyboard-handler.d.ts +30 -0
- package/dist/keyboard-handler.d.ts.map +1 -0
- package/dist/keyboard-handler.js +96 -0
- package/dist/keyboard-handler.js.map +1 -0
- package/dist/profiler.d.ts +2 -0
- package/dist/profiler.d.ts.map +1 -0
- package/dist/profiler.js +41 -0
- package/dist/profiler.js.map +1 -0
- package/dist/runtime/context.d.ts +8 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/context.jsx +11 -0
- package/dist/runtime/context.jsx.map +1 -0
- package/dist/runtime/factory.d.ts +12 -0
- package/dist/runtime/factory.d.ts.map +1 -0
- package/dist/runtime/factory.js +37 -0
- package/dist/runtime/factory.js.map +1 -0
- package/dist/runtime/git/git-info.d.ts +3 -0
- package/dist/runtime/git/git-info.d.ts.map +1 -0
- package/dist/runtime/git/git-info.js +29 -0
- package/dist/runtime/git/git-info.js.map +1 -0
- package/dist/runtime/session/session-controller.d.ts +48 -0
- package/dist/runtime/session/session-controller.d.ts.map +1 -0
- package/dist/runtime/session/session-controller.js +159 -0
- package/dist/runtime/session/session-controller.js.map +1 -0
- package/dist/session-manager.d.ts +2 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +2 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/session-picker.d.ts +6 -0
- package/dist/session-picker.d.ts.map +1 -0
- package/dist/session-picker.jsx +96 -0
- package/dist/session-picker.jsx.map +1 -0
- package/dist/shell-runner.d.ts +21 -0
- package/dist/shell-runner.d.ts.map +1 -0
- package/dist/shell-runner.js +106 -0
- package/dist/shell-runner.js.map +1 -0
- package/dist/syntax-highlighting.d.ts +4 -0
- package/dist/syntax-highlighting.d.ts.map +1 -0
- package/dist/syntax-highlighting.js +108 -0
- package/dist/syntax-highlighting.js.map +1 -0
- package/dist/theme-names.d.ts +7 -0
- package/dist/theme-names.d.ts.map +1 -0
- package/dist/theme-names.js +38 -0
- package/dist/theme-names.js.map +1 -0
- package/dist/tool-ui-contracts.d.ts +30 -0
- package/dist/tool-ui-contracts.d.ts.map +1 -0
- package/dist/tool-ui-contracts.js +53 -0
- package/dist/tool-ui-contracts.js.map +1 -0
- package/dist/tui-open-rendering.d.ts +37 -0
- package/dist/tui-open-rendering.d.ts.map +1 -0
- package/dist/tui-open-rendering.jsx +462 -0
- package/dist/tui-open-rendering.jsx.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/app-shell/TuiApp.d.ts +6 -0
- package/dist/ui/app-shell/TuiApp.d.ts.map +1 -0
- package/dist/ui/app-shell/TuiApp.jsx +480 -0
- package/dist/ui/app-shell/TuiApp.jsx.map +1 -0
- package/dist/ui/clipboard/osc52.d.ts +2 -0
- package/dist/ui/clipboard/osc52.d.ts.map +1 -0
- package/dist/ui/clipboard/osc52.js +19 -0
- package/dist/ui/clipboard/osc52.js.map +1 -0
- package/dist/ui/components/modals/ConfirmModal.d.ts +8 -0
- package/dist/ui/components/modals/ConfirmModal.d.ts.map +1 -0
- package/dist/ui/components/modals/ConfirmModal.jsx +39 -0
- package/dist/ui/components/modals/ConfirmModal.jsx.map +1 -0
- package/dist/ui/components/modals/EditorModal.d.ts +8 -0
- package/dist/ui/components/modals/EditorModal.d.ts.map +1 -0
- package/dist/ui/components/modals/EditorModal.jsx +23 -0
- package/dist/ui/components/modals/EditorModal.jsx.map +1 -0
- package/dist/ui/components/modals/InputModal.d.ts +8 -0
- package/dist/ui/components/modals/InputModal.d.ts.map +1 -0
- package/dist/ui/components/modals/InputModal.jsx +15 -0
- package/dist/ui/components/modals/InputModal.jsx.map +1 -0
- package/dist/ui/components/modals/ModalContainer.d.ts +8 -0
- package/dist/ui/components/modals/ModalContainer.d.ts.map +1 -0
- package/dist/ui/components/modals/ModalContainer.jsx +34 -0
- package/dist/ui/components/modals/ModalContainer.jsx.map +1 -0
- package/dist/ui/components/modals/SelectModal.d.ts +8 -0
- package/dist/ui/components/modals/SelectModal.d.ts.map +1 -0
- package/dist/ui/components/modals/SelectModal.jsx +32 -0
- package/dist/ui/components/modals/SelectModal.jsx.map +1 -0
- package/{src/ui/components/modals/index.ts → dist/ui/components/modals/index.d.ts} +5 -4
- package/dist/ui/components/modals/index.d.ts.map +1 -0
- package/dist/ui/components/modals/index.js +5 -0
- package/dist/ui/components/modals/index.js.map +1 -0
- package/dist/ui/features/composer/Composer.d.ts +16 -0
- package/dist/ui/features/composer/Composer.d.ts.map +1 -0
- package/dist/ui/features/composer/Composer.jsx +39 -0
- package/dist/ui/features/composer/Composer.jsx.map +1 -0
- package/dist/ui/features/composer/SlashCommandHandler.d.ts +14 -0
- package/dist/ui/features/composer/SlashCommandHandler.d.ts.map +1 -0
- package/dist/ui/features/composer/SlashCommandHandler.js +43 -0
- package/dist/ui/features/composer/SlashCommandHandler.js.map +1 -0
- package/dist/ui/features/composer/keyboard.d.ts +3 -0
- package/dist/ui/features/composer/keyboard.d.ts.map +1 -0
- package/dist/ui/features/composer/keyboard.js +3 -0
- package/dist/ui/features/composer/keyboard.js.map +1 -0
- package/dist/ui/features/main-view/MainView.d.ts +52 -0
- package/dist/ui/features/main-view/MainView.d.ts.map +1 -0
- package/dist/ui/features/main-view/MainView.jsx +269 -0
- package/dist/ui/features/main-view/MainView.jsx.map +1 -0
- package/dist/ui/features/message-pane/MessagePane.d.ts +15 -0
- package/dist/ui/features/message-pane/MessagePane.d.ts.map +1 -0
- package/dist/ui/features/message-pane/MessagePane.jsx +7 -0
- package/dist/ui/features/message-pane/MessagePane.jsx.map +1 -0
- package/dist/ui/hooks/useModals.d.ts +35 -0
- package/dist/ui/hooks/useModals.d.ts.map +1 -0
- package/dist/ui/hooks/useModals.js +36 -0
- package/dist/ui/hooks/useModals.js.map +1 -0
- package/dist/ui/state/app-store.d.ts +42 -0
- package/dist/ui/state/app-store.d.ts.map +1 -0
- package/dist/ui/state/app-store.js +28 -0
- package/dist/ui/state/app-store.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +3 -0
- package/dist/utils.js.map +1 -0
- package/package.json +19 -6
- package/src/adapters/acp/index.ts +0 -305
- package/src/adapters/acp/protocol.ts +0 -191
- package/src/adapters/acp/session.ts +0 -289
- package/src/adapters/acp/updates.ts +0 -96
- package/src/adapters/cli/headless.ts +0 -112
- package/src/adapters/cli/validate.ts +0 -50
- package/src/adapters/tui/app.tsx +0 -39
- package/src/agent-events.ts +0 -671
- package/src/args.ts +0 -102
- package/src/autocomplete-commands.ts +0 -102
- package/src/commands.ts +0 -23
- package/src/compact-handler.ts +0 -272
- package/src/components/Footer.tsx +0 -49
- package/src/components/Header.tsx +0 -218
- package/src/components/MessageList.tsx +0 -380
- package/src/config.ts +0 -1
- package/src/domain/commands/builtin/clear.ts +0 -14
- package/src/domain/commands/builtin/compact.ts +0 -96
- package/src/domain/commands/builtin/conceal.ts +0 -9
- package/src/domain/commands/builtin/diffwrap.ts +0 -9
- package/src/domain/commands/builtin/editor.ts +0 -24
- package/src/domain/commands/builtin/exit.ts +0 -14
- package/src/domain/commands/builtin/followup.ts +0 -24
- package/src/domain/commands/builtin/index.ts +0 -29
- package/src/domain/commands/builtin/login.ts +0 -118
- package/src/domain/commands/builtin/model.ts +0 -66
- package/src/domain/commands/builtin/status.ts +0 -32
- package/src/domain/commands/builtin/steer.ts +0 -24
- package/src/domain/commands/builtin/theme.ts +0 -23
- package/src/domain/commands/builtin/thinking.ts +0 -16
- package/src/domain/commands/helpers.ts +0 -41
- package/src/domain/commands/registry.ts +0 -42
- package/src/domain/commands/types.ts +0 -69
- package/src/domain/messaging/content.ts +0 -117
- package/src/editor.ts +0 -103
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useAgentEvents.ts +0 -28
- package/src/hooks/useEditorBridge.ts +0 -101
- package/src/hooks/useGitStatus.ts +0 -28
- package/src/hooks/usePromptQueue.ts +0 -7
- package/src/hooks/useSessionController.ts +0 -5
- package/src/hooks/useSpinner.ts +0 -28
- package/src/hooks/useToastManager.ts +0 -26
- package/src/index.ts +0 -188
- package/src/keyboard-handler.ts +0 -134
- package/src/profiler.ts +0 -40
- package/src/runtime/context.tsx +0 -16
- package/src/runtime/factory.ts +0 -63
- package/src/runtime/git/git-info.ts +0 -25
- package/src/runtime/session/session-controller.ts +0 -208
- package/src/session-manager.ts +0 -1
- package/src/session-picker.tsx +0 -134
- package/src/shell-runner.ts +0 -134
- package/src/syntax-highlighting.ts +0 -114
- package/src/theme-names.ts +0 -37
- package/src/tool-ui-contracts.ts +0 -77
- package/src/tui-open-rendering.tsx +0 -565
- package/src/types.ts +0 -89
- package/src/ui/app-shell/TuiApp.tsx +0 -586
- package/src/ui/clipboard/osc52.ts +0 -18
- package/src/ui/components/modals/ConfirmModal.tsx +0 -52
- package/src/ui/components/modals/EditorModal.tsx +0 -39
- package/src/ui/components/modals/InputModal.tsx +0 -30
- package/src/ui/components/modals/ModalContainer.tsx +0 -67
- package/src/ui/components/modals/SelectModal.tsx +0 -48
- package/src/ui/features/composer/Composer.tsx +0 -73
- package/src/ui/features/composer/SlashCommandHandler.ts +0 -58
- package/src/ui/features/composer/keyboard.ts +0 -3
- package/src/ui/features/main-view/MainView.tsx +0 -367
- package/src/ui/features/message-pane/MessagePane.tsx +0 -34
- package/src/ui/hooks/useModals.ts +0 -74
- package/src/ui/state/app-store.ts +0 -67
- package/src/utils.ts +0 -14
package/src/agent-events.ts
DELETED
|
@@ -1,671 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent event handler for TUI application
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { batch } from "solid-js"
|
|
6
|
-
import { profile } from "./profiler.js"
|
|
7
|
-
import type { AgentEvent, AppMessage } from "@yeshwanthyk/agent-core"
|
|
8
|
-
import type { AgentToolResult, AssistantMessage, ToolResultMessage } from "@yeshwanthyk/ai"
|
|
9
|
-
import type { Theme } from "@yeshwanthyk/open-tui"
|
|
10
|
-
import type { JSX } from "solid-js"
|
|
11
|
-
import type { SessionManager } from "./session-manager.js"
|
|
12
|
-
import type { UIMessage, UIAssistantMessage, ToolBlock, ActivityState, UIContentBlock } from "./types.js"
|
|
13
|
-
import {
|
|
14
|
-
appendWithCap,
|
|
15
|
-
buildThinkingSummary,
|
|
16
|
-
extractOrderedBlocks,
|
|
17
|
-
extractThinking,
|
|
18
|
-
extractText,
|
|
19
|
-
getEditDiffText,
|
|
20
|
-
getToolText,
|
|
21
|
-
} from "@domain/messaging/content.js"
|
|
22
|
-
import type { PromptQueue } from "./hooks/usePromptQueue.js"
|
|
23
|
-
import type { HookRunner } from "./hooks/index.js"
|
|
24
|
-
import type { RenderResultOptions } from "@yeshwanthyk/runtime-effect/extensibility/custom-tools/types.js"
|
|
25
|
-
|
|
26
|
-
/** Tool metadata for UI rendering */
|
|
27
|
-
export interface ToolMeta {
|
|
28
|
-
label: string
|
|
29
|
-
source: "builtin" | "custom"
|
|
30
|
-
sourcePath?: string
|
|
31
|
-
renderCall?: (args: any, theme: Theme) => JSX.Element
|
|
32
|
-
renderResult?: (result: AgentToolResult<any>, opts: RenderResultOptions, theme: Theme) => JSX.Element
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface EventHandlerContext {
|
|
36
|
-
// State setters
|
|
37
|
-
setMessages: (updater: (prev: UIMessage[]) => UIMessage[]) => void
|
|
38
|
-
setToolBlocks: (updater: (prev: ToolBlock[]) => ToolBlock[]) => void
|
|
39
|
-
setActivityState: (s: ActivityState) => void
|
|
40
|
-
setIsResponding: (v: boolean) => void
|
|
41
|
-
setContextTokens: (v: number) => void
|
|
42
|
-
setCacheStats: (v: { cacheRead: number; input: number } | null) => void
|
|
43
|
-
setRetryStatus: (v: string | null) => void
|
|
44
|
-
setTurnCount: (v: number) => void
|
|
45
|
-
|
|
46
|
-
// Queue management
|
|
47
|
-
promptQueue: PromptQueue
|
|
48
|
-
|
|
49
|
-
// Session management
|
|
50
|
-
sessionManager: SessionManager
|
|
51
|
-
|
|
52
|
-
// Streaming message tracking (mutable ref)
|
|
53
|
-
streamingMessageId: { current: string | null }
|
|
54
|
-
|
|
55
|
-
// Retry configuration
|
|
56
|
-
retryConfig: { enabled: boolean; maxRetries: number; baseDelayMs: number }
|
|
57
|
-
retryablePattern: RegExp
|
|
58
|
-
retryState: { attempt: number; abortController: AbortController | null }
|
|
59
|
-
|
|
60
|
-
// Agent reference for retry logic
|
|
61
|
-
agent: {
|
|
62
|
-
state: { messages: unknown[] }
|
|
63
|
-
replaceMessages: (messages: unknown[]) => void
|
|
64
|
-
continue: () => Promise<void>
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Hook runner for lifecycle events (optional for backwards compat)
|
|
68
|
-
hookRunner?: HookRunner
|
|
69
|
-
|
|
70
|
-
// Tool metadata registry for custom tool rendering
|
|
71
|
-
toolByName?: Map<string, ToolMeta>
|
|
72
|
-
|
|
73
|
-
// Context window getter for usage calculations
|
|
74
|
-
getContextWindow?: () => number
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export type AgentEventHandler = ((event: AgentEvent) => void) & { dispose: () => void }
|
|
78
|
-
|
|
79
|
-
const UPDATE_THROTTLE_MS = 150 // ~7fps during streaming - smoother perceived text flow
|
|
80
|
-
const UPDATE_THROTTLE_SLOW_MS = 180
|
|
81
|
-
const UPDATE_THROTTLE_SLOWEST_MS = 220
|
|
82
|
-
const TOOL_UPDATE_THROTTLE_MS = 50 // Throttle tool streaming updates
|
|
83
|
-
const STREAMING_TAIL_CHARS = 4000
|
|
84
|
-
|
|
85
|
-
function computeUpdateThrottleMs(textLength: number): number {
|
|
86
|
-
if (textLength > 12000) return UPDATE_THROTTLE_SLOWEST_MS
|
|
87
|
-
if (textLength > 6000) return UPDATE_THROTTLE_SLOW_MS
|
|
88
|
-
return UPDATE_THROTTLE_MS
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Incremental extraction cache - avoids re-parsing entire content array each update */
|
|
92
|
-
interface ExtractionCache {
|
|
93
|
-
// Track processed content length for incremental updates
|
|
94
|
-
lastContentLength: number
|
|
95
|
-
// Total streaming text length (full content, even if view is tailed)
|
|
96
|
-
textLength: number
|
|
97
|
-
// Tail of streaming text for display
|
|
98
|
-
textTail: string
|
|
99
|
-
thinking: { summary: string; preview: string; full: string } | null
|
|
100
|
-
contentBlocks: UIContentBlock[]
|
|
101
|
-
// For thinking block ID generation
|
|
102
|
-
thinkingCounter: number
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function createExtractionCache(): ExtractionCache {
|
|
106
|
-
return {
|
|
107
|
-
lastContentLength: 0,
|
|
108
|
-
textLength: 0,
|
|
109
|
-
textTail: "",
|
|
110
|
-
thinking: null,
|
|
111
|
-
contentBlocks: [],
|
|
112
|
-
thinkingCounter: 0,
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function appendStreamingTail(current: string, next: string): string {
|
|
117
|
-
if (next.length >= STREAMING_TAIL_CHARS) return next.slice(-STREAMING_TAIL_CHARS)
|
|
118
|
-
if (current.length + next.length <= STREAMING_TAIL_CHARS) return current + next
|
|
119
|
-
return (current + next).slice(-STREAMING_TAIL_CHARS)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** Incrementally extract new content blocks, appending to cached results */
|
|
123
|
-
function extractIncremental(content: unknown[], cache: ExtractionCache): ExtractionCache {
|
|
124
|
-
const len = content.length
|
|
125
|
-
if (len === cache.lastContentLength) return cache // No change
|
|
126
|
-
|
|
127
|
-
// Process only new blocks
|
|
128
|
-
let textLength = cache.textLength
|
|
129
|
-
let textTail = cache.textTail
|
|
130
|
-
let thinking = cache.thinking
|
|
131
|
-
const contentBlocks = cache.contentBlocks
|
|
132
|
-
let thinkingCounter = cache.thinkingCounter
|
|
133
|
-
|
|
134
|
-
for (let i = cache.lastContentLength; i < len; i++) {
|
|
135
|
-
const block = content[i]
|
|
136
|
-
if (typeof block !== "object" || block === null) continue
|
|
137
|
-
const b = block as Record<string, unknown>
|
|
138
|
-
|
|
139
|
-
if (b.type === "text" && typeof b.text === "string") {
|
|
140
|
-
textLength += b.text.length
|
|
141
|
-
textTail = appendStreamingTail(textTail, b.text)
|
|
142
|
-
// Merge with last text block or add new
|
|
143
|
-
const lastBlock = contentBlocks[contentBlocks.length - 1]
|
|
144
|
-
if (lastBlock?.type === "text") {
|
|
145
|
-
lastBlock.text = appendStreamingTail(lastBlock.text, b.text)
|
|
146
|
-
} else {
|
|
147
|
-
contentBlocks.push({ type: "text", text: appendStreamingTail("", b.text) })
|
|
148
|
-
}
|
|
149
|
-
} else if (b.type === "thinking" && typeof b.thinking === "string") {
|
|
150
|
-
const full = b.thinking
|
|
151
|
-
const { summary, preview } = buildThinkingSummary(full)
|
|
152
|
-
thinking = { summary, preview, full }
|
|
153
|
-
contentBlocks.push({ type: "thinking", id: `thinking-${thinkingCounter++}`, summary, preview, full })
|
|
154
|
-
} else if (b.type === "toolCall" && typeof b.id === "string" && typeof b.name === "string") {
|
|
155
|
-
contentBlocks.push({
|
|
156
|
-
type: "tool",
|
|
157
|
-
tool: { id: b.id, name: b.name, args: b.arguments ?? {}, isError: false, isComplete: false },
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return { lastContentLength: len, textLength, textTail, thinking, contentBlocks, thinkingCounter }
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export function createAgentEventHandler(ctx: EventHandlerContext): AgentEventHandler {
|
|
166
|
-
let pendingUpdate: Extract<AgentEvent, { type: "message_update" }> | null = null
|
|
167
|
-
let updateTimeout: ReturnType<typeof setTimeout> | null = null
|
|
168
|
-
let disposed = false
|
|
169
|
-
let turnIndex = 0
|
|
170
|
-
|
|
171
|
-
// Incremental extraction cache - reset on new message
|
|
172
|
-
let extractionCache = createExtractionCache()
|
|
173
|
-
|
|
174
|
-
// Tool update throttling - track pending updates per tool
|
|
175
|
-
const pendingToolUpdates = new Map<string, Extract<AgentEvent, { type: "tool_execution_update" }>>()
|
|
176
|
-
let toolUpdateTimeout: ReturnType<typeof setTimeout> | null = null
|
|
177
|
-
|
|
178
|
-
const dispose = () => {
|
|
179
|
-
disposed = true
|
|
180
|
-
pendingUpdate = null
|
|
181
|
-
pendingToolUpdates.clear()
|
|
182
|
-
extractionCache = createExtractionCache()
|
|
183
|
-
if (updateTimeout) clearTimeout(updateTimeout)
|
|
184
|
-
if (toolUpdateTimeout) clearTimeout(toolUpdateTimeout)
|
|
185
|
-
updateTimeout = null
|
|
186
|
-
toolUpdateTimeout = null
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// Inline update handler - accesses extractionCache from closure
|
|
190
|
-
const handleMessageUpdate = (ev: Extract<AgentEvent, { type: "message_update" }>) =>
|
|
191
|
-
profile("stream_message_update", () => {
|
|
192
|
-
const content = ev.message.content as unknown[]
|
|
193
|
-
|
|
194
|
-
// Use incremental extraction - only processes new blocks
|
|
195
|
-
extractionCache = extractIncremental(content, extractionCache)
|
|
196
|
-
const { textLength, textTail, thinking, contentBlocks } = extractionCache
|
|
197
|
-
updateThrottleMs = computeUpdateThrottleMs(textLength)
|
|
198
|
-
|
|
199
|
-
updateStreamingMessage(ctx, (msg) => {
|
|
200
|
-
const nextThinking = thinking || msg.thinking
|
|
201
|
-
return { ...msg, content: textTail, thinking: nextThinking, contentBlocks }
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
if (thinking && textLength === 0) ctx.setActivityState("thinking")
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
const flushPendingUpdate = () => {
|
|
208
|
-
if (!pendingUpdate) return
|
|
209
|
-
const event = pendingUpdate
|
|
210
|
-
pendingUpdate = null
|
|
211
|
-
handleMessageUpdate(event)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
let updateThrottleMs = UPDATE_THROTTLE_MS
|
|
215
|
-
|
|
216
|
-
const scheduleUpdate = () => {
|
|
217
|
-
if (updateTimeout) return
|
|
218
|
-
updateTimeout = setTimeout(() => {
|
|
219
|
-
updateTimeout = null
|
|
220
|
-
if (disposed) return
|
|
221
|
-
flushPendingUpdate()
|
|
222
|
-
}, updateThrottleMs)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const flushToolUpdates = () => {
|
|
226
|
-
if (pendingToolUpdates.size === 0) return
|
|
227
|
-
for (const event of pendingToolUpdates.values()) {
|
|
228
|
-
handleToolUpdateImmediate(event, ctx)
|
|
229
|
-
}
|
|
230
|
-
pendingToolUpdates.clear()
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const scheduleToolUpdate = () => {
|
|
234
|
-
if (toolUpdateTimeout) return
|
|
235
|
-
toolUpdateTimeout = setTimeout(() => {
|
|
236
|
-
toolUpdateTimeout = null
|
|
237
|
-
if (disposed) return
|
|
238
|
-
flushToolUpdates()
|
|
239
|
-
}, TOOL_UPDATE_THROTTLE_MS)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const handler = ((event: AgentEvent) => {
|
|
243
|
-
if (disposed) return
|
|
244
|
-
|
|
245
|
-
// Emit hook events for agent lifecycle (fire-and-forget)
|
|
246
|
-
if (event.type === "agent_start") {
|
|
247
|
-
turnIndex = 0
|
|
248
|
-
ctx.setTurnCount(0) // Reset turn count for new agent run
|
|
249
|
-
extractionCache = createExtractionCache() // Reset for new agent run
|
|
250
|
-
void ctx.hookRunner?.emit({
|
|
251
|
-
type: "agent.start",
|
|
252
|
-
sessionId: ctx.sessionManager.sessionId,
|
|
253
|
-
})
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (event.type === "turn_start") {
|
|
257
|
-
ctx.setTurnCount(turnIndex + 1) // Update UI with current turn (1-indexed for display)
|
|
258
|
-
void ctx.hookRunner?.emit({
|
|
259
|
-
type: "turn.start",
|
|
260
|
-
sessionId: ctx.sessionManager.sessionId,
|
|
261
|
-
turnIndex,
|
|
262
|
-
})
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (event.type === "turn_end") {
|
|
266
|
-
// Extract usage from message for hook consumption
|
|
267
|
-
const msgUsage = event.message as { usage?: { inputTokens?: number; outputTokens?: number; totalTokens?: number; cacheReadInputTokens?: number; cacheCreationInputTokens?: number } }
|
|
268
|
-
const contextWindow = ctx.getContextWindow?.() ?? 0
|
|
269
|
-
const currentTokens = msgUsage.usage?.totalTokens ?? 0
|
|
270
|
-
|
|
271
|
-
const tokens = {
|
|
272
|
-
input: msgUsage.usage?.inputTokens ?? 0,
|
|
273
|
-
output: msgUsage.usage?.outputTokens ?? 0,
|
|
274
|
-
cacheRead: msgUsage.usage?.cacheReadInputTokens,
|
|
275
|
-
cacheWrite: msgUsage.usage?.cacheCreationInputTokens,
|
|
276
|
-
total: currentTokens,
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Update hook runner with token usage for session context
|
|
280
|
-
ctx.hookRunner?.updateTokenUsage(tokens, contextWindow)
|
|
281
|
-
|
|
282
|
-
void ctx.hookRunner?.emit({
|
|
283
|
-
type: "turn.end",
|
|
284
|
-
sessionId: ctx.sessionManager.sessionId,
|
|
285
|
-
turnIndex,
|
|
286
|
-
message: event.message,
|
|
287
|
-
toolResults: event.toolResults as ToolResultMessage[],
|
|
288
|
-
tokens,
|
|
289
|
-
contextLimit: contextWindow,
|
|
290
|
-
usage: contextWindow > 0 && currentTokens > 0
|
|
291
|
-
? { current: currentTokens, max: contextWindow, percent: (currentTokens / contextWindow) * 100 }
|
|
292
|
-
: undefined,
|
|
293
|
-
})
|
|
294
|
-
turnIndex++
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (event.type === "message_start") {
|
|
298
|
-
handleMessageStart(event, ctx, { current: extractionCache, set: (c) => { extractionCache = c } })
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (event.type === "message_update" && event.message.role === "assistant") {
|
|
302
|
-
pendingUpdate = event
|
|
303
|
-
scheduleUpdate()
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (event.type === "message_end" && event.message.role === "assistant") {
|
|
307
|
-
pendingUpdate = null
|
|
308
|
-
handleMessageEnd(event, ctx)
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
if (event.type === "message_end" && event.message.role === "toolResult") {
|
|
312
|
-
// Persist tool results so sessions can be resumed with tool output context.
|
|
313
|
-
ctx.sessionManager.appendMessage(event.message as AppMessage)
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (event.type === "tool_execution_start") {
|
|
317
|
-
handleToolStart(event, ctx)
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
if (event.type === "tool_execution_update") {
|
|
321
|
-
// Throttle tool updates - coalesce per tool
|
|
322
|
-
pendingToolUpdates.set(event.toolCallId, event)
|
|
323
|
-
scheduleToolUpdate()
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (event.type === "tool_execution_end") {
|
|
327
|
-
// Clear any pending throttled update for this tool
|
|
328
|
-
pendingToolUpdates.delete(event.toolCallId)
|
|
329
|
-
handleToolEnd(event, ctx)
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (event.type === "turn_end") {
|
|
333
|
-
ctx.streamingMessageId.current = null
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
if (event.type === "agent_end") {
|
|
337
|
-
handleAgentEnd(event, ctx)
|
|
338
|
-
}
|
|
339
|
-
}) as AgentEventHandler
|
|
340
|
-
|
|
341
|
-
handler.dispose = dispose
|
|
342
|
-
return handler
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
function updateStreamingMessage(ctx: EventHandlerContext, updater: (msg: UIAssistantMessage) => UIAssistantMessage): void {
|
|
346
|
-
const streamingId = ctx.streamingMessageId.current
|
|
347
|
-
if (!streamingId) return
|
|
348
|
-
|
|
349
|
-
ctx.setMessages((prev) => {
|
|
350
|
-
if (prev.length === 0) return prev
|
|
351
|
-
|
|
352
|
-
const lastIdx = prev.length - 1
|
|
353
|
-
const last = prev[lastIdx]
|
|
354
|
-
if (last?.id === streamingId && last.role === "assistant") {
|
|
355
|
-
const nextLast = updater(last)
|
|
356
|
-
if (nextLast === last) return prev
|
|
357
|
-
const next = prev.slice()
|
|
358
|
-
next[lastIdx] = nextLast
|
|
359
|
-
return next
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const idx = prev.findIndex((m) => m.id === streamingId)
|
|
363
|
-
if (idx === -1) return prev
|
|
364
|
-
|
|
365
|
-
const current = prev[idx]!
|
|
366
|
-
if (current.role !== "assistant") return prev
|
|
367
|
-
const updated = updater(current)
|
|
368
|
-
if (updated === current) return prev
|
|
369
|
-
|
|
370
|
-
const next = prev.slice()
|
|
371
|
-
next[idx] = updated
|
|
372
|
-
return next
|
|
373
|
-
})
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function handleMessageStart(
|
|
377
|
-
event: Extract<AgentEvent, { type: "message_start" }>,
|
|
378
|
-
ctx: EventHandlerContext,
|
|
379
|
-
cache: { current: ExtractionCache; set: (c: ExtractionCache) => void }
|
|
380
|
-
): void {
|
|
381
|
-
// Handle queued user message being processed
|
|
382
|
-
if (event.message.role === "user") {
|
|
383
|
-
const text = typeof event.message.content === "string"
|
|
384
|
-
? event.message.content
|
|
385
|
-
: extractText(event.message.content as unknown[])
|
|
386
|
-
|
|
387
|
-
// Only consume from queue if this message matches the queued text
|
|
388
|
-
const peeked = ctx.promptQueue.peek()
|
|
389
|
-
if (peeked !== undefined && peeked.text === text) {
|
|
390
|
-
ctx.promptQueue.shift() // consume the matched message
|
|
391
|
-
ctx.sessionManager.appendMessage(event.message as AppMessage)
|
|
392
|
-
ctx.setMessages((prev) => appendWithCap(prev, { id: crypto.randomUUID(), role: "user", content: text, timestamp: Date.now() }))
|
|
393
|
-
ctx.setActivityState("thinking")
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Create streaming assistant message
|
|
398
|
-
if (event.message.role === "assistant") {
|
|
399
|
-
ctx.streamingMessageId.current = crypto.randomUUID()
|
|
400
|
-
cache.current = createExtractionCache() // Reset cache for new message
|
|
401
|
-
batch(() => {
|
|
402
|
-
ctx.setActivityState("streaming")
|
|
403
|
-
ctx.setMessages((prev) => appendWithCap(prev, {
|
|
404
|
-
id: ctx.streamingMessageId.current!,
|
|
405
|
-
role: "assistant",
|
|
406
|
-
content: "",
|
|
407
|
-
isStreaming: true,
|
|
408
|
-
tools: [],
|
|
409
|
-
timestamp: Date.now(),
|
|
410
|
-
}))
|
|
411
|
-
})
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
function handleMessageEnd(
|
|
416
|
-
event: Extract<AgentEvent, { type: "message_end" }>,
|
|
417
|
-
ctx: EventHandlerContext
|
|
418
|
-
): void {
|
|
419
|
-
const content = event.message.content as unknown[]
|
|
420
|
-
const text = extractText(content)
|
|
421
|
-
const thinking = extractThinking(content)
|
|
422
|
-
const orderedBlocks = extractOrderedBlocks(content)
|
|
423
|
-
|
|
424
|
-
// Convert ordered blocks to UIContentBlocks, preserving order
|
|
425
|
-
const contentBlocks: UIContentBlock[] = orderedBlocks.map((block) => {
|
|
426
|
-
if (block.type === "thinking") {
|
|
427
|
-
return { type: "thinking" as const, id: block.id, summary: block.summary, preview: block.preview, full: block.full }
|
|
428
|
-
} else if (block.type === "text") {
|
|
429
|
-
return { type: "text" as const, text: block.text }
|
|
430
|
-
} else {
|
|
431
|
-
// toolCall - create a stub tool block (will be updated by handleToolEnd)
|
|
432
|
-
return {
|
|
433
|
-
type: "tool" as const,
|
|
434
|
-
tool: { id: block.id, name: block.name, args: block.args, isError: false, isComplete: false },
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
})
|
|
438
|
-
|
|
439
|
-
updateStreamingMessage(ctx, (msg) => {
|
|
440
|
-
const nextThinking = thinking || msg.thinking
|
|
441
|
-
return { ...msg, content: text, thinking: nextThinking, contentBlocks, isStreaming: false }
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
ctx.streamingMessageId.current = null
|
|
445
|
-
|
|
446
|
-
// Save message to session
|
|
447
|
-
ctx.sessionManager.appendMessage(event.message as AppMessage)
|
|
448
|
-
|
|
449
|
-
// Update usage - context window budget includes input + output for the full request
|
|
450
|
-
// totalTokens is already computed by providers as: (uncached_input + cacheRead + cacheWrite) + output
|
|
451
|
-
// Only update if totalTokens > 0 to avoid clearing bar on aborted responses
|
|
452
|
-
const msg = event.message as { usage?: { totalTokens?: number; cacheRead?: number; input?: number } }
|
|
453
|
-
if (msg.usage?.totalTokens) {
|
|
454
|
-
ctx.setContextTokens(msg.usage.totalTokens)
|
|
455
|
-
}
|
|
456
|
-
// Update cache stats for efficiency indicator
|
|
457
|
-
if (msg.usage && typeof msg.usage.cacheRead === "number" && typeof msg.usage.input === "number") {
|
|
458
|
-
ctx.setCacheStats({ cacheRead: msg.usage.cacheRead, input: msg.usage.input })
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/** Update a tool in both tools array and contentBlocks */
|
|
463
|
-
function updateToolInContentBlocks(
|
|
464
|
-
contentBlocks: UIContentBlock[] | undefined,
|
|
465
|
-
toolId: string,
|
|
466
|
-
updater: (tool: ToolBlock) => ToolBlock
|
|
467
|
-
): UIContentBlock[] | undefined {
|
|
468
|
-
if (!contentBlocks) return undefined
|
|
469
|
-
for (let i = 0; i < contentBlocks.length; i++) {
|
|
470
|
-
const block = contentBlocks[i]
|
|
471
|
-
if (block.type !== "tool" || block.tool.id !== toolId) continue
|
|
472
|
-
const updated = updater(block.tool)
|
|
473
|
-
if (updated === block.tool) return contentBlocks
|
|
474
|
-
contentBlocks[i] = { ...block, tool: updated }
|
|
475
|
-
return contentBlocks
|
|
476
|
-
}
|
|
477
|
-
return contentBlocks
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
function updateToolById(
|
|
481
|
-
tools: ToolBlock[],
|
|
482
|
-
toolId: string,
|
|
483
|
-
updater: (tool: ToolBlock) => ToolBlock
|
|
484
|
-
): ToolBlock[] {
|
|
485
|
-
const idx = tools.findIndex((t) => t.id === toolId)
|
|
486
|
-
if (idx === -1) return tools
|
|
487
|
-
const current = tools[idx]
|
|
488
|
-
if (!current) return tools
|
|
489
|
-
const updated = updater(current)
|
|
490
|
-
if (updated === current) return tools
|
|
491
|
-
const next = tools.slice()
|
|
492
|
-
next[idx] = updated
|
|
493
|
-
return next
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
function handleToolStart(
|
|
497
|
-
event: Extract<AgentEvent, { type: "tool_execution_start" }>,
|
|
498
|
-
ctx: EventHandlerContext
|
|
499
|
-
): void {
|
|
500
|
-
ctx.setActivityState("tool")
|
|
501
|
-
|
|
502
|
-
// Attach tool metadata from registry if available
|
|
503
|
-
const meta = ctx.toolByName?.get(event.toolName)
|
|
504
|
-
|
|
505
|
-
const newTool: ToolBlock = {
|
|
506
|
-
id: event.toolCallId,
|
|
507
|
-
name: event.toolName,
|
|
508
|
-
args: event.args,
|
|
509
|
-
updateSeq: 0,
|
|
510
|
-
isError: false,
|
|
511
|
-
isComplete: false,
|
|
512
|
-
// Attach metadata for custom rendering
|
|
513
|
-
label: meta?.label,
|
|
514
|
-
source: meta?.source,
|
|
515
|
-
sourcePath: meta?.sourcePath,
|
|
516
|
-
renderCall: meta?.renderCall,
|
|
517
|
-
renderResult: meta?.renderResult,
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
updateStreamingMessage(ctx, (msg) => ({
|
|
521
|
-
...msg,
|
|
522
|
-
tools: [...(msg.tools || []), newTool],
|
|
523
|
-
// Update tool in contentBlocks if it exists there (as stub from message_end)
|
|
524
|
-
contentBlocks: updateToolInContentBlocks(msg.contentBlocks, event.toolCallId, () => newTool),
|
|
525
|
-
}))
|
|
526
|
-
|
|
527
|
-
ctx.setToolBlocks((prev) => [...prev, newTool])
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function handleToolUpdateImmediate(
|
|
531
|
-
event: Extract<AgentEvent, { type: "tool_execution_update" }>,
|
|
532
|
-
ctx: EventHandlerContext
|
|
533
|
-
): void {
|
|
534
|
-
const toolUpdater = (t: ToolBlock): ToolBlock => ({
|
|
535
|
-
...t,
|
|
536
|
-
updateSeq: (t.updateSeq ?? 0) + 1,
|
|
537
|
-
output: getToolText(event.partialResult),
|
|
538
|
-
result: event.partialResult,
|
|
539
|
-
})
|
|
540
|
-
const updateTools = (tools: ToolBlock[]) => updateToolById(tools, event.toolCallId, toolUpdater)
|
|
541
|
-
|
|
542
|
-
batch(() => {
|
|
543
|
-
ctx.setToolBlocks(updateTools)
|
|
544
|
-
updateStreamingMessage(ctx, (msg) => ({
|
|
545
|
-
...msg,
|
|
546
|
-
tools: updateTools(msg.tools || []),
|
|
547
|
-
contentBlocks: updateToolInContentBlocks(msg.contentBlocks, event.toolCallId, toolUpdater),
|
|
548
|
-
}))
|
|
549
|
-
})
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
function handleToolEnd(
|
|
553
|
-
event: Extract<AgentEvent, { type: "tool_execution_end" }>,
|
|
554
|
-
ctx: EventHandlerContext
|
|
555
|
-
): void {
|
|
556
|
-
const toolUpdater = (t: ToolBlock): ToolBlock => ({
|
|
557
|
-
...t,
|
|
558
|
-
output: getToolText(event.result),
|
|
559
|
-
editDiff: getEditDiffText(event.result) || undefined,
|
|
560
|
-
isError: event.isError,
|
|
561
|
-
isComplete: true,
|
|
562
|
-
result: event.result,
|
|
563
|
-
})
|
|
564
|
-
|
|
565
|
-
const updateTools = (tools: ToolBlock[]) => updateToolById(tools, event.toolCallId, toolUpdater)
|
|
566
|
-
ctx.setToolBlocks(updateTools)
|
|
567
|
-
|
|
568
|
-
// Update message containing this tool - find by tool ID since streamingMessageId
|
|
569
|
-
// may be null if message_end fired before tool_execution_end
|
|
570
|
-
ctx.setMessages((prev) => {
|
|
571
|
-
const idx = prev.findIndex(
|
|
572
|
-
(m) =>
|
|
573
|
-
m.role === "assistant" && (
|
|
574
|
-
m.tools?.some((t: ToolBlock) => t.id === event.toolCallId) ||
|
|
575
|
-
m.contentBlocks?.some((b: UIContentBlock) => b.type === "tool" && b.tool.id === event.toolCallId)
|
|
576
|
-
)
|
|
577
|
-
)
|
|
578
|
-
if (idx === -1) return prev
|
|
579
|
-
|
|
580
|
-
const msg = prev[idx]!
|
|
581
|
-
if (msg.role !== "assistant") return prev
|
|
582
|
-
const updated: UIAssistantMessage = {
|
|
583
|
-
...msg,
|
|
584
|
-
tools: updateTools(msg.tools || []),
|
|
585
|
-
contentBlocks: updateToolInContentBlocks(msg.contentBlocks, event.toolCallId, toolUpdater),
|
|
586
|
-
}
|
|
587
|
-
const next = prev.slice()
|
|
588
|
-
next[idx] = updated
|
|
589
|
-
return next
|
|
590
|
-
})
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
function handleAgentEnd(
|
|
594
|
-
event: Extract<AgentEvent, { type: "agent_end" }>,
|
|
595
|
-
ctx: EventHandlerContext
|
|
596
|
-
): void {
|
|
597
|
-
ctx.streamingMessageId.current = null
|
|
598
|
-
|
|
599
|
-
// Emit hook event - aggregate total tokens from all turns
|
|
600
|
-
const totalTokens = ctx.hookRunner?.getContext?.()?.session?.getTokenUsage?.() ?? { input: 0, output: 0, total: 0 }
|
|
601
|
-
const contextLimit = ctx.getContextWindow?.() ?? 0
|
|
602
|
-
void ctx.hookRunner?.emit({
|
|
603
|
-
type: "agent.end",
|
|
604
|
-
sessionId: ctx.sessionManager.sessionId,
|
|
605
|
-
messages: event.messages,
|
|
606
|
-
totalTokens,
|
|
607
|
-
contextLimit,
|
|
608
|
-
})
|
|
609
|
-
|
|
610
|
-
// Check for retryable error
|
|
611
|
-
const lastMsg = ctx.agent.state.messages[ctx.agent.state.messages.length - 1] as AssistantMessage | undefined
|
|
612
|
-
const errorMsg = lastMsg?.role === "assistant" && (lastMsg as AssistantMessage).errorMessage
|
|
613
|
-
const isRetryable = errorMsg && ctx.retryablePattern.test(errorMsg)
|
|
614
|
-
|
|
615
|
-
if (isRetryable && ctx.retryConfig.enabled && ctx.retryState.attempt < ctx.retryConfig.maxRetries) {
|
|
616
|
-
ctx.retryState.attempt++
|
|
617
|
-
const delay = ctx.retryConfig.baseDelayMs * Math.pow(2, ctx.retryState.attempt - 1)
|
|
618
|
-
ctx.setRetryStatus(`Retrying (${ctx.retryState.attempt}/${ctx.retryConfig.maxRetries}) in ${Math.round(delay / 1000)}s... (esc to cancel)`)
|
|
619
|
-
|
|
620
|
-
ctx.retryState.abortController = new AbortController()
|
|
621
|
-
const signal = ctx.retryState.abortController.signal
|
|
622
|
-
|
|
623
|
-
const sleep = (ms: number) =>
|
|
624
|
-
new Promise<void>((resolve, reject) => {
|
|
625
|
-
const timeout = setTimeout(resolve, ms)
|
|
626
|
-
signal.addEventListener(
|
|
627
|
-
"abort",
|
|
628
|
-
() => {
|
|
629
|
-
clearTimeout(timeout)
|
|
630
|
-
reject(new Error("cancelled"))
|
|
631
|
-
},
|
|
632
|
-
{ once: true }
|
|
633
|
-
)
|
|
634
|
-
})
|
|
635
|
-
|
|
636
|
-
sleep(delay)
|
|
637
|
-
.then(() => {
|
|
638
|
-
if (signal.aborted) return
|
|
639
|
-
ctx.setRetryStatus(null)
|
|
640
|
-
ctx.retryState.abortController = null
|
|
641
|
-
// Remove last error message and retry
|
|
642
|
-
ctx.agent.replaceMessages(ctx.agent.state.messages.slice(0, -1))
|
|
643
|
-
ctx.setActivityState("thinking")
|
|
644
|
-
void ctx.agent.continue().catch((err) => {
|
|
645
|
-
ctx.setActivityState("idle")
|
|
646
|
-
ctx.setIsResponding(false)
|
|
647
|
-
ctx.setMessages((prev) => [
|
|
648
|
-
...prev,
|
|
649
|
-
{
|
|
650
|
-
id: crypto.randomUUID(),
|
|
651
|
-
role: "assistant",
|
|
652
|
-
content: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
653
|
-
},
|
|
654
|
-
])
|
|
655
|
-
})
|
|
656
|
-
})
|
|
657
|
-
.catch(() => {
|
|
658
|
-
// Retry cancelled
|
|
659
|
-
ctx.setIsResponding(false)
|
|
660
|
-
ctx.setActivityState("idle")
|
|
661
|
-
})
|
|
662
|
-
return
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
ctx.retryState.attempt = 0
|
|
666
|
-
batch(() => {
|
|
667
|
-
ctx.setIsResponding(false)
|
|
668
|
-
ctx.setActivityState("idle")
|
|
669
|
-
ctx.setTurnCount(0) // Reset turn count when agent completes
|
|
670
|
-
})
|
|
671
|
-
}
|