@intentcomputing/koko-agent-sdk 1.0.1
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/CHANGELOG.md +10 -0
- package/CODE_OF_CONDUCT.md +3 -0
- package/CONTRIBUTING.md +9 -0
- package/LICENSE +21 -0
- package/README.md +65 -0
- package/README.zh-CN.md +50 -0
- package/SECURITY.md +5 -0
- package/android/build.gradle +40 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/cn/intentcomputing/kokoagentsdk/KokoAgentSdkModule.java +1356 -0
- package/android/src/main/java/cn/intentcomputing/kokoagentsdk/KokoAgentSdkPackage.java +23 -0
- package/docs/INTEGRATION.md +168 -0
- package/docs/INTEGRATION.zh-CN.md +140 -0
- package/docs/PRIVACY.md +11 -0
- package/docs/PRIVACY.zh-CN.md +11 -0
- package/docs/PUBLISH.md +11 -0
- package/docs/PUBLISH.zh-CN.md +11 -0
- package/ios/KokoAgentSdk/KokoAgentSdk.h +5 -0
- package/ios/KokoAgentSdk/KokoAgentSdk.m +2464 -0
- package/ios/KokoAgentSdk/KokoOcrBounds.h +20 -0
- package/ios/KokoAgentSdk/KokoScrollBounds.h +21 -0
- package/koko-agent-sdk.podspec +23 -0
- package/lib/commonjs/KokoAgent.js +1427 -0
- package/lib/commonjs/KokoAgent.js.map +1 -0
- package/lib/commonjs/assist/OnDeviceAssist.js +94 -0
- package/lib/commonjs/assist/OnDeviceAssist.js.map +1 -0
- package/lib/commonjs/assist/intentClassify.js +100 -0
- package/lib/commonjs/assist/intentClassify.js.map +1 -0
- package/lib/commonjs/assist/nodeRank.js +120 -0
- package/lib/commonjs/assist/nodeRank.js.map +1 -0
- package/lib/commonjs/assist/ocrTarget.js +135 -0
- package/lib/commonjs/assist/ocrTarget.js.map +1 -0
- package/lib/commonjs/assist/webVisualChange.js +29 -0
- package/lib/commonjs/assist/webVisualChange.js.map +1 -0
- package/lib/commonjs/client/ActionOutcomeUnknownError.js +28 -0
- package/lib/commonjs/client/ActionOutcomeUnknownError.js.map +1 -0
- package/lib/commonjs/client/AgentSession.js +858 -0
- package/lib/commonjs/client/AgentSession.js.map +1 -0
- package/lib/commonjs/client/GatewayClient.js +302 -0
- package/lib/commonjs/client/GatewayClient.js.map +1 -0
- package/lib/commonjs/client/OperationReplayGuard.js +62 -0
- package/lib/commonjs/client/OperationReplayGuard.js.map +1 -0
- package/lib/commonjs/client/RunCheckpoint.js +139 -0
- package/lib/commonjs/client/RunCheckpoint.js.map +1 -0
- package/lib/commonjs/client/loopDetect.js +184 -0
- package/lib/commonjs/client/loopDetect.js.map +1 -0
- package/lib/commonjs/client/recentSearch.js +50 -0
- package/lib/commonjs/client/recentSearch.js.map +1 -0
- package/lib/commonjs/client/walletChoiceGuard.js +18 -0
- package/lib/commonjs/client/walletChoiceGuard.js.map +1 -0
- package/lib/commonjs/client/webResultCategory.js +38 -0
- package/lib/commonjs/client/webResultCategory.js.map +1 -0
- package/lib/commonjs/commercial/AccountStore.js +78 -0
- package/lib/commonjs/commercial/AccountStore.js.map +1 -0
- package/lib/commonjs/commercial/AgentDebug.js +104 -0
- package/lib/commonjs/commercial/AgentDebug.js.map +1 -0
- package/lib/commonjs/commercial/ExecutionGuard.js +53 -0
- package/lib/commonjs/commercial/ExecutionGuard.js.map +1 -0
- package/lib/commonjs/commercial/UsageBus.js +42 -0
- package/lib/commonjs/commercial/UsageBus.js.map +1 -0
- package/lib/commonjs/commercial/branding.js +69 -0
- package/lib/commonjs/commercial/branding.js.map +1 -0
- package/lib/commonjs/commercial/devMode.js +52 -0
- package/lib/commonjs/commercial/devMode.js.map +1 -0
- package/lib/commonjs/commercial/trust.js +69 -0
- package/lib/commonjs/commercial/trust.js.map +1 -0
- package/lib/commonjs/confirmation/gate.js +62 -0
- package/lib/commonjs/confirmation/gate.js.map +1 -0
- package/lib/commonjs/cursor/CursorOverlay.js +141 -0
- package/lib/commonjs/cursor/CursorOverlay.js.map +1 -0
- package/lib/commonjs/cursor/PointerHand.js +51 -0
- package/lib/commonjs/cursor/PointerHand.js.map +1 -0
- package/lib/commonjs/cursor/controller.js +91 -0
- package/lib/commonjs/cursor/controller.js.map +1 -0
- package/lib/commonjs/cursor/pointer.js +49 -0
- package/lib/commonjs/cursor/pointer.js.map +1 -0
- package/lib/commonjs/debug/KokoRemoteSmoke.js +611 -0
- package/lib/commonjs/debug/KokoRemoteSmoke.js.map +1 -0
- package/lib/commonjs/explore/ExplorationGraph.js +418 -0
- package/lib/commonjs/explore/ExplorationGraph.js.map +1 -0
- package/lib/commonjs/explore/bootstrapExplore.js +59 -0
- package/lib/commonjs/explore/bootstrapExplore.js.map +1 -0
- package/lib/commonjs/host/HostActions.js +266 -0
- package/lib/commonjs/host/HostActions.js.map +1 -0
- package/lib/commonjs/i18n/index.js +169 -0
- package/lib/commonjs/i18n/index.js.map +1 -0
- package/lib/commonjs/i18n/runtimeMessages.js +184 -0
- package/lib/commonjs/i18n/runtimeMessages.js.map +1 -0
- package/lib/commonjs/index.js +640 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/native/NativeBridge.js +132 -0
- package/lib/commonjs/native/NativeBridge.js.map +1 -0
- package/lib/commonjs/native/navigationLabel.js +16 -0
- package/lib/commonjs/native/navigationLabel.js.map +1 -0
- package/lib/commonjs/native/normalizeViewTree.js +28 -0
- package/lib/commonjs/native/normalizeViewTree.js.map +1 -0
- package/lib/commonjs/native/pruneOffscreen.js +76 -0
- package/lib/commonjs/native/pruneOffscreen.js.map +1 -0
- package/lib/commonjs/native/scrollViewport.js +69 -0
- package/lib/commonjs/native/scrollViewport.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/privacy/redact.js +108 -0
- package/lib/commonjs/privacy/redact.js.map +1 -0
- package/lib/commonjs/privacy/screenEvidence.js +59 -0
- package/lib/commonjs/privacy/screenEvidence.js.map +1 -0
- package/lib/commonjs/privacy/screenModel.js +404 -0
- package/lib/commonjs/privacy/screenModel.js.map +1 -0
- package/lib/commonjs/privacy/sensitiveScreen.js +58 -0
- package/lib/commonjs/privacy/sensitiveScreen.js.map +1 -0
- package/lib/commonjs/privacy/userGate.js +213 -0
- package/lib/commonjs/privacy/userGate.js.map +1 -0
- package/lib/commonjs/protocol/actions.js +112 -0
- package/lib/commonjs/protocol/actions.js.map +1 -0
- package/lib/commonjs/provider/HostAppearanceStore.js +111 -0
- package/lib/commonjs/provider/HostAppearanceStore.js.map +1 -0
- package/lib/commonjs/provider/KokoProvider.js +81 -0
- package/lib/commonjs/provider/KokoProvider.js.map +1 -0
- package/lib/commonjs/provider/KokoUiContext.js +102 -0
- package/lib/commonjs/provider/KokoUiContext.js.map +1 -0
- package/lib/commonjs/selector/match.js +378 -0
- package/lib/commonjs/selector/match.js.map +1 -0
- package/lib/commonjs/task/TaskStore.js +361 -0
- package/lib/commonjs/task/TaskStore.js.map +1 -0
- package/lib/commonjs/task/types.js +2 -0
- package/lib/commonjs/task/types.js.map +1 -0
- package/lib/commonjs/task/useTaskStore.js +14 -0
- package/lib/commonjs/task/useTaskStore.js.map +1 -0
- package/lib/commonjs/types.js +2 -0
- package/lib/commonjs/types.js.map +1 -0
- package/lib/commonjs/ui/KokoChatSheet.js +885 -0
- package/lib/commonjs/ui/KokoChatSheet.js.map +1 -0
- package/lib/commonjs/ui/KokoComposer.js +161 -0
- package/lib/commonjs/ui/KokoComposer.js.map +1 -0
- package/lib/commonjs/ui/KokoDialogHost.js +254 -0
- package/lib/commonjs/ui/KokoDialogHost.js.map +1 -0
- package/lib/commonjs/ui/KokoEntryButton.js +81 -0
- package/lib/commonjs/ui/KokoEntryButton.js.map +1 -0
- package/lib/commonjs/ui/KokoObserver.js +522 -0
- package/lib/commonjs/ui/KokoObserver.js.map +1 -0
- package/lib/commonjs/ui/KokoOverlayLayer.js +45 -0
- package/lib/commonjs/ui/KokoOverlayLayer.js.map +1 -0
- package/lib/commonjs/ui/KokoSubtitle.js +95 -0
- package/lib/commonjs/ui/KokoSubtitle.js.map +1 -0
- package/lib/commonjs/ui/KokoTaskPanel.js +322 -0
- package/lib/commonjs/ui/KokoTaskPanel.js.map +1 -0
- package/lib/commonjs/ui/hostOverlay.js +126 -0
- package/lib/commonjs/ui/hostOverlay.js.map +1 -0
- package/lib/commonjs/ui/icons.js +132 -0
- package/lib/commonjs/ui/icons.js.map +1 -0
- package/lib/commonjs/ui/progressChrome.js +66 -0
- package/lib/commonjs/ui/progressChrome.js.map +1 -0
- package/lib/commonjs/ui/safeArea.js +96 -0
- package/lib/commonjs/ui/safeArea.js.map +1 -0
- package/lib/commonjs/ui/useOverlayOrigin.js +40 -0
- package/lib/commonjs/ui/useOverlayOrigin.js.map +1 -0
- package/lib/module/KokoAgent.js +1418 -0
- package/lib/module/KokoAgent.js.map +1 -0
- package/lib/module/assist/OnDeviceAssist.js +89 -0
- package/lib/module/assist/OnDeviceAssist.js.map +1 -0
- package/lib/module/assist/intentClassify.js +95 -0
- package/lib/module/assist/intentClassify.js.map +1 -0
- package/lib/module/assist/nodeRank.js +115 -0
- package/lib/module/assist/nodeRank.js.map +1 -0
- package/lib/module/assist/ocrTarget.js +123 -0
- package/lib/module/assist/ocrTarget.js.map +1 -0
- package/lib/module/assist/webVisualChange.js +24 -0
- package/lib/module/assist/webVisualChange.js.map +1 -0
- package/lib/module/client/ActionOutcomeUnknownError.js +23 -0
- package/lib/module/client/ActionOutcomeUnknownError.js.map +1 -0
- package/lib/module/client/AgentSession.js +854 -0
- package/lib/module/client/AgentSession.js.map +1 -0
- package/lib/module/client/GatewayClient.js +293 -0
- package/lib/module/client/GatewayClient.js.map +1 -0
- package/lib/module/client/OperationReplayGuard.js +58 -0
- package/lib/module/client/OperationReplayGuard.js.map +1 -0
- package/lib/module/client/RunCheckpoint.js +135 -0
- package/lib/module/client/RunCheckpoint.js.map +1 -0
- package/lib/module/client/loopDetect.js +177 -0
- package/lib/module/client/loopDetect.js.map +1 -0
- package/lib/module/client/recentSearch.js +46 -0
- package/lib/module/client/recentSearch.js.map +1 -0
- package/lib/module/client/walletChoiceGuard.js +14 -0
- package/lib/module/client/walletChoiceGuard.js.map +1 -0
- package/lib/module/client/webResultCategory.js +34 -0
- package/lib/module/client/webResultCategory.js.map +1 -0
- package/lib/module/commercial/AccountStore.js +75 -0
- package/lib/module/commercial/AccountStore.js.map +1 -0
- package/lib/module/commercial/AgentDebug.js +99 -0
- package/lib/module/commercial/AgentDebug.js.map +1 -0
- package/lib/module/commercial/ExecutionGuard.js +49 -0
- package/lib/module/commercial/ExecutionGuard.js.map +1 -0
- package/lib/module/commercial/UsageBus.js +38 -0
- package/lib/module/commercial/UsageBus.js.map +1 -0
- package/lib/module/commercial/branding.js +63 -0
- package/lib/module/commercial/branding.js.map +1 -0
- package/lib/module/commercial/devMode.js +45 -0
- package/lib/module/commercial/devMode.js.map +1 -0
- package/lib/module/commercial/trust.js +62 -0
- package/lib/module/commercial/trust.js.map +1 -0
- package/lib/module/confirmation/gate.js +54 -0
- package/lib/module/confirmation/gate.js.map +1 -0
- package/lib/module/cursor/CursorOverlay.js +136 -0
- package/lib/module/cursor/CursorOverlay.js.map +1 -0
- package/lib/module/cursor/PointerHand.js +47 -0
- package/lib/module/cursor/PointerHand.js.map +1 -0
- package/lib/module/cursor/controller.js +87 -0
- package/lib/module/cursor/controller.js.map +1 -0
- package/lib/module/cursor/pointer.js +45 -0
- package/lib/module/cursor/pointer.js.map +1 -0
- package/lib/module/debug/KokoRemoteSmoke.js +608 -0
- package/lib/module/debug/KokoRemoteSmoke.js.map +1 -0
- package/lib/module/explore/ExplorationGraph.js +406 -0
- package/lib/module/explore/ExplorationGraph.js.map +1 -0
- package/lib/module/explore/bootstrapExplore.js +55 -0
- package/lib/module/explore/bootstrapExplore.js.map +1 -0
- package/lib/module/host/HostActions.js +255 -0
- package/lib/module/host/HostActions.js.map +1 -0
- package/lib/module/i18n/index.js +159 -0
- package/lib/module/i18n/index.js.map +1 -0
- package/lib/module/i18n/runtimeMessages.js +180 -0
- package/lib/module/i18n/runtimeMessages.js.map +1 -0
- package/lib/module/index.js +44 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/native/NativeBridge.js +128 -0
- package/lib/module/native/NativeBridge.js.map +1 -0
- package/lib/module/native/navigationLabel.js +12 -0
- package/lib/module/native/navigationLabel.js.map +1 -0
- package/lib/module/native/normalizeViewTree.js +25 -0
- package/lib/module/native/normalizeViewTree.js.map +1 -0
- package/lib/module/native/pruneOffscreen.js +72 -0
- package/lib/module/native/pruneOffscreen.js.map +1 -0
- package/lib/module/native/scrollViewport.js +63 -0
- package/lib/module/native/scrollViewport.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/privacy/redact.js +103 -0
- package/lib/module/privacy/redact.js.map +1 -0
- package/lib/module/privacy/screenEvidence.js +50 -0
- package/lib/module/privacy/screenEvidence.js.map +1 -0
- package/lib/module/privacy/screenModel.js +397 -0
- package/lib/module/privacy/screenModel.js.map +1 -0
- package/lib/module/privacy/sensitiveScreen.js +52 -0
- package/lib/module/privacy/sensitiveScreen.js.map +1 -0
- package/lib/module/privacy/userGate.js +202 -0
- package/lib/module/privacy/userGate.js.map +1 -0
- package/lib/module/protocol/actions.js +108 -0
- package/lib/module/protocol/actions.js.map +1 -0
- package/lib/module/provider/HostAppearanceStore.js +101 -0
- package/lib/module/provider/HostAppearanceStore.js.map +1 -0
- package/lib/module/provider/KokoProvider.js +74 -0
- package/lib/module/provider/KokoProvider.js.map +1 -0
- package/lib/module/provider/KokoUiContext.js +96 -0
- package/lib/module/provider/KokoUiContext.js.map +1 -0
- package/lib/module/selector/match.js +366 -0
- package/lib/module/selector/match.js.map +1 -0
- package/lib/module/task/TaskStore.js +356 -0
- package/lib/module/task/TaskStore.js.map +1 -0
- package/lib/module/task/types.js +2 -0
- package/lib/module/task/types.js.map +1 -0
- package/lib/module/task/useTaskStore.js +10 -0
- package/lib/module/task/useTaskStore.js.map +1 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/ui/KokoChatSheet.js +879 -0
- package/lib/module/ui/KokoChatSheet.js.map +1 -0
- package/lib/module/ui/KokoComposer.js +155 -0
- package/lib/module/ui/KokoComposer.js.map +1 -0
- package/lib/module/ui/KokoDialogHost.js +247 -0
- package/lib/module/ui/KokoDialogHost.js.map +1 -0
- package/lib/module/ui/KokoEntryButton.js +74 -0
- package/lib/module/ui/KokoEntryButton.js.map +1 -0
- package/lib/module/ui/KokoObserver.js +516 -0
- package/lib/module/ui/KokoObserver.js.map +1 -0
- package/lib/module/ui/KokoOverlayLayer.js +39 -0
- package/lib/module/ui/KokoOverlayLayer.js.map +1 -0
- package/lib/module/ui/KokoSubtitle.js +90 -0
- package/lib/module/ui/KokoSubtitle.js.map +1 -0
- package/lib/module/ui/KokoTaskPanel.js +316 -0
- package/lib/module/ui/KokoTaskPanel.js.map +1 -0
- package/lib/module/ui/hostOverlay.js +120 -0
- package/lib/module/ui/hostOverlay.js.map +1 -0
- package/lib/module/ui/icons.js +124 -0
- package/lib/module/ui/icons.js.map +1 -0
- package/lib/module/ui/progressChrome.js +58 -0
- package/lib/module/ui/progressChrome.js.map +1 -0
- package/lib/module/ui/safeArea.js +92 -0
- package/lib/module/ui/safeArea.js.map +1 -0
- package/lib/module/ui/useOverlayOrigin.js +36 -0
- package/lib/module/ui/useOverlayOrigin.js.map +1 -0
- package/lib/typescript/commonjs/KokoAgent.d.ts +167 -0
- package/lib/typescript/commonjs/KokoAgent.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/OnDeviceAssist.d.ts +31 -0
- package/lib/typescript/commonjs/assist/OnDeviceAssist.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/intentClassify.d.ts +18 -0
- package/lib/typescript/commonjs/assist/intentClassify.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/nodeRank.d.ts +32 -0
- package/lib/typescript/commonjs/assist/nodeRank.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/ocrTarget.d.ts +25 -0
- package/lib/typescript/commonjs/assist/ocrTarget.d.ts.map +1 -0
- package/lib/typescript/commonjs/assist/webVisualChange.d.ts +6 -0
- package/lib/typescript/commonjs/assist/webVisualChange.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/ActionOutcomeUnknownError.d.ts +13 -0
- package/lib/typescript/commonjs/client/ActionOutcomeUnknownError.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/AgentSession.d.ts +56 -0
- package/lib/typescript/commonjs/client/AgentSession.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/GatewayClient.d.ts +149 -0
- package/lib/typescript/commonjs/client/GatewayClient.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/OperationReplayGuard.d.ts +13 -0
- package/lib/typescript/commonjs/client/OperationReplayGuard.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/RunCheckpoint.d.ts +57 -0
- package/lib/typescript/commonjs/client/RunCheckpoint.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/loopDetect.d.ts +15 -0
- package/lib/typescript/commonjs/client/loopDetect.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/recentSearch.d.ts +5 -0
- package/lib/typescript/commonjs/client/recentSearch.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/walletChoiceGuard.d.ts +4 -0
- package/lib/typescript/commonjs/client/walletChoiceGuard.d.ts.map +1 -0
- package/lib/typescript/commonjs/client/webResultCategory.d.ts +5 -0
- package/lib/typescript/commonjs/client/webResultCategory.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/AccountStore.d.ts +17 -0
- package/lib/typescript/commonjs/commercial/AccountStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/AgentDebug.d.ts +25 -0
- package/lib/typescript/commonjs/commercial/AgentDebug.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/ExecutionGuard.d.ts +18 -0
- package/lib/typescript/commonjs/commercial/ExecutionGuard.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/UsageBus.d.ts +18 -0
- package/lib/typescript/commonjs/commercial/UsageBus.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/branding.d.ts +25 -0
- package/lib/typescript/commonjs/commercial/branding.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/devMode.d.ts +26 -0
- package/lib/typescript/commonjs/commercial/devMode.d.ts.map +1 -0
- package/lib/typescript/commonjs/commercial/trust.d.ts +21 -0
- package/lib/typescript/commonjs/commercial/trust.d.ts.map +1 -0
- package/lib/typescript/commonjs/confirmation/gate.d.ts +18 -0
- package/lib/typescript/commonjs/confirmation/gate.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/CursorOverlay.d.ts +13 -0
- package/lib/typescript/commonjs/cursor/CursorOverlay.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/PointerHand.d.ts +16 -0
- package/lib/typescript/commonjs/cursor/PointerHand.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/controller.d.ts +30 -0
- package/lib/typescript/commonjs/cursor/controller.d.ts.map +1 -0
- package/lib/typescript/commonjs/cursor/pointer.d.ts +23 -0
- package/lib/typescript/commonjs/cursor/pointer.d.ts.map +1 -0
- package/lib/typescript/commonjs/debug/KokoRemoteSmoke.d.ts +96 -0
- package/lib/typescript/commonjs/debug/KokoRemoteSmoke.d.ts.map +1 -0
- package/lib/typescript/commonjs/explore/ExplorationGraph.d.ts +96 -0
- package/lib/typescript/commonjs/explore/ExplorationGraph.d.ts.map +1 -0
- package/lib/typescript/commonjs/explore/bootstrapExplore.d.ts +40 -0
- package/lib/typescript/commonjs/explore/bootstrapExplore.d.ts.map +1 -0
- package/lib/typescript/commonjs/host/HostActions.d.ts +101 -0
- package/lib/typescript/commonjs/host/HostActions.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/index.d.ts +20 -0
- package/lib/typescript/commonjs/i18n/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/runtimeMessages.d.ts +178 -0
- package/lib/typescript/commonjs/i18n/runtimeMessages.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +66 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/NativeBridge.d.ts +70 -0
- package/lib/typescript/commonjs/native/NativeBridge.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/navigationLabel.d.ts +4 -0
- package/lib/typescript/commonjs/native/navigationLabel.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/normalizeViewTree.d.ts +4 -0
- package/lib/typescript/commonjs/native/normalizeViewTree.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/pruneOffscreen.d.ts +3 -0
- package/lib/typescript/commonjs/native/pruneOffscreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/native/scrollViewport.d.ts +13 -0
- package/lib/typescript/commonjs/native/scrollViewport.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/privacy/redact.d.ts +9 -0
- package/lib/typescript/commonjs/privacy/redact.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/screenEvidence.d.ts +14 -0
- package/lib/typescript/commonjs/privacy/screenEvidence.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/screenModel.d.ts +26 -0
- package/lib/typescript/commonjs/privacy/screenModel.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/sensitiveScreen.d.ts +8 -0
- package/lib/typescript/commonjs/privacy/sensitiveScreen.d.ts.map +1 -0
- package/lib/typescript/commonjs/privacy/userGate.d.ts +58 -0
- package/lib/typescript/commonjs/privacy/userGate.d.ts.map +1 -0
- package/lib/typescript/commonjs/protocol/actions.d.ts +7 -0
- package/lib/typescript/commonjs/protocol/actions.d.ts.map +1 -0
- package/lib/typescript/commonjs/provider/HostAppearanceStore.d.ts +64 -0
- package/lib/typescript/commonjs/provider/HostAppearanceStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/provider/KokoProvider.d.ts +39 -0
- package/lib/typescript/commonjs/provider/KokoProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/provider/KokoUiContext.d.ts +22 -0
- package/lib/typescript/commonjs/provider/KokoUiContext.d.ts.map +1 -0
- package/lib/typescript/commonjs/selector/match.d.ts +27 -0
- package/lib/typescript/commonjs/selector/match.d.ts.map +1 -0
- package/lib/typescript/commonjs/task/TaskStore.d.ts +65 -0
- package/lib/typescript/commonjs/task/TaskStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/task/types.d.ts +66 -0
- package/lib/typescript/commonjs/task/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/task/useTaskStore.d.ts +3 -0
- package/lib/typescript/commonjs/task/useTaskStore.d.ts.map +1 -0
- package/lib/typescript/commonjs/types.d.ts +372 -0
- package/lib/typescript/commonjs/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoChatSheet.d.ts +8 -0
- package/lib/typescript/commonjs/ui/KokoChatSheet.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoComposer.d.ts +13 -0
- package/lib/typescript/commonjs/ui/KokoComposer.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoDialogHost.d.ts +32 -0
- package/lib/typescript/commonjs/ui/KokoDialogHost.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoEntryButton.d.ts +18 -0
- package/lib/typescript/commonjs/ui/KokoEntryButton.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoObserver.d.ts +13 -0
- package/lib/typescript/commonjs/ui/KokoObserver.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoOverlayLayer.d.ts +35 -0
- package/lib/typescript/commonjs/ui/KokoOverlayLayer.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoSubtitle.d.ts +7 -0
- package/lib/typescript/commonjs/ui/KokoSubtitle.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/KokoTaskPanel.d.ts +7 -0
- package/lib/typescript/commonjs/ui/KokoTaskPanel.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hostOverlay.d.ts +28 -0
- package/lib/typescript/commonjs/ui/hostOverlay.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/icons.d.ts +26 -0
- package/lib/typescript/commonjs/ui/icons.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/progressChrome.d.ts +21 -0
- package/lib/typescript/commonjs/ui/progressChrome.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/safeArea.d.ts +12 -0
- package/lib/typescript/commonjs/ui/safeArea.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/useOverlayOrigin.d.ts +22 -0
- package/lib/typescript/commonjs/ui/useOverlayOrigin.d.ts.map +1 -0
- package/lib/typescript/module/KokoAgent.d.ts +167 -0
- package/lib/typescript/module/KokoAgent.d.ts.map +1 -0
- package/lib/typescript/module/assist/OnDeviceAssist.d.ts +31 -0
- package/lib/typescript/module/assist/OnDeviceAssist.d.ts.map +1 -0
- package/lib/typescript/module/assist/intentClassify.d.ts +18 -0
- package/lib/typescript/module/assist/intentClassify.d.ts.map +1 -0
- package/lib/typescript/module/assist/nodeRank.d.ts +32 -0
- package/lib/typescript/module/assist/nodeRank.d.ts.map +1 -0
- package/lib/typescript/module/assist/ocrTarget.d.ts +25 -0
- package/lib/typescript/module/assist/ocrTarget.d.ts.map +1 -0
- package/lib/typescript/module/assist/webVisualChange.d.ts +6 -0
- package/lib/typescript/module/assist/webVisualChange.d.ts.map +1 -0
- package/lib/typescript/module/client/ActionOutcomeUnknownError.d.ts +13 -0
- package/lib/typescript/module/client/ActionOutcomeUnknownError.d.ts.map +1 -0
- package/lib/typescript/module/client/AgentSession.d.ts +56 -0
- package/lib/typescript/module/client/AgentSession.d.ts.map +1 -0
- package/lib/typescript/module/client/GatewayClient.d.ts +149 -0
- package/lib/typescript/module/client/GatewayClient.d.ts.map +1 -0
- package/lib/typescript/module/client/OperationReplayGuard.d.ts +13 -0
- package/lib/typescript/module/client/OperationReplayGuard.d.ts.map +1 -0
- package/lib/typescript/module/client/RunCheckpoint.d.ts +57 -0
- package/lib/typescript/module/client/RunCheckpoint.d.ts.map +1 -0
- package/lib/typescript/module/client/loopDetect.d.ts +15 -0
- package/lib/typescript/module/client/loopDetect.d.ts.map +1 -0
- package/lib/typescript/module/client/recentSearch.d.ts +5 -0
- package/lib/typescript/module/client/recentSearch.d.ts.map +1 -0
- package/lib/typescript/module/client/walletChoiceGuard.d.ts +4 -0
- package/lib/typescript/module/client/walletChoiceGuard.d.ts.map +1 -0
- package/lib/typescript/module/client/webResultCategory.d.ts +5 -0
- package/lib/typescript/module/client/webResultCategory.d.ts.map +1 -0
- package/lib/typescript/module/commercial/AccountStore.d.ts +17 -0
- package/lib/typescript/module/commercial/AccountStore.d.ts.map +1 -0
- package/lib/typescript/module/commercial/AgentDebug.d.ts +25 -0
- package/lib/typescript/module/commercial/AgentDebug.d.ts.map +1 -0
- package/lib/typescript/module/commercial/ExecutionGuard.d.ts +18 -0
- package/lib/typescript/module/commercial/ExecutionGuard.d.ts.map +1 -0
- package/lib/typescript/module/commercial/UsageBus.d.ts +18 -0
- package/lib/typescript/module/commercial/UsageBus.d.ts.map +1 -0
- package/lib/typescript/module/commercial/branding.d.ts +25 -0
- package/lib/typescript/module/commercial/branding.d.ts.map +1 -0
- package/lib/typescript/module/commercial/devMode.d.ts +26 -0
- package/lib/typescript/module/commercial/devMode.d.ts.map +1 -0
- package/lib/typescript/module/commercial/trust.d.ts +21 -0
- package/lib/typescript/module/commercial/trust.d.ts.map +1 -0
- package/lib/typescript/module/confirmation/gate.d.ts +18 -0
- package/lib/typescript/module/confirmation/gate.d.ts.map +1 -0
- package/lib/typescript/module/cursor/CursorOverlay.d.ts +13 -0
- package/lib/typescript/module/cursor/CursorOverlay.d.ts.map +1 -0
- package/lib/typescript/module/cursor/PointerHand.d.ts +16 -0
- package/lib/typescript/module/cursor/PointerHand.d.ts.map +1 -0
- package/lib/typescript/module/cursor/controller.d.ts +30 -0
- package/lib/typescript/module/cursor/controller.d.ts.map +1 -0
- package/lib/typescript/module/cursor/pointer.d.ts +23 -0
- package/lib/typescript/module/cursor/pointer.d.ts.map +1 -0
- package/lib/typescript/module/debug/KokoRemoteSmoke.d.ts +96 -0
- package/lib/typescript/module/debug/KokoRemoteSmoke.d.ts.map +1 -0
- package/lib/typescript/module/explore/ExplorationGraph.d.ts +96 -0
- package/lib/typescript/module/explore/ExplorationGraph.d.ts.map +1 -0
- package/lib/typescript/module/explore/bootstrapExplore.d.ts +40 -0
- package/lib/typescript/module/explore/bootstrapExplore.d.ts.map +1 -0
- package/lib/typescript/module/host/HostActions.d.ts +101 -0
- package/lib/typescript/module/host/HostActions.d.ts.map +1 -0
- package/lib/typescript/module/i18n/index.d.ts +20 -0
- package/lib/typescript/module/i18n/index.d.ts.map +1 -0
- package/lib/typescript/module/i18n/runtimeMessages.d.ts +178 -0
- package/lib/typescript/module/i18n/runtimeMessages.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +66 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/native/NativeBridge.d.ts +70 -0
- package/lib/typescript/module/native/NativeBridge.d.ts.map +1 -0
- package/lib/typescript/module/native/navigationLabel.d.ts +4 -0
- package/lib/typescript/module/native/navigationLabel.d.ts.map +1 -0
- package/lib/typescript/module/native/normalizeViewTree.d.ts +4 -0
- package/lib/typescript/module/native/normalizeViewTree.d.ts.map +1 -0
- package/lib/typescript/module/native/pruneOffscreen.d.ts +3 -0
- package/lib/typescript/module/native/pruneOffscreen.d.ts.map +1 -0
- package/lib/typescript/module/native/scrollViewport.d.ts +13 -0
- package/lib/typescript/module/native/scrollViewport.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/privacy/redact.d.ts +9 -0
- package/lib/typescript/module/privacy/redact.d.ts.map +1 -0
- package/lib/typescript/module/privacy/screenEvidence.d.ts +14 -0
- package/lib/typescript/module/privacy/screenEvidence.d.ts.map +1 -0
- package/lib/typescript/module/privacy/screenModel.d.ts +26 -0
- package/lib/typescript/module/privacy/screenModel.d.ts.map +1 -0
- package/lib/typescript/module/privacy/sensitiveScreen.d.ts +8 -0
- package/lib/typescript/module/privacy/sensitiveScreen.d.ts.map +1 -0
- package/lib/typescript/module/privacy/userGate.d.ts +58 -0
- package/lib/typescript/module/privacy/userGate.d.ts.map +1 -0
- package/lib/typescript/module/protocol/actions.d.ts +7 -0
- package/lib/typescript/module/protocol/actions.d.ts.map +1 -0
- package/lib/typescript/module/provider/HostAppearanceStore.d.ts +64 -0
- package/lib/typescript/module/provider/HostAppearanceStore.d.ts.map +1 -0
- package/lib/typescript/module/provider/KokoProvider.d.ts +39 -0
- package/lib/typescript/module/provider/KokoProvider.d.ts.map +1 -0
- package/lib/typescript/module/provider/KokoUiContext.d.ts +22 -0
- package/lib/typescript/module/provider/KokoUiContext.d.ts.map +1 -0
- package/lib/typescript/module/selector/match.d.ts +27 -0
- package/lib/typescript/module/selector/match.d.ts.map +1 -0
- package/lib/typescript/module/task/TaskStore.d.ts +65 -0
- package/lib/typescript/module/task/TaskStore.d.ts.map +1 -0
- package/lib/typescript/module/task/types.d.ts +66 -0
- package/lib/typescript/module/task/types.d.ts.map +1 -0
- package/lib/typescript/module/task/useTaskStore.d.ts +3 -0
- package/lib/typescript/module/task/useTaskStore.d.ts.map +1 -0
- package/lib/typescript/module/types.d.ts +372 -0
- package/lib/typescript/module/types.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoChatSheet.d.ts +8 -0
- package/lib/typescript/module/ui/KokoChatSheet.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoComposer.d.ts +13 -0
- package/lib/typescript/module/ui/KokoComposer.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoDialogHost.d.ts +32 -0
- package/lib/typescript/module/ui/KokoDialogHost.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoEntryButton.d.ts +18 -0
- package/lib/typescript/module/ui/KokoEntryButton.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoObserver.d.ts +13 -0
- package/lib/typescript/module/ui/KokoObserver.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoOverlayLayer.d.ts +35 -0
- package/lib/typescript/module/ui/KokoOverlayLayer.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoSubtitle.d.ts +7 -0
- package/lib/typescript/module/ui/KokoSubtitle.d.ts.map +1 -0
- package/lib/typescript/module/ui/KokoTaskPanel.d.ts +7 -0
- package/lib/typescript/module/ui/KokoTaskPanel.d.ts.map +1 -0
- package/lib/typescript/module/ui/hostOverlay.d.ts +28 -0
- package/lib/typescript/module/ui/hostOverlay.d.ts.map +1 -0
- package/lib/typescript/module/ui/icons.d.ts +26 -0
- package/lib/typescript/module/ui/icons.d.ts.map +1 -0
- package/lib/typescript/module/ui/progressChrome.d.ts +21 -0
- package/lib/typescript/module/ui/progressChrome.d.ts.map +1 -0
- package/lib/typescript/module/ui/safeArea.d.ts +12 -0
- package/lib/typescript/module/ui/safeArea.d.ts.map +1 -0
- package/lib/typescript/module/ui/useOverlayOrigin.d.ts +22 -0
- package/lib/typescript/module/ui/useOverlayOrigin.d.ts.map +1 -0
- package/package.json +153 -0
- package/react-native.config.js +12 -0
- package/src/KokoAgent.ts +1415 -0
- package/src/assist/OnDeviceAssist.ts +133 -0
- package/src/assist/intentClassify.ts +122 -0
- package/src/assist/nodeRank.ts +167 -0
- package/src/assist/ocrTarget.ts +146 -0
- package/src/assist/webVisualChange.ts +24 -0
- package/src/client/ActionOutcomeUnknownError.ts +18 -0
- package/src/client/AgentSession.ts +952 -0
- package/src/client/GatewayClient.ts +439 -0
- package/src/client/OperationReplayGuard.ts +61 -0
- package/src/client/RunCheckpoint.ts +154 -0
- package/src/client/loopDetect.ts +213 -0
- package/src/client/recentSearch.ts +47 -0
- package/src/client/walletChoiceGuard.ts +15 -0
- package/src/client/webResultCategory.ts +28 -0
- package/src/commercial/AccountStore.ts +85 -0
- package/src/commercial/AgentDebug.ts +142 -0
- package/src/commercial/ExecutionGuard.ts +67 -0
- package/src/commercial/UsageBus.ts +44 -0
- package/src/commercial/branding.ts +97 -0
- package/src/commercial/devMode.ts +48 -0
- package/src/commercial/trust.ts +67 -0
- package/src/confirmation/gate.ts +82 -0
- package/src/cursor/CursorOverlay.tsx +138 -0
- package/src/cursor/PointerHand.tsx +49 -0
- package/src/cursor/controller.ts +98 -0
- package/src/cursor/pointer.ts +40 -0
- package/src/debug/KokoRemoteSmoke.tsx +561 -0
- package/src/explore/ExplorationGraph.ts +518 -0
- package/src/explore/bootstrapExplore.ts +89 -0
- package/src/host/HostActions.ts +349 -0
- package/src/i18n/index.ts +229 -0
- package/src/i18n/runtimeMessages.ts +180 -0
- package/src/index.ts +203 -0
- package/src/native/NativeBridge.ts +207 -0
- package/src/native/navigationLabel.ts +11 -0
- package/src/native/normalizeViewTree.ts +16 -0
- package/src/native/pruneOffscreen.ts +72 -0
- package/src/native/scrollViewport.ts +51 -0
- package/src/privacy/redact.ts +115 -0
- package/src/privacy/screenEvidence.ts +55 -0
- package/src/privacy/screenModel.ts +504 -0
- package/src/privacy/sensitiveScreen.ts +55 -0
- package/src/privacy/userGate.ts +233 -0
- package/src/protocol/actions.ts +66 -0
- package/src/provider/HostAppearanceStore.ts +148 -0
- package/src/provider/KokoProvider.tsx +118 -0
- package/src/provider/KokoUiContext.tsx +162 -0
- package/src/selector/match.ts +417 -0
- package/src/task/TaskStore.ts +387 -0
- package/src/task/types.ts +82 -0
- package/src/task/useTaskStore.ts +9 -0
- package/src/types.ts +318 -0
- package/src/ui/KokoChatSheet.tsx +930 -0
- package/src/ui/KokoComposer.tsx +174 -0
- package/src/ui/KokoDialogHost.tsx +249 -0
- package/src/ui/KokoEntryButton.tsx +74 -0
- package/src/ui/KokoObserver.tsx +587 -0
- package/src/ui/KokoOverlayLayer.tsx +53 -0
- package/src/ui/KokoSubtitle.tsx +80 -0
- package/src/ui/KokoTaskPanel.tsx +299 -0
- package/src/ui/hostOverlay.tsx +148 -0
- package/src/ui/icons.tsx +145 -0
- package/src/ui/progressChrome.ts +73 -0
- package/src/ui/safeArea.ts +95 -0
- package/src/ui/useOverlayOrigin.ts +29 -0
|
@@ -0,0 +1,952 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import type { KokoAgent } from '../KokoAgent';
|
|
3
|
+
import { runPreflightConfirm } from '../confirmation/gate';
|
|
4
|
+
import { viewTreeOutline } from '../privacy/redact';
|
|
5
|
+
import { sensitiveScreenKind, SensitiveScreenError } from '../privacy/sensitiveScreen';
|
|
6
|
+
import { screenModelText, screenSnapshotLine, extractAffordances } from '../privacy/screenModel';
|
|
7
|
+
import {
|
|
8
|
+
HostActionsStore,
|
|
9
|
+
filterVisibleHostActions,
|
|
10
|
+
hostActionsModelText,
|
|
11
|
+
} from '../host/HostActions';
|
|
12
|
+
import {
|
|
13
|
+
AppUserGateStore,
|
|
14
|
+
detectAppUserGate,
|
|
15
|
+
gateMessageValue,
|
|
16
|
+
userGateModelText,
|
|
17
|
+
} from '../privacy/userGate';
|
|
18
|
+
import type { Selector, ViewNode } from '../types';
|
|
19
|
+
import {
|
|
20
|
+
GatewayClient,
|
|
21
|
+
GatewayError,
|
|
22
|
+
type AgentHistoryItem,
|
|
23
|
+
type GatewayAction,
|
|
24
|
+
type GatewayConfig,
|
|
25
|
+
} from './GatewayClient';
|
|
26
|
+
import { UsageBus } from '../commercial/UsageBus';
|
|
27
|
+
import { AccountStore } from '../commercial/AccountStore';
|
|
28
|
+
import { ExecutionGuard } from '../commercial/ExecutionGuard';
|
|
29
|
+
import { AgentDebug } from '../commercial/AgentDebug';
|
|
30
|
+
import { scrollPosition } from '../native/scrollViewport';
|
|
31
|
+
import { TaskStore } from '../task/TaskStore';
|
|
32
|
+
import { isLooping } from './loopDetect';
|
|
33
|
+
import {
|
|
34
|
+
ExplorationGraph,
|
|
35
|
+
exploreHintsModelText,
|
|
36
|
+
goalExploreQuery,
|
|
37
|
+
} from '../explore/ExplorationGraph';
|
|
38
|
+
import { RunCheckpoint } from './RunCheckpoint';
|
|
39
|
+
import { ActionOutcomeUnknownError, ActionValidationError } from './ActionOutcomeUnknownError';
|
|
40
|
+
import { OperationReplayGuard } from './OperationReplayGuard';
|
|
41
|
+
import { recentSearchAction } from './recentSearch';
|
|
42
|
+
import { webResultCategory } from './webResultCategory';
|
|
43
|
+
import { wrongHostWalletChoice } from './walletChoiceGuard';
|
|
44
|
+
import { currentLocale, gatewayLocale, runtimeText, message, resolveText, type MessageKey, type MessageVars } from '../i18n';
|
|
45
|
+
|
|
46
|
+
import { buildOnDeviceAssist } from '../assist/OnDeviceAssist';
|
|
47
|
+
import { NativeBridge } from '../native/NativeBridge';
|
|
48
|
+
import { webVisualChanged, webVisualLabels } from '../assist/webVisualChange';
|
|
49
|
+
import { ocrHitInFrames, visibleWebViewFrames } from '../assist/ocrTarget';
|
|
50
|
+
|
|
51
|
+
/** Soft ETA-style start; extend while progressing. Absolute safety wall only. */
|
|
52
|
+
const SOFT_MAX_STEPS = 40;
|
|
53
|
+
const HARD_MAX_STEPS = 200;
|
|
54
|
+
|
|
55
|
+
function affordanceLabels(tree: ViewNode | null | undefined): string[] {
|
|
56
|
+
if (!tree) return [];
|
|
57
|
+
return extractAffordances(tree, 40).map((a) => a.label);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type AskUserHandler = (question: string) => Promise<string | null>;
|
|
61
|
+
|
|
62
|
+
export type AgentSessionOptions = GatewayConfig & {
|
|
63
|
+
locale?: string;
|
|
64
|
+
localRetries?: number;
|
|
65
|
+
onAskUser?: AskUserHandler;
|
|
66
|
+
onNarration?: (text: string) => void;
|
|
67
|
+
userGateTimeoutMs?: number;
|
|
68
|
+
/** Picked up after a JS-context restart killed the original run. */
|
|
69
|
+
resumedFromReload?: boolean;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type AgentRunResult = {
|
|
73
|
+
success: boolean;
|
|
74
|
+
summary: string;
|
|
75
|
+
steps: number;
|
|
76
|
+
sessionId: string;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Cursor-like session with:
|
|
81
|
+
* - Preflight risk confirm (before loop)
|
|
82
|
+
* - Unattended execution (stop only)
|
|
83
|
+
* - Pause when App shows password/PIN/OTP until user finishes
|
|
84
|
+
*/
|
|
85
|
+
export class AgentSession {
|
|
86
|
+
private readonly agent: KokoAgent;
|
|
87
|
+
private readonly gateway: GatewayClient;
|
|
88
|
+
private readonly opts: AgentSessionOptions;
|
|
89
|
+
private sessionId: string | undefined;
|
|
90
|
+
private history: AgentHistoryItem[] = [];
|
|
91
|
+
private stopped = false;
|
|
92
|
+
private running = false;
|
|
93
|
+
private readonly operationReplayGuard = new OperationReplayGuard();
|
|
94
|
+
|
|
95
|
+
constructor(agent: KokoAgent, opts: AgentSessionOptions) {
|
|
96
|
+
this.agent = agent;
|
|
97
|
+
this.gateway = new GatewayClient({
|
|
98
|
+
token: opts.token,
|
|
99
|
+
baseUrl: opts.baseUrl,
|
|
100
|
+
});
|
|
101
|
+
this.opts = opts;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
stop() {
|
|
105
|
+
this.stopped = true;
|
|
106
|
+
this.agent.cancelPendingActions();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private uiLocale() {
|
|
110
|
+
return currentLocale(this.opts.locale ?? this.agent.getConfig().locale);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private text(key: MessageKey, vars?: MessageVars) {
|
|
114
|
+
return runtimeText(key, vars, this.opts.locale ?? this.agent.getConfig().locale);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private message(key: MessageKey, vars?: MessageVars) {
|
|
118
|
+
return message(key, vars, this.opts.locale ?? this.agent.getConfig().locale);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private assertRunning() {
|
|
122
|
+
if (this.stopped) throw new Error('KokoAgent: task cancelled');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async run(goal: string): Promise<AgentRunResult> {
|
|
126
|
+
if (this.running) throw new Error(this.text('runtime.alreadyRunning'));
|
|
127
|
+
const acquired = this.agent.acquireSession(this);
|
|
128
|
+
this.running = true;
|
|
129
|
+
try {
|
|
130
|
+
return await this.runInternal(goal);
|
|
131
|
+
} finally {
|
|
132
|
+
this.running = false;
|
|
133
|
+
if (acquired) this.agent.releaseSession(this);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private async runInternal(goal: string): Promise<AgentRunResult> {
|
|
138
|
+
// A stop issued while runGoal persists its checkpoint must remain effective.
|
|
139
|
+
this.operationReplayGuard.reset();
|
|
140
|
+
this.history = [];
|
|
141
|
+
this.sessionId = undefined;
|
|
142
|
+
// Mark running immediately so host freezeOnBlur stays off across sheet→run gap.
|
|
143
|
+
this.agent.startTask(goal);
|
|
144
|
+
const cfg = this.agent.getConfig();
|
|
145
|
+
AgentDebug.runStart(cfg, goal);
|
|
146
|
+
// Only after startTask: appendNode with no active task invents a task of
|
|
147
|
+
// its own that nothing ever finishes.
|
|
148
|
+
if (this.opts.resumedFromReload) {
|
|
149
|
+
this.agent.log('info', this.message('resume.note'));
|
|
150
|
+
}
|
|
151
|
+
// A resumed run starts blind: the action that reloaded the App probably
|
|
152
|
+
// already achieved the goal, and labels learned before the reload may be
|
|
153
|
+
// gone (a locale change renames every one of them). Without this the
|
|
154
|
+
// planner starts over, fails to re-find its entry point and reports a
|
|
155
|
+
// false failure for work that in fact succeeded. Planner-only — the task
|
|
156
|
+
// title and every goal heuristic keep the user's original wording.
|
|
157
|
+
const plannerGoal = () => this.opts.resumedFromReload
|
|
158
|
+
? `${goal}\n\n${this.text('resume.verifyFirst')}`
|
|
159
|
+
: goal;
|
|
160
|
+
if (this.stopped) {
|
|
161
|
+
this.agent.finishTask('cancelled', this.message('runtime.cancelled'));
|
|
162
|
+
return { success: false, summary: this.text('runtime.cancelled'), steps: 0, sessionId: '' };
|
|
163
|
+
}
|
|
164
|
+
const preflightOk = await runPreflightConfirm(
|
|
165
|
+
goal,
|
|
166
|
+
cfg.confirmation,
|
|
167
|
+
cfg.onConfirmSensitive,
|
|
168
|
+
);
|
|
169
|
+
if (!preflightOk || this.stopped) {
|
|
170
|
+
const summary = this.stopped ? this.text('runtime.cancelled') : this.text('runtime.confirmationCancelled');
|
|
171
|
+
this.agent.finishTask('cancelled', summary);
|
|
172
|
+
return { success: false, summary, steps: 0, sessionId: '' };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Soft budget extends while making progress; only HARD + isLooping stop a run.
|
|
176
|
+
let stepBudget = SOFT_MAX_STEPS;
|
|
177
|
+
let userReply: string | undefined;
|
|
178
|
+
let awaitingObservationVerdict = false;
|
|
179
|
+
this.agent.activeGoal = goal;
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
// Session + permit before first dump (production soft gate).
|
|
183
|
+
this.assertRunning();
|
|
184
|
+
const began = await this.gateway.beginSession();
|
|
185
|
+
this.assertRunning();
|
|
186
|
+
this.sessionId = began.session_id;
|
|
187
|
+
ExecutionGuard.setPermit(began.execution_permit, began.session_id);
|
|
188
|
+
|
|
189
|
+
const initialGate = await this.waitForAppUserGateIfNeeded();
|
|
190
|
+
if (initialGate === 'stopped' || initialGate === 'timeout') {
|
|
191
|
+
const summary = initialGate === 'stopped' ? this.text('runtime.cancelled') : this.text('runtime.gateTimeout');
|
|
192
|
+
this.agent.finishTask(initialGate === 'stopped' ? 'cancelled' : 'failed', summary);
|
|
193
|
+
return { success: false, summary, steps: 0, sessionId: this.sessionId || '' };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
await ExplorationGraph.ensureLoaded();
|
|
197
|
+
this.assertRunning();
|
|
198
|
+
const exploreQuery = goalExploreQuery(goal);
|
|
199
|
+
|
|
200
|
+
// Learned paths are suggestions in the screen model. Every action still
|
|
201
|
+
// goes through the planner, current-screen guards and result observation.
|
|
202
|
+
|
|
203
|
+
for (let step = 0; step < HARD_MAX_STEPS; step++) {
|
|
204
|
+
// Age of the checkpoint gates resume, so it has to track liveness
|
|
205
|
+
// rather than when the run began.
|
|
206
|
+
void RunCheckpoint.touch().catch(() => {});
|
|
207
|
+
if (this.stopped) {
|
|
208
|
+
this.agent.finishTask('cancelled', this.message('runtime.cancelled'));
|
|
209
|
+
return {
|
|
210
|
+
success: false,
|
|
211
|
+
summary: this.text('runtime.cancelled'),
|
|
212
|
+
steps: this.history.length,
|
|
213
|
+
sessionId: this.sessionId || '',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Still progressing → extend soft budget (KokoAgent-style).
|
|
218
|
+
if (
|
|
219
|
+
step >= stepBudget &&
|
|
220
|
+
stepBudget < HARD_MAX_STEPS &&
|
|
221
|
+
!isLooping(this.history)
|
|
222
|
+
) {
|
|
223
|
+
stepBudget = Math.min(HARD_MAX_STEPS, stepBudget + 8);
|
|
224
|
+
this.agent.log(
|
|
225
|
+
'info',
|
|
226
|
+
this.message('runtime.progressBudget', { steps: stepBudget }),
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// App-owned auth: wait for user, do not open Koko Q&A.
|
|
231
|
+
const gateWait = await this.waitForAppUserGateIfNeeded();
|
|
232
|
+
if (gateWait === 'stopped') {
|
|
233
|
+
this.agent.finishTask('cancelled', this.message('runtime.cancelled'));
|
|
234
|
+
return {
|
|
235
|
+
success: false,
|
|
236
|
+
summary: this.text('runtime.cancelled'),
|
|
237
|
+
steps: this.history.length,
|
|
238
|
+
sessionId: this.sessionId || '',
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (gateWait === 'timeout') {
|
|
242
|
+
this.agent.finishTask('failed', this.message('runtime.gateTimeout'));
|
|
243
|
+
return {
|
|
244
|
+
success: false,
|
|
245
|
+
summary: this.text('runtime.gateTimeout'),
|
|
246
|
+
steps: this.history.length,
|
|
247
|
+
sessionId: this.sessionId || '',
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const tree = await this.safeDump();
|
|
252
|
+
this.assertRunning();
|
|
253
|
+
// The screen can change between the gate poll and this dump. Do not
|
|
254
|
+
// run OCR or construct a cloud request for a newly presented gate.
|
|
255
|
+
if (detectAppUserGate(tree)) {
|
|
256
|
+
step--;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
this.agent.setPlanningTree(tree);
|
|
260
|
+
const outline = tree ? viewTreeOutline(tree) : undefined;
|
|
261
|
+
const gate = detectAppUserGate(tree);
|
|
262
|
+
const visibleHosts = filterVisibleHostActions(
|
|
263
|
+
HostActionsStore.getActions(),
|
|
264
|
+
tree,
|
|
265
|
+
);
|
|
266
|
+
const exploreHints = tree
|
|
267
|
+
? ExplorationGraph.hintLabelsTowardGoal(
|
|
268
|
+
affordanceLabels(tree),
|
|
269
|
+
exploreQuery.targetTokens,
|
|
270
|
+
6,
|
|
271
|
+
)
|
|
272
|
+
: [];
|
|
273
|
+
// On-device assist (JS intent/rank + iOS Vision/Core ML OCR) enriches
|
|
274
|
+
// the planner model; cloud LLM still owns action planning.
|
|
275
|
+
const assist = await buildOnDeviceAssist(goal, tree);
|
|
276
|
+
this.assertRunning();
|
|
277
|
+
let hostWalletAliases = cfg.webWalletAliases || [];
|
|
278
|
+
if (assist.walletChoices?.length && hostWalletAliases.length && tree) {
|
|
279
|
+
const frame = visibleWebViewFrames(tree)[0];
|
|
280
|
+
if (frame) {
|
|
281
|
+
try {
|
|
282
|
+
const flags = await NativeBridge.inspectWebWalletProvider({
|
|
283
|
+
x: frame.x + frame.width / 2, y: frame.y + frame.height / 2,
|
|
284
|
+
});
|
|
285
|
+
if (flags && (!flags.present || !flags.hasRequest)) hostWalletAliases = [];
|
|
286
|
+
else if (flags && !flags.isMetaMask) hostWalletAliases = hostWalletAliases.filter(alias => alias !== 'MetaMask');
|
|
287
|
+
} catch {
|
|
288
|
+
// A failed provider inspection is not evidence of an injected wallet.
|
|
289
|
+
hostWalletAliases = [];
|
|
290
|
+
}
|
|
291
|
+
this.assertRunning();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const hostModel = [
|
|
295
|
+
hostActionsModelText(visibleHosts),
|
|
296
|
+
exploreHintsModelText(exploreHints),
|
|
297
|
+
userGateModelText(gate),
|
|
298
|
+
assist.modelText,
|
|
299
|
+
]
|
|
300
|
+
.filter(Boolean)
|
|
301
|
+
.join('\n');
|
|
302
|
+
const model = tree
|
|
303
|
+
? screenModelText(tree, 40, hostModel || undefined)
|
|
304
|
+
: hostModel || undefined;
|
|
305
|
+
if (assist.modelText && AgentDebug.enabled(cfg)) {
|
|
306
|
+
// eslint-disable-next-line no-console
|
|
307
|
+
console.log(
|
|
308
|
+
`[koko] on-device assist: intent=${assist.intent} backend=${assist.backend} ranked=${assist.ranked.length} ocr=${assist.ocrTokens.length}`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
// Debug: what raw texts did native dump actually return?
|
|
312
|
+
if (tree && AgentDebug.enabled(cfg)) {
|
|
313
|
+
const texts: string[] = [];
|
|
314
|
+
const walk = (n: ViewNode) => {
|
|
315
|
+
const t = (n.text || n.accessibilityLabel || '').trim();
|
|
316
|
+
if (t && t.length <= 40) texts.push(t);
|
|
317
|
+
if (n.testID) texts.push(`#${n.testID}`);
|
|
318
|
+
for (const c of n.children) walk(c);
|
|
319
|
+
};
|
|
320
|
+
walk(tree);
|
|
321
|
+
const uniq = [...new Set(texts)].slice(0, 40);
|
|
322
|
+
// eslint-disable-next-line no-console
|
|
323
|
+
console.log(
|
|
324
|
+
`[koko] dump texts (${uniq.length}): ${uniq.join(' · ').slice(0, 500)}`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
AgentDebug.screenCapabilities(cfg, tree);
|
|
328
|
+
|
|
329
|
+
const planningLocale = gatewayLocale(this.uiLocale());
|
|
330
|
+
let next: Awaited<ReturnType<GatewayClient['next']>>;
|
|
331
|
+
try {
|
|
332
|
+
next = await this.nextWithRetry({
|
|
333
|
+
session_id: this.sessionId,
|
|
334
|
+
goal: this.operationReplayGuard.hasHandoff
|
|
335
|
+
? `${plannerGoal()}\n\n${this.text('gate.verifyResultFirst')}`
|
|
336
|
+
: plannerGoal(),
|
|
337
|
+
ui_tree: tree || undefined,
|
|
338
|
+
ui_outline: outline,
|
|
339
|
+
ui_screen_model: model,
|
|
340
|
+
local_ocr_goal_labels: assist.goalOcrLabels,
|
|
341
|
+
local_ocr_wallet_choices: assist.walletChoices,
|
|
342
|
+
local_web_wallet_aliases: hostWalletAliases,
|
|
343
|
+
history: this.history,
|
|
344
|
+
locale: planningLocale,
|
|
345
|
+
user_reply: userReply,
|
|
346
|
+
platform:
|
|
347
|
+
Platform.OS === 'ios'
|
|
348
|
+
? 'ios'
|
|
349
|
+
: Platform.OS === 'android'
|
|
350
|
+
? 'android'
|
|
351
|
+
: 'unknown',
|
|
352
|
+
});
|
|
353
|
+
} catch (error) {
|
|
354
|
+
if (error instanceof SensitiveScreenError) {
|
|
355
|
+
this.operationReplayGuard.markHandoff();
|
|
356
|
+
this.history = [];
|
|
357
|
+
step--;
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
362
|
+
this.assertRunning();
|
|
363
|
+
userReply = undefined;
|
|
364
|
+
this.sessionId = next.session_id;
|
|
365
|
+
ExecutionGuard.setPermit(next.execution_permit, next.session_id);
|
|
366
|
+
// A response planned in the previous language must not put stale
|
|
367
|
+
// narration/questions/results back into the live progress UI.
|
|
368
|
+
if (planningLocale !== gatewayLocale(this.uiLocale())) {
|
|
369
|
+
this.pushHistory({ tool: 'dump', args: {} }, this.text('runtime.localeChanged'), false);
|
|
370
|
+
step--;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
UsageBus.emit({
|
|
375
|
+
type: 'agent_step',
|
|
376
|
+
sessionId: next.session_id,
|
|
377
|
+
step: next.step,
|
|
378
|
+
tool: next.action.tool,
|
|
379
|
+
at: Date.now(),
|
|
380
|
+
});
|
|
381
|
+
AgentDebug.appAction(
|
|
382
|
+
cfg,
|
|
383
|
+
next.step,
|
|
384
|
+
next.action.tool,
|
|
385
|
+
actionDetail(next.action),
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
// After repeated read-only observations, the gateway may only return a
|
|
389
|
+
// final evidence-based verdict. Never turn this review into another act.
|
|
390
|
+
if (awaitingObservationVerdict && next.action.tool !== 'done') {
|
|
391
|
+
this.agent.finishTask('failed', this.message('runtime.loopStopped'));
|
|
392
|
+
return { success: false, summary: this.text('runtime.loopStopped'),
|
|
393
|
+
steps: this.history.length, sessionId: this.sessionId || '' };
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
let recentAction = recentSearchAction(next.action, tree, goal) ||
|
|
397
|
+
(!awaitingObservationVerdict ? webResultCategory(next.action, tree, goal, this.history) : null);
|
|
398
|
+
let hostWalletChoice = false;
|
|
399
|
+
if (!recentAction && !awaitingObservationVerdict && next.action.tool === 'dump' && tree && assist.walletChoices?.length) {
|
|
400
|
+
const aliases = hostWalletAliases.filter(alias => assist.walletChoices!.includes(alias));
|
|
401
|
+
const alias = aliases.length === 1 ? aliases[0] : undefined;
|
|
402
|
+
const attempted = alias && this.history.some(item => item.tool === 'tap' &&
|
|
403
|
+
String(item.args?.label || '').toLocaleLowerCase().includes(alias.toLocaleLowerCase()));
|
|
404
|
+
if (alias && !attempted) {
|
|
405
|
+
const target = await this.agent.find({ match: [{ text: alias, exact: true }] }, tree);
|
|
406
|
+
this.assertRunning();
|
|
407
|
+
if (target && ocrHitInFrames({ text: alias, confidence: 1, frame: target.frame }, visibleWebViewFrames(tree))) {
|
|
408
|
+
recentAction = { tool: 'tap', args: { nodeId: target.id, label: alias } };
|
|
409
|
+
hostWalletChoice = true;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
if (recentAction) {
|
|
414
|
+
this.agent.log('info', gatewayLocale(this.uiLocale()) === 'zh'
|
|
415
|
+
? (hostWalletChoice ? '选择宿主钱包入口。' : next.action.tool === 'type' ? '使用匹配的最近搜索。' : '选择相关应用分类。')
|
|
416
|
+
: (hostWalletChoice ? 'Selecting the host wallet.' : next.action.tool === 'type' ? 'Using the matching recent search.' : 'Selecting the relevant app category.'));
|
|
417
|
+
} else if (next.narration) {
|
|
418
|
+
this.opts.onNarration?.(next.narration);
|
|
419
|
+
this.agent.log('info', next.narration);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const action = recentAction || next.action;
|
|
423
|
+
if (wrongHostWalletChoice(goal, action, assist.walletChoices || [], hostWalletAliases,
|
|
424
|
+
action.tool === 'tap' ? this.agent.observedOcrLabel(action.args.nodeId) : undefined)) {
|
|
425
|
+
this.pushHistory(action, 'Host wallet does not match this option; select the configured host wallet or try another browser mode.', false);
|
|
426
|
+
if (isLooping(this.history)) {
|
|
427
|
+
this.agent.finishTask('failed', this.message('runtime.loopStopped'));
|
|
428
|
+
return { success: false, summary: this.text('runtime.loopStopped'), steps: this.history.length, sessionId: this.sessionId || '' };
|
|
429
|
+
}
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
if (action.tool === 'done') {
|
|
433
|
+
this.pushHistory(action, action.args.summary, action.args.success);
|
|
434
|
+
this.agent.finishTask(
|
|
435
|
+
action.args.success ? 'success' : 'failed',
|
|
436
|
+
action.args.summary,
|
|
437
|
+
);
|
|
438
|
+
AgentDebug.runEnd(cfg, action.args.summary, action.args.success);
|
|
439
|
+
return {
|
|
440
|
+
success: action.args.success,
|
|
441
|
+
summary: action.args.summary,
|
|
442
|
+
steps: this.history.length,
|
|
443
|
+
sessionId: this.sessionId,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (action.tool === 'ask_user') {
|
|
448
|
+
this.agent.log(
|
|
449
|
+
'info',
|
|
450
|
+
this.message('runtime.waitForApp', { request: action.args.question }),
|
|
451
|
+
);
|
|
452
|
+
this.opts.onNarration?.(
|
|
453
|
+
this.text('runtime.waitForApp', { request: action.args.question }),
|
|
454
|
+
);
|
|
455
|
+
const w = await this.waitForAppUserGateIfNeeded({
|
|
456
|
+
forceMessage: action.args.question,
|
|
457
|
+
minWaitMs: 1500,
|
|
458
|
+
});
|
|
459
|
+
this.pushHistory(
|
|
460
|
+
action,
|
|
461
|
+
w === 'cleared'
|
|
462
|
+
? this.text('runtime.userContinued')
|
|
463
|
+
: w === 'timeout'
|
|
464
|
+
? this.text('runtime.userTimeout')
|
|
465
|
+
: this.text('runtime.cancelled'),
|
|
466
|
+
w === 'cleared',
|
|
467
|
+
);
|
|
468
|
+
if (w === 'stopped' || w === 'timeout') {
|
|
469
|
+
const summary = w === 'stopped' ? this.text('runtime.cancelled') : this.text('runtime.userTimeout');
|
|
470
|
+
this.agent.finishTask(w === 'stopped' ? 'cancelled' : 'failed', summary);
|
|
471
|
+
return {
|
|
472
|
+
success: false,
|
|
473
|
+
summary,
|
|
474
|
+
steps: this.history.length,
|
|
475
|
+
sessionId: this.sessionId,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
if (isLooping(this.history)) {
|
|
479
|
+
this.agent.finishTask('failed', this.message('runtime.loopStopped'));
|
|
480
|
+
return {
|
|
481
|
+
success: false,
|
|
482
|
+
summary: this.text('runtime.loopStopped'),
|
|
483
|
+
steps: this.history.length,
|
|
484
|
+
sessionId: this.sessionId,
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
userReply = this.text('runtime.userContinued');
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const beforeSnap = tree ? screenSnapshotLine(tree) : '';
|
|
492
|
+
const webTap = action.tool === 'tap' && Boolean(action.args.nodeId?.startsWith('ocr:'));
|
|
493
|
+
const beforeWeb = webTap ? await this.webVisualLabels(tree) : null;
|
|
494
|
+
this.assertRunning();
|
|
495
|
+
const beforeLabels = affordanceLabels(tree);
|
|
496
|
+
if (this.operationReplayGuard.blocks(action, tree)) {
|
|
497
|
+
const summary = this.text('gate.replayStopped');
|
|
498
|
+
this.agent.log('info', summary);
|
|
499
|
+
this.agent.finishTask('failed', summary);
|
|
500
|
+
return { success: false, summary, steps: this.history.length, sessionId: this.sessionId || '' };
|
|
501
|
+
}
|
|
502
|
+
const exec = await this.executeWithRetry(action);
|
|
503
|
+
this.assertRunning();
|
|
504
|
+
if (exec.ok) this.operationReplayGuard.record(action, tree);
|
|
505
|
+
// Let host animations / navigation commit before noop detection.
|
|
506
|
+
if (action.tool === 'tap' || action.tool === 'swipe' || action.tool === 'type') {
|
|
507
|
+
await sleep(280);
|
|
508
|
+
}
|
|
509
|
+
let after = await this.safeDump();
|
|
510
|
+
this.assertRunning();
|
|
511
|
+
let snap = after ? screenSnapshotLine(after) : '';
|
|
512
|
+
// Dump raced navigation / host async work — give UI one more beat.
|
|
513
|
+
if (
|
|
514
|
+
action.tool === 'tap' &&
|
|
515
|
+
exec.ok &&
|
|
516
|
+
beforeSnap &&
|
|
517
|
+
snap &&
|
|
518
|
+
beforeSnap === snap
|
|
519
|
+
) {
|
|
520
|
+
await sleep(550);
|
|
521
|
+
after = await this.safeDump();
|
|
522
|
+
this.assertRunning();
|
|
523
|
+
snap = after ? screenSnapshotLine(after) : '';
|
|
524
|
+
}
|
|
525
|
+
// Window subviews stack in the order they were added, so a host sheet
|
|
526
|
+
// that animates in after the action lands above our chrome and buries
|
|
527
|
+
// the progress pill and its stop button. Re-front once the screen has
|
|
528
|
+
// settled, which is the first moment that sheet actually exists.
|
|
529
|
+
TaskStore.liftChrome();
|
|
530
|
+
// Grow on-device exploration graph from successful taps.
|
|
531
|
+
if (action.tool === 'tap' && exec.ok && !sensitiveScreenKind(after)) {
|
|
532
|
+
const tapLabel = String(
|
|
533
|
+
action.args.label ||
|
|
534
|
+
this.agent.lastTapViaHost?.label ||
|
|
535
|
+
'',
|
|
536
|
+
).trim();
|
|
537
|
+
if (tapLabel) {
|
|
538
|
+
ExplorationGraph.recordTransition(
|
|
539
|
+
beforeLabels,
|
|
540
|
+
tapLabel,
|
|
541
|
+
affordanceLabels(after),
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
let ok = exec.ok;
|
|
546
|
+
if (action.tool === 'swipe' && exec.ok && tree && after && !sensitiveScreenKind(after)) {
|
|
547
|
+
const beforePosition = scrollPosition(tree, action.args.from);
|
|
548
|
+
const afterPosition = scrollPosition(after, action.args.from);
|
|
549
|
+
if (beforePosition && afterPosition) {
|
|
550
|
+
snap += ` scroll_position=${afterPosition}`;
|
|
551
|
+
if (beforePosition === afterPosition) {
|
|
552
|
+
ok = false;
|
|
553
|
+
exec.result = this.text('runtime.scrollNoop');
|
|
554
|
+
} else {
|
|
555
|
+
exec.result = this.text('runtime.scrollChanged');
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
let resultWithObs = snap ? `${exec.result} || ${snap}` : exec.result;
|
|
560
|
+
const changedWeb = webTap && exec.ok ? webVisualChanged(beforeWeb, await this.webVisualLabels(after)) : false;
|
|
561
|
+
this.assertRunning();
|
|
562
|
+
if (changedWeb) resultWithObs = `${exec.result} (web content changed; verify the new state) || ${snap}`;
|
|
563
|
+
// `lastTapViaHost` is only set once the agent has confirmed the host
|
|
564
|
+
// action moved the screen, so it annotates the trace but no longer
|
|
565
|
+
// exempts the step from noop detection.
|
|
566
|
+
const viaHost = Boolean(this.agent.lastTapViaHost);
|
|
567
|
+
if (viaHost && action.tool === 'tap' && exec.ok) {
|
|
568
|
+
resultWithObs = snap
|
|
569
|
+
? `${exec.result} (host run) || ${snap}`
|
|
570
|
+
: `${exec.result} (host run)`;
|
|
571
|
+
}
|
|
572
|
+
if (
|
|
573
|
+
// Tap claimed success but UI fingerprint unchanged → treat as noop so
|
|
574
|
+
// loop detection / planner can escape instead of empty dumping.
|
|
575
|
+
// Skip when both sides are empty — that is dump failure, not a dead tap.
|
|
576
|
+
action.tool === 'tap' &&
|
|
577
|
+
exec.ok &&
|
|
578
|
+
!changedWeb &&
|
|
579
|
+
beforeSnap &&
|
|
580
|
+
snap &&
|
|
581
|
+
beforeSnap === snap &&
|
|
582
|
+
snap !== 'screen: (empty)'
|
|
583
|
+
) {
|
|
584
|
+
ok = false;
|
|
585
|
+
resultWithObs = `tap_noop (screen unchanged) || ${snap}`;
|
|
586
|
+
}
|
|
587
|
+
if (assist.walletChoices?.length) {
|
|
588
|
+
// Only allowlisted public names are kept; no raw OCR or account data.
|
|
589
|
+
resultWithObs += ` || visible wallet options: ${assist.walletChoices.join(', ')}`;
|
|
590
|
+
}
|
|
591
|
+
this.pushHistory(action, resultWithObs, ok);
|
|
592
|
+
|
|
593
|
+
if (isLooping(this.history)) {
|
|
594
|
+
const lastThree = this.history.slice(-3);
|
|
595
|
+
if (!awaitingObservationVerdict && lastThree.length === 3 && lastThree.every(h => h.tool === 'dump')) {
|
|
596
|
+
// The last observation may already prove the goal. Ask for one
|
|
597
|
+
// read-only verdict instead of treating a stall as evidence of failure.
|
|
598
|
+
awaitingObservationVerdict = true;
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
this.agent.finishTask('failed', this.message('runtime.loopStopped'));
|
|
602
|
+
AgentDebug.runEnd(cfg, this.text('runtime.loopStopped'), false);
|
|
603
|
+
return {
|
|
604
|
+
success: false,
|
|
605
|
+
summary: this.text('runtime.loopStopped'),
|
|
606
|
+
steps: this.history.length,
|
|
607
|
+
sessionId: this.sessionId || '',
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
await this.waitForAppUserGateIfNeeded();
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
this.agent.finishTask('failed', this.message('runtime.stepLimit'));
|
|
615
|
+
return {
|
|
616
|
+
success: false,
|
|
617
|
+
summary: this.text('runtime.stepLimit'),
|
|
618
|
+
steps: this.history.length,
|
|
619
|
+
sessionId: this.sessionId || '',
|
|
620
|
+
};
|
|
621
|
+
} catch (e) {
|
|
622
|
+
if (this.stopped) {
|
|
623
|
+
this.agent.finishTask('cancelled', this.message('runtime.cancelled'));
|
|
624
|
+
return { success: false, summary: this.text('runtime.cancelled'), steps: this.history.length, sessionId: this.sessionId || '' };
|
|
625
|
+
}
|
|
626
|
+
const diagnostic = e instanceof Error ? e.message : String(e);
|
|
627
|
+
const copy = e instanceof ActionOutcomeUnknownError || e instanceof ActionValidationError
|
|
628
|
+
? e.localizedMessage : this.message('runtime.operationFailed');
|
|
629
|
+
const failureMessage = resolveText(copy);
|
|
630
|
+
if (e instanceof GatewayError && e.code === 'quota_exceeded') {
|
|
631
|
+
UsageBus.emit({
|
|
632
|
+
type: 'quota_exceeded',
|
|
633
|
+
message: failureMessage,
|
|
634
|
+
quota: e.quota,
|
|
635
|
+
at: Date.now(),
|
|
636
|
+
});
|
|
637
|
+
if (this.opts.token) {
|
|
638
|
+
void AccountStore.refresh({
|
|
639
|
+
token: this.opts.token,
|
|
640
|
+
baseUrl: this.opts.baseUrl,
|
|
641
|
+
});
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
AgentDebug.runIssue(cfg, diagnostic);
|
|
645
|
+
this.agent.log('error', copy);
|
|
646
|
+
this.agent.finishTask('failed', copy);
|
|
647
|
+
return {
|
|
648
|
+
success: false,
|
|
649
|
+
summary: failureMessage,
|
|
650
|
+
steps: this.history.length,
|
|
651
|
+
sessionId: this.sessionId || '',
|
|
652
|
+
};
|
|
653
|
+
} finally {
|
|
654
|
+
this.agent.activeGoal = undefined;
|
|
655
|
+
ExecutionGuard.clear();
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
private pushHistory(action: GatewayAction, result: string, ok?: boolean) {
|
|
660
|
+
this.history.push({
|
|
661
|
+
tool: action.tool,
|
|
662
|
+
args: 'args' in action ? (action.args as Record<string, unknown>) : undefined,
|
|
663
|
+
result,
|
|
664
|
+
ok,
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/** Retry transient upstream / network failures so a completed UI goal is not
|
|
669
|
+
* marked failed just because the next planning round could not reach the LLM. */
|
|
670
|
+
private async nextWithRetry(
|
|
671
|
+
body: Parameters<GatewayClient['next']>[0],
|
|
672
|
+
): Promise<Awaited<ReturnType<GatewayClient['next']>>> {
|
|
673
|
+
const maxAttempts = 3;
|
|
674
|
+
let last: unknown;
|
|
675
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
676
|
+
this.assertRunning();
|
|
677
|
+
try {
|
|
678
|
+
const result = await this.gateway.next(body);
|
|
679
|
+
this.assertRunning();
|
|
680
|
+
return result;
|
|
681
|
+
} catch (e) {
|
|
682
|
+
this.assertRunning();
|
|
683
|
+
last = e;
|
|
684
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
685
|
+
const status = e instanceof GatewayError ? e.status : 0;
|
|
686
|
+
const retryable =
|
|
687
|
+
status === 502 ||
|
|
688
|
+
status === 503 ||
|
|
689
|
+
status === 504 ||
|
|
690
|
+
/fetch failed|network request failed|ECONNRESET|ETIMEDOUT|upstream_failed|socket/i.test(
|
|
691
|
+
msg,
|
|
692
|
+
);
|
|
693
|
+
if (!retryable || i === maxAttempts - 1) throw e;
|
|
694
|
+
AgentDebug.runIssue(
|
|
695
|
+
this.agent.getConfig(),
|
|
696
|
+
this.text('runtime.gatewayRetry', { attempt: i + 1, total: maxAttempts - 1 }),
|
|
697
|
+
);
|
|
698
|
+
await sleep(500 * (i + 1));
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
throw last;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
private async safeDump(): Promise<ViewNode | null> {
|
|
705
|
+
try {
|
|
706
|
+
let tree = await this.agent.dump({ silent: true });
|
|
707
|
+
if (sensitiveScreenKind(tree)) return tree;
|
|
708
|
+
// Loading / transition settle: empty screens often need a beat.
|
|
709
|
+
for (let i = 0; i < 3; i++) {
|
|
710
|
+
const items = tree ? extractAffordances(tree, 8) : [];
|
|
711
|
+
if (items.length > 0) break;
|
|
712
|
+
await sleep(350);
|
|
713
|
+
if (this.stopped) break;
|
|
714
|
+
tree = await this.agent.dump({ silent: true });
|
|
715
|
+
}
|
|
716
|
+
return tree;
|
|
717
|
+
} catch {
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
private async webVisualLabels(tree: ViewNode | null): Promise<Set<string> | null> {
|
|
723
|
+
if (!tree || sensitiveScreenKind(tree) || !NativeBridge.isAvailable()) return null;
|
|
724
|
+
try {
|
|
725
|
+
const ocr = await NativeBridge.recognizeScreenText({ maxTokens: 64, hideOverlays: true });
|
|
726
|
+
return webVisualLabels(tree, ocr.texts || []);
|
|
727
|
+
} catch {
|
|
728
|
+
return null;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* When the App presents credentials or recovery material, wait locally.
|
|
734
|
+
* Koko does not collect secrets — user types in the App UI.
|
|
735
|
+
*/
|
|
736
|
+
private async waitForAppUserGateIfNeeded(opts?: {
|
|
737
|
+
forceMessage?: string;
|
|
738
|
+
minWaitMs?: number;
|
|
739
|
+
}): Promise<'cleared' | 'timeout' | 'stopped' | 'none'> {
|
|
740
|
+
const tree = await this.safeDump();
|
|
741
|
+
const gate = tree ? detectAppUserGate(tree) : detectAppUserGate(null);
|
|
742
|
+
if (!gate && !opts?.forceMessage) return 'none';
|
|
743
|
+
if (sensitiveScreenKind(tree)) {
|
|
744
|
+
this.operationReplayGuard.markHandoff();
|
|
745
|
+
this.history = [];
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
const msg = gate
|
|
749
|
+
? gateMessageValue(gate, this.opts.locale ?? this.agent.getConfig().locale)
|
|
750
|
+
: opts?.forceMessage
|
|
751
|
+
? this.message('runtime.waitForApp', { request: opts.forceMessage })
|
|
752
|
+
: this.message('runtime.inputInApp');
|
|
753
|
+
|
|
754
|
+
this.agent.log('info', msg);
|
|
755
|
+
this.opts.onNarration?.(resolveText(msg));
|
|
756
|
+
TaskStore.setUserGateWaiting(msg);
|
|
757
|
+
const waitNode = TaskStore.appendNode({
|
|
758
|
+
kind: 'confirm',
|
|
759
|
+
title: msg,
|
|
760
|
+
status: 'running',
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
const timeout = this.opts.userGateTimeoutMs ?? 300_000;
|
|
764
|
+
const pollMs = 700;
|
|
765
|
+
const started = Date.now();
|
|
766
|
+
const minWait = opts?.minWaitMs ?? 0;
|
|
767
|
+
let checkedResumeAt = started;
|
|
768
|
+
let fingerprint = gate
|
|
769
|
+
? `${gate.kind}:${gate.nodeId}:${gate.label}`
|
|
770
|
+
: `force:${opts?.forceMessage ?? ''}`;
|
|
771
|
+
|
|
772
|
+
try {
|
|
773
|
+
while (Date.now() - started < timeout) {
|
|
774
|
+
if (this.stopped) return 'stopped';
|
|
775
|
+
await sleep(pollMs);
|
|
776
|
+
if (this.stopped) return 'stopped';
|
|
777
|
+
|
|
778
|
+
// A status check is not permission to bypass a still-private page.
|
|
779
|
+
if (AppUserGateStore.wasManuallyResumedSince(checkedResumeAt)) {
|
|
780
|
+
checkedResumeAt = Date.now() + 1;
|
|
781
|
+
const current = await this.safeDump();
|
|
782
|
+
if (current && !sensitiveScreenKind(current) && !AppUserGateStore.getHostGate()) {
|
|
783
|
+
TaskStore.updateNode(waitNode.id, {
|
|
784
|
+
status: 'done',
|
|
785
|
+
title: this.message('runtime.gateConfirmed'),
|
|
786
|
+
});
|
|
787
|
+
return 'cleared';
|
|
788
|
+
}
|
|
789
|
+
const feedback = this.message(current ? 'gate.stillPrivate' : 'gate.unreadable');
|
|
790
|
+
TaskStore.setUserGateWaiting(feedback);
|
|
791
|
+
TaskStore.updateNode(waitNode.id, { title: feedback });
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const now = await this.safeDump();
|
|
796
|
+
if (!now) continue;
|
|
797
|
+
const g2 = detectAppUserGate(now);
|
|
798
|
+
if (!g2) {
|
|
799
|
+
if (Date.now() - started >= minWait) {
|
|
800
|
+
TaskStore.updateNode(waitNode.id, {
|
|
801
|
+
status: 'done',
|
|
802
|
+
title: this.message('runtime.gateCompleted'),
|
|
803
|
+
});
|
|
804
|
+
return 'cleared';
|
|
805
|
+
}
|
|
806
|
+
continue;
|
|
807
|
+
}
|
|
808
|
+
const fp2 = `${g2.kind}:${g2.nodeId}:${g2.label}`;
|
|
809
|
+
if (fp2 !== fingerprint) {
|
|
810
|
+
fingerprint = fp2;
|
|
811
|
+
const nextMsg = gateMessageValue(g2, this.opts.locale ?? this.agent.getConfig().locale);
|
|
812
|
+
this.opts.onNarration?.(resolveText(nextMsg));
|
|
813
|
+
TaskStore.setUserGateWaiting(nextMsg);
|
|
814
|
+
TaskStore.updateNode(waitNode.id, { title: nextMsg });
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
TaskStore.updateNode(waitNode.id, {
|
|
818
|
+
status: 'failed',
|
|
819
|
+
title: this.message('runtime.gateInputTimeout'),
|
|
820
|
+
});
|
|
821
|
+
return 'timeout';
|
|
822
|
+
} finally {
|
|
823
|
+
TaskStore.setUserGateWaiting(null);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
private async executeWithRetry(
|
|
828
|
+
action: GatewayAction,
|
|
829
|
+
): Promise<{ ok: boolean; result: string }> {
|
|
830
|
+
// Only observations are safe to repeat after an exception. A rejected
|
|
831
|
+
// native promise or timed-out host callback can follow a committed action.
|
|
832
|
+
const readOnly = action.tool === 'dump' || action.tool === 'find';
|
|
833
|
+
const configured = this.opts.localRetries ?? 3;
|
|
834
|
+
const retries = readOnly && Number.isFinite(configured)
|
|
835
|
+
? Math.max(0, Math.min(3, Math.floor(configured))) : 0;
|
|
836
|
+
let last = '';
|
|
837
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
838
|
+
this.assertRunning();
|
|
839
|
+
try {
|
|
840
|
+
const result = await this.executeOnce(action);
|
|
841
|
+
this.assertRunning();
|
|
842
|
+
return { ok: true, result };
|
|
843
|
+
} catch (e) {
|
|
844
|
+
this.assertRunning();
|
|
845
|
+
last = e instanceof Error ? e.message : String(e);
|
|
846
|
+
if (e instanceof ActionValidationError || e instanceof SensitiveScreenError) {
|
|
847
|
+
// The action was rejected before dispatch; let the planner observe
|
|
848
|
+
// and choose a different target without replaying a real touch.
|
|
849
|
+
return { ok: false, result: `pre_dispatch: ${last}` };
|
|
850
|
+
}
|
|
851
|
+
if (!readOnly) throw e instanceof ActionOutcomeUnknownError ? e : new ActionOutcomeUnknownError(last);
|
|
852
|
+
if (attempt < retries) await sleep(200);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
return { ok: false, result: last || 'failed' };
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
private async executeOnce(action: GatewayAction): Promise<string> {
|
|
859
|
+
switch (action.tool) {
|
|
860
|
+
case 'dump': {
|
|
861
|
+
const tree = await this.agent.dump();
|
|
862
|
+
return `dumped || ${screenSnapshotLine(tree)}`;
|
|
863
|
+
}
|
|
864
|
+
case 'find': {
|
|
865
|
+
const selector = {
|
|
866
|
+
match: action.args.match as Selector['match'],
|
|
867
|
+
index: action.args.index,
|
|
868
|
+
};
|
|
869
|
+
// A model lookup observes the current page; it must not secretly turn
|
|
870
|
+
// into a scroll search before the planner considers visible navigation.
|
|
871
|
+
const currentTree = await this.safeDump();
|
|
872
|
+
if (!currentTree) throw new Error(this.text('runtime.unreadable'));
|
|
873
|
+
const node = await this.agent.find(selector, currentTree);
|
|
874
|
+
if (!node) return 'null';
|
|
875
|
+
return JSON.stringify({
|
|
876
|
+
id: node.id,
|
|
877
|
+
text: node.text,
|
|
878
|
+
accessibilityLabel: node.accessibilityLabel,
|
|
879
|
+
clickable: node.clickable,
|
|
880
|
+
selected: node.selected,
|
|
881
|
+
enabled: node.enabled,
|
|
882
|
+
visible: node.visible,
|
|
883
|
+
secure: node.secure,
|
|
884
|
+
frame: node.frame,
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
case 'tap': {
|
|
888
|
+
await this.agent.tap({
|
|
889
|
+
selector: action.args.selector,
|
|
890
|
+
nodeId: action.args.nodeId,
|
|
891
|
+
point: action.args.point,
|
|
892
|
+
label: action.args.label,
|
|
893
|
+
options: { revealIfNeeded: false },
|
|
894
|
+
});
|
|
895
|
+
return `tapped ${action.args.label || action.args.nodeId || 'target'}`;
|
|
896
|
+
}
|
|
897
|
+
case 'swipe': {
|
|
898
|
+
await this.agent.swipe(action.args.from, action.args.to);
|
|
899
|
+
return 'swiped';
|
|
900
|
+
}
|
|
901
|
+
case 'pinch': {
|
|
902
|
+
await this.agent.pinch(action.args.center, action.args.scale);
|
|
903
|
+
return `pinched scale=${action.args.scale}`;
|
|
904
|
+
}
|
|
905
|
+
case 'type': {
|
|
906
|
+
// Never type into secure fields — wait for user instead.
|
|
907
|
+
const root = await this.safeDump();
|
|
908
|
+
this.assertRunning();
|
|
909
|
+
if (root && detectAppUserGate(root)) {
|
|
910
|
+
await this.waitForAppUserGateIfNeeded();
|
|
911
|
+
return 'skipped type: waited for user secure input';
|
|
912
|
+
}
|
|
913
|
+
await this.agent.type(action.args.text, {
|
|
914
|
+
selector: action.args.selector,
|
|
915
|
+
nodeId: action.args.nodeId,
|
|
916
|
+
options: { clear: action.args.clear },
|
|
917
|
+
label: action.args.label,
|
|
918
|
+
});
|
|
919
|
+
return `typed ${action.args.text.slice(0, 40)}`;
|
|
920
|
+
}
|
|
921
|
+
default:
|
|
922
|
+
return 'noop';
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function actionDetail(action: GatewayAction): string | undefined {
|
|
928
|
+
switch (action.tool) {
|
|
929
|
+
case 'tap':
|
|
930
|
+
return action.args.label;
|
|
931
|
+
case 'type':
|
|
932
|
+
return action.args.label || action.args.text?.slice(0, 24);
|
|
933
|
+
case 'swipe':
|
|
934
|
+
return action.args.label;
|
|
935
|
+
case 'pinch':
|
|
936
|
+
return action.args.label || `×${action.args.scale}`;
|
|
937
|
+
case 'find': {
|
|
938
|
+
const first = action.args.match?.[0] as { text?: string } | undefined;
|
|
939
|
+
return first?.text;
|
|
940
|
+
}
|
|
941
|
+
case 'ask_user':
|
|
942
|
+
return action.args.question?.slice(0, 60);
|
|
943
|
+
case 'done':
|
|
944
|
+
return action.args.summary?.slice(0, 80);
|
|
945
|
+
default:
|
|
946
|
+
return undefined;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
function sleep(ms: number): Promise<void> {
|
|
951
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
952
|
+
}
|