@open-mercato/ai-assistant 0.6.6-develop.6465.1.019f0fb26f → 0.6.6-develop.6471.1.9ab5bdd79a
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/dist/frontend/hooks/useCommandPalette.js +16 -14
- package/dist/frontend/hooks/useCommandPalette.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/actions/[id]/cancel/route.js +3 -1
- package/dist/modules/ai_assistant/api/ai/actions/[id]/cancel/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/actions/[id]/confirm/route.js +3 -1
- package/dist/modules/ai_assistant/api/ai/actions/[id]/confirm/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/actions/[id]/route.js +3 -1
- package/dist/modules/ai_assistant/api/ai/actions/[id]/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/loop-override/route.js +5 -3
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/loop-override/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/models/route.js +4 -2
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/models/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.js +5 -3
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.js +4 -2
- package/dist/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/agents/route.js +3 -1
- package/dist/modules/ai_assistant/api/ai/agents/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/chat/route.js +6 -7
- package/dist/modules/ai_assistant/api/ai/chat/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/conversations/[conversationId]/route.js +5 -3
- package/dist/modules/ai_assistant/api/ai/conversations/[conversationId]/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/conversations/import/route.js +3 -1
- package/dist/modules/ai_assistant/api/ai/conversations/import/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/conversations/route.js +4 -2
- package/dist/modules/ai_assistant/api/ai/conversations/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/ai/run-object/route.js +3 -1
- package/dist/modules/ai_assistant/api/ai/run-object/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/chat/route.js +23 -14
- package/dist/modules/ai_assistant/api/chat/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/health/route.js +3 -1
- package/dist/modules/ai_assistant/api/health/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/mcp-key/route.js +3 -1
- package/dist/modules/ai_assistant/api/mcp-key/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/route/route.js +11 -9
- package/dist/modules/ai_assistant/api/route/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/session-key/route.js +3 -1
- package/dist/modules/ai_assistant/api/session-key/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/settings/allowlist/route.js +4 -2
- package/dist/modules/ai_assistant/api/settings/allowlist/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/settings/route.js +6 -4
- package/dist/modules/ai_assistant/api/settings/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/tools/execute/route.js +3 -1
- package/dist/modules/ai_assistant/api/tools/execute/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/tools/route.js +3 -1
- package/dist/modules/ai_assistant/api/tools/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/usage/daily/route.js +3 -1
- package/dist/modules/ai_assistant/api/usage/daily/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/usage/sessions/[sessionId]/route.js +3 -1
- package/dist/modules/ai_assistant/api/usage/sessions/[sessionId]/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/usage/sessions/route.js +3 -1
- package/dist/modules/ai_assistant/api/usage/sessions/route.js.map +2 -2
- package/dist/modules/ai_assistant/cli.js +3 -0
- package/dist/modules/ai_assistant/cli.js.map +2 -2
- package/dist/modules/ai_assistant/lib/agent-policy.js +7 -5
- package/dist/modules/ai_assistant/lib/agent-policy.js.map +2 -2
- package/dist/modules/ai_assistant/lib/agent-registry.js +11 -13
- package/dist/modules/ai_assistant/lib/agent-registry.js.map +2 -2
- package/dist/modules/ai_assistant/lib/agent-runtime.js +21 -44
- package/dist/modules/ai_assistant/lib/agent-runtime.js.map +2 -2
- package/dist/modules/ai_assistant/lib/agent-tools.js +5 -10
- package/dist/modules/ai_assistant/lib/agent-tools.js.map +2 -2
- package/dist/modules/ai_assistant/lib/ai-overrides.js +5 -9
- package/dist/modules/ai_assistant/lib/ai-overrides.js.map +2 -2
- package/dist/modules/ai_assistant/lib/api-endpoint-index.js +22 -22
- package/dist/modules/ai_assistant/lib/api-endpoint-index.js.map +2 -2
- package/dist/modules/ai_assistant/lib/attachment-parts.js +10 -26
- package/dist/modules/ai_assistant/lib/attachment-parts.js.map +2 -2
- package/dist/modules/ai_assistant/lib/auth.js +3 -1
- package/dist/modules/ai_assistant/lib/auth.js.map +2 -2
- package/dist/modules/ai_assistant/lib/codemode-tools.js +15 -17
- package/dist/modules/ai_assistant/lib/codemode-tools.js.map +2 -2
- package/dist/modules/ai_assistant/lib/entity-index.js +7 -5
- package/dist/modules/ai_assistant/lib/entity-index.js.map +2 -2
- package/dist/modules/ai_assistant/lib/generated-registry-loader.js +3 -4
- package/dist/modules/ai_assistant/lib/generated-registry-loader.js.map +2 -2
- package/dist/modules/ai_assistant/lib/http-server.js +45 -48
- package/dist/modules/ai_assistant/lib/http-server.js.map +2 -2
- package/dist/modules/ai_assistant/lib/llm-bootstrap.js +5 -12
- package/dist/modules/ai_assistant/lib/llm-bootstrap.js.map +2 -2
- package/dist/modules/ai_assistant/lib/mcp-client.js +3 -1
- package/dist/modules/ai_assistant/lib/mcp-client.js.map +2 -2
- package/dist/modules/ai_assistant/lib/mcp-dev-key-resolution.js +3 -1
- package/dist/modules/ai_assistant/lib/mcp-dev-key-resolution.js.map +2 -2
- package/dist/modules/ai_assistant/lib/mcp-dev-server.js +3 -1
- package/dist/modules/ai_assistant/lib/mcp-dev-server.js.map +2 -2
- package/dist/modules/ai_assistant/lib/mcp-server.js +24 -19
- package/dist/modules/ai_assistant/lib/mcp-server.js.map +2 -2
- package/dist/modules/ai_assistant/lib/mcp-tool-adapter.js +3 -1
- package/dist/modules/ai_assistant/lib/mcp-tool-adapter.js.map +2 -2
- package/dist/modules/ai_assistant/lib/model-factory.js +4 -2
- package/dist/modules/ai_assistant/lib/model-factory.js.map +2 -2
- package/dist/modules/ai_assistant/lib/opencode-client.js +5 -3
- package/dist/modules/ai_assistant/lib/opencode-client.js.map +2 -2
- package/dist/modules/ai_assistant/lib/opencode-handlers.js +30 -12
- package/dist/modules/ai_assistant/lib/opencode-handlers.js.map +2 -2
- package/dist/modules/ai_assistant/lib/pending-action-cancel.js +3 -1
- package/dist/modules/ai_assistant/lib/pending-action-cancel.js.map +2 -2
- package/dist/modules/ai_assistant/lib/pending-action-executor.js +3 -1
- package/dist/modules/ai_assistant/lib/pending-action-executor.js.map +2 -2
- package/dist/modules/ai_assistant/lib/prepare-mutation.js +4 -6
- package/dist/modules/ai_assistant/lib/prepare-mutation.js.map +2 -2
- package/dist/modules/ai_assistant/lib/schema-utils.js +3 -1
- package/dist/modules/ai_assistant/lib/schema-utils.js.map +2 -2
- package/dist/modules/ai_assistant/lib/token-usage-recorder.js +4 -8
- package/dist/modules/ai_assistant/lib/token-usage-recorder.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-executor.js +3 -1
- package/dist/modules/ai_assistant/lib/tool-executor.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-loader.js +18 -25
- package/dist/modules/ai_assistant/lib/tool-loader.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-registry.js +3 -1
- package/dist/modules/ai_assistant/lib/tool-registry.js.map +2 -2
- package/dist/modules/ai_assistant/lib/tool-test-runner.js +3 -1
- package/dist/modules/ai_assistant/lib/tool-test-runner.js.map +2 -2
- package/dist/modules/ai_assistant/setup.js +4 -8
- package/dist/modules/ai_assistant/setup.js.map +2 -2
- package/dist/modules/ai_assistant/subscribers/conversation-shared-notify.js +3 -1
- package/dist/modules/ai_assistant/subscribers/conversation-shared-notify.js.map +2 -2
- package/dist/modules/ai_assistant/workers/ai-pending-action-cleanup.js +7 -19
- package/dist/modules/ai_assistant/workers/ai-pending-action-cleanup.js.map +2 -2
- package/dist/modules/ai_assistant/workers/ai-token-usage-prune.js +5 -11
- package/dist/modules/ai_assistant/workers/ai-token-usage-prune.js.map +2 -2
- package/package.json +6 -6
- package/src/frontend/hooks/useCommandPalette.ts +17 -16
- package/src/modules/ai_assistant/__tests__/events.test.ts +23 -5
- package/src/modules/ai_assistant/__tests__/integration/ws-c-attachment-bridge.test.ts +21 -3
- package/src/modules/ai_assistant/__tests__/integration/ws-c-policy-and-tools.test.ts +22 -3
- package/src/modules/ai_assistant/__tests__/token-usage-recorder.test.ts +26 -5
- package/src/modules/ai_assistant/api/ai/actions/[id]/cancel/route.ts +4 -1
- package/src/modules/ai_assistant/api/ai/actions/[id]/confirm/route.ts +4 -1
- package/src/modules/ai_assistant/api/ai/actions/[id]/route.ts +4 -1
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/loop-override/route.ts +6 -3
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/models/route.ts +5 -2
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/mutation-policy/route.ts +6 -3
- package/src/modules/ai_assistant/api/ai/agents/[agentId]/prompt-override/route.ts +5 -2
- package/src/modules/ai_assistant/api/ai/agents/route.ts +4 -1
- package/src/modules/ai_assistant/api/ai/chat/route.ts +7 -7
- package/src/modules/ai_assistant/api/ai/conversations/[conversationId]/route.ts +6 -3
- package/src/modules/ai_assistant/api/ai/conversations/import/route.ts +4 -1
- package/src/modules/ai_assistant/api/ai/conversations/route.ts +5 -2
- package/src/modules/ai_assistant/api/ai/run-object/route.ts +4 -1
- package/src/modules/ai_assistant/api/chat/route.ts +24 -15
- package/src/modules/ai_assistant/api/health/route.ts +4 -1
- package/src/modules/ai_assistant/api/mcp-key/route.ts +4 -1
- package/src/modules/ai_assistant/api/route/route.ts +12 -9
- package/src/modules/ai_assistant/api/session-key/route.ts +4 -1
- package/src/modules/ai_assistant/api/settings/allowlist/route.ts +5 -2
- package/src/modules/ai_assistant/api/settings/route.ts +7 -4
- package/src/modules/ai_assistant/api/tools/execute/route.ts +4 -1
- package/src/modules/ai_assistant/api/tools/route.ts +4 -1
- package/src/modules/ai_assistant/api/usage/daily/route.ts +4 -1
- package/src/modules/ai_assistant/api/usage/sessions/[sessionId]/route.ts +4 -1
- package/src/modules/ai_assistant/api/usage/sessions/route.ts +4 -1
- package/src/modules/ai_assistant/cli.ts +5 -0
- package/src/modules/ai_assistant/lib/__tests__/agent-policy.mutation-override.test.ts +20 -2
- package/src/modules/ai_assistant/lib/__tests__/agent-registry.test.ts +25 -5
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-loop-phase0.test.ts +21 -2
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-parity.test.ts +23 -3
- package/src/modules/ai_assistant/lib/__tests__/agent-runtime-phase4a.test.ts +20 -2
- package/src/modules/ai_assistant/lib/__tests__/agent-tools.test.ts +22 -3
- package/src/modules/ai_assistant/lib/__tests__/ai-overrides.test.ts +23 -3
- package/src/modules/ai_assistant/lib/__tests__/attachment-parts.test.ts +25 -7
- package/src/modules/ai_assistant/lib/__tests__/model-factory.test.ts +25 -5
- package/src/modules/ai_assistant/lib/__tests__/pending-action-cancel.test.ts +19 -1
- package/src/modules/ai_assistant/lib/__tests__/prepare-mutation.test.ts +22 -3
- package/src/modules/ai_assistant/lib/agent-policy.ts +8 -5
- package/src/modules/ai_assistant/lib/agent-registry.ts +12 -15
- package/src/modules/ai_assistant/lib/agent-runtime.ts +23 -46
- package/src/modules/ai_assistant/lib/agent-tools.ts +7 -11
- package/src/modules/ai_assistant/lib/ai-overrides.ts +6 -9
- package/src/modules/ai_assistant/lib/api-endpoint-index.ts +23 -22
- package/src/modules/ai_assistant/lib/attachment-parts.ts +14 -29
- package/src/modules/ai_assistant/lib/auth.ts +4 -1
- package/src/modules/ai_assistant/lib/codemode-tools.ts +17 -17
- package/src/modules/ai_assistant/lib/entity-index.ts +8 -5
- package/src/modules/ai_assistant/lib/generated-registry-loader.ts +4 -4
- package/src/modules/ai_assistant/lib/http-server.ts +46 -48
- package/src/modules/ai_assistant/lib/llm-bootstrap.ts +7 -13
- package/src/modules/ai_assistant/lib/mcp-client.ts +4 -1
- package/src/modules/ai_assistant/lib/mcp-dev-key-resolution.ts +4 -1
- package/src/modules/ai_assistant/lib/mcp-dev-server.ts +4 -1
- package/src/modules/ai_assistant/lib/mcp-server.ts +27 -19
- package/src/modules/ai_assistant/lib/mcp-tool-adapter.ts +4 -1
- package/src/modules/ai_assistant/lib/model-factory.ts +6 -3
- package/src/modules/ai_assistant/lib/opencode-client.ts +6 -3
- package/src/modules/ai_assistant/lib/opencode-handlers.ts +32 -12
- package/src/modules/ai_assistant/lib/pending-action-cancel.ts +4 -1
- package/src/modules/ai_assistant/lib/pending-action-executor.ts +4 -1
- package/src/modules/ai_assistant/lib/prepare-mutation.ts +5 -6
- package/src/modules/ai_assistant/lib/schema-utils.ts +4 -1
- package/src/modules/ai_assistant/lib/token-usage-recorder.ts +5 -8
- package/src/modules/ai_assistant/lib/tool-executor.ts +4 -1
- package/src/modules/ai_assistant/lib/tool-loader.ts +19 -25
- package/src/modules/ai_assistant/lib/tool-registry.ts +4 -1
- package/src/modules/ai_assistant/lib/tool-test-runner.ts +4 -1
- package/src/modules/ai_assistant/setup.ts +5 -8
- package/src/modules/ai_assistant/subscribers/conversation-shared-notify.ts +4 -1
- package/src/modules/ai_assistant/workers/ai-pending-action-cleanup.ts +8 -19
- package/src/modules/ai_assistant/workers/ai-token-usage-prune.ts +6 -11
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
2
3
|
import { useState, useCallback, useEffect, useMemo, useRef } from "react";
|
|
3
4
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
4
5
|
import { apiFetch } from "@open-mercato/ui/backend/utils/api";
|
|
@@ -8,6 +9,7 @@ import { useMcpTools } from "./useMcpTools.js";
|
|
|
8
9
|
import { useRecentActions } from "./useRecentActions.js";
|
|
9
10
|
import { useRecentTools } from "./useRecentTools.js";
|
|
10
11
|
import { useAiAssistantVisibility } from "./useAiAssistantVisibility.js";
|
|
12
|
+
const logger = createLogger("ai_assistant").child({ component: "command-palette" });
|
|
11
13
|
function generateId() {
|
|
12
14
|
return Math.random().toString(36).substring(2, 15);
|
|
13
15
|
}
|
|
@@ -123,29 +125,29 @@ function useCommandPalette(options) {
|
|
|
123
125
|
useEffect(() => {
|
|
124
126
|
if (state.isOpen && tools.length > 0) {
|
|
125
127
|
if (!initialContext) {
|
|
126
|
-
|
|
128
|
+
logger.debug("Fetching initial context via context_whoami");
|
|
127
129
|
executeToolApi("context_whoami", {}).then((result) => {
|
|
128
130
|
if (result.success && result.result) {
|
|
129
|
-
|
|
131
|
+
logger.debug("Got initial context");
|
|
130
132
|
const ctx = result.result;
|
|
131
133
|
setInitialContext(ctx);
|
|
132
134
|
}
|
|
133
135
|
}).catch((err) => {
|
|
134
|
-
|
|
136
|
+
logger.error("Failed to fetch initial context", { err });
|
|
135
137
|
});
|
|
136
138
|
}
|
|
137
139
|
if (!availableEntities) {
|
|
138
|
-
|
|
140
|
+
logger.debug("Fetching available entities via search_schema");
|
|
139
141
|
executeToolApi("search_schema", {}).then((result) => {
|
|
140
142
|
if (result.success && result.result) {
|
|
141
143
|
const schemaResult = result.result;
|
|
142
|
-
|
|
144
|
+
logger.debug("Got entity schema", { entities: schemaResult.entities?.length });
|
|
143
145
|
if (schemaResult.entities) {
|
|
144
146
|
setAvailableEntities(schemaResult.entities.filter((e) => e.enabled));
|
|
145
147
|
}
|
|
146
148
|
}
|
|
147
149
|
}).catch((err) => {
|
|
148
|
-
|
|
150
|
+
logger.error("Failed to fetch entity schema", { err });
|
|
149
151
|
});
|
|
150
152
|
}
|
|
151
153
|
}
|
|
@@ -420,7 +422,7 @@ function useCommandPalette(options) {
|
|
|
420
422
|
});
|
|
421
423
|
if (!response.ok) {
|
|
422
424
|
const errorText = await response.text();
|
|
423
|
-
|
|
425
|
+
logger.error("Chat request returned error response", { status: response.status });
|
|
424
426
|
throw new Error(`Chat request failed: ${response.status} - ${errorText}`);
|
|
425
427
|
}
|
|
426
428
|
const reader = response.body?.getReader();
|
|
@@ -500,7 +502,7 @@ function useCommandPalette(options) {
|
|
|
500
502
|
setAgentStatus({ type: "thinking" });
|
|
501
503
|
}
|
|
502
504
|
} else if (event.type === "error") {
|
|
503
|
-
|
|
505
|
+
logger.error("Chat stream error event", { err: event.error });
|
|
504
506
|
setAgentStatus({ type: "idle" });
|
|
505
507
|
} else if (event.type === "done") {
|
|
506
508
|
setIsThinking(false);
|
|
@@ -534,7 +536,7 @@ function useCommandPalette(options) {
|
|
|
534
536
|
setIsSessionAuthorized(true);
|
|
535
537
|
}
|
|
536
538
|
} catch (parseError) {
|
|
537
|
-
|
|
539
|
+
logger.warn("Failed to parse chat stream event", { err: parseError });
|
|
538
540
|
}
|
|
539
541
|
}
|
|
540
542
|
}
|
|
@@ -544,7 +546,7 @@ function useCommandPalette(options) {
|
|
|
544
546
|
if (error instanceof Error && error.name === "AbortError") {
|
|
545
547
|
return;
|
|
546
548
|
}
|
|
547
|
-
|
|
549
|
+
logger.error("Agentic chat failed", { err: error });
|
|
548
550
|
setAgentStatus({ type: "idle" });
|
|
549
551
|
setMessages((prev) => [
|
|
550
552
|
...prev,
|
|
@@ -626,7 +628,7 @@ function useCommandPalette(options) {
|
|
|
626
628
|
}
|
|
627
629
|
setMessages((prev) => prev.map((m) => m.id === "streaming" ? { ...m, id: generateId() } : m));
|
|
628
630
|
} catch (error) {
|
|
629
|
-
|
|
631
|
+
logger.error("General chat failed", { err: error });
|
|
630
632
|
setMessages((prev) => [
|
|
631
633
|
...prev,
|
|
632
634
|
{
|
|
@@ -933,7 +935,7 @@ function useCommandPalette(options) {
|
|
|
933
935
|
if (error instanceof Error && error.name === "AbortError") {
|
|
934
936
|
return;
|
|
935
937
|
}
|
|
936
|
-
|
|
938
|
+
logger.error("Tool chat failed", { err: error });
|
|
937
939
|
setAgentStatus({ type: "idle" });
|
|
938
940
|
setMessages((prev) => [
|
|
939
941
|
...prev,
|
|
@@ -999,7 +1001,7 @@ function useCommandPalette(options) {
|
|
|
999
1001
|
throw new Error(result?.error || `Answer request failed: ${status}`);
|
|
1000
1002
|
}
|
|
1001
1003
|
} catch (error) {
|
|
1002
|
-
|
|
1004
|
+
logger.error("Answer question failed", { err: error });
|
|
1003
1005
|
setIsThinking(false);
|
|
1004
1006
|
setAgentStatus({ type: "idle" });
|
|
1005
1007
|
setMessages((prev) => [
|
|
@@ -1075,7 +1077,7 @@ function useCommandPalette(options) {
|
|
|
1075
1077
|
}
|
|
1076
1078
|
setMessages((prev) => prev.map((m) => m.id === "streaming" ? { ...m, id: generateId() } : m));
|
|
1077
1079
|
} catch (error) {
|
|
1078
|
-
|
|
1080
|
+
logger.error("Chat failed", { err: error });
|
|
1079
1081
|
setMessages((prev) => [
|
|
1080
1082
|
...prev,
|
|
1081
1083
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/frontend/hooks/useCommandPalette.ts"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport { useState, useCallback, useEffect, useMemo, useRef } from 'react'\nimport type {\n AgentStatus,\n CommandPaletteMode,\n CommandPalettePage,\n CommandPaletteState,\n ConnectionStatus,\n PalettePhase,\n PageContext,\n SelectedEntity,\n ToolInfo,\n ToolExecutionResult,\n PendingToolCall,\n ChatMessage,\n RouteResult,\n DebugEvent,\n DebugEventType,\n OpenCodeQuestion,\n} from '../types'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { apiFetch } from '@open-mercato/ui/backend/utils/api'\nimport { COMMAND_PALETTE_SHORTCUT, AI_CHAT_SHORTCUT } from '../constants'\nimport { filterTools } from '../utils/toolMatcher'\nimport { useMcpTools } from './useMcpTools'\nimport { useRecentActions } from './useRecentActions'\nimport { useRecentTools } from './useRecentTools'\nimport { useAiAssistantVisibility } from './useAiAssistantVisibility'\n\ninterface UseCommandPaletteOptions {\n pageContext: PageContext | null\n selectedEntities?: SelectedEntity[]\n disableKeyboardShortcut?: boolean\n}\n\nfunction generateId(): string {\n return Math.random().toString(36).substring(2, 15)\n}\n\n// Tools that are safe to auto-execute without user confirmation\nconst SAFE_TOOL_PATTERNS = [\n /^search_/, // search_query, search_schema, search_get, search_aggregate, search_status\n /^get_/, // get_ operations are read-only\n /^list_/, // list_ operations are read-only\n /^view_/, // view_ operations are read-only\n /^context_/, // context_whoami etc.\n /_get$/, // tools ending with _get\n /_list$/, // tools ending with _list\n /_status$/, // tools ending with _status\n /_schema$/, // tools ending with _schema\n]\n\n// Tools that should always require confirmation\nconst DANGEROUS_TOOL_PATTERNS = [\n /^delete_/,\n /^remove_/,\n /_delete$/,\n /_remove$/,\n /^reindex_/,\n /_reindex$/,\n]\n\nfunction isToolSafeToAutoExecute(toolName: string): boolean {\n // First check if it's a dangerous tool\n if (DANGEROUS_TOOL_PATTERNS.some(p => p.test(toolName))) {\n return false\n }\n // Then check if it matches safe patterns\n return SAFE_TOOL_PATTERNS.some(p => p.test(toolName))\n}\n\nfunction getToolPrompt(tool: ToolInfo): string {\n const schema = tool.inputSchema\n if (!schema || typeof schema !== 'object') {\n return 'What would you like to do?'\n }\n\n const properties = (schema as { properties?: Record<string, unknown> }).properties\n if (!properties || Object.keys(properties).length === 0) {\n return 'This tool has no parameters. Ready to execute?'\n }\n\n const paramNames = Object.keys(properties).slice(0, 3)\n return `Please provide the following: ${paramNames.join(', ')}.`\n}\n\nexport function useCommandPalette(options: UseCommandPaletteOptions) {\n const { pageContext, selectedEntities = [], disableKeyboardShortcut = false } = options\n\n // Check if AI assistant is enabled (for Cmd+J shortcut)\n const { isEnabled: isAiAssistantEnabled } = useAiAssistantVisibility()\n\n // Core state with phase-based navigation for intelligent routing\n const [state, setState] = useState<CommandPaletteState>({\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n selectedIndex: 0,\n isLoading: false,\n isStreaming: false,\n connectionStatus: 'disconnected',\n // Legacy fields for backwards compatibility\n page: 'home',\n mode: 'commands',\n })\n\n // Tool-related hooks\n const { tools, isLoading: toolsLoading, executeTool: executeToolApi } = useMcpTools()\n const { recentActions, addRecentAction } = useRecentActions()\n const { recentTools, saveRecentTool } = useRecentTools(tools)\n\n // Selected tool for tool-chat page\n const [selectedTool, setSelectedTool] = useState<ToolInfo | null>(null)\n\n // Chat state for tool-chat page\n const [messages, setMessages] = useState<ChatMessage[]>([])\n const [pendingToolCalls, setPendingToolCalls] = useState<PendingToolCall[]>([])\n\n // Initial context from context_whoami - fetched when palette opens\n const [initialContext, setInitialContext] = useState<{\n tenantId: string | null\n organizationId: string | null\n userId: string\n isSuperAdmin: boolean\n features: string[]\n } | null>(null)\n\n // Available entity types from search_schema - fetched when palette opens\n const [availableEntities, setAvailableEntities] = useState<Array<{\n entityId: string\n enabled: boolean\n }> | null>(null)\n\n // Debug mode state\n const [debugEvents, setDebugEvents] = useState<DebugEvent[]>([])\n const [showDebug, setShowDebug] = useState(false)\n\n // OpenCode session state for conversation persistence\n // Use both state (for React reactivity) and ref (to avoid stale closures in callbacks)\n const [opencodeSessionId, setOpencodeSessionId] = useState<string | null>(null)\n const opencodeSessionIdRef = useRef<string | null>(null)\n const [isThinking, setIsThinking] = useState(false)\n const [agentStatus, setAgentStatus] = useState<AgentStatus>({ type: 'idle' })\n const [isSessionAuthorized, setIsSessionAuthorized] = useState(false)\n\n // Pending question from OpenCode requiring user confirmation\n const [pendingQuestion, setPendingQuestion] = useState<OpenCodeQuestion | null>(null)\n\n // Track answered question IDs to prevent re-showing them\n const answeredQuestionIds = useRef<Set<string>>(new Set())\n\n // Flag to indicate the next text event should start a new message (after answering question)\n const shouldStartNewMessage = useRef<boolean>(false)\n\n // AbortController for current streaming request - allows canceling when answering questions\n const currentStreamController = useRef<AbortController | null>(null)\n\n // Wrapper to update both state and ref for opencodeSessionId\n // This ensures the ref is always in sync and callbacks get the latest value\n const updateOpencodeSessionId = useCallback((id: string | null) => {\n opencodeSessionIdRef.current = id\n setOpencodeSessionId(id)\n }, [])\n\n // Helper to add debug events\n const addDebugEvent = useCallback((type: DebugEventType, data: unknown) => {\n // Deep clone the data to capture state at this moment (prevents mutation issues)\n const clonedData = JSON.parse(JSON.stringify(data))\n setDebugEvents((prev) => [\n ...prev.slice(-999), // Keep last 1000 events\n {\n id: generateId(),\n timestamp: new Date(),\n type,\n data: clonedData,\n },\n ])\n }, [])\n\n const clearDebugEvents = useCallback(() => {\n setDebugEvents([])\n }, [])\n\n // Update connection status when tools load\n useEffect(() => {\n if (toolsLoading) {\n setState((prev) => ({ ...prev, connectionStatus: 'connecting' }))\n } else if (tools.length > 0) {\n setState((prev) => ({ ...prev, connectionStatus: 'connected' }))\n } else {\n setState((prev) => ({ ...prev, connectionStatus: 'disconnected' }))\n }\n }, [tools, toolsLoading])\n\n // Fetch initial context and entity schema when palette opens and tools are available\n useEffect(() => {\n if (state.isOpen && tools.length > 0) {\n // Fetch auth context if not already loaded\n if (!initialContext) {\n console.log('[CommandPalette] Fetching initial context via context_whoami...')\n executeToolApi('context_whoami', {})\n .then((result) => {\n if (result.success && result.result) {\n console.log('[CommandPalette] Got initial context:', result.result)\n const ctx = result.result as {\n tenantId: string | null\n organizationId: string | null\n userId: string\n isSuperAdmin: boolean\n features: string[]\n }\n setInitialContext(ctx)\n }\n })\n .catch((err) => {\n console.error('[CommandPalette] Failed to fetch initial context:', err)\n })\n }\n\n // Fetch available entity types if not already loaded\n if (!availableEntities) {\n console.log('[CommandPalette] Fetching available entities via search_schema...')\n executeToolApi('search_schema', {})\n .then((result) => {\n if (result.success && result.result) {\n const schemaResult = result.result as { entities?: Array<{ entityId: string; enabled: boolean }> }\n console.log('[CommandPalette] Got entity schema:', schemaResult.entities?.length, 'entities')\n if (schemaResult.entities) {\n setAvailableEntities(schemaResult.entities.filter(e => e.enabled))\n }\n }\n })\n .catch((err) => {\n console.error('[CommandPalette] Failed to fetch entity schema:', err)\n })\n }\n }\n }, [state.isOpen, tools.length, initialContext, availableEntities, executeToolApi])\n\n // Filtered tools based on input\n const filteredTools = useMemo(() => {\n const query = state.inputValue.startsWith('/') ? state.inputValue.slice(1) : state.inputValue\n return filterTools(tools, query)\n }, [tools, state.inputValue])\n\n // Listen for global open-chat event (from settings page, etc.)\n useEffect(() => {\n const handleOpenChat = () => {\n setState((prev) => ({\n ...prev,\n isOpen: true,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n }\n\n window.addEventListener('om:open-ai-chat', handleOpenChat)\n return () => window.removeEventListener('om:open-ai-chat', handleOpenChat)\n }, [])\n\n // Keyboard shortcut handler\n useEffect(() => {\n if (disableKeyboardShortcut) return\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Open/close with Cmd+K or Ctrl+K\n if (\n (event.metaKey || event.ctrlKey) &&\n event.key.toLowerCase() === AI_CHAT_SHORTCUT.key\n ) {\n event.preventDefault()\n setState((prev) => {\n if (prev.isOpen) {\n // Closing - reset to idle\n return {\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }\n } else {\n // Opening\n return {\n ...prev,\n isOpen: true,\n }\n }\n })\n // Reset selected tool when closing\n if (state.isOpen) {\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n }\n }\n\n // Open directly to AI chat mode with Cmd+J or Ctrl+J (only if enabled)\n if (\n (event.metaKey || event.ctrlKey) &&\n event.key.toLowerCase() === AI_CHAT_SHORTCUT.key\n ) {\n // Skip if AI assistant is disabled (but allow closing if already open)\n if (!isAiAssistantEnabled && !state.isOpen) {\n return\n }\n event.preventDefault()\n if (state.isOpen) {\n // Already open - close it\n setState((prev) => ({\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n } else {\n // Open directly in chatting phase\n setState((prev) => ({\n ...prev,\n isOpen: true,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n }\n }\n\n // Escape - reset or close\n if (event.key === 'Escape' && state.isOpen) {\n event.preventDefault()\n if (state.phase !== 'idle') {\n // Reset to idle\n setState((prev) => ({\n ...prev,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n } else {\n // Close palette\n setState((prev) => ({\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n }\n }\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [state.isOpen, state.phase, state.inputValue, disableKeyboardShortcut, isAiAssistantEnabled])\n\n // Actions\n const open = useCallback(() => {\n setState((prev) => ({ ...prev, isOpen: true }))\n }, [])\n\n // Open directly in chat mode (for Cmd+J / header button)\n const openChat = useCallback(() => {\n setState((prev) => ({\n ...prev,\n isOpen: true,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n }, [])\n\n const close = useCallback(() => {\n setState((prev) => ({\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n updateOpencodeSessionId(null)\n setIsSessionAuthorized(false)\n setAgentStatus({ type: 'idle' })\n // Don't reset initialContext - it stays valid for the session\n }, [updateOpencodeSessionId])\n\n // Reset to idle state (without closing)\n const reset = useCallback(() => {\n setState((prev) => ({\n ...prev,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n updateOpencodeSessionId(null)\n setIsSessionAuthorized(false)\n setAgentStatus({ type: 'idle' })\n }, [updateOpencodeSessionId])\n\n const setIsOpen = useCallback(\n (isOpen: boolean) => {\n if (isOpen) {\n open()\n } else {\n close()\n }\n },\n [open, close]\n )\n\n const setMode = useCallback((mode: CommandPaletteMode) => {\n setState((prev) => ({ ...prev, mode }))\n }, [])\n\n const setInputValue = useCallback((value: string) => {\n setState((prev) => ({ ...prev, inputValue: value, selectedIndex: 0 }))\n }, [])\n\n const setSelectedIndex = useCallback((index: number) => {\n setState((prev) => ({ ...prev, selectedIndex: index }))\n }, [])\n\n // Page navigation - go to tool chat\n const goToToolChat = useCallback(\n (tool: ToolInfo) => {\n setSelectedTool(tool)\n saveRecentTool(tool.name)\n\n // Create initial assistant message\n const initialMessage: ChatMessage = {\n id: generateId(),\n role: 'assistant',\n content: `I'll help you with \"${tool.name}\". ${getToolPrompt(tool)}`,\n createdAt: new Date(),\n }\n setMessages([initialMessage])\n setPendingToolCalls([])\n\n setState((prev) => ({\n ...prev,\n page: 'tool-chat',\n inputValue: '',\n selectedIndex: 0,\n mode: 'chat',\n }))\n },\n [saveRecentTool]\n )\n\n // Page navigation - go back (legacy, kept for compatibility)\n const goBack = useCallback(() => {\n if (state.phase !== 'idle') {\n setState((prev) => ({\n ...prev,\n phase: 'idle',\n page: 'home',\n inputValue: '',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n }\n }, [state.phase])\n\n // Route query using fast model\n const routeQuery = useCallback(\n async (query: string): Promise<RouteResult> => {\n const { ok, result, status } = await apiCall<RouteResult>('/api/ai_assistant/route', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n query,\n availableTools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n })),\n }),\n })\n\n if (!ok) {\n throw new Error(`Routing failed: ${status}`)\n }\n\n if (!result) {\n throw new Error('Routing returned empty response')\n }\n\n return result\n },\n [tools]\n )\n\n // Start agentic chat - AI has access to all tools\n const startAgenticChat = useCallback(\n async (initialQuery: string) => {\n setState((prev) => ({\n ...prev,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n\n // Send the initial query to the chat API\n setState((prev) => ({ ...prev, isStreaming: true }))\n setAgentStatus({ type: 'thinking' })\n\n try {\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: initialQuery,\n createdAt: new Date(),\n }\n setMessages([userMessage])\n\n // Create abort controller for this stream\n currentStreamController.current?.abort()\n const controller = new AbortController()\n currentStreamController.current = controller\n\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: initialQuery }],\n context: pageContext,\n authContext: initialContext,\n availableEntities: availableEntities?.map(e => e.entityId),\n mode: 'agentic',\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n console.error('[startAgenticChat] Error response body:', errorText)\n throw new Error(`Chat request failed: ${response.status} - ${errorText}`)\n }\n\n // Process the SSE stream\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n let buffer = ''\n let chunkCount = 0\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n chunkCount++\n const rawChunk = decoder.decode(value, { stream: true })\n buffer += rawChunk\n\n const lines = buffer.split('\\n')\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6)\n if (data === '[DONE]') continue\n\n try {\n const event = JSON.parse(data)\n\n\n // Track all events for debug panel (except question - handled separately with enriched data)\n if (event.type !== 'question') {\n addDebugEvent(event.type as DebugEventType, event)\n }\n\n if (event.type === 'text') {\n // Text received - now responding\n setIsThinking(false)\n setAgentStatus({ type: 'responding' })\n\n // Check if we need to start a new message (e.g., after answering a question)\n if (shouldStartNewMessage.current) {\n shouldStartNewMessage.current = false\n // Finalize the current streaming message and reset content\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n assistantContent = '' // Reset for new message\n }\n\n assistantContent += event.content || ''\n setMessages((prev) => {\n const existingAssistant = prev.find((m) => m.id === 'streaming')\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n } else if (event.type === 'tool-call') {\n // Tool calls are executed SERVER-SIDE via the AI SDK's maxSteps feature\n const toolName = event.toolName as string\n const toolArgs = event.args ?? {}\n\n // Update status to show the tool being used\n setAgentStatus({ type: 'tool', toolName })\n\n // For dangerous tools, show a confirmation indicator\n if (!isToolSafeToAutoExecute(toolName)) {\n // Note: Server already executed this - just show visual feedback\n setPendingToolCalls((prev) => [\n ...prev,\n {\n id: event.id,\n toolName: toolName,\n args: toolArgs,\n status: 'completed' as const, // Already executed server-side\n },\n ])\n }\n // Safe tools: no action needed, server handled execution and AI interprets results\n } else if (event.type === 'debug') {\n // Handle debug events for agent status updates\n const debugEvent = event as { partType?: string; data?: Record<string, unknown> }\n\n // Handle step-start: indicates tool execution beginning\n if (debugEvent.partType === 'step-start') {\n setAgentStatus({ type: 'executing' })\n }\n // Handle step-finish: tools completed\n if (debugEvent.partType === 'step-finish' && debugEvent.data?.reason === 'tool-calls') {\n // Tools finished, back to thinking for next step\n setAgentStatus({ type: 'thinking' })\n }\n } else if (event.type === 'error') {\n console.error('[startAgenticChat] Error event:', event.error)\n setAgentStatus({ type: 'idle' })\n } else if (event.type === 'done') {\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n // Save session ID for conversation continuity\n if (event.sessionId) {\n updateOpencodeSessionId(event.sessionId)\n }\n } else if (event.type === 'question') {\n // OpenCode is asking for confirmation\n const question = event.question as OpenCodeQuestion\n // Skip if already answered\n if (answeredQuestionIds.current.has(question.id)) {\n // Already answered\n } else {\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n setPendingQuestion(question)\n // Save session ID for conversation continuity\n if (question.sessionID) {\n updateOpencodeSessionId(question.sessionID)\n }\n // Add enriched debug event with question details visible at top level\n addDebugEvent('question', {\n type: 'question',\n questionId: question.id,\n sessionID: question.sessionID,\n questionText: question.questions?.[0]?.question || 'No question text',\n header: question.questions?.[0]?.header || 'Confirmation',\n options: question.questions?.[0]?.options?.map(o => o.label) || [],\n fullQuestion: question,\n })\n }\n } else if (event.type === 'session-authorized') {\n // Session has been authorized with ephemeral API key\n setIsSessionAuthorized(true)\n }\n } catch (parseError) {\n console.warn('[startAgenticChat] Failed to parse event:', data, parseError)\n }\n }\n }\n }\n\n // Finalize the assistant message\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n // Ignore AbortError - this happens when we intentionally cancel the stream\n if (error instanceof Error && error.name === 'AbortError') {\n return\n }\n console.error('[startAgenticChat] Error:', error)\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : 'Unknown error'}`,\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n setAgentStatus({ type: 'idle' })\n }\n },\n [pageContext, initialContext, availableEntities, executeToolApi, addDebugEvent, updateOpencodeSessionId]\n )\n\n // Start general chat (no specific tool)\n const startGeneralChat = useCallback(\n async (initialQuery: string) => {\n setState((prev) => ({\n ...prev,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n\n setState((prev) => ({ ...prev, isStreaming: true }))\n\n try {\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: initialQuery,\n createdAt: new Date(),\n }\n setMessages([userMessage])\n\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: initialQuery }],\n context: pageContext,\n authContext: initialContext,\n availableEntities: availableEntities?.map(e => e.entityId),\n mode: 'default',\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Chat request failed: ${response.status}`)\n }\n\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n assistantContent += chunk\n\n setMessages((prev) => {\n const existingAssistant = prev.find((m) => m.id === 'streaming')\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n console.error('General chat error:', error)\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: 'Sorry, I encountered an error. Please try again.',\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n }\n },\n [pageContext, initialContext, availableEntities]\n )\n\n // Execute tool directly\n const executeTool = useCallback(\n async (toolName: string, args: Record<string, unknown> = {}): Promise<ToolExecutionResult> => {\n setState((prev) => ({ ...prev, isLoading: true }))\n\n try {\n const result = await executeToolApi(toolName, args)\n\n if (result.success) {\n // Add to recent actions\n const tool = tools.find((t) => t.name === toolName)\n addRecentAction({\n toolName,\n displayName: tool?.description || toolName,\n args,\n })\n }\n\n return result\n } finally {\n setState((prev) => ({ ...prev, isLoading: false }))\n }\n },\n [executeToolApi, tools, addRecentAction]\n )\n\n // Approve a pending tool call\n const approveToolCall = useCallback(\n async (toolCallId: string) => {\n const toolCall = pendingToolCalls.find((tc) => tc.id === toolCallId)\n if (!toolCall) return\n\n // Update status to executing\n setPendingToolCalls((prev) =>\n prev.map((tc) => (tc.id === toolCallId ? { ...tc, status: 'executing' as const } : tc))\n )\n\n try {\n // Execute the tool\n const result = await executeToolApi(toolCall.toolName, toolCall.args)\n\n // Update tool call with result\n setPendingToolCalls((prev) =>\n prev.map((tc) =>\n tc.id === toolCallId\n ? {\n ...tc,\n status: result.success ? ('completed' as const) : ('error' as const),\n result: result.result,\n error: result.error,\n }\n : tc\n )\n )\n\n // Add to recent actions on success, show error on failure\n // Don't add raw JSON - the AI will provide human-friendly interpretation\n if (result.success) {\n const tool = tools.find((t) => t.name === toolCall.toolName)\n addRecentAction({\n toolName: toolCall.toolName,\n displayName: tool?.description || toolCall.toolName,\n args: toolCall.args,\n })\n // Add a brief success indicator (optional - AI can interpret the result)\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `Done! The ${toolCall.toolName.replace(/_/g, ' ')} operation completed successfully.`,\n createdAt: new Date(),\n },\n ])\n } else {\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `I encountered an issue: ${result.error || 'Unknown error'}`,\n createdAt: new Date(),\n },\n ])\n }\n } catch (error) {\n setPendingToolCalls((prev) =>\n prev.map((tc) =>\n tc.id === toolCallId\n ? {\n ...tc,\n status: 'error' as const,\n error: error instanceof Error ? error.message : 'Unknown error',\n }\n : tc\n )\n )\n }\n },\n [pendingToolCalls, executeToolApi, tools, addRecentAction]\n )\n\n // Reject a pending tool call\n const rejectToolCall = useCallback((toolCallId: string) => {\n setPendingToolCalls((prev) =>\n prev.map((tc) => (tc.id === toolCallId ? { ...tc, status: 'rejected' as const } : tc))\n )\n\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: 'Tool call cancelled. How else can I help?',\n createdAt: new Date(),\n },\n ])\n }, [])\n\n // Send message in agentic chat (via OpenCode agent)\n const sendAgenticMessage = useCallback(\n async (content: string) => {\n if (!content.trim()) return\n\n // Add user message\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: content.trim(),\n createdAt: new Date(),\n }\n setMessages((prev) => [...prev, userMessage])\n setState((prev) => ({ ...prev, isStreaming: true }))\n setIsThinking(true)\n setAgentStatus({ type: 'thinking' })\n\n try {\n // Create abort controller for this stream\n currentStreamController.current?.abort()\n const controller = new AbortController()\n currentStreamController.current = controller\n\n // Send to chat API with OpenCode session for context persistence\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n sessionId: opencodeSessionIdRef.current,\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n throw new Error(`Chat request failed: ${response.status}`)\n }\n\n // Read the streaming response\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n let buffer = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n\n // Process SSE events\n const lines = buffer.split('\\n')\n buffer = lines.pop() || '' // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6)\n if (data === '[DONE]') continue\n\n try {\n const event = JSON.parse(data)\n\n\n // Track all events for debug panel (except question - handled separately with enriched data)\n if (event.type !== 'question') {\n addDebugEvent(event.type as DebugEventType, event)\n }\n\n if (event.type === 'thinking') {\n // OpenCode is processing - keep thinking state active\n setIsThinking(true)\n setAgentStatus({ type: 'thinking' })\n } else if (event.type === 'session-authorized') {\n // Session has been authorized with ephemeral API key\n setIsSessionAuthorized(true)\n } else if (event.type === 'text') {\n // Check if we need to start a new message (e.g., after answering a question)\n if (shouldStartNewMessage.current) {\n shouldStartNewMessage.current = false\n // Finalize the current streaming message and reset content\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n assistantContent = '' // Reset for new message\n }\n\n // Text received - now responding\n setIsThinking(false)\n setAgentStatus({ type: 'responding' })\n assistantContent += event.content || ''\n // Update assistant message in real-time\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n } else if (event.type === 'done') {\n // Stream complete - save session ID for conversation persistence\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n if (event.sessionId) {\n updateOpencodeSessionId(event.sessionId)\n }\n } else if (event.type === 'error') {\n // Handle error event\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `Error: ${event.error || 'Unknown error occurred'}`,\n createdAt: new Date(),\n },\n ])\n } else if (event.type === 'tool-call') {\n // Tool calls are executed SERVER-SIDE via the AI SDK's maxSteps feature\n const toolName = event.toolName as string\n const toolArgs = event.args ?? {}\n\n // Update status to show the tool being used\n setAgentStatus({ type: 'tool', toolName })\n\n // For dangerous tools, show visual feedback (server already executed)\n if (!isToolSafeToAutoExecute(toolName)) {\n setPendingToolCalls((prev) => [\n ...prev,\n { id: event.id, toolName, args: toolArgs, status: 'completed' as const },\n ])\n }\n // Safe tools: no action needed, server handled execution\n } else if (event.type === 'question') {\n // OpenCode is asking for confirmation\n const question = event.question as OpenCodeQuestion\n // Skip if already answered\n if (answeredQuestionIds.current.has(question.id)) {\n // Already answered\n } else {\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n setPendingQuestion(question)\n // Add enriched debug event with question details visible at top level\n addDebugEvent('question', {\n type: 'question',\n questionId: question.id,\n sessionID: question.sessionID,\n questionText: question.questions?.[0]?.question || 'No question text',\n header: question.questions?.[0]?.header || 'Confirmation',\n options: question.questions?.[0]?.options?.map(o => o.label) || [],\n fullQuestion: question,\n })\n }\n } else if (event.type === 'debug') {\n // Handle debug events for agent status updates\n const debugEvent = event as { partType?: string; data?: Record<string, unknown> }\n\n // Handle step-start: indicates tool execution beginning\n if (debugEvent.partType === 'step-start') {\n setAgentStatus({ type: 'executing' })\n }\n // Handle step-finish: tools completed\n if (debugEvent.partType === 'step-finish' && debugEvent.data?.reason === 'tool-calls') {\n // Tools finished, back to thinking for next step\n setAgentStatus({ type: 'thinking' })\n }\n }\n } catch {\n // Plain text chunk (fallback for non-SSE responses)\n assistantContent += data\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n } else if (line.trim() && !line.startsWith(':')) {\n // Plain text (not SSE format)\n assistantContent += line\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n }\n }\n\n // Finalize the assistant message\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n // Ignore AbortError - this happens when we intentionally cancel the stream\n if (error instanceof Error && error.name === 'AbortError') {\n return\n }\n console.error('Tool chat error:', error)\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: 'Sorry, I encountered an error. Please try again.',\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n }\n },\n [messages, addDebugEvent, updateOpencodeSessionId]\n )\n\n // Main submit handler - starts agentic chat or continues existing session\n const handleSubmit = useCallback(\n async (query: string) => {\n if (!query.trim()) return\n\n // If we have an existing session, continue the conversation\n // Use ref to get latest value (avoids stale closure issues)\n if (opencodeSessionIdRef.current) {\n await sendAgenticMessage(query)\n } else {\n // Start new agentic session where AI has access to all tools\n await startAgenticChat(query)\n }\n },\n [startAgenticChat, sendAgenticMessage]\n )\n\n // Answer a pending OpenCode question\n // The original SSE stream continues running and will receive the follow-up response\n const answerQuestion = useCallback(\n async (answer: number) => {\n if (!pendingQuestion) return\n\n // Mark question as answered BEFORE sending - prevents duplicate display\n const questionId = pendingQuestion.id\n answeredQuestionIds.current.add(questionId)\n\n // Signal that the next text event should start a NEW message (not update the old one)\n shouldStartNewMessage.current = true\n\n // Clear the pending question UI and show thinking state\n setPendingQuestion(null)\n setIsThinking(true)\n setAgentStatus({ type: 'thinking' })\n\n // Add visual feedback of the answer\n const selectedOption = pendingQuestion.questions[0]?.options[answer]\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'user' as const,\n content: `[Confirmed: ${selectedOption?.label || 'Yes'}]`,\n createdAt: new Date(),\n },\n ])\n\n try {\n // Send answer as simple POST - the original SSE stream will receive the follow-up\n const sessionId = pendingQuestion.sessionID\n const { ok, result, status } = await apiCall<{ error?: string }>('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n answerQuestion: {\n questionId,\n answer,\n sessionId,\n },\n }),\n })\n\n if (!ok) {\n throw new Error(result?.error || `Answer request failed: ${status}`)\n }\n\n // Answer sent successfully - the original stream will handle the response\n // Note: isThinking stays true until the original stream sends 'done' or more 'text'\n } catch (error) {\n console.error('[answerQuestion] Error:', error)\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `Error: ${error instanceof Error ? error.message : 'Failed to send answer'}`,\n createdAt: new Date(),\n },\n ])\n }\n },\n [pendingQuestion]\n )\n\n // Legacy sendMessage function (for backwards compatibility)\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim()) return\n\n // Add user message\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: content.trim(),\n createdAt: new Date(),\n }\n setMessages((prev) => [...prev, userMessage])\n setState((prev) => ({ ...prev, isStreaming: true }))\n\n try {\n // Send to chat API\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n context: pageContext,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Chat request failed: ${response.status}`)\n }\n\n // Read the streaming response\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n assistantContent += chunk\n\n // Update assistant message in real-time\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n\n // Finalize the assistant message\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n console.error('Chat error:', error)\n // Add error message\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: 'Sorry, I encountered an error. Please try again.',\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n }\n },\n [messages, pageContext]\n )\n\n const clearMessages = useCallback(() => {\n setMessages([])\n setPendingToolCalls([])\n }, [])\n\n // Stop/cancel the current streaming execution\n const stopExecution = useCallback(() => {\n // Abort the current stream\n currentStreamController.current?.abort()\n currentStreamController.current = null\n\n // Reset streaming state\n setState((prev) => ({ ...prev, isStreaming: false }))\n setAgentStatus({ type: 'idle' })\n setIsThinking(false)\n\n // Add cancellation message to chat\n setMessages((prev) => [\n ...prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)), // Finalize any streaming message\n {\n id: generateId(),\n role: 'system' as const,\n content: 'Execution stopped by user.',\n createdAt: new Date(),\n },\n ])\n }, [])\n\n return {\n // State\n state: {\n ...state,\n isLoading: state.isLoading || toolsLoading,\n },\n isThinking,\n agentStatus,\n isSessionAuthorized,\n pageContext,\n selectedEntities,\n tools,\n filteredTools,\n recentActions,\n recentTools,\n messages,\n pendingToolCalls,\n selectedTool,\n initialContext,\n availableEntities,\n\n // Navigation actions\n open,\n openChat,\n close,\n setIsOpen,\n setInputValue,\n setSelectedIndex,\n\n // Intelligent routing - submit natural language query\n handleSubmit,\n reset,\n\n // Page navigation (legacy, kept for compatibility)\n goToToolChat,\n goBack,\n\n // Tool execution\n executeTool,\n approveToolCall,\n rejectToolCall,\n\n // Chat actions\n sendMessage,\n sendAgenticMessage,\n clearMessages,\n stopExecution,\n\n // Legacy compatibility\n setMode,\n\n // Debug mode\n debugEvents,\n showDebug,\n setShowDebug,\n clearDebugEvents,\n\n // OpenCode question handling\n pendingQuestion,\n answerQuestion,\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { useState, useCallback, useEffect, useMemo, useRef } from 'react'\nimport type {\n AgentStatus,\n CommandPaletteMode,\n CommandPalettePage,\n CommandPaletteState,\n ConnectionStatus,\n PalettePhase,\n PageContext,\n SelectedEntity,\n ToolInfo,\n ToolExecutionResult,\n PendingToolCall,\n ChatMessage,\n RouteResult,\n DebugEvent,\n DebugEventType,\n OpenCodeQuestion,\n} from '../types'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { apiFetch } from '@open-mercato/ui/backend/utils/api'\nimport { COMMAND_PALETTE_SHORTCUT, AI_CHAT_SHORTCUT } from '../constants'\nimport { filterTools } from '../utils/toolMatcher'\nimport { useMcpTools } from './useMcpTools'\nimport { useRecentActions } from './useRecentActions'\nimport { useRecentTools } from './useRecentTools'\nimport { useAiAssistantVisibility } from './useAiAssistantVisibility'\n\nconst logger = createLogger('ai_assistant').child({ component: 'command-palette' })\n\ninterface UseCommandPaletteOptions {\n pageContext: PageContext | null\n selectedEntities?: SelectedEntity[]\n disableKeyboardShortcut?: boolean\n}\n\nfunction generateId(): string {\n return Math.random().toString(36).substring(2, 15)\n}\n\n// Tools that are safe to auto-execute without user confirmation\nconst SAFE_TOOL_PATTERNS = [\n /^search_/, // search_query, search_schema, search_get, search_aggregate, search_status\n /^get_/, // get_ operations are read-only\n /^list_/, // list_ operations are read-only\n /^view_/, // view_ operations are read-only\n /^context_/, // context_whoami etc.\n /_get$/, // tools ending with _get\n /_list$/, // tools ending with _list\n /_status$/, // tools ending with _status\n /_schema$/, // tools ending with _schema\n]\n\n// Tools that should always require confirmation\nconst DANGEROUS_TOOL_PATTERNS = [\n /^delete_/,\n /^remove_/,\n /_delete$/,\n /_remove$/,\n /^reindex_/,\n /_reindex$/,\n]\n\nfunction isToolSafeToAutoExecute(toolName: string): boolean {\n // First check if it's a dangerous tool\n if (DANGEROUS_TOOL_PATTERNS.some(p => p.test(toolName))) {\n return false\n }\n // Then check if it matches safe patterns\n return SAFE_TOOL_PATTERNS.some(p => p.test(toolName))\n}\n\nfunction getToolPrompt(tool: ToolInfo): string {\n const schema = tool.inputSchema\n if (!schema || typeof schema !== 'object') {\n return 'What would you like to do?'\n }\n\n const properties = (schema as { properties?: Record<string, unknown> }).properties\n if (!properties || Object.keys(properties).length === 0) {\n return 'This tool has no parameters. Ready to execute?'\n }\n\n const paramNames = Object.keys(properties).slice(0, 3)\n return `Please provide the following: ${paramNames.join(', ')}.`\n}\n\nexport function useCommandPalette(options: UseCommandPaletteOptions) {\n const { pageContext, selectedEntities = [], disableKeyboardShortcut = false } = options\n\n // Check if AI assistant is enabled (for Cmd+J shortcut)\n const { isEnabled: isAiAssistantEnabled } = useAiAssistantVisibility()\n\n // Core state with phase-based navigation for intelligent routing\n const [state, setState] = useState<CommandPaletteState>({\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n selectedIndex: 0,\n isLoading: false,\n isStreaming: false,\n connectionStatus: 'disconnected',\n // Legacy fields for backwards compatibility\n page: 'home',\n mode: 'commands',\n })\n\n // Tool-related hooks\n const { tools, isLoading: toolsLoading, executeTool: executeToolApi } = useMcpTools()\n const { recentActions, addRecentAction } = useRecentActions()\n const { recentTools, saveRecentTool } = useRecentTools(tools)\n\n // Selected tool for tool-chat page\n const [selectedTool, setSelectedTool] = useState<ToolInfo | null>(null)\n\n // Chat state for tool-chat page\n const [messages, setMessages] = useState<ChatMessage[]>([])\n const [pendingToolCalls, setPendingToolCalls] = useState<PendingToolCall[]>([])\n\n // Initial context from context_whoami - fetched when palette opens\n const [initialContext, setInitialContext] = useState<{\n tenantId: string | null\n organizationId: string | null\n userId: string\n isSuperAdmin: boolean\n features: string[]\n } | null>(null)\n\n // Available entity types from search_schema - fetched when palette opens\n const [availableEntities, setAvailableEntities] = useState<Array<{\n entityId: string\n enabled: boolean\n }> | null>(null)\n\n // Debug mode state\n const [debugEvents, setDebugEvents] = useState<DebugEvent[]>([])\n const [showDebug, setShowDebug] = useState(false)\n\n // OpenCode session state for conversation persistence\n // Use both state (for React reactivity) and ref (to avoid stale closures in callbacks)\n const [opencodeSessionId, setOpencodeSessionId] = useState<string | null>(null)\n const opencodeSessionIdRef = useRef<string | null>(null)\n const [isThinking, setIsThinking] = useState(false)\n const [agentStatus, setAgentStatus] = useState<AgentStatus>({ type: 'idle' })\n const [isSessionAuthorized, setIsSessionAuthorized] = useState(false)\n\n // Pending question from OpenCode requiring user confirmation\n const [pendingQuestion, setPendingQuestion] = useState<OpenCodeQuestion | null>(null)\n\n // Track answered question IDs to prevent re-showing them\n const answeredQuestionIds = useRef<Set<string>>(new Set())\n\n // Flag to indicate the next text event should start a new message (after answering question)\n const shouldStartNewMessage = useRef<boolean>(false)\n\n // AbortController for current streaming request - allows canceling when answering questions\n const currentStreamController = useRef<AbortController | null>(null)\n\n // Wrapper to update both state and ref for opencodeSessionId\n // This ensures the ref is always in sync and callbacks get the latest value\n const updateOpencodeSessionId = useCallback((id: string | null) => {\n opencodeSessionIdRef.current = id\n setOpencodeSessionId(id)\n }, [])\n\n // Helper to add debug events\n const addDebugEvent = useCallback((type: DebugEventType, data: unknown) => {\n // Deep clone the data to capture state at this moment (prevents mutation issues)\n const clonedData = JSON.parse(JSON.stringify(data))\n setDebugEvents((prev) => [\n ...prev.slice(-999), // Keep last 1000 events\n {\n id: generateId(),\n timestamp: new Date(),\n type,\n data: clonedData,\n },\n ])\n }, [])\n\n const clearDebugEvents = useCallback(() => {\n setDebugEvents([])\n }, [])\n\n // Update connection status when tools load\n useEffect(() => {\n if (toolsLoading) {\n setState((prev) => ({ ...prev, connectionStatus: 'connecting' }))\n } else if (tools.length > 0) {\n setState((prev) => ({ ...prev, connectionStatus: 'connected' }))\n } else {\n setState((prev) => ({ ...prev, connectionStatus: 'disconnected' }))\n }\n }, [tools, toolsLoading])\n\n // Fetch initial context and entity schema when palette opens and tools are available\n useEffect(() => {\n if (state.isOpen && tools.length > 0) {\n // Fetch auth context if not already loaded\n if (!initialContext) {\n logger.debug('Fetching initial context via context_whoami')\n executeToolApi('context_whoami', {})\n .then((result) => {\n if (result.success && result.result) {\n logger.debug('Got initial context')\n const ctx = result.result as {\n tenantId: string | null\n organizationId: string | null\n userId: string\n isSuperAdmin: boolean\n features: string[]\n }\n setInitialContext(ctx)\n }\n })\n .catch((err) => {\n logger.error('Failed to fetch initial context', { err })\n })\n }\n\n // Fetch available entity types if not already loaded\n if (!availableEntities) {\n logger.debug('Fetching available entities via search_schema')\n executeToolApi('search_schema', {})\n .then((result) => {\n if (result.success && result.result) {\n const schemaResult = result.result as { entities?: Array<{ entityId: string; enabled: boolean }> }\n logger.debug('Got entity schema', { entities: schemaResult.entities?.length })\n if (schemaResult.entities) {\n setAvailableEntities(schemaResult.entities.filter(e => e.enabled))\n }\n }\n })\n .catch((err) => {\n logger.error('Failed to fetch entity schema', { err })\n })\n }\n }\n }, [state.isOpen, tools.length, initialContext, availableEntities, executeToolApi])\n\n // Filtered tools based on input\n const filteredTools = useMemo(() => {\n const query = state.inputValue.startsWith('/') ? state.inputValue.slice(1) : state.inputValue\n return filterTools(tools, query)\n }, [tools, state.inputValue])\n\n // Listen for global open-chat event (from settings page, etc.)\n useEffect(() => {\n const handleOpenChat = () => {\n setState((prev) => ({\n ...prev,\n isOpen: true,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n }\n\n window.addEventListener('om:open-ai-chat', handleOpenChat)\n return () => window.removeEventListener('om:open-ai-chat', handleOpenChat)\n }, [])\n\n // Keyboard shortcut handler\n useEffect(() => {\n if (disableKeyboardShortcut) return\n\n const handleKeyDown = (event: KeyboardEvent) => {\n // Open/close with Cmd+K or Ctrl+K\n if (\n (event.metaKey || event.ctrlKey) &&\n event.key.toLowerCase() === AI_CHAT_SHORTCUT.key\n ) {\n event.preventDefault()\n setState((prev) => {\n if (prev.isOpen) {\n // Closing - reset to idle\n return {\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }\n } else {\n // Opening\n return {\n ...prev,\n isOpen: true,\n }\n }\n })\n // Reset selected tool when closing\n if (state.isOpen) {\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n }\n }\n\n // Open directly to AI chat mode with Cmd+J or Ctrl+J (only if enabled)\n if (\n (event.metaKey || event.ctrlKey) &&\n event.key.toLowerCase() === AI_CHAT_SHORTCUT.key\n ) {\n // Skip if AI assistant is disabled (but allow closing if already open)\n if (!isAiAssistantEnabled && !state.isOpen) {\n return\n }\n event.preventDefault()\n if (state.isOpen) {\n // Already open - close it\n setState((prev) => ({\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n } else {\n // Open directly in chatting phase\n setState((prev) => ({\n ...prev,\n isOpen: true,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n }\n }\n\n // Escape - reset or close\n if (event.key === 'Escape' && state.isOpen) {\n event.preventDefault()\n if (state.phase !== 'idle') {\n // Reset to idle\n setState((prev) => ({\n ...prev,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n } else {\n // Close palette\n setState((prev) => ({\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n }\n }\n }\n\n window.addEventListener('keydown', handleKeyDown)\n return () => window.removeEventListener('keydown', handleKeyDown)\n }, [state.isOpen, state.phase, state.inputValue, disableKeyboardShortcut, isAiAssistantEnabled])\n\n // Actions\n const open = useCallback(() => {\n setState((prev) => ({ ...prev, isOpen: true }))\n }, [])\n\n // Open directly in chat mode (for Cmd+J / header button)\n const openChat = useCallback(() => {\n setState((prev) => ({\n ...prev,\n isOpen: true,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n }, [])\n\n const close = useCallback(() => {\n setState((prev) => ({\n ...prev,\n isOpen: false,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n updateOpencodeSessionId(null)\n setIsSessionAuthorized(false)\n setAgentStatus({ type: 'idle' })\n // Don't reset initialContext - it stays valid for the session\n }, [updateOpencodeSessionId])\n\n // Reset to idle state (without closing)\n const reset = useCallback(() => {\n setState((prev) => ({\n ...prev,\n phase: 'idle',\n inputValue: '',\n page: 'home',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n updateOpencodeSessionId(null)\n setIsSessionAuthorized(false)\n setAgentStatus({ type: 'idle' })\n }, [updateOpencodeSessionId])\n\n const setIsOpen = useCallback(\n (isOpen: boolean) => {\n if (isOpen) {\n open()\n } else {\n close()\n }\n },\n [open, close]\n )\n\n const setMode = useCallback((mode: CommandPaletteMode) => {\n setState((prev) => ({ ...prev, mode }))\n }, [])\n\n const setInputValue = useCallback((value: string) => {\n setState((prev) => ({ ...prev, inputValue: value, selectedIndex: 0 }))\n }, [])\n\n const setSelectedIndex = useCallback((index: number) => {\n setState((prev) => ({ ...prev, selectedIndex: index }))\n }, [])\n\n // Page navigation - go to tool chat\n const goToToolChat = useCallback(\n (tool: ToolInfo) => {\n setSelectedTool(tool)\n saveRecentTool(tool.name)\n\n // Create initial assistant message\n const initialMessage: ChatMessage = {\n id: generateId(),\n role: 'assistant',\n content: `I'll help you with \"${tool.name}\". ${getToolPrompt(tool)}`,\n createdAt: new Date(),\n }\n setMessages([initialMessage])\n setPendingToolCalls([])\n\n setState((prev) => ({\n ...prev,\n page: 'tool-chat',\n inputValue: '',\n selectedIndex: 0,\n mode: 'chat',\n }))\n },\n [saveRecentTool]\n )\n\n // Page navigation - go back (legacy, kept for compatibility)\n const goBack = useCallback(() => {\n if (state.phase !== 'idle') {\n setState((prev) => ({\n ...prev,\n phase: 'idle',\n page: 'home',\n inputValue: '',\n selectedIndex: 0,\n mode: 'commands',\n }))\n setSelectedTool(null)\n setMessages([])\n setPendingToolCalls([])\n }\n }, [state.phase])\n\n // Route query using fast model\n const routeQuery = useCallback(\n async (query: string): Promise<RouteResult> => {\n const { ok, result, status } = await apiCall<RouteResult>('/api/ai_assistant/route', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n query,\n availableTools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n })),\n }),\n })\n\n if (!ok) {\n throw new Error(`Routing failed: ${status}`)\n }\n\n if (!result) {\n throw new Error('Routing returned empty response')\n }\n\n return result\n },\n [tools]\n )\n\n // Start agentic chat - AI has access to all tools\n const startAgenticChat = useCallback(\n async (initialQuery: string) => {\n setState((prev) => ({\n ...prev,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n\n // Send the initial query to the chat API\n setState((prev) => ({ ...prev, isStreaming: true }))\n setAgentStatus({ type: 'thinking' })\n\n try {\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: initialQuery,\n createdAt: new Date(),\n }\n setMessages([userMessage])\n\n // Create abort controller for this stream\n currentStreamController.current?.abort()\n const controller = new AbortController()\n currentStreamController.current = controller\n\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: initialQuery }],\n context: pageContext,\n authContext: initialContext,\n availableEntities: availableEntities?.map(e => e.entityId),\n mode: 'agentic',\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n logger.error('Chat request returned error response', { status: response.status })\n throw new Error(`Chat request failed: ${response.status} - ${errorText}`)\n }\n\n // Process the SSE stream\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n let buffer = ''\n let chunkCount = 0\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n chunkCount++\n const rawChunk = decoder.decode(value, { stream: true })\n buffer += rawChunk\n\n const lines = buffer.split('\\n')\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6)\n if (data === '[DONE]') continue\n\n try {\n const event = JSON.parse(data)\n\n // Track all events for debug panel (except question - handled separately with enriched data)\n if (event.type !== 'question') {\n addDebugEvent(event.type as DebugEventType, event)\n }\n\n if (event.type === 'text') {\n // Text received - now responding\n setIsThinking(false)\n setAgentStatus({ type: 'responding' })\n\n // Check if we need to start a new message (e.g., after answering a question)\n if (shouldStartNewMessage.current) {\n shouldStartNewMessage.current = false\n // Finalize the current streaming message and reset content\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n assistantContent = '' // Reset for new message\n }\n\n assistantContent += event.content || ''\n setMessages((prev) => {\n const existingAssistant = prev.find((m) => m.id === 'streaming')\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n } else if (event.type === 'tool-call') {\n // Tool calls are executed SERVER-SIDE via the AI SDK's maxSteps feature\n const toolName = event.toolName as string\n const toolArgs = event.args ?? {}\n\n // Update status to show the tool being used\n setAgentStatus({ type: 'tool', toolName })\n\n // For dangerous tools, show a confirmation indicator\n if (!isToolSafeToAutoExecute(toolName)) {\n // Note: Server already executed this - just show visual feedback\n setPendingToolCalls((prev) => [\n ...prev,\n {\n id: event.id,\n toolName: toolName,\n args: toolArgs,\n status: 'completed' as const, // Already executed server-side\n },\n ])\n }\n // Safe tools: no action needed, server handled execution and AI interprets results\n } else if (event.type === 'debug') {\n // Handle debug events for agent status updates\n const debugEvent = event as { partType?: string; data?: Record<string, unknown> }\n\n // Handle step-start: indicates tool execution beginning\n if (debugEvent.partType === 'step-start') {\n setAgentStatus({ type: 'executing' })\n }\n // Handle step-finish: tools completed\n if (debugEvent.partType === 'step-finish' && debugEvent.data?.reason === 'tool-calls') {\n // Tools finished, back to thinking for next step\n setAgentStatus({ type: 'thinking' })\n }\n } else if (event.type === 'error') {\n logger.error('Chat stream error event', { err: event.error })\n setAgentStatus({ type: 'idle' })\n } else if (event.type === 'done') {\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n // Save session ID for conversation continuity\n if (event.sessionId) {\n updateOpencodeSessionId(event.sessionId)\n }\n } else if (event.type === 'question') {\n // OpenCode is asking for confirmation\n const question = event.question as OpenCodeQuestion\n // Skip if already answered\n if (answeredQuestionIds.current.has(question.id)) {\n // Already answered\n } else {\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n setPendingQuestion(question)\n // Save session ID for conversation continuity\n if (question.sessionID) {\n updateOpencodeSessionId(question.sessionID)\n }\n // Add enriched debug event with question details visible at top level\n addDebugEvent('question', {\n type: 'question',\n questionId: question.id,\n sessionID: question.sessionID,\n questionText: question.questions?.[0]?.question || 'No question text',\n header: question.questions?.[0]?.header || 'Confirmation',\n options: question.questions?.[0]?.options?.map(o => o.label) || [],\n fullQuestion: question,\n })\n }\n } else if (event.type === 'session-authorized') {\n // Session has been authorized with ephemeral API key\n setIsSessionAuthorized(true)\n }\n } catch (parseError) {\n logger.warn('Failed to parse chat stream event', { err: parseError })\n }\n }\n }\n }\n\n // Finalize the assistant message\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n // Ignore AbortError - this happens when we intentionally cancel the stream\n if (error instanceof Error && error.name === 'AbortError') {\n return\n }\n logger.error('Agentic chat failed', { err: error })\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: `Sorry, I encountered an error: ${error instanceof Error ? error.message : 'Unknown error'}`,\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n setAgentStatus({ type: 'idle' })\n }\n },\n [pageContext, initialContext, availableEntities, executeToolApi, addDebugEvent, updateOpencodeSessionId]\n )\n\n // Start general chat (no specific tool)\n const startGeneralChat = useCallback(\n async (initialQuery: string) => {\n setState((prev) => ({\n ...prev,\n phase: 'chatting',\n page: 'tool-chat',\n inputValue: '',\n mode: 'chat',\n }))\n\n setState((prev) => ({ ...prev, isStreaming: true }))\n\n try {\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: initialQuery,\n createdAt: new Date(),\n }\n setMessages([userMessage])\n\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [{ role: 'user', content: initialQuery }],\n context: pageContext,\n authContext: initialContext,\n availableEntities: availableEntities?.map(e => e.entityId),\n mode: 'default',\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Chat request failed: ${response.status}`)\n }\n\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n assistantContent += chunk\n\n setMessages((prev) => {\n const existingAssistant = prev.find((m) => m.id === 'streaming')\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n logger.error('General chat failed', { err: error })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: 'Sorry, I encountered an error. Please try again.',\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n }\n },\n [pageContext, initialContext, availableEntities]\n )\n\n // Execute tool directly\n const executeTool = useCallback(\n async (toolName: string, args: Record<string, unknown> = {}): Promise<ToolExecutionResult> => {\n setState((prev) => ({ ...prev, isLoading: true }))\n\n try {\n const result = await executeToolApi(toolName, args)\n\n if (result.success) {\n // Add to recent actions\n const tool = tools.find((t) => t.name === toolName)\n addRecentAction({\n toolName,\n displayName: tool?.description || toolName,\n args,\n })\n }\n\n return result\n } finally {\n setState((prev) => ({ ...prev, isLoading: false }))\n }\n },\n [executeToolApi, tools, addRecentAction]\n )\n\n // Approve a pending tool call\n const approveToolCall = useCallback(\n async (toolCallId: string) => {\n const toolCall = pendingToolCalls.find((tc) => tc.id === toolCallId)\n if (!toolCall) return\n\n // Update status to executing\n setPendingToolCalls((prev) =>\n prev.map((tc) => (tc.id === toolCallId ? { ...tc, status: 'executing' as const } : tc))\n )\n\n try {\n // Execute the tool\n const result = await executeToolApi(toolCall.toolName, toolCall.args)\n\n // Update tool call with result\n setPendingToolCalls((prev) =>\n prev.map((tc) =>\n tc.id === toolCallId\n ? {\n ...tc,\n status: result.success ? ('completed' as const) : ('error' as const),\n result: result.result,\n error: result.error,\n }\n : tc\n )\n )\n\n // Add to recent actions on success, show error on failure\n // Don't add raw JSON - the AI will provide human-friendly interpretation\n if (result.success) {\n const tool = tools.find((t) => t.name === toolCall.toolName)\n addRecentAction({\n toolName: toolCall.toolName,\n displayName: tool?.description || toolCall.toolName,\n args: toolCall.args,\n })\n // Add a brief success indicator (optional - AI can interpret the result)\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `Done! The ${toolCall.toolName.replace(/_/g, ' ')} operation completed successfully.`,\n createdAt: new Date(),\n },\n ])\n } else {\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `I encountered an issue: ${result.error || 'Unknown error'}`,\n createdAt: new Date(),\n },\n ])\n }\n } catch (error) {\n setPendingToolCalls((prev) =>\n prev.map((tc) =>\n tc.id === toolCallId\n ? {\n ...tc,\n status: 'error' as const,\n error: error instanceof Error ? error.message : 'Unknown error',\n }\n : tc\n )\n )\n }\n },\n [pendingToolCalls, executeToolApi, tools, addRecentAction]\n )\n\n // Reject a pending tool call\n const rejectToolCall = useCallback((toolCallId: string) => {\n setPendingToolCalls((prev) =>\n prev.map((tc) => (tc.id === toolCallId ? { ...tc, status: 'rejected' as const } : tc))\n )\n\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: 'Tool call cancelled. How else can I help?',\n createdAt: new Date(),\n },\n ])\n }, [])\n\n // Send message in agentic chat (via OpenCode agent)\n const sendAgenticMessage = useCallback(\n async (content: string) => {\n if (!content.trim()) return\n\n // Add user message\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: content.trim(),\n createdAt: new Date(),\n }\n setMessages((prev) => [...prev, userMessage])\n setState((prev) => ({ ...prev, isStreaming: true }))\n setIsThinking(true)\n setAgentStatus({ type: 'thinking' })\n\n try {\n // Create abort controller for this stream\n currentStreamController.current?.abort()\n const controller = new AbortController()\n currentStreamController.current = controller\n\n // Send to chat API with OpenCode session for context persistence\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n sessionId: opencodeSessionIdRef.current,\n }),\n signal: controller.signal,\n })\n\n if (!response.ok) {\n throw new Error(`Chat request failed: ${response.status}`)\n }\n\n // Read the streaming response\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n let buffer = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n\n // Process SSE events\n const lines = buffer.split('\\n')\n buffer = lines.pop() || '' // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n const data = line.slice(6)\n if (data === '[DONE]') continue\n\n try {\n const event = JSON.parse(data)\n\n // Track all events for debug panel (except question - handled separately with enriched data)\n if (event.type !== 'question') {\n addDebugEvent(event.type as DebugEventType, event)\n }\n\n if (event.type === 'thinking') {\n // OpenCode is processing - keep thinking state active\n setIsThinking(true)\n setAgentStatus({ type: 'thinking' })\n } else if (event.type === 'session-authorized') {\n // Session has been authorized with ephemeral API key\n setIsSessionAuthorized(true)\n } else if (event.type === 'text') {\n // Check if we need to start a new message (e.g., after answering a question)\n if (shouldStartNewMessage.current) {\n shouldStartNewMessage.current = false\n // Finalize the current streaming message and reset content\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n assistantContent = '' // Reset for new message\n }\n\n // Text received - now responding\n setIsThinking(false)\n setAgentStatus({ type: 'responding' })\n assistantContent += event.content || ''\n // Update assistant message in real-time\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n } else if (event.type === 'done') {\n // Stream complete - save session ID for conversation persistence\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n if (event.sessionId) {\n updateOpencodeSessionId(event.sessionId)\n }\n } else if (event.type === 'error') {\n // Handle error event\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `Error: ${event.error || 'Unknown error occurred'}`,\n createdAt: new Date(),\n },\n ])\n } else if (event.type === 'tool-call') {\n // Tool calls are executed SERVER-SIDE via the AI SDK's maxSteps feature\n const toolName = event.toolName as string\n const toolArgs = event.args ?? {}\n\n // Update status to show the tool being used\n setAgentStatus({ type: 'tool', toolName })\n\n // For dangerous tools, show visual feedback (server already executed)\n if (!isToolSafeToAutoExecute(toolName)) {\n setPendingToolCalls((prev) => [\n ...prev,\n { id: event.id, toolName, args: toolArgs, status: 'completed' as const },\n ])\n }\n // Safe tools: no action needed, server handled execution\n } else if (event.type === 'question') {\n // OpenCode is asking for confirmation\n const question = event.question as OpenCodeQuestion\n // Skip if already answered\n if (answeredQuestionIds.current.has(question.id)) {\n // Already answered\n } else {\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setState((prev) => ({ ...prev, isStreaming: false }))\n setPendingQuestion(question)\n // Add enriched debug event with question details visible at top level\n addDebugEvent('question', {\n type: 'question',\n questionId: question.id,\n sessionID: question.sessionID,\n questionText: question.questions?.[0]?.question || 'No question text',\n header: question.questions?.[0]?.header || 'Confirmation',\n options: question.questions?.[0]?.options?.map(o => o.label) || [],\n fullQuestion: question,\n })\n }\n } else if (event.type === 'debug') {\n // Handle debug events for agent status updates\n const debugEvent = event as { partType?: string; data?: Record<string, unknown> }\n\n // Handle step-start: indicates tool execution beginning\n if (debugEvent.partType === 'step-start') {\n setAgentStatus({ type: 'executing' })\n }\n // Handle step-finish: tools completed\n if (debugEvent.partType === 'step-finish' && debugEvent.data?.reason === 'tool-calls') {\n // Tools finished, back to thinking for next step\n setAgentStatus({ type: 'thinking' })\n }\n }\n } catch {\n // Plain text chunk (fallback for non-SSE responses)\n assistantContent += data\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n } else if (line.trim() && !line.startsWith(':')) {\n // Plain text (not SSE format)\n assistantContent += line\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n }\n }\n\n // Finalize the assistant message\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n // Ignore AbortError - this happens when we intentionally cancel the stream\n if (error instanceof Error && error.name === 'AbortError') {\n return\n }\n logger.error('Tool chat failed', { err: error })\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: 'Sorry, I encountered an error. Please try again.',\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n }\n },\n [messages, addDebugEvent, updateOpencodeSessionId]\n )\n\n // Main submit handler - starts agentic chat or continues existing session\n const handleSubmit = useCallback(\n async (query: string) => {\n if (!query.trim()) return\n\n // If we have an existing session, continue the conversation\n // Use ref to get latest value (avoids stale closure issues)\n if (opencodeSessionIdRef.current) {\n await sendAgenticMessage(query)\n } else {\n // Start new agentic session where AI has access to all tools\n await startAgenticChat(query)\n }\n },\n [startAgenticChat, sendAgenticMessage]\n )\n\n // Answer a pending OpenCode question\n // The original SSE stream continues running and will receive the follow-up response\n const answerQuestion = useCallback(\n async (answer: number) => {\n if (!pendingQuestion) return\n\n // Mark question as answered BEFORE sending - prevents duplicate display\n const questionId = pendingQuestion.id\n answeredQuestionIds.current.add(questionId)\n\n // Signal that the next text event should start a NEW message (not update the old one)\n shouldStartNewMessage.current = true\n\n // Clear the pending question UI and show thinking state\n setPendingQuestion(null)\n setIsThinking(true)\n setAgentStatus({ type: 'thinking' })\n\n // Add visual feedback of the answer\n const selectedOption = pendingQuestion.questions[0]?.options[answer]\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'user' as const,\n content: `[Confirmed: ${selectedOption?.label || 'Yes'}]`,\n createdAt: new Date(),\n },\n ])\n\n try {\n // Send answer as simple POST - the original SSE stream will receive the follow-up\n const sessionId = pendingQuestion.sessionID\n const { ok, result, status } = await apiCall<{ error?: string }>('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n answerQuestion: {\n questionId,\n answer,\n sessionId,\n },\n }),\n })\n\n if (!ok) {\n throw new Error(result?.error || `Answer request failed: ${status}`)\n }\n\n // Answer sent successfully - the original stream will handle the response\n // Note: isThinking stays true until the original stream sends 'done' or more 'text'\n } catch (error) {\n logger.error('Answer question failed', { err: error })\n setIsThinking(false)\n setAgentStatus({ type: 'idle' })\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant' as const,\n content: `Error: ${error instanceof Error ? error.message : 'Failed to send answer'}`,\n createdAt: new Date(),\n },\n ])\n }\n },\n [pendingQuestion]\n )\n\n // Legacy sendMessage function (for backwards compatibility)\n const sendMessage = useCallback(\n async (content: string) => {\n if (!content.trim()) return\n\n // Add user message\n const userMessage: ChatMessage = {\n id: generateId(),\n role: 'user',\n content: content.trim(),\n createdAt: new Date(),\n }\n setMessages((prev) => [...prev, userMessage])\n setState((prev) => ({ ...prev, isStreaming: true }))\n\n try {\n // Send to chat API\n const response = await apiFetch('/api/ai_assistant/chat', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n messages: [...messages, userMessage].map((m) => ({\n role: m.role,\n content: m.content,\n })),\n context: pageContext,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Chat request failed: ${response.status}`)\n }\n\n // Read the streaming response\n const reader = response.body?.getReader()\n if (!reader) {\n throw new Error('No response body')\n }\n\n const decoder = new TextDecoder()\n let assistantContent = ''\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n const chunk = decoder.decode(value, { stream: true })\n assistantContent += chunk\n\n // Update assistant message in real-time\n setMessages((prev) => {\n const existingAssistant = prev.find(\n (m) => m.role === 'assistant' && m.id === 'streaming'\n )\n if (existingAssistant) {\n return prev.map((m) =>\n m.id === 'streaming' ? { ...m, content: assistantContent } : m\n )\n } else {\n return [\n ...prev,\n {\n id: 'streaming',\n role: 'assistant' as const,\n content: assistantContent,\n createdAt: new Date(),\n },\n ]\n }\n })\n }\n\n // Finalize the assistant message\n setMessages((prev) => prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)))\n } catch (error) {\n logger.error('Chat failed', { err: error })\n // Add error message\n setMessages((prev) => [\n ...prev,\n {\n id: generateId(),\n role: 'assistant',\n content: 'Sorry, I encountered an error. Please try again.',\n createdAt: new Date(),\n },\n ])\n } finally {\n setState((prev) => ({ ...prev, isStreaming: false }))\n }\n },\n [messages, pageContext]\n )\n\n const clearMessages = useCallback(() => {\n setMessages([])\n setPendingToolCalls([])\n }, [])\n\n // Stop/cancel the current streaming execution\n const stopExecution = useCallback(() => {\n // Abort the current stream\n currentStreamController.current?.abort()\n currentStreamController.current = null\n\n // Reset streaming state\n setState((prev) => ({ ...prev, isStreaming: false }))\n setAgentStatus({ type: 'idle' })\n setIsThinking(false)\n\n // Add cancellation message to chat\n setMessages((prev) => [\n ...prev.map((m) => (m.id === 'streaming' ? { ...m, id: generateId() } : m)), // Finalize any streaming message\n {\n id: generateId(),\n role: 'system' as const,\n content: 'Execution stopped by user.',\n createdAt: new Date(),\n },\n ])\n }, [])\n\n return {\n // State\n state: {\n ...state,\n isLoading: state.isLoading || toolsLoading,\n },\n isThinking,\n agentStatus,\n isSessionAuthorized,\n pageContext,\n selectedEntities,\n tools,\n filteredTools,\n recentActions,\n recentTools,\n messages,\n pendingToolCalls,\n selectedTool,\n initialContext,\n availableEntities,\n\n // Navigation actions\n open,\n openChat,\n close,\n setIsOpen,\n setInputValue,\n setSelectedIndex,\n\n // Intelligent routing - submit natural language query\n handleSubmit,\n reset,\n\n // Page navigation (legacy, kept for compatibility)\n goToToolChat,\n goBack,\n\n // Tool execution\n executeTool,\n approveToolCall,\n rejectToolCall,\n\n // Chat actions\n sendMessage,\n sendAgenticMessage,\n clearMessages,\n stopExecution,\n\n // Legacy compatibility\n setMode,\n\n // Debug mode\n debugEvents,\n showDebug,\n setShowDebug,\n clearDebugEvents,\n\n // OpenCode question handling\n pendingQuestion,\n answerQuestion,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
1
2
|
import { NextResponse } from "next/server";
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
@@ -7,6 +8,7 @@ import { hasRequiredFeatures } from "../../../../../lib/auth.js";
|
|
|
7
8
|
import { serializePendingActionForClient } from "../../../../../lib/pending-action-client.js";
|
|
8
9
|
import { checkStatusAndExpiry } from "../../../../../lib/pending-action-recheck.js";
|
|
9
10
|
import { executePendingActionCancel } from "../../../../../lib/pending-action-cancel.js";
|
|
11
|
+
const logger = createLogger("ai_assistant");
|
|
10
12
|
const REQUIRED_FEATURE = "ai_assistant.view";
|
|
11
13
|
const idParamSchema = z.object({
|
|
12
14
|
id: z.string().trim().min(1, "id must be a non-empty string").max(128, "id exceeds the maximum length of 128 characters")
|
|
@@ -159,7 +161,7 @@ async function POST(req, context) {
|
|
|
159
161
|
pendingAction: serializePendingActionForClient(cancelResult.row)
|
|
160
162
|
});
|
|
161
163
|
} catch (error) {
|
|
162
|
-
|
|
164
|
+
logger.error("AI Pending Action CANCEL \u2014 Failure", { err: error });
|
|
163
165
|
return jsonError(
|
|
164
166
|
500,
|
|
165
167
|
error instanceof Error ? error.message : "Failed to cancel pending action.",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../../src/modules/ai_assistant/api/ai/actions/%5Bid%5D/cancel/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse, type NextRequest } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { AiPendingActionRepository } from '../../../../../data/repositories/AiPendingActionRepository'\nimport { hasRequiredFeatures } from '../../../../../lib/auth'\nimport { serializePendingActionForClient } from '../../../../../lib/pending-action-client'\nimport { checkStatusAndExpiry } from '../../../../../lib/pending-action-recheck'\nimport { executePendingActionCancel } from '../../../../../lib/pending-action-cancel'\n\n/**\n * POST `/api/ai/actions/:id/cancel` \u2014 mutation approval gate cancel\n * endpoint (spec \u00A79.4, Step 5.9).\n *\n * Siblings the Step 5.8 confirm route: flips `pending \u2192 cancelled` and\n * emits `ai.action.cancelled`. The tool handler is NEVER invoked.\n *\n * The route re-uses only the `status + expiry + tenant-scope` guards\n * from `pending-action-recheck.ts` \u2014 the agent / tool / attachment /\n * record-version guards are confirm-only. A caller may cancel even when\n * they'd be blocked from confirming; cancelling does not touch data.\n *\n * Idempotency: calling this endpoint twice on an already-`cancelled`\n * row returns 200 with the current row without re-emitting the event.\n */\n\nconst REQUIRED_FEATURE = 'ai_assistant.view'\n\nconst idParamSchema = z.object({\n id: z\n .string()\n .trim()\n .min(1, 'id must be a non-empty string')\n .max(128, 'id exceeds the maximum length of 128 characters'),\n})\n\nconst bodySchema = z\n .object({\n reason: z\n .string()\n .max(500, 'reason must be at most 500 characters')\n .optional(),\n })\n .strict()\n .optional()\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'AI Assistant',\n summary: 'Pending action (mutation approval gate) cancel',\n methods: {\n POST: {\n operationId: 'aiAssistantCancelPendingAction',\n summary: 'Cancel an AI pending action without executing the wrapped tool.',\n description:\n 'Flips a pending AI action from `pending` to `cancelled` and emits the ' +\n '`ai.action.cancelled` event. The tool handler is never invoked. Idempotent: ' +\n 'a second call on a row already in `cancelled` status returns 200 with the ' +\n 'current row without re-emitting the event. Rows whose `expiresAt` is in the ' +\n 'past are flipped to `expired` and returned as 409 `expired` so the client can ' +\n 'surface the TTL loss instead of silently masking it as a cancellation.',\n responses: [\n {\n status: 200,\n description: 'Cancellation complete (or idempotent replay); body includes the serialized pending action with status `cancelled`.',\n mediaType: 'application/json',\n },\n ],\n errors: [\n { status: 400, description: 'Invalid cancel request body (unknown field, reason exceeds 500 chars, wrong type).' },\n { status: 401, description: 'Unauthenticated caller.' },\n { status: 403, description: 'Caller lacks `ai_assistant.view`.' },\n { status: 404, description: 'Pending action not found in the caller scope.' },\n { status: 409, description: 'Pending action is not in `pending` status (already confirmed/failed/executing) or has expired.' },\n { status: 500, description: 'Unexpected server failure during cancel.' },\n ],\n },\n },\n}\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: [REQUIRED_FEATURE] },\n}\n\ninterface RouteContext {\n params: Promise<{ id: string }>\n}\n\nfunction jsonError(\n status: number,\n message: string,\n code: string,\n extra?: Record<string, unknown>,\n): NextResponse {\n return NextResponse.json({ error: message, code, ...(extra ?? {}) }, { status })\n}\n\nasync function readRequestBody(req: NextRequest): Promise<unknown> {\n try {\n const text = await req.text()\n if (!text || text.trim().length === 0) return undefined\n return JSON.parse(text)\n } catch {\n return Symbol.for('ai_assistant.cancel.bad_json')\n }\n}\n\nexport async function POST(req: NextRequest, context: RouteContext): Promise<Response> {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return jsonError(401, 'Unauthorized', 'unauthenticated')\n }\n\n const rawParams = await context.params\n const paramResult = idParamSchema.safeParse(rawParams)\n if (!paramResult.success) {\n return jsonError(400, 'Invalid pending action id.', 'validation_error', {\n issues: paramResult.error.issues,\n })\n }\n const pendingActionId = paramResult.data.id\n\n const rawBody = await readRequestBody(req)\n if (rawBody === Symbol.for('ai_assistant.cancel.bad_json')) {\n return jsonError(400, 'Invalid JSON body.', 'validation_error')\n }\n const bodyResult = bodySchema.safeParse(rawBody)\n if (!bodyResult.success) {\n return jsonError(400, 'Invalid cancel body.', 'validation_error', {\n issues: bodyResult.error.issues,\n })\n }\n const parsedBody = bodyResult.data ?? {}\n\n try {\n const container = await createRequestContainer()\n const rbacService = container.resolve<RbacService>('rbacService')\n const acl = await rbacService.loadAcl(auth.sub, {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n })\n\n if (!hasRequiredFeatures([REQUIRED_FEATURE], acl.features, acl.isSuperAdmin, rbacService)) {\n return jsonError(403, `Caller lacks required feature \"${REQUIRED_FEATURE}\".`, 'forbidden')\n }\n\n if (!auth.tenantId) {\n return jsonError(\n 404,\n `No pending action \"${pendingActionId}\" accessible to the caller.`,\n 'pending_action_not_found',\n )\n }\n\n const em = container.resolve<EntityManager>('em')\n const repo = new AiPendingActionRepository(em)\n const row = await repo.getById(pendingActionId, {\n tenantId: auth.tenantId,\n organizationId: auth.orgId ?? null,\n userId: auth.sub,\n })\n if (!row) {\n return jsonError(\n 404,\n `No pending action \"${pendingActionId}\" accessible to the caller.`,\n 'pending_action_not_found',\n )\n }\n\n // Idempotent replay: second cancel on an already-cancelled row returns\n // 200 with the current row and does NOT emit a second event.\n if (row.status === 'cancelled') {\n return NextResponse.json({\n ok: true,\n pendingAction: serializePendingActionForClient(row),\n })\n }\n\n const statusCheck = checkStatusAndExpiry(row)\n if (!statusCheck.ok) {\n // Expired short-circuit: flip to `expired` + emit `ai.action.expired`\n // so Step 5.12 does not race to do it. Return 409 so the client\n // surfaces the TTL loss rather than silently cancelling.\n if (statusCheck.code === 'expired') {\n const cancelResult = await executePendingActionCancel({\n action: row,\n ctx: {\n tenantId: auth.tenantId,\n organizationId: auth.orgId ?? null,\n userId: auth.sub,\n container,\n },\n repo,\n })\n return jsonError(409, statusCheck.message, 'expired', {\n pendingAction: serializePendingActionForClient(cancelResult.row),\n })\n }\n return jsonError(statusCheck.status, statusCheck.message, statusCheck.code, statusCheck.extra)\n }\n\n const cancelResult = await executePendingActionCancel({\n action: row,\n ctx: {\n tenantId: auth.tenantId,\n organizationId: auth.orgId ?? null,\n userId: auth.sub,\n container,\n },\n reason: parsedBody.reason,\n repo,\n })\n\n if (cancelResult.status === 'expired') {\n return jsonError(\n 409,\n 'Pending action has expired. The model must re-propose the mutation.',\n 'expired',\n { pendingAction: serializePendingActionForClient(cancelResult.row) },\n )\n }\n\n return NextResponse.json({\n ok: true,\n pendingAction: serializePendingActionForClient(cancelResult.row),\n })\n } catch (error) {\n
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAsC;AAC/C,SAAS,SAAS;AAGlB,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AAEvC,SAAS,iCAAiC;AAC1C,SAAS,2BAA2B;AACpC,SAAS,uCAAuC;AAChD,SAAS,4BAA4B;AACrC,SAAS,kCAAkC;
|
|
4
|
+
"sourcesContent": ["import { createLogger } from '@open-mercato/shared/lib/logger'\nimport { NextResponse, type NextRequest } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { AiPendingActionRepository } from '../../../../../data/repositories/AiPendingActionRepository'\nimport { hasRequiredFeatures } from '../../../../../lib/auth'\nimport { serializePendingActionForClient } from '../../../../../lib/pending-action-client'\nimport { checkStatusAndExpiry } from '../../../../../lib/pending-action-recheck'\nimport { executePendingActionCancel } from '../../../../../lib/pending-action-cancel'\n\nconst logger = createLogger('ai_assistant')\n\n/**\n * POST `/api/ai/actions/:id/cancel` \u2014 mutation approval gate cancel\n * endpoint (spec \u00A79.4, Step 5.9).\n *\n * Siblings the Step 5.8 confirm route: flips `pending \u2192 cancelled` and\n * emits `ai.action.cancelled`. The tool handler is NEVER invoked.\n *\n * The route re-uses only the `status + expiry + tenant-scope` guards\n * from `pending-action-recheck.ts` \u2014 the agent / tool / attachment /\n * record-version guards are confirm-only. A caller may cancel even when\n * they'd be blocked from confirming; cancelling does not touch data.\n *\n * Idempotency: calling this endpoint twice on an already-`cancelled`\n * row returns 200 with the current row without re-emitting the event.\n */\n\nconst REQUIRED_FEATURE = 'ai_assistant.view'\n\nconst idParamSchema = z.object({\n id: z\n .string()\n .trim()\n .min(1, 'id must be a non-empty string')\n .max(128, 'id exceeds the maximum length of 128 characters'),\n})\n\nconst bodySchema = z\n .object({\n reason: z\n .string()\n .max(500, 'reason must be at most 500 characters')\n .optional(),\n })\n .strict()\n .optional()\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'AI Assistant',\n summary: 'Pending action (mutation approval gate) cancel',\n methods: {\n POST: {\n operationId: 'aiAssistantCancelPendingAction',\n summary: 'Cancel an AI pending action without executing the wrapped tool.',\n description:\n 'Flips a pending AI action from `pending` to `cancelled` and emits the ' +\n '`ai.action.cancelled` event. The tool handler is never invoked. Idempotent: ' +\n 'a second call on a row already in `cancelled` status returns 200 with the ' +\n 'current row without re-emitting the event. Rows whose `expiresAt` is in the ' +\n 'past are flipped to `expired` and returned as 409 `expired` so the client can ' +\n 'surface the TTL loss instead of silently masking it as a cancellation.',\n responses: [\n {\n status: 200,\n description: 'Cancellation complete (or idempotent replay); body includes the serialized pending action with status `cancelled`.',\n mediaType: 'application/json',\n },\n ],\n errors: [\n { status: 400, description: 'Invalid cancel request body (unknown field, reason exceeds 500 chars, wrong type).' },\n { status: 401, description: 'Unauthenticated caller.' },\n { status: 403, description: 'Caller lacks `ai_assistant.view`.' },\n { status: 404, description: 'Pending action not found in the caller scope.' },\n { status: 409, description: 'Pending action is not in `pending` status (already confirmed/failed/executing) or has expired.' },\n { status: 500, description: 'Unexpected server failure during cancel.' },\n ],\n },\n },\n}\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: [REQUIRED_FEATURE] },\n}\n\ninterface RouteContext {\n params: Promise<{ id: string }>\n}\n\nfunction jsonError(\n status: number,\n message: string,\n code: string,\n extra?: Record<string, unknown>,\n): NextResponse {\n return NextResponse.json({ error: message, code, ...(extra ?? {}) }, { status })\n}\n\nasync function readRequestBody(req: NextRequest): Promise<unknown> {\n try {\n const text = await req.text()\n if (!text || text.trim().length === 0) return undefined\n return JSON.parse(text)\n } catch {\n return Symbol.for('ai_assistant.cancel.bad_json')\n }\n}\n\nexport async function POST(req: NextRequest, context: RouteContext): Promise<Response> {\n const auth = await getAuthFromRequest(req)\n if (!auth) {\n return jsonError(401, 'Unauthorized', 'unauthenticated')\n }\n\n const rawParams = await context.params\n const paramResult = idParamSchema.safeParse(rawParams)\n if (!paramResult.success) {\n return jsonError(400, 'Invalid pending action id.', 'validation_error', {\n issues: paramResult.error.issues,\n })\n }\n const pendingActionId = paramResult.data.id\n\n const rawBody = await readRequestBody(req)\n if (rawBody === Symbol.for('ai_assistant.cancel.bad_json')) {\n return jsonError(400, 'Invalid JSON body.', 'validation_error')\n }\n const bodyResult = bodySchema.safeParse(rawBody)\n if (!bodyResult.success) {\n return jsonError(400, 'Invalid cancel body.', 'validation_error', {\n issues: bodyResult.error.issues,\n })\n }\n const parsedBody = bodyResult.data ?? {}\n\n try {\n const container = await createRequestContainer()\n const rbacService = container.resolve<RbacService>('rbacService')\n const acl = await rbacService.loadAcl(auth.sub, {\n tenantId: auth.tenantId,\n organizationId: auth.orgId,\n })\n\n if (!hasRequiredFeatures([REQUIRED_FEATURE], acl.features, acl.isSuperAdmin, rbacService)) {\n return jsonError(403, `Caller lacks required feature \"${REQUIRED_FEATURE}\".`, 'forbidden')\n }\n\n if (!auth.tenantId) {\n return jsonError(\n 404,\n `No pending action \"${pendingActionId}\" accessible to the caller.`,\n 'pending_action_not_found',\n )\n }\n\n const em = container.resolve<EntityManager>('em')\n const repo = new AiPendingActionRepository(em)\n const row = await repo.getById(pendingActionId, {\n tenantId: auth.tenantId,\n organizationId: auth.orgId ?? null,\n userId: auth.sub,\n })\n if (!row) {\n return jsonError(\n 404,\n `No pending action \"${pendingActionId}\" accessible to the caller.`,\n 'pending_action_not_found',\n )\n }\n\n // Idempotent replay: second cancel on an already-cancelled row returns\n // 200 with the current row and does NOT emit a second event.\n if (row.status === 'cancelled') {\n return NextResponse.json({\n ok: true,\n pendingAction: serializePendingActionForClient(row),\n })\n }\n\n const statusCheck = checkStatusAndExpiry(row)\n if (!statusCheck.ok) {\n // Expired short-circuit: flip to `expired` + emit `ai.action.expired`\n // so Step 5.12 does not race to do it. Return 409 so the client\n // surfaces the TTL loss rather than silently cancelling.\n if (statusCheck.code === 'expired') {\n const cancelResult = await executePendingActionCancel({\n action: row,\n ctx: {\n tenantId: auth.tenantId,\n organizationId: auth.orgId ?? null,\n userId: auth.sub,\n container,\n },\n repo,\n })\n return jsonError(409, statusCheck.message, 'expired', {\n pendingAction: serializePendingActionForClient(cancelResult.row),\n })\n }\n return jsonError(statusCheck.status, statusCheck.message, statusCheck.code, statusCheck.extra)\n }\n\n const cancelResult = await executePendingActionCancel({\n action: row,\n ctx: {\n tenantId: auth.tenantId,\n organizationId: auth.orgId ?? null,\n userId: auth.sub,\n container,\n },\n reason: parsedBody.reason,\n repo,\n })\n\n if (cancelResult.status === 'expired') {\n return jsonError(\n 409,\n 'Pending action has expired. The model must re-propose the mutation.',\n 'expired',\n { pendingAction: serializePendingActionForClient(cancelResult.row) },\n )\n }\n\n return NextResponse.json({\n ok: true,\n pendingAction: serializePendingActionForClient(cancelResult.row),\n })\n } catch (error) {\n logger.error('AI Pending Action CANCEL \u2014 Failure', { err: error })\n return jsonError(\n 500,\n error instanceof Error ? error.message : 'Failed to cancel pending action.',\n 'cancel_internal_error',\n )\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["cancelResult"]
|
|
7
7
|
}
|