akanjs 3.0.0-alpha.2 → 3.0.0-alpha.21
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.ko.md +1 -1
- package/README.md +1 -1
- package/base/symbols.ts +4 -0
- package/client/clientRuntime.ts +8 -0
- package/client/cn.ts +7 -0
- package/client/csrTypes.ts +2 -0
- package/client/frameDebug.ts +3 -2
- package/common/Logger.ts +4 -0
- package/common/deepObjectify.ts +21 -7
- package/common/index.ts +14 -0
- package/common/mcpExposure.ts +99 -0
- package/common/pathSet.ts +17 -5
- package/common/routeConvention.ts +30 -0
- package/constant/crystalize.ts +3 -1
- package/constant/fieldInfo.ts +6 -0
- package/constant/getDefault.ts +37 -9
- package/constant/immerify.ts +1 -1
- package/constant/index.ts +2 -0
- package/constant/labelOf.ts +17 -0
- package/constant/mask.ts +60 -0
- package/constant/purify.ts +17 -11
- package/constant/types.ts +14 -12
- package/dictionary/DictionaryLookup.ts +30 -0
- package/dictionary/agent.dictionary.ts +31 -0
- package/dictionary/agentTurn.dictionary.ts +29 -0
- package/dictionary/base.dictionary.ts +8 -0
- package/dictionary/dictInfo.ts +8 -0
- package/dictionary/dictionary.ts +9 -3
- package/dictionary/index.ts +1 -0
- package/document/database.ts +21 -0
- package/document/filterMeta.ts +7 -0
- package/document/index.ts +1 -0
- package/document/into.ts +7 -1
- package/document/noDocumentError.ts +12 -0
- package/fetch/agentTurn.ts +19 -0
- package/fetch/client/fetchClient.ts +71 -13
- package/fetch/client/wsClient.ts +17 -2
- package/fetch/fetchType/endpointFetch.type.ts +10 -4
- package/fetch/index.ts +1 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db-wal +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-wal +0 -0
- package/package.json +11 -9
- package/server/akanApp.ts +30 -34
- package/server/akanOption.ts +65 -7
- package/server/akanServer.ts +172 -7
- package/server/animatedImage.ts +83 -0
- package/server/artifact/routeClientCache.ts +14 -0
- package/server/assetEncoding.ts +47 -0
- package/server/devtools/signalSerializer.ts +2 -2
- package/server/devtools/types.ts +2 -2
- package/server/di/diLifecycle.ts +31 -3
- package/server/di/predefinedAdaptor.ts +6 -0
- package/server/imageOptimizer.ts +33 -46
- package/server/index.ts +1 -2
- package/server/mcp/McpAuth.ts +177 -0
- package/server/mcp/McpDispatcher.ts +245 -0
- package/server/mcp/McpEventStream.ts +76 -0
- package/server/mcp/McpExecutionContext.ts +105 -0
- package/server/mcp/McpRouter.ts +591 -0
- package/server/mcp/index.ts +5 -0
- package/server/resolver/CascadeRunner.ts +1 -1
- package/server/resolver/database.resolver.ts +42 -5
- package/server/resolver/service.resolver.ts +29 -0
- package/server/resolver/signal.resolver.ts +16 -1
- package/server/routeTreeBuilder.ts +2 -44
- package/server/rscWorker.tsx +6 -2
- package/server/subRouteIndexDocument.tsx +61 -0
- package/server/systemPageDocument.tsx +2 -2
- package/server/systemPages.tsx +49 -16
- package/server/vendor/akanjs-fetch.ts +1 -0
- package/server/webRouter.ts +159 -35
- package/service/agent.service.ts +14 -0
- package/service/base.service.ts +2 -1
- package/service/index.ts +1 -0
- package/service/predefinedAdaptor/database.adaptor.ts +78 -24
- package/service/predefinedAdaptor/deepseekLlm.ts +230 -0
- package/service/predefinedAdaptor/index.ts +3 -0
- package/service/predefinedAdaptor/insightQuery.ts +183 -0
- package/service/predefinedAdaptor/llm.adaptor.ts +76 -0
- package/service/predefinedAdaptor/role.adaptor.ts +2 -0
- package/service/predefinedAdaptor/schedule.adaptor.ts +12 -5
- package/service/serviceModule.ts +17 -0
- package/service/types.ts +4 -0
- package/signal/agent/AgentCatalogue.ts +165 -0
- package/signal/agent/index.ts +1 -0
- package/signal/agent.signal.ts +42 -0
- package/signal/agentTurn.ts +8 -0
- package/signal/agentTurnStream.ts +48 -0
- package/signal/base.signal.ts +2 -1
- package/signal/endpointInfo.ts +38 -2
- package/signal/guard.ts +13 -1
- package/signal/guards.ts +52 -1
- package/signal/index.ts +6 -0
- package/signal/mcp/McpDocument.ts +286 -0
- package/signal/mcp/McpProgress.ts +106 -0
- package/signal/mcp/McpUriTemplate.ts +85 -0
- package/signal/mcp/Msg.ts +368 -0
- package/signal/mcp/index.ts +5 -0
- package/signal/mcp/mcpProtocol.ts +120 -0
- package/signal/middleware.ts +7 -3
- package/signal/openapi/openapi.ts +32 -171
- package/signal/schema/JsonSchemaBuilder.ts +211 -0
- package/signal/schema/index.ts +1 -0
- package/signal/signalContext.ts +85 -9
- package/signal/slice.ts +9 -9
- package/signal/types.ts +1 -1
- package/store/action.ts +11 -22
- package/store/actionTag.ts +33 -0
- package/store/agent/AgentBridge.ts +323 -0
- package/store/agent/AgentContext.ts +74 -0
- package/store/agent/AgentPrompts.ts +82 -0
- package/store/agent/AgentVisibility.ts +68 -0
- package/store/agent/ScreenReader.ts +208 -0
- package/store/agent/StoreCatalogue.ts +351 -0
- package/store/agent/StoreSurfaceSource.ts +122 -0
- package/store/agent/index.ts +9 -0
- package/store/agent/storeSurface.ts +28 -0
- package/store/agent/types.ts +50 -0
- package/store/agentic/StToolBuilder.ts +199 -0
- package/store/agentic/attachAgentic.ts +22 -0
- package/store/agentic/index.ts +5 -0
- package/store/agentic/readableValue.ts +17 -0
- package/store/agentic/useStExpose.ts +18 -0
- package/store/agentic/useStState.ts +35 -0
- package/store/baseSt.ts +7 -0
- package/store/databaseStateNames.ts +31 -0
- package/store/formSetterNames.ts +21 -0
- package/store/index.ts +8 -0
- package/store/rootStore.ts +3 -1
- package/store/sliceRole.ts +36 -0
- package/store/state.ts +2 -12
- package/store/store.ts +19 -1
- package/store/storeInstance.ts +165 -20
- package/store/storeRegistry.ts +16 -1
- package/store/types.ts +18 -0
- package/store/withSelector.ts +7 -8
- package/test/registerDom.ts +4 -0
- package/types/base/symbols.d.ts +4 -0
- package/types/client/cn.d.ts +5 -0
- package/types/client/csrTypes.d.ts +2 -0
- package/types/common/Logger.d.ts +2 -0
- package/types/common/deepObjectify.d.ts +4 -2
- package/types/common/index.d.ts +2 -1
- package/types/common/mcpExposure.d.ts +60 -0
- package/types/common/routeConvention.d.ts +8 -0
- package/types/constant/fieldInfo.d.ts +1 -0
- package/types/constant/getDefault.d.ts +5 -0
- package/types/constant/index.d.ts +2 -0
- package/types/constant/labelOf.d.ts +6 -0
- package/types/constant/mask.d.ts +34 -0
- package/types/constant/purify.d.ts +2 -2
- package/types/constant/types.d.ts +2 -2
- package/types/dictionary/DictionaryLookup.d.ts +14 -0
- package/types/dictionary/agent.dictionary.d.ts +1 -0
- package/types/dictionary/agentTurn.dictionary.d.ts +1 -0
- package/types/dictionary/base.dictionary.d.ts +1 -1
- package/types/dictionary/dictInfo.d.ts +6 -0
- package/types/dictionary/dictionary.d.ts +11 -9
- package/types/dictionary/index.d.ts +1 -0
- package/types/document/database.d.ts +20 -0
- package/types/document/filterMeta.d.ts +1 -0
- package/types/document/index.d.ts +1 -0
- package/types/document/into.d.ts +6 -1
- package/types/document/noDocumentError.d.ts +12 -0
- package/types/fetch/agentTurn.d.ts +593 -0
- package/types/fetch/client/fetchClient.d.ts +10 -0
- package/types/fetch/fetchType/endpointFetch.type.d.ts +5 -3
- package/types/fetch/index.d.ts +1 -0
- package/types/server/akanOption.d.ts +35 -7
- package/types/server/akanServer.d.ts +44 -1
- package/types/server/animatedImage.d.ts +7 -0
- package/types/server/artifact/routeClientCache.d.ts +6 -0
- package/types/server/assetEncoding.d.ts +7 -0
- package/types/server/devtools/types.d.ts +2 -2
- package/types/server/di/predefinedAdaptor.d.ts +4 -1
- package/types/server/index.d.ts +0 -2
- package/types/server/mcp/McpAuth.d.ts +62 -0
- package/types/server/mcp/McpDispatcher.d.ts +54 -0
- package/types/server/mcp/McpEventStream.d.ts +18 -0
- package/types/server/mcp/McpExecutionContext.d.ts +44 -0
- package/types/server/mcp/McpRouter.d.ts +60 -0
- package/types/server/mcp/index.d.ts +5 -0
- package/types/server/mcp.d.ts +1 -0
- package/types/server/subRouteIndexDocument.d.ts +8 -0
- package/types/server/systemPageDocument.d.ts +1 -0
- package/types/server/systemPages.d.ts +5 -0
- package/types/server/vendor/akanjs-fetch.d.ts +1 -0
- package/types/service/agent.service.d.ts +12 -0
- package/types/service/base.service.d.ts +4 -0
- package/types/service/index.d.ts +1 -0
- package/types/service/predefinedAdaptor/database.adaptor.d.ts +24 -2
- package/types/service/predefinedAdaptor/deepseekLlm.d.ts +64 -0
- package/types/service/predefinedAdaptor/index.d.ts +3 -0
- package/types/service/predefinedAdaptor/insightQuery.d.ts +50 -0
- package/types/service/predefinedAdaptor/llm.adaptor.d.ts +68 -0
- package/types/service/predefinedAdaptor/role.adaptor.d.ts +2 -0
- package/types/service/predefinedAdaptor/schedule.adaptor.d.ts +10 -6
- package/types/service/types.d.ts +4 -1
- package/types/signal/agent/AgentCatalogue.d.ts +100 -0
- package/types/signal/agent/index.d.ts +1 -0
- package/types/signal/agent.d.ts +1 -0
- package/types/signal/agent.signal.d.ts +29 -0
- package/types/signal/agentTurn.d.ts +9 -0
- package/types/signal/agentTurnStream.d.ts +16 -0
- package/types/signal/base.signal.d.ts +1 -1
- package/types/signal/endpointInfo.d.ts +21 -3
- package/types/signal/guard.d.ts +11 -0
- package/types/signal/guards.d.ts +22 -1
- package/types/signal/index.d.ts +6 -0
- package/types/signal/mcp/McpDocument.d.ts +65 -0
- package/types/signal/mcp/McpProgress.d.ts +40 -0
- package/types/signal/mcp/McpUriTemplate.d.ts +26 -0
- package/types/signal/mcp/Msg.d.ts +143 -0
- package/types/signal/mcp/index.d.ts +5 -0
- package/types/signal/mcp/mcpProtocol.d.ts +107 -0
- package/types/signal/mcp.d.ts +1 -0
- package/types/signal/openapi/openapi.d.ts +3 -3
- package/types/signal/schema/JsonSchemaBuilder.d.ts +47 -0
- package/types/signal/schema/index.d.ts +1 -0
- package/types/signal/schema.d.ts +1 -0
- package/types/signal/signalContext.d.ts +16 -1
- package/types/signal/slice.d.ts +8 -8
- package/types/signal/types.d.ts +1 -1
- package/types/store/actionTag.d.ts +21 -0
- package/types/store/agent/AgentBridge.d.ts +77 -0
- package/types/store/agent/AgentContext.d.ts +16 -0
- package/types/store/agent/AgentPrompts.d.ts +31 -0
- package/types/store/agent/AgentVisibility.d.ts +21 -0
- package/types/store/agent/ScreenReader.d.ts +11 -0
- package/types/store/agent/StoreCatalogue.d.ts +26 -0
- package/types/store/agent/StoreSurfaceSource.d.ts +18 -0
- package/types/store/agent/index.d.ts +9 -0
- package/types/store/agent/storeSurface.d.ts +14 -0
- package/types/store/agent/types.d.ts +49 -0
- package/types/store/agent.d.ts +1 -0
- package/types/store/agentic/StToolBuilder.d.ts +41 -0
- package/types/store/agentic/attachAgentic.d.ts +14 -0
- package/types/store/agentic/index.d.ts +5 -0
- package/types/store/agentic/readableValue.d.ts +3 -0
- package/types/store/agentic/useStExpose.d.ts +8 -0
- package/types/store/agentic/useStState.d.ts +12 -0
- package/types/store/agentic.d.ts +1 -0
- package/types/store/baseSt.d.ts +29 -22
- package/types/store/databaseStateNames.d.ts +25 -0
- package/types/store/formSetterNames.d.ts +16 -0
- package/types/store/index.d.ts +7 -0
- package/types/store/rootStore.d.ts +5 -1
- package/types/store/sliceRole.d.ts +25 -0
- package/types/store/store.d.ts +7 -2
- package/types/store/storeInstance.d.ts +33 -1
- package/types/store/storeRegistry.d.ts +5 -0
- package/types/store/types.d.ts +15 -0
- package/types/store/withSelector.d.ts +7 -8
- package/types/test/registerDom.d.ts +1 -0
- package/types/ui/Agent/Approval.d.ts +7 -0
- package/types/ui/Agent/Bubble.d.ts +13 -0
- package/types/ui/Agent/Chat.d.ts +24 -0
- package/types/ui/Agent/Context.d.ts +9 -0
- package/types/ui/Agent/Dock.d.ts +16 -0
- package/types/ui/Agent/Guide.d.ts +9 -0
- package/types/ui/Agent/Section.d.ts +10 -0
- package/types/ui/Agent/StateKey.d.ts +16 -0
- package/types/ui/Agent/Tool.d.ts +15 -0
- package/types/ui/Agent/Transcript.d.ts +13 -0
- package/types/ui/Agent/Zone.d.ts +23 -0
- package/types/ui/Agent/fetchRunner.d.ts +12 -0
- package/types/ui/Agent/index.d.ts +17 -0
- package/types/ui/Agent/index_.d.ts +1 -0
- package/types/ui/Agent/sessionHistory.d.ts +12 -0
- package/types/ui/Agent.d.ts +1 -0
- package/types/ui/Badge.d.ts +1 -1
- package/types/ui/Button.d.ts +1 -1
- package/types/ui/CsrImage.d.ts +1 -1
- package/types/ui/Dropdown.d.ts +2 -0
- package/types/ui/Image.d.ts +3 -3
- package/types/ui/Layout/BottomInset.d.ts +2 -1
- package/types/ui/Layout/index.d.ts +1 -1
- package/types/ui/Signal/style.d.ts +4 -1
- package/types/ui/UiOverride/context.d.ts +14 -2
- package/types/ui/agentAttrs.d.ts +14 -0
- package/types/ui/index.d.ts +4 -1
- package/types/ui/overlayLayer.d.ts +24 -0
- package/types/ui/recipe/badgeRecipe.d.ts +7 -3
- package/types/ui/recipe/buttonRecipe.d.ts +7 -3
- package/types/ui/recipe/inputRecipe.d.ts +5 -1
- package/types/vendor/use-agentic/AgentProvider.d.ts +18 -0
- package/types/vendor/use-agentic/AgentScope.d.ts +9 -0
- package/types/vendor/use-agentic/AgentSession.d.ts +50 -0
- package/types/vendor/use-agentic/Agentic.d.ts +21 -0
- package/types/vendor/use-agentic/AgenticSurface.d.ts +44 -0
- package/types/vendor/use-agentic/httpRunner.d.ts +15 -0
- package/types/vendor/use-agentic/index.d.ts +13 -0
- package/types/vendor/use-agentic/surfaceContext.d.ts +5 -0
- package/types/vendor/use-agentic/types.d.ts +133 -0
- package/types/vendor/use-agentic/useAgent.d.ts +4 -0
- package/types/vendor/use-agentic/useAgentGuide.d.ts +6 -0
- package/types/vendor/use-agentic/useAgentResource.d.ts +7 -0
- package/types/vendor/use-agentic/useAgentState.d.ts +13 -0
- package/types/vendor/use-agentic/useAgentTool.d.ts +16 -0
- package/types/vendor/use-agentic.d.ts +1 -0
- package/types/webkit/index.d.ts +3 -0
- package/types/webkit/lazy.d.ts +12 -0
- package/types/webkit/useCsrValues.d.ts +3 -3
- package/types/webkit/useEscapeKey.d.ts +5 -0
- package/types/webkit/useFrameRuntime.d.ts +6 -1
- package/types/webkit/useScreenScope.d.ts +18 -0
- package/ui/Agent/Approval.tsx +29 -0
- package/ui/Agent/Bubble.tsx +74 -0
- package/ui/Agent/Chat.tsx +225 -0
- package/ui/Agent/Context.tsx +38 -0
- package/ui/Agent/Dock.tsx +72 -0
- package/ui/Agent/Guide.tsx +16 -0
- package/ui/Agent/Section.tsx +24 -0
- package/ui/Agent/StateKey.tsx +44 -0
- package/ui/Agent/Tool.tsx +66 -0
- package/ui/Agent/Transcript.tsx +33 -0
- package/ui/Agent/Zone.tsx +48 -0
- package/ui/Agent/fetchRunner.ts +30 -0
- package/ui/Agent/index.ts +12 -0
- package/ui/Agent/index_.tsx +4 -0
- package/ui/Agent/sessionHistory.ts +33 -0
- package/ui/Badge.tsx +3 -3
- package/ui/BottomSheet.tsx +5 -0
- package/ui/Button.tsx +6 -2
- package/ui/Constant/Doc.tsx +1 -1
- package/ui/CsrImage.tsx +1 -1
- package/ui/Data/ListContainer.tsx +1 -1
- package/ui/DatePicker.tsx +5 -4
- package/ui/Dialog/Modal.tsx +12 -15
- package/ui/DraggableList.tsx +3 -1
- package/ui/Dropdown.tsx +33 -11
- package/ui/Field.tsx +30 -16
- package/ui/Image.tsx +3 -3
- package/ui/Input.tsx +14 -5
- package/ui/Layout/BottomInset.tsx +6 -1
- package/ui/Load/Units.tsx +11 -2
- package/ui/Load/View.tsx +7 -2
- package/ui/Loading/ProgressBar.tsx +8 -1
- package/ui/Menu.tsx +7 -8
- package/ui/Model/EditModal.tsx +37 -2
- package/ui/Model/SureToRemove.tsx +2 -1
- package/ui/Model/index_.tsx +42 -15
- package/ui/ObjectId.tsx +3 -4
- package/ui/Pagination.tsx +3 -4
- package/ui/Popconfirm.tsx +8 -7
- package/ui/Select.tsx +6 -4
- package/ui/Signal/RestApi.tsx +43 -16
- package/ui/Signal/WebSocket.tsx +1 -1
- package/ui/Signal/style.ts +6 -1
- package/ui/Switch.tsx +2 -0
- package/ui/System/CSR.tsx +6 -2
- package/ui/System/ThemeToggle.tsx +55 -33
- package/ui/ToggleSelect.tsx +4 -3
- package/ui/Tooltip.tsx +2 -1
- package/ui/UiOverride/context.ts +14 -2
- package/ui/agentAttrs.ts +19 -0
- package/ui/index.ts +10 -1
- package/ui/overlayLayer.ts +39 -0
- package/ui/recipe/badgeRecipe.ts +22 -3
- package/ui/recipe/buttonRecipe.ts +51 -2
- package/ui/recipe/factory.ts +2 -2
- package/ui/recipe/inputRecipe.ts +18 -4
- package/vendor/use-agentic/AgentProvider.tsx +39 -0
- package/vendor/use-agentic/AgentScope.tsx +20 -0
- package/vendor/use-agentic/AgentSession.ts +292 -0
- package/vendor/use-agentic/Agentic.tsx +44 -0
- package/vendor/use-agentic/AgenticSurface.ts +294 -0
- package/vendor/use-agentic/WIRE.md +57 -0
- package/vendor/use-agentic/httpRunner.ts +115 -0
- package/vendor/use-agentic/index.ts +14 -0
- package/vendor/use-agentic/surfaceContext.ts +9 -0
- package/vendor/use-agentic/types.ts +144 -0
- package/vendor/use-agentic/useAgent.ts +17 -0
- package/vendor/use-agentic/useAgentGuide.ts +16 -0
- package/vendor/use-agentic/useAgentResource.ts +30 -0
- package/vendor/use-agentic/useAgentState.ts +61 -0
- package/vendor/use-agentic/useAgentTool.ts +55 -0
- package/webkit/bootCsr.tsx +2 -33
- package/webkit/index.ts +3 -0
- package/webkit/lazy.tsx +27 -3
- package/webkit/useCsrValues.ts +121 -4
- package/webkit/useEscapeKey.tsx +42 -0
- package/webkit/useFrameRuntime.ts +65 -32
- package/webkit/useScreenScope.tsx +49 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentRunner } from "./types.d.ts";
|
|
2
|
+
export interface HttpRunnerOptions {
|
|
3
|
+
url: string;
|
|
4
|
+
headers?: () => Record<string, string>;
|
|
5
|
+
/** Swap the transport — tests, a framework's own HTTP client, a custom fetch with credentials. */
|
|
6
|
+
fetcher?: typeof fetch;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The default runner: one stateless POST per assistant turn, negotiated via `accept`. A server that streams
|
|
10
|
+
* answers `text/event-stream` — one `RunnerEvent` JSON per SSE `data:` line, ending with `done` — and one that
|
|
11
|
+
* does not answers the single JSON `TurnAnswer`; both ride the same endpoint and the same request JSON.
|
|
12
|
+
*
|
|
13
|
+
* The wire is documented in WIRE.md so any backend can serve it.
|
|
14
|
+
*/
|
|
15
|
+
export declare const httpRunner: ({ url, headers, fetcher }: HttpRunnerOptions) => AgentRunner;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export * from "./Agentic.d.ts";
|
|
2
|
+
export * from "./AgenticSurface.d.ts";
|
|
3
|
+
export * from "./AgentProvider.d.ts";
|
|
4
|
+
export * from "./AgentScope.d.ts";
|
|
5
|
+
export * from "./AgentSession.d.ts";
|
|
6
|
+
export * from "./httpRunner.d.ts";
|
|
7
|
+
export * from "./surfaceContext.d.ts";
|
|
8
|
+
export * from "./types.d.ts";
|
|
9
|
+
export * from "./useAgent.d.ts";
|
|
10
|
+
export * from "./useAgentGuide.d.ts";
|
|
11
|
+
export * from "./useAgentResource.d.ts";
|
|
12
|
+
export * from "./useAgentState.d.ts";
|
|
13
|
+
export * from "./useAgentTool.d.ts";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AgenticSurface } from "./AgenticSurface.d.ts";
|
|
2
|
+
export declare const SurfaceContext: import("react").Context<AgenticSurface | null>;
|
|
3
|
+
export declare const ScopeContext: import("react").Context<string[]>;
|
|
4
|
+
export declare const useSurface: () => AgenticSurface;
|
|
5
|
+
export declare const useScopePath: () => string[];
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export type JsonSchema = Record<string, unknown>;
|
|
2
|
+
export type ToolEffect = "state" | "query" | "mutation";
|
|
3
|
+
/** `true` asks with a default message, a string is the message, a function decides from the arguments. */
|
|
4
|
+
export type ToolConfirm = boolean | string | ((args: Record<string, unknown>) => string | boolean);
|
|
5
|
+
/** Re-checked at the moment of execution; a string is the refusal reason the agent reads. */
|
|
6
|
+
export type ToolGuard = (args: Record<string, unknown>) => true | string;
|
|
7
|
+
export interface ToolEntry {
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
parameters?: JsonSchema;
|
|
11
|
+
effect?: ToolEffect;
|
|
12
|
+
confirm?: ToolConfirm;
|
|
13
|
+
guard?: ToolGuard;
|
|
14
|
+
run: (args: Record<string, unknown>) => unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface ResourceEntry {
|
|
17
|
+
name: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
/** `false` keeps it out of post-call diff reports — for values that change on their own every second. */
|
|
20
|
+
report?: boolean;
|
|
21
|
+
read: () => unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface ScopeEntry {
|
|
24
|
+
id: string;
|
|
25
|
+
label?: string;
|
|
26
|
+
kind?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A bulk contributor of entries whose names are already full — how a host store joins the surface. `view` is the
|
|
30
|
+
* scope path a zone session reads through; a source that ignores it contributes the same entries to every view.
|
|
31
|
+
*/
|
|
32
|
+
export interface SurfaceSource {
|
|
33
|
+
tools?: (view?: string[]) => ToolEntry[];
|
|
34
|
+
resources?: (view?: string[]) => ResourceEntry[];
|
|
35
|
+
subscribe?: (listener: () => void) => () => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The reading half of a surface — what a session consumes. `AgenticSurface` is one; `surface.view(path)` answers a
|
|
39
|
+
* zone-scoped one over the same registry, so zones are views of the screen, never walls between its parts.
|
|
40
|
+
*/
|
|
41
|
+
export interface SurfaceView {
|
|
42
|
+
snapshot(): SurfaceSnapshot;
|
|
43
|
+
tool(name: string): ToolEntry | null;
|
|
44
|
+
call(name: string, args?: Record<string, unknown>): Promise<unknown>;
|
|
45
|
+
read(name: string): unknown;
|
|
46
|
+
diffSince(before: SurfaceSnapshot): ResourceDiff[];
|
|
47
|
+
subscribe(listener: () => void): () => void;
|
|
48
|
+
}
|
|
49
|
+
export interface PublishedTool {
|
|
50
|
+
name: string;
|
|
51
|
+
description?: string;
|
|
52
|
+
parameters?: JsonSchema;
|
|
53
|
+
effect?: ToolEffect;
|
|
54
|
+
needsConfirm: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface PublishedResource {
|
|
57
|
+
name: string;
|
|
58
|
+
description?: string;
|
|
59
|
+
value?: unknown;
|
|
60
|
+
error?: string;
|
|
61
|
+
}
|
|
62
|
+
export interface PublishedScope {
|
|
63
|
+
path: string;
|
|
64
|
+
label?: string;
|
|
65
|
+
kind?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface SurfaceSnapshot {
|
|
68
|
+
tools: PublishedTool[];
|
|
69
|
+
resources: PublishedResource[];
|
|
70
|
+
scopes: PublishedScope[];
|
|
71
|
+
/** Standing guidance texts, in registration order. Folded into the turn's instructions, not into context. */
|
|
72
|
+
guides: string[];
|
|
73
|
+
}
|
|
74
|
+
export interface ResourceDiff {
|
|
75
|
+
name: string;
|
|
76
|
+
value?: unknown;
|
|
77
|
+
error?: string;
|
|
78
|
+
removed?: boolean;
|
|
79
|
+
}
|
|
80
|
+
export type ChatRole = "user" | "assistant" | "tool";
|
|
81
|
+
export interface ToolCallRequest {
|
|
82
|
+
id: string;
|
|
83
|
+
name: string;
|
|
84
|
+
args: Record<string, unknown>;
|
|
85
|
+
}
|
|
86
|
+
export interface ToolCallResult {
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
/** What `run` returned. Must be JSON-serializable — it rides the wire back to the model. */
|
|
90
|
+
result?: unknown;
|
|
91
|
+
/** What the call changed on the surface — the whole report for a tool that returns nothing. */
|
|
92
|
+
changes?: ResourceDiff[];
|
|
93
|
+
error?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface ChatMessage {
|
|
96
|
+
role: ChatRole;
|
|
97
|
+
text?: string;
|
|
98
|
+
toolCalls?: ToolCallRequest[];
|
|
99
|
+
toolResults?: ToolCallResult[];
|
|
100
|
+
/** A failed or capped turn, recorded in the transcript rather than thrown past it. */
|
|
101
|
+
error?: string;
|
|
102
|
+
}
|
|
103
|
+
/** One block of screen context the host assembles per turn. `kind` is the host's vocabulary; the wire forwards it verbatim. */
|
|
104
|
+
export interface ContextBlock {
|
|
105
|
+
kind: string;
|
|
106
|
+
[key: string]: unknown;
|
|
107
|
+
}
|
|
108
|
+
export type RunnerEvent = {
|
|
109
|
+
type: "text";
|
|
110
|
+
delta: string;
|
|
111
|
+
} | {
|
|
112
|
+
type: "toolCall";
|
|
113
|
+
id: string;
|
|
114
|
+
name: string;
|
|
115
|
+
args: Record<string, unknown>;
|
|
116
|
+
} | {
|
|
117
|
+
type: "done";
|
|
118
|
+
stop: "end" | "toolUse";
|
|
119
|
+
} | {
|
|
120
|
+
type: "error";
|
|
121
|
+
message: string;
|
|
122
|
+
};
|
|
123
|
+
export interface RunnerRequest {
|
|
124
|
+
messages: ChatMessage[];
|
|
125
|
+
tools: PublishedTool[];
|
|
126
|
+
context: ContextBlock[];
|
|
127
|
+
instructions?: string;
|
|
128
|
+
signal: AbortSignal;
|
|
129
|
+
}
|
|
130
|
+
/** One model turn: request in, streamed events out. Where the loop runs is the implementation's business. */
|
|
131
|
+
export interface AgentRunner {
|
|
132
|
+
run: (request: RunnerRequest) => AsyncIterable<RunnerEvent>;
|
|
133
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { AgentSession } from "./AgentSession.d.ts";
|
|
2
|
+
export declare const SessionContext: import("react").Context<AgentSession | null>;
|
|
3
|
+
/** The enclosing session, re-rendering on every session change. `send`/`abort` are safe to destructure. */
|
|
4
|
+
export declare const useAgent: () => AgentSession;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers standing guidance for the agent while the component is mounted. Guidance is folded into the turn's
|
|
3
|
+
* instructions — it directs the model, unlike context, which is framed as data. The text is captured at mount
|
|
4
|
+
* like every declaration on the surface; remount to change it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const useAgentGuide: (text: string) => void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface AgentResourceMeta {
|
|
2
|
+
description?: string;
|
|
3
|
+
serialize?: (value: unknown) => unknown;
|
|
4
|
+
report?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Publishes a read-only view of any value the component already holds — derived totals, statuses, labels. */
|
|
7
|
+
export declare const useAgentResource: (name: string, value: unknown, meta?: AgentResourceMeta) => void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Dispatch, type SetStateAction } from "react";
|
|
2
|
+
import type { JsonSchema } from "./types.d.ts";
|
|
3
|
+
export interface AgentStateMeta<T> {
|
|
4
|
+
description?: string;
|
|
5
|
+
serialize?: (value: T) => unknown;
|
|
6
|
+
report?: boolean;
|
|
7
|
+
/** Schema of the setter's `value` argument. Without it the state is published read-only. */
|
|
8
|
+
set?: JsonSchema;
|
|
9
|
+
/** Validates or coerces the setter's incoming `value` — throw to refuse the write. Nothing else enforces `set`. */
|
|
10
|
+
parse?: (value: unknown) => T;
|
|
11
|
+
}
|
|
12
|
+
/** `useState` the agent can read — and write only through a named setter tool, and only when `set` declares one. */
|
|
13
|
+
export declare const useAgentState: <T>(name: string, initial: T | (() => T), meta?: AgentStateMeta<T>) => [T, Dispatch<SetStateAction<T>>];
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { JsonSchema, ToolConfirm, ToolEffect, ToolGuard } from "./types.d.ts";
|
|
2
|
+
export interface AgentToolMeta {
|
|
3
|
+
description?: string;
|
|
4
|
+
parameters?: JsonSchema;
|
|
5
|
+
effect?: ToolEffect;
|
|
6
|
+
confirm?: ToolConfirm;
|
|
7
|
+
guard?: ToolGuard;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Publishes one tool for as long as the component is mounted.
|
|
11
|
+
*
|
|
12
|
+
* Identity is the scoped name, not the callback — `run`, `guard`, and `confirm` read the latest render through a
|
|
13
|
+
* ref, so there is no dependency array and no stale closure for the agent to hit. `description` and `parameters`
|
|
14
|
+
* are declaration data, read once at mount.
|
|
15
|
+
*/
|
|
16
|
+
export declare const useAgentTool: <Args extends Record<string, unknown> = Record<string, unknown>, Result = unknown>(name: string, meta: AgentToolMeta, run: (args: Args) => Result | Promise<Result>) => ((args?: Args) => Promise<Result>);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./use-agentic/index.d.ts";
|
package/types/webkit/index.d.ts
CHANGED
|
@@ -8,9 +8,12 @@ export { useCodepush } from "./useCodepush.d.ts";
|
|
|
8
8
|
export { useContact } from "./useContact.d.ts";
|
|
9
9
|
export { useCsrValues } from "./useCsrValues.d.ts";
|
|
10
10
|
export { useDebounce } from "./useDebounce.d.ts";
|
|
11
|
+
export { useEscapeKey } from "./useEscapeKey.d.ts";
|
|
11
12
|
export { useFetch, useFetchFn } from "./useFetch.d.ts";
|
|
12
13
|
export { useGeoLocation } from "./useGeoLocation.d.ts";
|
|
13
14
|
export { useHistory } from "./useHistory.d.ts";
|
|
14
15
|
export { useInterval } from "./useInterval.d.ts";
|
|
15
16
|
export { useLocation } from "./useLocation.d.ts";
|
|
17
|
+
export type { ScreenScopeItem } from "./useScreenScope.d.ts";
|
|
18
|
+
export { useScreenScope } from "./useScreenScope.d.ts";
|
|
16
19
|
export { useThrottle } from "./useThrottle.d.ts";
|
package/types/webkit/lazy.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* `suspense` puts a Suspense boundary around the lazy component, so a chunk that resolves *after* the
|
|
4
|
+
* page is painted — a modal body, a dropdown menu — suspends only itself. Without one the suspension
|
|
5
|
+
* travels up to the nearest boundary, which is the route (`server/routeElementComposer.tsx`), and the
|
|
6
|
+
* whole page repaints as its loading fallback on the first open.
|
|
7
|
+
*
|
|
8
|
+
* It is opt-in rather than the default because a boundary also changes server rendering: under the
|
|
9
|
+
* default `renderMode: "stream"` the boundary's subtree leaves the shell as `loading` and arrives later
|
|
10
|
+
* in the stream. That is fine for an interaction shell and wrong for a page body, which SEO snapshots,
|
|
11
|
+
* prerendering and pre-hydration E2E read out of the shell.
|
|
12
|
+
*/
|
|
2
13
|
type LazyOption = {
|
|
3
14
|
ssr?: boolean;
|
|
15
|
+
suspense?: boolean;
|
|
4
16
|
loading?: () => ReactNode;
|
|
5
17
|
};
|
|
6
18
|
type LoadedOf<Loaded> = Loaded extends {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type NavigationIntent, type PathRoute, type RouteGuide, type RouterInstance, type TransitionType } from "akanjs/client";
|
|
1
|
+
import { type NavigationIntent, type PageTransition, type PathRoute, type RouteGuide, type RouterInstance, type TransitionType } from "akanjs/client";
|
|
2
2
|
export declare const useCsrValues: (rootRouteGuide: RouteGuide, pathRoutes: PathRoute[]) => {
|
|
3
|
+
page: PageTransition | null;
|
|
3
4
|
topSafeArea: import("akanjs/client").SafeAreaTransition | null;
|
|
4
|
-
|
|
5
|
-
prevPage: import("akanjs/client").PageTransition | null;
|
|
5
|
+
prevPage: PageTransition | null;
|
|
6
6
|
topInset: import("akanjs/client").ContainerTransition | null;
|
|
7
7
|
bottomInset: import("akanjs/client").ContainerTransition | null;
|
|
8
8
|
topLeftAction: import("akanjs/client").ContainerTransition | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Close `onEscape` on Escape while `active`, but only while this surface is the topmost active one.
|
|
3
|
+
* The callback is read through a ref, so a fresh closure per render does not reshuffle the stack.
|
|
4
|
+
*/
|
|
5
|
+
export declare const useEscapeKey: (active: boolean, onEscape: () => void) => void;
|
|
@@ -4,7 +4,10 @@ export type FrameSlotBucket = "active" | "pending";
|
|
|
4
4
|
export type FrameSlotMapByBucket = Record<FrameSlotBucket, FrameSlotMap>;
|
|
5
5
|
export declare const PENDING_FRAME_READY_TIMEOUT_MS = 80;
|
|
6
6
|
export declare const PENDING_FRAME_READY_MAX_TIMEOUT_MS = 120;
|
|
7
|
-
export declare const
|
|
7
|
+
export declare const KEYBOARD_SHOW_ANIMATION_DURATION_MS = 420;
|
|
8
|
+
export declare const KEYBOARD_HIDE_ANIMATION_DURATION_MS = 90;
|
|
9
|
+
export declare const KEYBOARD_SHOW_ANIMATION_EASING = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
10
|
+
export declare const KEYBOARD_HIDE_ANIMATION_EASING = "cubic-bezier(0.7, 0, 0.84, 0)";
|
|
8
11
|
export declare const FRAME_Z_INDEX: {
|
|
9
12
|
readonly page: 10;
|
|
10
13
|
readonly previousPage: 0;
|
|
@@ -39,6 +42,7 @@ export declare function useFrameViewport(): {
|
|
|
39
42
|
export declare function getKeyboardAccessorySlots(path: string, frameSlots: FrameSlotMap): FrameSlotRegistration[];
|
|
40
43
|
export declare function resolveKeyboardAccessoryHeight(path: string, frameSlots: FrameSlotMap): number;
|
|
41
44
|
export declare function hasKeyboardStickySlot(path: string, frameSlots: FrameSlotMap): boolean;
|
|
45
|
+
export declare function hasBottomAnchoredKeyboardSlot(path: string, frameSlots: FrameSlotMap): boolean;
|
|
42
46
|
export declare function resolveKeyboardFrame({ keyboardHeight, bottomSafeArea, visualViewportKeyboardHeight, platformProfile, sticky, freeze, }: {
|
|
43
47
|
keyboardHeight: number;
|
|
44
48
|
bottomSafeArea: number;
|
|
@@ -57,6 +61,7 @@ export declare function useKeyboardFrame({ bottomSafeArea, sticky, viewport, pla
|
|
|
57
61
|
bottomSafeArea: number;
|
|
58
62
|
sticky: boolean;
|
|
59
63
|
viewport: {
|
|
64
|
+
height: number;
|
|
60
65
|
visualHeight: number;
|
|
61
66
|
visualOffsetTop: number;
|
|
62
67
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ScreenScopeItem {
|
|
2
|
+
id: string;
|
|
3
|
+
label?: string;
|
|
4
|
+
}
|
|
5
|
+
interface ScreenScopeOptions {
|
|
6
|
+
id: string;
|
|
7
|
+
kind: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
items?: () => ScreenScopeItem[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Announces what a component has on screen: one scope for its mounted lifetime, plus an `<id>.items` resource
|
|
13
|
+
* naming what it currently renders. `Load.Units`/`Load.View` call this, so every list and detail view is visible
|
|
14
|
+
* to the in-page agent with no app code. Items are capped and the cap is declared — a truncated list must never
|
|
15
|
+
* read as the whole one.
|
|
16
|
+
*/
|
|
17
|
+
export declare const useScreenScope: ({ id, kind, label, items }: ScreenScopeOptions) => void;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn, usePage } from "akanjs/client";
|
|
3
|
+
import type { PendingApproval } from "../../vendor/use-agentic";
|
|
4
|
+
import { Button } from "../Button";
|
|
5
|
+
|
|
6
|
+
interface ApprovalProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
approval: PendingApproval;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function Approval({ className, approval }: ApprovalProps) {
|
|
12
|
+
const { l } = usePage();
|
|
13
|
+
return (
|
|
14
|
+
<div className={cn("flex flex-col gap-2 border-warning/30 border-t bg-warning/10 px-4 py-3", className)}>
|
|
15
|
+
<p className="text-sm">{approval.message}</p>
|
|
16
|
+
<pre className="max-h-24 overflow-auto rounded-field bg-base-100/60 p-2 font-mono text-[10px]">
|
|
17
|
+
{JSON.stringify(approval.args, null, 2)}
|
|
18
|
+
</pre>
|
|
19
|
+
<div className="flex justify-end gap-2">
|
|
20
|
+
<Button onClick={() => approval.reject()} size="xs" variant="ghost">
|
|
21
|
+
{l("base.decline")}
|
|
22
|
+
</Button>
|
|
23
|
+
<Button onClick={approval.approve} size="xs">
|
|
24
|
+
{l("base.approve")}
|
|
25
|
+
</Button>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "akanjs/client";
|
|
3
|
+
import type { ChatMessage, ToolCallResult } from "../../vendor/use-agentic";
|
|
4
|
+
|
|
5
|
+
interface BubbleProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
message: ChatMessage;
|
|
8
|
+
/**
|
|
9
|
+
* Results by call id, gathered across the transcript. A call and its result are two wire messages — the model
|
|
10
|
+
* needs both — but they are one thing that happened, so the call's own row resolves in place instead of the
|
|
11
|
+
* name appearing again as a second row.
|
|
12
|
+
*/
|
|
13
|
+
results?: ReadonlyMap<string, ToolCallResult>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface RowProps {
|
|
17
|
+
name: string;
|
|
18
|
+
args?: Record<string, unknown>;
|
|
19
|
+
result?: ToolCallResult;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The arguments ride along because two calls of one tool are the same row otherwise — two searches, one name. */
|
|
23
|
+
const Row = ({ name, args, result }: RowProps) => (
|
|
24
|
+
<div className="flex items-baseline gap-2 rounded-field bg-muted px-2 py-1">
|
|
25
|
+
{result ? (
|
|
26
|
+
<span className={cn("shrink-0 text-[10px]", result.error ? "text-error" : "text-success")}>
|
|
27
|
+
{result.error ? "✕" : "✓"}
|
|
28
|
+
</span>
|
|
29
|
+
) : (
|
|
30
|
+
<span className="size-1.5 shrink-0 animate-pulse rounded-full bg-warning" />
|
|
31
|
+
)}
|
|
32
|
+
<span className="shrink-0 font-mono text-xs">{name}</span>
|
|
33
|
+
{args && Object.keys(args).length ? (
|
|
34
|
+
<span className="truncate font-mono text-[10px] text-foreground/50">{JSON.stringify(args)}</span>
|
|
35
|
+
) : null}
|
|
36
|
+
{result?.error ? <span className="truncate text-[10px] text-error">{result.error}</span> : null}
|
|
37
|
+
{result?.changes?.length ? (
|
|
38
|
+
<span className="ml-auto shrink-0 text-[10px] text-foreground/40">Δ {result.changes.length}</span>
|
|
39
|
+
) : null}
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export default function Bubble({ className, message, results }: BubbleProps) {
|
|
44
|
+
if (message.role === "tool")
|
|
45
|
+
return (
|
|
46
|
+
<div className={cn("flex flex-col gap-1", className)}>
|
|
47
|
+
{(message.toolResults ?? []).map((result) => (
|
|
48
|
+
<Row key={result.id} name={result.name} result={result} />
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
if (message.role === "user")
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
55
|
+
className={cn(
|
|
56
|
+
"max-w-[85%] self-end whitespace-pre-wrap rounded-box bg-primary/10 px-3 py-2 text-sm",
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
>
|
|
60
|
+
{message.text}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
const isDrafting = !message.text && !message.toolCalls?.length && !message.error;
|
|
64
|
+
return (
|
|
65
|
+
<div className={cn("flex max-w-[85%] flex-col gap-1 self-start", className)}>
|
|
66
|
+
{message.text ? <p className="whitespace-pre-wrap text-sm">{message.text}</p> : null}
|
|
67
|
+
{(message.toolCalls ?? []).map((call) => (
|
|
68
|
+
<Row key={call.id} args={call.args} name={call.name} result={results?.get(call.id)} />
|
|
69
|
+
))}
|
|
70
|
+
{message.error ? <p className="text-error text-xs">{message.error}</p> : null}
|
|
71
|
+
{isDrafting ? <span className="size-2 animate-pulse rounded-full bg-foreground/30" /> : null}
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn, fetch, usePage } from "akanjs/client";
|
|
3
|
+
import type { PromptResult } from "akanjs/signal";
|
|
4
|
+
import { AgentContext, type AgentPrompt, AgentPrompts, ensureStoreSurface } from "akanjs/store";
|
|
5
|
+
import { useContext, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
6
|
+
import { AiOutlineClear, AiOutlineClose, AiOutlineRobot } from "react-icons/ai";
|
|
7
|
+
import { type AgentRunner, AgentSession, SessionContext } from "../../vendor/use-agentic";
|
|
8
|
+
import { Button } from "../Button";
|
|
9
|
+
import { inputRecipe } from "../recipe";
|
|
10
|
+
import { createOverridable } from "../UiOverride";
|
|
11
|
+
import Approval from "./Approval";
|
|
12
|
+
import Bubble from "./Bubble";
|
|
13
|
+
import { fetchRunner } from "./fetchRunner";
|
|
14
|
+
import { type PersistOption, sessionHistoryOf } from "./sessionHistory";
|
|
15
|
+
|
|
16
|
+
export interface ChatProps {
|
|
17
|
+
className?: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
/** App-global framing. Route-scoped guidance layers on it through mounted `Agent.Guide`s. */
|
|
20
|
+
instructions?: string;
|
|
21
|
+
/** Swap the transport; the default drives the app's `runAgentTurn` endpoint. */
|
|
22
|
+
runner?: AgentRunner;
|
|
23
|
+
maxTurns?: number;
|
|
24
|
+
defaultOpen?: boolean;
|
|
25
|
+
/** Keeps the transcript across reloads — sessionStorage by default, `{ storage: "local" }` to outlive the tab. */
|
|
26
|
+
persist?: PersistOption;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The user-facing half of the in-page agent: one floating chat wired to the same surface the dock inspects.
|
|
31
|
+
* The conversation loop runs in this browser session — every tool call executes here, gated by the approval
|
|
32
|
+
* card — and the session lives in a ref, so it survives reopening the panel and dies with the page (v1 keeps
|
|
33
|
+
* no history). An enclosing AgentProvider's session wins, which is how an app isolates a surface or swaps the
|
|
34
|
+
* loop while keeping this UI.
|
|
35
|
+
*/
|
|
36
|
+
export const DefaultChat = ({
|
|
37
|
+
className,
|
|
38
|
+
title,
|
|
39
|
+
instructions,
|
|
40
|
+
runner,
|
|
41
|
+
maxTurns,
|
|
42
|
+
defaultOpen = false,
|
|
43
|
+
persist,
|
|
44
|
+
}: ChatProps) => {
|
|
45
|
+
const { l } = usePage();
|
|
46
|
+
const provided = useContext(SessionContext);
|
|
47
|
+
const held = useRef<AgentSession | null>(null);
|
|
48
|
+
held.current ??=
|
|
49
|
+
provided ??
|
|
50
|
+
new AgentSession(ensureStoreSurface().surface, runner ?? fetchRunner(), {
|
|
51
|
+
buildContext: (surface) => AgentContext.of().blocks(surface),
|
|
52
|
+
...(instructions ? { instructions } : {}),
|
|
53
|
+
...(maxTurns ? { maxTurns } : {}),
|
|
54
|
+
...(persist ? { history: sessionHistoryOf(persist) } : {}),
|
|
55
|
+
});
|
|
56
|
+
const session = held.current;
|
|
57
|
+
const prompts = useRef<AgentPrompts | null>(null);
|
|
58
|
+
prompts.current ??= AgentPrompts.of();
|
|
59
|
+
const version = useSyncExternalStore(
|
|
60
|
+
session.subscribe,
|
|
61
|
+
() => session.version,
|
|
62
|
+
() => session.version,
|
|
63
|
+
);
|
|
64
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
65
|
+
const [draft, setDraft] = useState("");
|
|
66
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
listRef.current?.scrollTo({ top: listRef.current.scrollHeight });
|
|
69
|
+
}, [version, open]);
|
|
70
|
+
const runPrompt = async (prompt: AgentPrompt, args: string[]) => {
|
|
71
|
+
const usage = `/${prompt.name} ${prompt.args.map((arg) => `<${arg.name}>`).join(" ")}`.trim();
|
|
72
|
+
if (args.length < prompt.args.filter((arg) => arg.required).length) {
|
|
73
|
+
session.report(`Usage: ${usage}`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const handler = (fetch as unknown as Record<string, (...callArgs: unknown[]) => Promise<PromptResult>>)[
|
|
77
|
+
prompt.name
|
|
78
|
+
];
|
|
79
|
+
if (typeof handler !== "function") {
|
|
80
|
+
session.report(`/${prompt.name} is not mounted on this app.`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const result = await handler(...args);
|
|
85
|
+
await session.send(AgentPrompts.messagesOf(result));
|
|
86
|
+
} catch (error) {
|
|
87
|
+
session.report(`/${prompt.name} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const pick = (prompt: AgentPrompt) => {
|
|
91
|
+
if (prompt.args.some((arg) => arg.required)) {
|
|
92
|
+
setDraft(`/${prompt.name} `);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
setDraft("");
|
|
96
|
+
void runPrompt(prompt, []);
|
|
97
|
+
};
|
|
98
|
+
const send = () => {
|
|
99
|
+
const text = draft.trim();
|
|
100
|
+
if (!text || session.isRunning) return;
|
|
101
|
+
const command = AgentPrompts.parseCommand(text);
|
|
102
|
+
const prompt = command ? prompts.current?.find(command.name) : null;
|
|
103
|
+
setDraft("");
|
|
104
|
+
if (command && prompt) {
|
|
105
|
+
void runPrompt(prompt, command.args);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
void session.send(text);
|
|
109
|
+
};
|
|
110
|
+
const menu = /^\/[A-Za-z0-9_-]*$/.test(draft)
|
|
111
|
+
? (prompts.current?.list() ?? []).filter((prompt) => `/${prompt.name}`.startsWith(draft))
|
|
112
|
+
: [];
|
|
113
|
+
|
|
114
|
+
const resultOf = new Map(session.messages.flatMap((message) => message.toolResults ?? []).map((r) => [r.id, r]));
|
|
115
|
+
const claimed = new Set(session.messages.flatMap((message) => message.toolCalls?.map((call) => call.id) ?? []));
|
|
116
|
+
const bubbles = session.messages.flatMap((message, idx) => {
|
|
117
|
+
if (message.role !== "tool") return [<Bubble key={idx} message={message} results={resultOf} />];
|
|
118
|
+
const orphans = (message.toolResults ?? []).filter((result) => !claimed.has(result.id));
|
|
119
|
+
return orphans.length ? [<Bubble key={idx} message={{ ...message, toolResults: orphans }} />] : [];
|
|
120
|
+
});
|
|
121
|
+
if (!open)
|
|
122
|
+
return (
|
|
123
|
+
<button
|
|
124
|
+
aria-label={l("base.agent")}
|
|
125
|
+
data-agent-ui=""
|
|
126
|
+
className={cn(
|
|
127
|
+
"fixed right-4 bottom-4 z-50 flex size-12 items-center justify-center rounded-full bg-primary text-primary-foreground shadow-lg transition-transform hover:scale-105",
|
|
128
|
+
className,
|
|
129
|
+
)}
|
|
130
|
+
onClick={() => setOpen(true)}
|
|
131
|
+
type="button"
|
|
132
|
+
>
|
|
133
|
+
<AiOutlineRobot className="text-2xl" />
|
|
134
|
+
</button>
|
|
135
|
+
);
|
|
136
|
+
return (
|
|
137
|
+
|
|
138
|
+
<aside
|
|
139
|
+
data-agent-ui=""
|
|
140
|
+
className={cn(
|
|
141
|
+
"fixed right-4 bottom-4 z-50 flex h-[min(600px,calc(100dvh-2rem))] w-[min(24rem,calc(100vw-2rem))] flex-col overflow-hidden rounded-box border border-border bg-background shadow-xl",
|
|
142
|
+
className,
|
|
143
|
+
)}
|
|
144
|
+
>
|
|
145
|
+
<header className="flex items-center gap-2 border-base-content/5 border-b px-4 py-3">
|
|
146
|
+
<span className="font-semibold text-sm">{title ?? l("base.agent")}</span>
|
|
147
|
+
{session.isRunning ? <span className="size-2 animate-pulse rounded-full bg-primary" /> : null}
|
|
148
|
+
<span className="ml-auto flex items-center gap-2">
|
|
149
|
+
{session.messages.length && !session.isRunning ? (
|
|
150
|
+
<button
|
|
151
|
+
aria-label={l("base.agentClear")}
|
|
152
|
+
className="text-foreground/50 hover:text-foreground"
|
|
153
|
+
onClick={() => session.reset()}
|
|
154
|
+
type="button"
|
|
155
|
+
>
|
|
156
|
+
<AiOutlineClear />
|
|
157
|
+
</button>
|
|
158
|
+
) : null}
|
|
159
|
+
<button
|
|
160
|
+
aria-label={l("base.cancel")}
|
|
161
|
+
className="text-foreground/50 hover:text-foreground"
|
|
162
|
+
onClick={() => setOpen(false)}
|
|
163
|
+
type="button"
|
|
164
|
+
>
|
|
165
|
+
<AiOutlineClose />
|
|
166
|
+
</button>
|
|
167
|
+
</span>
|
|
168
|
+
</header>
|
|
169
|
+
<div className="flex flex-1 flex-col gap-2 overflow-y-auto px-4 py-3" ref={listRef}>
|
|
170
|
+
{bubbles.length ? (
|
|
171
|
+
bubbles
|
|
172
|
+
) : (
|
|
173
|
+
<p className="py-6 text-center text-foreground/40 text-sm">{l("base.agentIntro")}</p>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
{session.pendingApproval ? <Approval approval={session.pendingApproval} /> : null}
|
|
177
|
+
{menu.length ? (
|
|
178
|
+
<div className="flex max-h-40 flex-col overflow-y-auto border-base-content/5 border-t py-1">
|
|
179
|
+
{menu.map((prompt) => (
|
|
180
|
+
<button
|
|
181
|
+
className="flex items-baseline gap-2 px-4 py-1.5 text-left hover:bg-muted"
|
|
182
|
+
key={prompt.name}
|
|
183
|
+
onClick={() => pick(prompt)}
|
|
184
|
+
type="button"
|
|
185
|
+
>
|
|
186
|
+
<span className="shrink-0 font-mono text-xs">/{prompt.name}</span>
|
|
187
|
+
{prompt.args.length ? (
|
|
188
|
+
<span className="shrink-0 font-mono text-[10px] text-foreground/40">
|
|
189
|
+
{prompt.args.map((arg) => `<${arg.name}>`).join(" ")}
|
|
190
|
+
</span>
|
|
191
|
+
) : null}
|
|
192
|
+
{prompt.description ? (
|
|
193
|
+
<span className="ml-auto truncate text-[10px] text-foreground/50">{prompt.description}</span>
|
|
194
|
+
) : null}
|
|
195
|
+
</button>
|
|
196
|
+
))}
|
|
197
|
+
</div>
|
|
198
|
+
) : null}
|
|
199
|
+
<div className="flex items-center gap-2 border-base-content/5 border-t p-3">
|
|
200
|
+
<input
|
|
201
|
+
className={inputRecipe({ size: "sm" }, "flex-1")}
|
|
202
|
+
onChange={(event) => setDraft(event.target.value)}
|
|
203
|
+
onKeyDown={(event) => {
|
|
204
|
+
if (event.key !== "Enter" || event.nativeEvent.isComposing) return;
|
|
205
|
+
event.preventDefault();
|
|
206
|
+
send();
|
|
207
|
+
}}
|
|
208
|
+
placeholder={l("base.agentPlaceholder")}
|
|
209
|
+
value={draft}
|
|
210
|
+
/>
|
|
211
|
+
{session.isRunning ? (
|
|
212
|
+
<Button onClick={session.abort} size="sm" variant="outline">
|
|
213
|
+
{l("base.stop")}
|
|
214
|
+
</Button>
|
|
215
|
+
) : (
|
|
216
|
+
<Button disabled={!draft.trim()} onClick={send} size="sm">
|
|
217
|
+
{l("base.send")}
|
|
218
|
+
</Button>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
</aside>
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export default createOverridable("AgentChat", DefaultChat);
|