@stigmer/react 0.0.36
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/LICENSE +190 -0
- package/README.md +248 -0
- package/agent/components/AgentCard.d.ts +9 -0
- package/agent/components/AgentCard.d.ts.map +1 -0
- package/agent/components/AgentCard.js +26 -0
- package/agent/components/AgentCard.js.map +1 -0
- package/agent/components/AgentOverview.d.ts +7 -0
- package/agent/components/AgentOverview.d.ts.map +1 -0
- package/agent/components/AgentOverview.js +36 -0
- package/agent/components/AgentOverview.js.map +1 -0
- package/agent/components/AgentPicker.d.ts +17 -0
- package/agent/components/AgentPicker.d.ts.map +1 -0
- package/agent/components/AgentPicker.js +86 -0
- package/agent/components/AgentPicker.js.map +1 -0
- package/agent/hooks/useAgentSearch.d.ts +28 -0
- package/agent/hooks/useAgentSearch.d.ts.map +1 -0
- package/agent/hooks/useAgentSearch.js +63 -0
- package/agent/hooks/useAgentSearch.js.map +1 -0
- package/agent/index.d.ts +9 -0
- package/agent/index.d.ts.map +1 -0
- package/agent/index.js +7 -0
- package/agent/index.js.map +1 -0
- package/agent-execution/components/ApprovalControls.d.ts +10 -0
- package/agent-execution/components/ApprovalControls.d.ts.map +1 -0
- package/agent-execution/components/ApprovalControls.js +19 -0
- package/agent-execution/components/ApprovalControls.js.map +1 -0
- package/agent-execution/components/ExecutionStatus.d.ts +8 -0
- package/agent-execution/components/ExecutionStatus.d.ts.map +1 -0
- package/agent-execution/components/ExecutionStatus.js +14 -0
- package/agent-execution/components/ExecutionStatus.js.map +1 -0
- package/agent-execution/components/ExecutionStream.d.ts +16 -0
- package/agent-execution/components/ExecutionStream.d.ts.map +1 -0
- package/agent-execution/components/ExecutionStream.js +39 -0
- package/agent-execution/components/ExecutionStream.js.map +1 -0
- package/agent-execution/components/MessageEntry.d.ts +17 -0
- package/agent-execution/components/MessageEntry.d.ts.map +1 -0
- package/agent-execution/components/MessageEntry.js +36 -0
- package/agent-execution/components/MessageEntry.js.map +1 -0
- package/agent-execution/components/MessageInput.d.ts +10 -0
- package/agent-execution/components/MessageInput.d.ts.map +1 -0
- package/agent-execution/components/MessageInput.js +27 -0
- package/agent-execution/components/MessageInput.js.map +1 -0
- package/agent-execution/components/OutputBlock.d.ts +9 -0
- package/agent-execution/components/OutputBlock.d.ts.map +1 -0
- package/agent-execution/components/OutputBlock.js +15 -0
- package/agent-execution/components/OutputBlock.js.map +1 -0
- package/agent-execution/components/SubAgentCard.d.ts +11 -0
- package/agent-execution/components/SubAgentCard.d.ts.map +1 -0
- package/agent-execution/components/SubAgentCard.js +19 -0
- package/agent-execution/components/SubAgentCard.js.map +1 -0
- package/agent-execution/components/ToolCallCard.d.ts +11 -0
- package/agent-execution/components/ToolCallCard.d.ts.map +1 -0
- package/agent-execution/components/ToolCallCard.js +25 -0
- package/agent-execution/components/ToolCallCard.js.map +1 -0
- package/agent-execution/helpers.d.ts +35 -0
- package/agent-execution/helpers.d.ts.map +1 -0
- package/agent-execution/helpers.js +157 -0
- package/agent-execution/helpers.js.map +1 -0
- package/agent-execution/hooks/useAgentExecution.d.ts +21 -0
- package/agent-execution/hooks/useAgentExecution.d.ts.map +1 -0
- package/agent-execution/hooks/useAgentExecution.js +99 -0
- package/agent-execution/hooks/useAgentExecution.js.map +1 -0
- package/agent-execution/hooks/useApproval.d.ts +12 -0
- package/agent-execution/hooks/useApproval.d.ts.map +1 -0
- package/agent-execution/hooks/useApproval.js +32 -0
- package/agent-execution/hooks/useApproval.js.map +1 -0
- package/agent-execution/index.d.ts +14 -0
- package/agent-execution/index.d.ts.map +1 -0
- package/agent-execution/index.js +15 -0
- package/agent-execution/index.js.map +1 -0
- package/catalog/components/ResourceSearchCard.d.ts +23 -0
- package/catalog/components/ResourceSearchCard.d.ts.map +1 -0
- package/catalog/components/ResourceSearchCard.js +36 -0
- package/catalog/components/ResourceSearchCard.js.map +1 -0
- package/catalog/index.d.ts +4 -0
- package/catalog/index.d.ts.map +1 -0
- package/catalog/index.js +5 -0
- package/catalog/index.js.map +1 -0
- package/catalog/internal/time.d.ts +13 -0
- package/catalog/internal/time.d.ts.map +1 -0
- package/catalog/internal/time.js +41 -0
- package/catalog/internal/time.js.map +1 -0
- package/context.d.ts +12 -0
- package/context.d.ts.map +1 -0
- package/context.js +13 -0
- package/context.js.map +1 -0
- package/hooks.d.ts +19 -0
- package/hooks.d.ts.map +1 -0
- package/hooks.js +28 -0
- package/hooks.js.map +1 -0
- package/index.d.ts +4 -0
- package/index.d.ts.map +1 -0
- package/index.js +6 -0
- package/index.js.map +1 -0
- package/internal/badge.d.ts +8 -0
- package/internal/badge.d.ts.map +1 -0
- package/internal/badge.js +34 -0
- package/internal/badge.js.map +1 -0
- package/internal/button.d.ts +9 -0
- package/internal/button.d.ts.map +1 -0
- package/internal/button.js +36 -0
- package/internal/button.js.map +1 -0
- package/internal/collapsible.d.ts +6 -0
- package/internal/collapsible.d.ts.map +1 -0
- package/internal/collapsible.js +14 -0
- package/internal/collapsible.js.map +1 -0
- package/internal/section.d.ts +8 -0
- package/internal/section.d.ts.map +1 -0
- package/internal/section.js +6 -0
- package/internal/section.js.map +1 -0
- package/internal/textarea.d.ts +4 -0
- package/internal/textarea.d.ts.map +1 -0
- package/internal/textarea.js +9 -0
- package/internal/textarea.js.map +1 -0
- package/mcp-server/hooks/useMcpServerSearch.d.ts +25 -0
- package/mcp-server/hooks/useMcpServerSearch.d.ts.map +1 -0
- package/mcp-server/hooks/useMcpServerSearch.js +57 -0
- package/mcp-server/hooks/useMcpServerSearch.js.map +1 -0
- package/mcp-server/index.d.ts +3 -0
- package/mcp-server/index.d.ts.map +1 -0
- package/mcp-server/index.js +3 -0
- package/mcp-server/index.js.map +1 -0
- package/package.json +75 -0
- package/provider.d.ts +55 -0
- package/provider.d.ts.map +1 -0
- package/provider.js +34 -0
- package/provider.js.map +1 -0
- package/session/components/AgentSessionHistory.d.ts +8 -0
- package/session/components/AgentSessionHistory.d.ts.map +1 -0
- package/session/components/AgentSessionHistory.js +11 -0
- package/session/components/AgentSessionHistory.js.map +1 -0
- package/session/components/SessionCard.d.ts +8 -0
- package/session/components/SessionCard.d.ts.map +1 -0
- package/session/components/SessionCard.js +57 -0
- package/session/components/SessionCard.js.map +1 -0
- package/session/hooks/useAgentSessionList.d.ts +21 -0
- package/session/hooks/useAgentSessionList.d.ts.map +1 -0
- package/session/hooks/useAgentSessionList.js +90 -0
- package/session/hooks/useAgentSessionList.js.map +1 -0
- package/session/index.d.ts +7 -0
- package/session/index.d.ts.map +1 -0
- package/session/index.js +6 -0
- package/session/index.js.map +1 -0
- package/skill/hooks/useSkillSearch.d.ts +25 -0
- package/skill/hooks/useSkillSearch.d.ts.map +1 -0
- package/skill/hooks/useSkillSearch.js +57 -0
- package/skill/hooks/useSkillSearch.js.map +1 -0
- package/skill/index.d.ts +3 -0
- package/skill/index.d.ts.map +1 -0
- package/skill/index.js +3 -0
- package/skill/index.js.map +1 -0
- package/src/agent/components/AgentCard.tsx +125 -0
- package/src/agent/components/AgentOverview.tsx +209 -0
- package/src/agent/components/AgentPicker.tsx +255 -0
- package/src/agent/hooks/useAgentSearch.ts +94 -0
- package/src/agent/index.ts +17 -0
- package/src/agent-execution/components/ApprovalControls.tsx +99 -0
- package/src/agent-execution/components/ExecutionStatus.tsx +33 -0
- package/src/agent-execution/components/ExecutionStream.tsx +148 -0
- package/src/agent-execution/components/MessageEntry.tsx +125 -0
- package/src/agent-execution/components/MessageInput.tsx +70 -0
- package/src/agent-execution/components/OutputBlock.tsx +43 -0
- package/src/agent-execution/components/SubAgentCard.tsx +138 -0
- package/src/agent-execution/components/ToolCallCard.tsx +153 -0
- package/src/agent-execution/helpers.ts +193 -0
- package/src/agent-execution/hooks/useAgentExecution.ts +147 -0
- package/src/agent-execution/hooks/useApproval.ts +56 -0
- package/src/agent-execution/index.ts +46 -0
- package/src/catalog/components/ResourceSearchCard.tsx +137 -0
- package/src/catalog/index.ts +6 -0
- package/src/catalog/internal/time.ts +40 -0
- package/src/context.ts +15 -0
- package/src/hooks.ts +32 -0
- package/src/index.ts +6 -0
- package/src/internal/badge.tsx +52 -0
- package/src/internal/button.tsx +60 -0
- package/src/internal/collapsible.tsx +21 -0
- package/src/internal/section.tsx +18 -0
- package/src/internal/textarea.tsx +23 -0
- package/src/mcp-server/hooks/useMcpServerSearch.ts +79 -0
- package/src/mcp-server/index.ts +6 -0
- package/src/provider.tsx +73 -0
- package/src/session/components/AgentSessionHistory.tsx +109 -0
- package/src/session/components/SessionCard.tsx +113 -0
- package/src/session/hooks/useAgentSessionList.ts +117 -0
- package/src/session/index.ts +13 -0
- package/src/skill/hooks/useSkillSearch.ts +79 -0
- package/src/skill/index.ts +6 -0
- package/src/styles.css +72 -0
- package/styles.css +2 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
import { Badge } from "../../internal/badge";
|
|
5
|
+
import {
|
|
6
|
+
Collapsible,
|
|
7
|
+
CollapsibleContent,
|
|
8
|
+
CollapsibleTrigger,
|
|
9
|
+
} from "../../internal/collapsible";
|
|
10
|
+
import { ApprovalControls } from "./ApprovalControls";
|
|
11
|
+
import {
|
|
12
|
+
toolCallStatusLabel,
|
|
13
|
+
toolCallStatusVariant,
|
|
14
|
+
qualifiedToolName,
|
|
15
|
+
formatDuration,
|
|
16
|
+
} from "../helpers";
|
|
17
|
+
import { ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
18
|
+
import type { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
19
|
+
import type { ToolCall } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
|
|
20
|
+
import { cn } from "@stigmer/theme";
|
|
21
|
+
import { ChevronRight, Wrench, Loader2 } from "lucide-react";
|
|
22
|
+
|
|
23
|
+
interface ToolCallCardProps {
|
|
24
|
+
toolCall: ToolCall;
|
|
25
|
+
onApproval?: (
|
|
26
|
+
toolCallId: string,
|
|
27
|
+
action: ApprovalAction,
|
|
28
|
+
comment?: string,
|
|
29
|
+
) => Promise<void>;
|
|
30
|
+
isApprovalSubmitting?: boolean;
|
|
31
|
+
className?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function ToolCallCard({
|
|
35
|
+
toolCall,
|
|
36
|
+
onApproval,
|
|
37
|
+
isApprovalSubmitting = false,
|
|
38
|
+
className,
|
|
39
|
+
}: ToolCallCardProps) {
|
|
40
|
+
const [open, setOpen] = useState(false);
|
|
41
|
+
const isWaitingApproval =
|
|
42
|
+
toolCall.status === ToolCallStatus.TOOL_CALL_WAITING_APPROVAL;
|
|
43
|
+
const isRunning = toolCall.status === ToolCallStatus.TOOL_CALL_RUNNING;
|
|
44
|
+
const duration = formatDuration(toolCall.startedAt, toolCall.completedAt);
|
|
45
|
+
const displayName = qualifiedToolName(toolCall.name, toolCall.mcpServerSlug);
|
|
46
|
+
|
|
47
|
+
const handleApproval = useCallback(
|
|
48
|
+
async (action: ApprovalAction, comment?: string) => {
|
|
49
|
+
await onApproval?.(toolCall.id, action, comment);
|
|
50
|
+
},
|
|
51
|
+
[onApproval, toolCall.id],
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<Collapsible open={open || isWaitingApproval} onOpenChange={setOpen}>
|
|
56
|
+
<div
|
|
57
|
+
className={cn(
|
|
58
|
+
"bg-card text-card-foreground rounded-lg border text-sm",
|
|
59
|
+
isWaitingApproval && "border-primary/40 ring-primary/20 ring-1",
|
|
60
|
+
className,
|
|
61
|
+
)}
|
|
62
|
+
>
|
|
63
|
+
<CollapsibleTrigger className="hover:bg-muted/50 flex w-full items-center gap-2 rounded-t-lg px-3 py-2 text-left transition-colors">
|
|
64
|
+
<ChevronRight
|
|
65
|
+
className={cn(
|
|
66
|
+
"text-muted-foreground size-3.5 shrink-0 transition-transform",
|
|
67
|
+
(open || isWaitingApproval) && "rotate-90",
|
|
68
|
+
)}
|
|
69
|
+
/>
|
|
70
|
+
{isRunning ? (
|
|
71
|
+
<Loader2 className="text-muted-foreground size-3.5 shrink-0 animate-spin" />
|
|
72
|
+
) : (
|
|
73
|
+
<Wrench className="text-muted-foreground size-3.5 shrink-0" />
|
|
74
|
+
)}
|
|
75
|
+
<span className="truncate font-mono text-xs">{displayName}</span>
|
|
76
|
+
<Badge
|
|
77
|
+
variant={toolCallStatusVariant(toolCall.status)}
|
|
78
|
+
className="ml-auto shrink-0 text-[10px]"
|
|
79
|
+
>
|
|
80
|
+
{toolCallStatusLabel(toolCall.status)}
|
|
81
|
+
</Badge>
|
|
82
|
+
{duration && (
|
|
83
|
+
<span className="text-muted-foreground shrink-0 text-[10px]">
|
|
84
|
+
{duration}
|
|
85
|
+
</span>
|
|
86
|
+
)}
|
|
87
|
+
</CollapsibleTrigger>
|
|
88
|
+
|
|
89
|
+
<CollapsibleContent>
|
|
90
|
+
<div className="space-y-2 border-t px-3 py-2">
|
|
91
|
+
{toolCall.args && Object.keys(toolCall.args).length > 0 && (
|
|
92
|
+
<ToolCallSection label="Arguments">
|
|
93
|
+
<pre className="bg-muted overflow-x-auto rounded p-2 text-[11px] leading-relaxed">
|
|
94
|
+
{JSON.stringify(toolCall.args, null, 2)}
|
|
95
|
+
</pre>
|
|
96
|
+
</ToolCallSection>
|
|
97
|
+
)}
|
|
98
|
+
|
|
99
|
+
{toolCall.result && (
|
|
100
|
+
<ToolCallSection label="Result">
|
|
101
|
+
<pre className="bg-muted overflow-x-auto rounded p-2 text-[11px] leading-relaxed whitespace-pre-wrap">
|
|
102
|
+
{toolCall.result}
|
|
103
|
+
</pre>
|
|
104
|
+
</ToolCallSection>
|
|
105
|
+
)}
|
|
106
|
+
|
|
107
|
+
{toolCall.error && (
|
|
108
|
+
<ToolCallSection label="Error">
|
|
109
|
+
<p className="text-destructive text-xs">{toolCall.error}</p>
|
|
110
|
+
</ToolCallSection>
|
|
111
|
+
)}
|
|
112
|
+
|
|
113
|
+
{toolCall.isStreaming && !toolCall.result && (
|
|
114
|
+
<div className="text-muted-foreground flex items-center gap-1.5 text-xs">
|
|
115
|
+
<Loader2 className="size-3 animate-spin" />
|
|
116
|
+
Executing...
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
{isWaitingApproval && onApproval && (
|
|
122
|
+
<div className="border-t px-3 py-2">
|
|
123
|
+
<ApprovalControls
|
|
124
|
+
approvalMessage={
|
|
125
|
+
toolCall.approvalMessage || `Execute tool: ${displayName}`
|
|
126
|
+
}
|
|
127
|
+
onSubmit={handleApproval}
|
|
128
|
+
isSubmitting={isApprovalSubmitting}
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
)}
|
|
132
|
+
</CollapsibleContent>
|
|
133
|
+
</div>
|
|
134
|
+
</Collapsible>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function ToolCallSection({
|
|
139
|
+
label,
|
|
140
|
+
children,
|
|
141
|
+
}: {
|
|
142
|
+
label: string;
|
|
143
|
+
children: React.ReactNode;
|
|
144
|
+
}) {
|
|
145
|
+
return (
|
|
146
|
+
<div>
|
|
147
|
+
<p className="text-muted-foreground mb-1 text-[10px] font-medium tracking-wider uppercase">
|
|
148
|
+
{label}
|
|
149
|
+
</p>
|
|
150
|
+
{children}
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExecutionPhase,
|
|
3
|
+
ToolCallStatus,
|
|
4
|
+
SubAgentStatus,
|
|
5
|
+
MessageType,
|
|
6
|
+
} from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
7
|
+
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
8
|
+
import type { SubAgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/subagent_pb";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Execution phase utilities
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
const TERMINAL_PHASES = new Set<ExecutionPhase>([
|
|
15
|
+
ExecutionPhase.EXECUTION_COMPLETED,
|
|
16
|
+
ExecutionPhase.EXECUTION_FAILED,
|
|
17
|
+
ExecutionPhase.EXECUTION_CANCELLED,
|
|
18
|
+
ExecutionPhase.EXECUTION_TERMINATED,
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
export function isTerminalPhase(phase: ExecutionPhase): boolean {
|
|
22
|
+
return TERMINAL_PHASES.has(phase);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const PHASE_LABELS: Record<ExecutionPhase, string> = {
|
|
26
|
+
[ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED]: "Unknown",
|
|
27
|
+
[ExecutionPhase.EXECUTION_PENDING]: "Pending",
|
|
28
|
+
[ExecutionPhase.EXECUTION_IN_PROGRESS]: "Running",
|
|
29
|
+
[ExecutionPhase.EXECUTION_COMPLETED]: "Completed",
|
|
30
|
+
[ExecutionPhase.EXECUTION_FAILED]: "Failed",
|
|
31
|
+
[ExecutionPhase.EXECUTION_CANCELLED]: "Cancelled",
|
|
32
|
+
[ExecutionPhase.EXECUTION_TERMINATED]: "Terminated",
|
|
33
|
+
[ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL]: "Waiting for Approval",
|
|
34
|
+
[ExecutionPhase.EXECUTION_PAUSED]: "Paused",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function phaseLabel(phase: ExecutionPhase): string {
|
|
38
|
+
return PHASE_LABELS[phase] ?? "Unknown";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type BadgeVariant = "default" | "secondary" | "destructive" | "outline";
|
|
42
|
+
|
|
43
|
+
const PHASE_VARIANTS: Record<ExecutionPhase, BadgeVariant> = {
|
|
44
|
+
[ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED]: "outline",
|
|
45
|
+
[ExecutionPhase.EXECUTION_PENDING]: "outline",
|
|
46
|
+
[ExecutionPhase.EXECUTION_IN_PROGRESS]: "default",
|
|
47
|
+
[ExecutionPhase.EXECUTION_COMPLETED]: "secondary",
|
|
48
|
+
[ExecutionPhase.EXECUTION_FAILED]: "destructive",
|
|
49
|
+
[ExecutionPhase.EXECUTION_CANCELLED]: "outline",
|
|
50
|
+
[ExecutionPhase.EXECUTION_TERMINATED]: "destructive",
|
|
51
|
+
[ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL]: "default",
|
|
52
|
+
[ExecutionPhase.EXECUTION_PAUSED]: "outline",
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export function phaseVariant(phase: ExecutionPhase): BadgeVariant {
|
|
56
|
+
return PHASE_VARIANTS[phase] ?? "outline";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Tool call status utilities
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
const TOOL_CALL_STATUS_LABELS: Record<ToolCallStatus, string> = {
|
|
64
|
+
[ToolCallStatus.TOOL_CALL_STATUS_UNSPECIFIED]: "Unknown",
|
|
65
|
+
[ToolCallStatus.TOOL_CALL_PENDING]: "Pending",
|
|
66
|
+
[ToolCallStatus.TOOL_CALL_RUNNING]: "Running",
|
|
67
|
+
[ToolCallStatus.TOOL_CALL_COMPLETED]: "Completed",
|
|
68
|
+
[ToolCallStatus.TOOL_CALL_FAILED]: "Failed",
|
|
69
|
+
[ToolCallStatus.TOOL_CALL_WAITING_APPROVAL]: "Awaiting Approval",
|
|
70
|
+
[ToolCallStatus.TOOL_CALL_SKIPPED]: "Skipped",
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export function toolCallStatusLabel(status: ToolCallStatus): string {
|
|
74
|
+
return TOOL_CALL_STATUS_LABELS[status] ?? "Unknown";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const TOOL_CALL_STATUS_VARIANTS: Record<ToolCallStatus, BadgeVariant> = {
|
|
78
|
+
[ToolCallStatus.TOOL_CALL_STATUS_UNSPECIFIED]: "outline",
|
|
79
|
+
[ToolCallStatus.TOOL_CALL_PENDING]: "outline",
|
|
80
|
+
[ToolCallStatus.TOOL_CALL_RUNNING]: "default",
|
|
81
|
+
[ToolCallStatus.TOOL_CALL_COMPLETED]: "secondary",
|
|
82
|
+
[ToolCallStatus.TOOL_CALL_FAILED]: "destructive",
|
|
83
|
+
[ToolCallStatus.TOOL_CALL_WAITING_APPROVAL]: "default",
|
|
84
|
+
[ToolCallStatus.TOOL_CALL_SKIPPED]: "outline",
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export function toolCallStatusVariant(status: ToolCallStatus): BadgeVariant {
|
|
88
|
+
return TOOL_CALL_STATUS_VARIANTS[status] ?? "outline";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function isToolCallTerminal(status: ToolCallStatus): boolean {
|
|
92
|
+
return (
|
|
93
|
+
status === ToolCallStatus.TOOL_CALL_COMPLETED ||
|
|
94
|
+
status === ToolCallStatus.TOOL_CALL_FAILED ||
|
|
95
|
+
status === ToolCallStatus.TOOL_CALL_SKIPPED
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Sub-agent status utilities
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
const SUB_AGENT_STATUS_LABELS: Record<SubAgentStatus, string> = {
|
|
104
|
+
[SubAgentStatus.SUB_AGENT_STATUS_UNSPECIFIED]: "Unknown",
|
|
105
|
+
[SubAgentStatus.SUB_AGENT_PENDING]: "Pending",
|
|
106
|
+
[SubAgentStatus.SUB_AGENT_IN_PROGRESS]: "Running",
|
|
107
|
+
[SubAgentStatus.SUB_AGENT_COMPLETED]: "Completed",
|
|
108
|
+
[SubAgentStatus.SUB_AGENT_FAILED]: "Failed",
|
|
109
|
+
[SubAgentStatus.SUB_AGENT_CANCELLED]: "Cancelled",
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export function subAgentStatusLabel(status: SubAgentStatus): string {
|
|
113
|
+
return SUB_AGENT_STATUS_LABELS[status] ?? "Unknown";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const SUB_AGENT_STATUS_VARIANTS: Record<SubAgentStatus, BadgeVariant> = {
|
|
117
|
+
[SubAgentStatus.SUB_AGENT_STATUS_UNSPECIFIED]: "outline",
|
|
118
|
+
[SubAgentStatus.SUB_AGENT_PENDING]: "outline",
|
|
119
|
+
[SubAgentStatus.SUB_AGENT_IN_PROGRESS]: "default",
|
|
120
|
+
[SubAgentStatus.SUB_AGENT_COMPLETED]: "secondary",
|
|
121
|
+
[SubAgentStatus.SUB_AGENT_FAILED]: "destructive",
|
|
122
|
+
[SubAgentStatus.SUB_AGENT_CANCELLED]: "outline",
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export function subAgentStatusVariant(status: SubAgentStatus): BadgeVariant {
|
|
126
|
+
return SUB_AGENT_STATUS_VARIANTS[status] ?? "outline";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Message type utilities
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
export function isHumanMessage(type: MessageType): boolean {
|
|
134
|
+
return type === MessageType.MESSAGE_HUMAN;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function isAiMessage(type: MessageType): boolean {
|
|
138
|
+
return type === MessageType.MESSAGE_AI;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function isToolMessage(type: MessageType): boolean {
|
|
142
|
+
return type === MessageType.MESSAGE_TOOL;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function isSystemMessage(type: MessageType): boolean {
|
|
146
|
+
return type === MessageType.MESSAGE_SYSTEM;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Execution-level helpers
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Build an index of sub-agent executions keyed by their ID.
|
|
155
|
+
* The sub-agent ID matches the tool call ID from the parent's "task" tool
|
|
156
|
+
* invocation, enabling O(1) lookup when rendering tool calls that represent
|
|
157
|
+
* sub-agent delegations.
|
|
158
|
+
*/
|
|
159
|
+
export function buildSubAgentIndex(
|
|
160
|
+
execution: AgentExecution,
|
|
161
|
+
): Map<string, SubAgentExecution> {
|
|
162
|
+
const subAgents = execution.status?.subAgentExecutions;
|
|
163
|
+
if (!subAgents || subAgents.length === 0) return new Map();
|
|
164
|
+
return new Map(subAgents.map((sa) => [sa.id, sa]));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Format a qualified tool name: "mcp-server/tool-name" when an MCP server
|
|
169
|
+
* slug is present, or just "tool-name" for built-in sandbox tools.
|
|
170
|
+
*/
|
|
171
|
+
export function qualifiedToolName(name: string, mcpServerSlug: string): string {
|
|
172
|
+
if (mcpServerSlug) return `${mcpServerSlug}/${name}`;
|
|
173
|
+
return name;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Format elapsed time between two ISO timestamps as a human-readable duration.
|
|
178
|
+
* Returns null if either timestamp is missing.
|
|
179
|
+
*/
|
|
180
|
+
export function formatDuration(
|
|
181
|
+
startedAt: string,
|
|
182
|
+
completedAt: string,
|
|
183
|
+
): string | null {
|
|
184
|
+
if (!startedAt || !completedAt) return null;
|
|
185
|
+
const ms = new Date(completedAt).getTime() - new Date(startedAt).getTime();
|
|
186
|
+
if (ms < 0) return null;
|
|
187
|
+
if (ms < 1000) return `${ms}ms`;
|
|
188
|
+
const seconds = ms / 1000;
|
|
189
|
+
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
190
|
+
const minutes = Math.floor(seconds / 60);
|
|
191
|
+
const remainingSeconds = Math.round(seconds % 60);
|
|
192
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
193
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
5
|
+
import { ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
6
|
+
import { create } from "@bufbuild/protobuf";
|
|
7
|
+
import { CancelAgentExecutionInputSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
|
|
8
|
+
import { useStigmer } from "../../hooks";
|
|
9
|
+
import { isTerminalPhase } from "../helpers";
|
|
10
|
+
|
|
11
|
+
export interface CreateExecutionInput {
|
|
12
|
+
agentId?: string;
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
message: string;
|
|
15
|
+
org: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UseAgentExecutionOptions {
|
|
19
|
+
executionId?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface UseAgentExecutionReturn {
|
|
23
|
+
execution: AgentExecution | null;
|
|
24
|
+
phase: ExecutionPhase;
|
|
25
|
+
isConnected: boolean;
|
|
26
|
+
error: string | null;
|
|
27
|
+
start: (input: CreateExecutionInput) => Promise<void>;
|
|
28
|
+
cancel: (reason?: string) => Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function useAgentExecution(
|
|
32
|
+
options?: UseAgentExecutionOptions,
|
|
33
|
+
): UseAgentExecutionReturn {
|
|
34
|
+
const stigmer = useStigmer();
|
|
35
|
+
const [execution, setExecution] = useState<AgentExecution | null>(null);
|
|
36
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
37
|
+
const [error, setError] = useState<string | null>(null);
|
|
38
|
+
|
|
39
|
+
const activeExecutionIdRef = useRef<string | null>(
|
|
40
|
+
options?.executionId ?? null,
|
|
41
|
+
);
|
|
42
|
+
const abortRef = useRef<AbortController | null>(null);
|
|
43
|
+
|
|
44
|
+
const subscribe = useCallback(
|
|
45
|
+
(executionId: string) => {
|
|
46
|
+
abortRef.current?.abort();
|
|
47
|
+
|
|
48
|
+
const controller = new AbortController();
|
|
49
|
+
abortRef.current = controller;
|
|
50
|
+
activeExecutionIdRef.current = executionId;
|
|
51
|
+
setIsConnected(true);
|
|
52
|
+
setError(null);
|
|
53
|
+
|
|
54
|
+
(async () => {
|
|
55
|
+
try {
|
|
56
|
+
const stream = stigmer.agentExecution.subscribe(
|
|
57
|
+
executionId,
|
|
58
|
+
controller.signal,
|
|
59
|
+
);
|
|
60
|
+
for await (const update of stream) {
|
|
61
|
+
if (controller.signal.aborted) break;
|
|
62
|
+
setExecution(update);
|
|
63
|
+
|
|
64
|
+
const phase =
|
|
65
|
+
update.status?.phase ??
|
|
66
|
+
ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED;
|
|
67
|
+
if (isTerminalPhase(phase)) {
|
|
68
|
+
setIsConnected(false);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch (err: unknown) {
|
|
73
|
+
if (controller.signal.aborted) return;
|
|
74
|
+
const message =
|
|
75
|
+
err instanceof Error ? err.message : "Stream disconnected";
|
|
76
|
+
setError(message);
|
|
77
|
+
} finally {
|
|
78
|
+
if (!controller.signal.aborted) {
|
|
79
|
+
setIsConnected(false);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
})();
|
|
83
|
+
},
|
|
84
|
+
[stigmer],
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (options?.executionId) {
|
|
89
|
+
subscribe(options.executionId);
|
|
90
|
+
}
|
|
91
|
+
return () => {
|
|
92
|
+
abortRef.current?.abort();
|
|
93
|
+
};
|
|
94
|
+
}, [options?.executionId, subscribe]);
|
|
95
|
+
|
|
96
|
+
const start = useCallback(
|
|
97
|
+
async (input: CreateExecutionInput) => {
|
|
98
|
+
setError(null);
|
|
99
|
+
setExecution(null);
|
|
100
|
+
try {
|
|
101
|
+
const created = await stigmer.agentExecution.create({
|
|
102
|
+
name: "",
|
|
103
|
+
org: input.org,
|
|
104
|
+
agentId: input.agentId,
|
|
105
|
+
sessionId: input.sessionId,
|
|
106
|
+
message: input.message,
|
|
107
|
+
});
|
|
108
|
+
const executionId = created.metadata?.id;
|
|
109
|
+
if (!executionId) {
|
|
110
|
+
throw new Error("Created execution missing metadata.id");
|
|
111
|
+
}
|
|
112
|
+
setExecution(created);
|
|
113
|
+
subscribe(executionId);
|
|
114
|
+
} catch (err: unknown) {
|
|
115
|
+
const message =
|
|
116
|
+
err instanceof Error ? err.message : "Failed to create execution";
|
|
117
|
+
setError(message);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
[stigmer, subscribe],
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const cancel = useCallback(
|
|
124
|
+
async (reason?: string) => {
|
|
125
|
+
const id = activeExecutionIdRef.current;
|
|
126
|
+
if (!id) return;
|
|
127
|
+
try {
|
|
128
|
+
await stigmer.agentExecution.cancel(
|
|
129
|
+
create(CancelAgentExecutionInputSchema, {
|
|
130
|
+
id,
|
|
131
|
+
reason: reason ?? "",
|
|
132
|
+
}),
|
|
133
|
+
);
|
|
134
|
+
} catch (err: unknown) {
|
|
135
|
+
const message =
|
|
136
|
+
err instanceof Error ? err.message : "Failed to cancel execution";
|
|
137
|
+
setError(message);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
[stigmer],
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const phase =
|
|
144
|
+
execution?.status?.phase ?? ExecutionPhase.EXECUTION_PHASE_UNSPECIFIED;
|
|
145
|
+
|
|
146
|
+
return { execution, phase, isConnected, error, start, cancel };
|
|
147
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useState } from "react";
|
|
4
|
+
import type { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
|
|
5
|
+
import { create } from "@bufbuild/protobuf";
|
|
6
|
+
import { SubmitApprovalInputSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
|
|
7
|
+
import { useStigmer } from "../../hooks";
|
|
8
|
+
|
|
9
|
+
export interface UseApprovalOptions {
|
|
10
|
+
executionId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UseApprovalReturn {
|
|
14
|
+
submit: (
|
|
15
|
+
toolCallId: string,
|
|
16
|
+
action: ApprovalAction,
|
|
17
|
+
comment?: string,
|
|
18
|
+
) => Promise<void>;
|
|
19
|
+
isSubmitting: boolean;
|
|
20
|
+
error: string | null;
|
|
21
|
+
clearError: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useApproval(options: UseApprovalOptions): UseApprovalReturn {
|
|
25
|
+
const stigmer = useStigmer();
|
|
26
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
27
|
+
const [error, setError] = useState<string | null>(null);
|
|
28
|
+
|
|
29
|
+
const submit = useCallback(
|
|
30
|
+
async (toolCallId: string, action: ApprovalAction, comment?: string) => {
|
|
31
|
+
setIsSubmitting(true);
|
|
32
|
+
setError(null);
|
|
33
|
+
try {
|
|
34
|
+
await stigmer.agentExecution.submitApproval(
|
|
35
|
+
create(SubmitApprovalInputSchema, {
|
|
36
|
+
agentExecutionId: options.executionId,
|
|
37
|
+
toolCallId,
|
|
38
|
+
action,
|
|
39
|
+
comment: comment ?? "",
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
} catch (err: unknown) {
|
|
43
|
+
const message =
|
|
44
|
+
err instanceof Error ? err.message : "Failed to submit approval";
|
|
45
|
+
setError(message);
|
|
46
|
+
} finally {
|
|
47
|
+
setIsSubmitting(false);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
[stigmer, options.executionId],
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const clearError = useCallback(() => setError(null), []);
|
|
54
|
+
|
|
55
|
+
return { submit, isSubmitting, error, clearError };
|
|
56
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Components
|
|
2
|
+
export { ExecutionStream } from "./components/ExecutionStream";
|
|
3
|
+
export { ExecutionStatus } from "./components/ExecutionStatus";
|
|
4
|
+
export { OutputBlock } from "./components/OutputBlock";
|
|
5
|
+
export { ToolCallCard } from "./components/ToolCallCard";
|
|
6
|
+
export { ApprovalControls } from "./components/ApprovalControls";
|
|
7
|
+
export { SubAgentCard } from "./components/SubAgentCard";
|
|
8
|
+
export { MessageInput } from "./components/MessageInput";
|
|
9
|
+
export {
|
|
10
|
+
MessageEntry,
|
|
11
|
+
HumanMessageBubble,
|
|
12
|
+
SystemMessageBlock,
|
|
13
|
+
} from "./components/MessageEntry";
|
|
14
|
+
|
|
15
|
+
// Hooks
|
|
16
|
+
export { useAgentExecution } from "./hooks/useAgentExecution";
|
|
17
|
+
export type {
|
|
18
|
+
UseAgentExecutionOptions,
|
|
19
|
+
UseAgentExecutionReturn,
|
|
20
|
+
CreateExecutionInput,
|
|
21
|
+
} from "./hooks/useAgentExecution";
|
|
22
|
+
|
|
23
|
+
export { useApproval } from "./hooks/useApproval";
|
|
24
|
+
export type {
|
|
25
|
+
UseApprovalOptions,
|
|
26
|
+
UseApprovalReturn,
|
|
27
|
+
} from "./hooks/useApproval";
|
|
28
|
+
|
|
29
|
+
// Helpers
|
|
30
|
+
export {
|
|
31
|
+
isTerminalPhase,
|
|
32
|
+
phaseLabel,
|
|
33
|
+
phaseVariant,
|
|
34
|
+
toolCallStatusLabel,
|
|
35
|
+
toolCallStatusVariant,
|
|
36
|
+
isToolCallTerminal,
|
|
37
|
+
subAgentStatusLabel,
|
|
38
|
+
subAgentStatusVariant,
|
|
39
|
+
isHumanMessage,
|
|
40
|
+
isAiMessage,
|
|
41
|
+
isToolMessage,
|
|
42
|
+
isSystemMessage,
|
|
43
|
+
buildSubAgentIndex,
|
|
44
|
+
qualifiedToolName,
|
|
45
|
+
formatDuration,
|
|
46
|
+
} from "./helpers";
|