From a000a4b9a79511f9e9d0007953f7b37053c6b2df Mon Sep 17 00:00:00 2001 From: "Julia Valenti (julvalen)" Date: Wed, 11 Feb 2026 09:23:58 -0800 Subject: [PATCH] feat: add diagnostic-report artifact component Fixes from PR #4: - Fixed zod import (named import) - Exported DiagnosticItemZod with .describe() annotations - Added Zod validation in action handler - Removed ArtifactTabZod discriminated union - Added DIAGNOSTIC_REPORT_DESCRIPTION barrel export - Used direct type reference instead of Extract<> Signed-off-by: Julia Valenti (julvalen) --- cli/src/registry/default/artifacts.ts | 49 ++++ .../registry/github-registry/artifacts.json | 18 ++ hax/artifacts/diagnostic-report/README.md | 261 +++++++++++++++++ hax/artifacts/diagnostic-report/action.ts | 62 ++++ .../diagnostic-report/description.ts | 36 +++ .../diagnostic-report/diagnostic-report.tsx | 266 ++++++++++++++++++ hax/artifacts/diagnostic-report/index.ts | 23 ++ hax/artifacts/diagnostic-report/types.ts | 42 +++ 8 files changed, 757 insertions(+) create mode 100644 hax/artifacts/diagnostic-report/README.md create mode 100644 hax/artifacts/diagnostic-report/action.ts create mode 100644 hax/artifacts/diagnostic-report/description.ts create mode 100644 hax/artifacts/diagnostic-report/diagnostic-report.tsx create mode 100644 hax/artifacts/diagnostic-report/index.ts create mode 100644 hax/artifacts/diagnostic-report/types.ts diff --git a/cli/src/registry/default/artifacts.ts b/cli/src/registry/default/artifacts.ts index e95ee65..fcd9b09 100644 --- a/cli/src/registry/default/artifacts.ts +++ b/cli/src/registry/default/artifacts.ts @@ -536,4 +536,53 @@ export const artifacts: RegistryItem[] = [ }, ], }, + { + name: "diagnostic-report", + type: "registry:artifacts", + dependencies: [ + "react", + "clsx", + "tailwind-merge", + "zod", + "@copilotkit/react-core", + ], + registryDependencies: ["button", "progress"], + files: [ + { + path: "hax/artifacts/diagnostic-report/diagnostic-report.tsx", + type: "registry:component", + content: readComponentFile( + "hax/artifacts/diagnostic-report/diagnostic-report.tsx", + ), + }, + { + path: "hax/artifacts/diagnostic-report/action.ts", + type: "registry:hook", + content: readComponentFile( + "hax/artifacts/diagnostic-report/action.ts", + ), + }, + { + path: "hax/artifacts/diagnostic-report/types.ts", + type: "registry:types", + content: readComponentFile( + "hax/artifacts/diagnostic-report/types.ts", + ), + }, + { + path: "hax/artifacts/diagnostic-report/index.ts", + type: "registry:index", + content: readComponentFile( + "hax/artifacts/diagnostic-report/index.ts", + ), + }, + { + path: "hax/artifacts/diagnostic-report/description.ts", + type: "registry:description", + content: readComponentFile( + "hax/artifacts/diagnostic-report/description.ts", + ), + }, + ], + }, ] diff --git a/cli/src/registry/github-registry/artifacts.json b/cli/src/registry/github-registry/artifacts.json index 774f9aa..a189116 100644 --- a/cli/src/registry/github-registry/artifacts.json +++ b/cli/src/registry/github-registry/artifacts.json @@ -255,5 +255,23 @@ { "name": "index.ts", "type": "registry:index" }, { "name": "description.ts", "type": "registry:description" } ] + }, + "diagnostic-report": { + "type": "registry:artifacts", + "dependencies": [ + "react", + "clsx", + "tailwind-merge", + "zod", + "@copilotkit/react-core" + ], + "registryDependencies": ["button", "progress"], + "files": [ + { "name": "diagnostic-report.tsx", "type": "registry:component" }, + { "name": "action.ts", "type": "registry:hook" }, + { "name": "types.ts", "type": "registry:types" }, + { "name": "index.ts", "type": "registry:index" }, + { "name": "description.ts", "type": "registry:description" } + ] } } diff --git a/hax/artifacts/diagnostic-report/README.md b/hax/artifacts/diagnostic-report/README.md new file mode 100644 index 0000000..69b9db4 --- /dev/null +++ b/hax/artifacts/diagnostic-report/README.md @@ -0,0 +1,261 @@ +# Diagnostic Report Component + +A structured diagnostic report component for presenting troubleshooting findings with confidence levels and actionable recommendations. + +## Installation + +Install the component using the HAX SDK CLI: + +```bash +hax init +hax add artifact diagnostic-report +``` + +This will install the component along with its required dependencies: +- `@copilotkit/react-core` +- `zod` + +## Usage + +### Basic Usage + +```tsx +import { + HAXDiagnosticReport, + DiagnosticItem, +} from "@/artifacts/diagnostic-report" + +const items: DiagnosticItem[] = [ + { + id: "1", + suspectedCause: "Memory leak in worker process", + confidence: 85, + confidenceLevel: "high", + rationale: "Memory usage increases linearly over time without recovery", + recommendedAction: "Restart worker process", + }, + { + id: "2", + suspectedCause: "Database connection pool exhausted", + confidence: 45, + confidenceLevel: "medium", + rationale: "Connection wait times have increased significantly", + recommendedAction: "Increase pool size", + }, +] + +function App() { + const handleAction = (itemId: string) => { + console.log(`Action clicked for item: ${itemId}`) + } + + return ( + + ) +} +``` + +### Using Individual Components + +```tsx +import { + DiagnosticReportCard, + DiagnosticValueCard, + DiagnosticTableHeader, + ConfidenceValue, +} from "@/artifacts/diagnostic-report" + +// Use DiagnosticReportCard for the full report + + +// Use individual components for custom layouts + + + console.log("Action clicked")} +/> + + +``` + +### CopilotKit Integration + +Use the `useDiagnosticReportAction` hook to enable AI agents to create diagnostic reports: + +```tsx +import { useDiagnosticReportAction } from "@/artifacts/diagnostic-report" + +function MyComponent() { + const addOrUpdateArtifact = (type, data) => { + // Handle the artifact creation/update + console.log("Artifact:", type, data) + } + + useDiagnosticReportAction({ addOrUpdateArtifact }) + + return
...
+} +``` + +## Schema + +### DiagnosticItem + +| Property | Type | Description | +|----------|------|-------------| +| `id` | `string` | Unique identifier for the diagnostic item | +| `suspectedCause` | `string` | Description of the potential cause | +| `confidence` | `number` | Confidence percentage (0-100) | +| `confidenceLevel` | `"high" \| "medium" \| "low"` | Categorical confidence level | +| `rationale` | `string` | Explanation supporting the assessment | +| `recommendedAction` | `string` | Actionable next step | + +### DiagnosticReportArtifact + +```typescript +{ + id: string + type: "diagnostic-report" + data: { + title?: string + items: DiagnosticItem[] + } +} +``` + +### Confidence Level Mapping + +| Level | Color | Range | Description | +|-------|-------|-------|-------------| +| `high` | Green (#2ca02c) | 70-100% | Strong evidence supports this cause | +| `medium` | Orange (#ff7f0e) | 40-69% | Moderate evidence, needs investigation | +| `low` | Yellow (#facc15) | 0-39% | Possible but requires validation | + +## Actions + +### create_diagnostic_report + +CopilotKit action for AI agents to create diagnostic reports. + +**Parameters:** + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `title` | `string` | No | Title for the diagnostic report card | +| `itemsJson` | `string` | Yes | JSON string of diagnostic items array | + +**Example Action Call:** + +```json +{ + "name": "create_diagnostic_report", + "parameters": { + "title": "Network Connectivity Analysis", + "itemsJson": "[{\"id\":\"1\",\"suspectedCause\":\"DNS resolution failure\",\"confidence\":90,\"confidenceLevel\":\"high\",\"rationale\":\"DNS queries timing out consistently\",\"recommendedAction\":\"Check DNS server\"}]" + } +} +``` + +## Component Props + +### HAXDiagnosticReport / DiagnosticReportCard + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `title` | `string` | `"Diagnostic Report With Actionables"` | Report title | +| `items` | `DiagnosticItem[]` | - | Array of diagnostic items | +| `onActionClick` | `(itemId: string) => void` | - | Callback when action button is clicked | +| `className` | `string` | - | Additional CSS classes | + +### DiagnosticValueCard + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `suspectedCause` | `string` | - | The suspected cause text | +| `confidence` | `number` | - | Confidence percentage (0-100) | +| `confidenceLevel` | `ConfidenceLevel` | - | Level: "high", "medium", or "low" | +| `rationale` | `string` | - | Explanation text | +| `recommendedAction` | `string` | - | Action button text | +| `onActionClick` | `() => void` | - | Action button callback | + +### DiagnosticTableHeader + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `showSuspectedCause` | `boolean` | `true` | Show suspected cause column | +| `showConfidence` | `boolean` | `true` | Show confidence column | +| `showRationale` | `boolean` | `true` | Show rationale column | +| `showRecommendedAction` | `boolean` | `true` | Show recommended action column | + +### ConfidenceValue + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `value` | `number` | - | Confidence percentage (0-100) | +| `level` | `ConfidenceLevel` | - | Level: "high", "medium", or "low" | + +## Exports + +```typescript +// Components +export { HAXDiagnosticReport } +export { DiagnosticReportCard } +export { DiagnosticValueCard } +export { DiagnosticTableHeader } +export { ConfidenceValue } + +// Hook +export { useDiagnosticReportAction } + +// Types +export type { DiagnosticItem } +export type { DiagnosticReportCardProps } +export type { DiagnosticValueCardProps } +export type { DiagnosticTableHeaderProps } +export type { ConfidenceValueProps } +export type { ConfidenceLevel } +export type { DiagnosticReportArtifact } + +// Zod Schema +export { DiagnosticReportArtifactZod } +``` + +## Best Practices + +- **Order by confidence**: Display items with highest confidence first to prioritize investigation +- **Be specific**: Keep suspected cause text concise and specific +- **Provide rationale**: Always include clear rationale connecting evidence to the suspected cause +- **Actionable recommendations**: Make recommended actions specific and actionable +- **Limit items**: Keep to 3-5 diagnostic items to avoid overwhelming users + +## When to Use + +- Troubleshooting results +- Root cause analysis +- System health assessments +- Any situation requiring potential causes ranked by confidence with actions + +## When NOT to Use + +- Simple status updates +- Single-cause issues +- Vague or generic suspected causes +- Items without supporting rationale diff --git a/hax/artifacts/diagnostic-report/action.ts b/hax/artifacts/diagnostic-report/action.ts new file mode 100644 index 0000000..0563d05 --- /dev/null +++ b/hax/artifacts/diagnostic-report/action.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2025 Cisco Systems, Inc. and its affiliates + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { z } from "zod" +import { useCopilotAction } from "@copilotkit/react-core" +import { DiagnosticReportArtifact, DiagnosticItemZod } from "./types" +import { DIAGNOSTIC_REPORT_DESCRIPTION } from "./description" + +interface UseDiagnosticReportActionProps { + addOrUpdateArtifact: ( + type: "diagnostic-report", + data: DiagnosticReportArtifact["data"], + ) => void +} + +export const useDiagnosticReportAction = ({ + addOrUpdateArtifact, +}: UseDiagnosticReportActionProps) => { + useCopilotAction({ + name: "create_diagnostic_report", + description: DIAGNOSTIC_REPORT_DESCRIPTION, + parameters: [ + { + name: "title", + type: "string", + description: "Title for the diagnostic report card", + required: false, + }, + { + name: "itemsJson", + type: "string", + description: + "JSON string of diagnostic items array. Each item must have: id, suspectedCause, confidence (0-100), confidenceLevel ('high'|'medium'|'low'), rationale, recommendedAction", + required: true, + }, + ], + handler: async (args) => { + const { title, itemsJson } = args + const parsed = JSON.parse(itemsJson) + const items = z.array(DiagnosticItemZod).parse(parsed) + + addOrUpdateArtifact("diagnostic-report", { title, items }) + + return `Created diagnostic report "${title || "Diagnostic Report"}" with ${items.length} items` + }, + }) +} diff --git a/hax/artifacts/diagnostic-report/description.ts b/hax/artifacts/diagnostic-report/description.ts new file mode 100644 index 0000000..0ade75f --- /dev/null +++ b/hax/artifacts/diagnostic-report/description.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2025 Cisco Systems, Inc. and its affiliates + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +export const DIAGNOSTIC_REPORT_DESCRIPTION = + `Use diagnostic report artifacts to present structured diagnostic findings with actionable recommendations. Best for troubleshooting results, root cause analysis, system health assessments, and any situation where users need to see potential causes ranked by confidence with corresponding actions. + +Structure each diagnostic item with a suspected cause, confidence level (high/medium/low with percentage), rationale explaining the assessment, and a recommended action. Multiple items are displayed in a tabular format for easy comparison. + +Confidence levels map to visual indicators: +- "high" (green): 70-100% confidence, strong evidence supports this cause +- "medium" (orange): 40-69% confidence, moderate evidence, needs investigation +- "low" (yellow): 0-39% confidence, possible but requires validation + +Best practices: +- Order items by confidence level (highest first) to prioritize investigation +- Keep suspected cause text concise and specific +- Provide clear rationale connecting evidence to the suspected cause +- Make recommended actions actionable and specific +- Limit to 3-5 diagnostic items to avoid overwhelming users + +Don't use diagnostic reports for simple status updates or single-cause issues. Avoid vague or generic suspected causes. Don't include items without supporting rationale.` as const diff --git a/hax/artifacts/diagnostic-report/diagnostic-report.tsx b/hax/artifacts/diagnostic-report/diagnostic-report.tsx new file mode 100644 index 0000000..9eb6d3f --- /dev/null +++ b/hax/artifacts/diagnostic-report/diagnostic-report.tsx @@ -0,0 +1,266 @@ +/* + * Copyright 2025 Cisco Systems, Inc. and its affiliates + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +"use client" + +import * as React from "react" + +import { cn } from "@/lib/utils" +import { Progress } from "@/components/ui/progress" +import { Button } from "@/components/ui/button" + +export type ConfidenceLevel = "high" | "medium" | "low" + +const confidenceLevelConfig: Record< + ConfidenceLevel, + { label: string; color: string } +> = { + high: { label: "High", color: "#2ca02c" }, + medium: { label: "Medium", color: "#ff7f0e" }, + low: { label: "Low", color: "#facc15" }, +} + +export interface ConfidenceValueProps + extends React.HTMLAttributes { + value: number + level: ConfidenceLevel +} + +export function ConfidenceValue({ + value, + level, + className, + ...props +}: ConfidenceValueProps) { + const { label, color } = confidenceLevelConfig[level] + + return ( +
+
+

{label}

+

({value}%)

+
+ +
+ ) +} + +export interface DiagnosticTableHeaderProps + extends React.HTMLAttributes { + showSuspectedCause?: boolean + showConfidence?: boolean + showRationale?: boolean + showRecommendedAction?: boolean +} + +export function DiagnosticTableHeader({ + showSuspectedCause = true, + showConfidence = true, + showRationale = true, + showRecommendedAction = true, + className, + ...props +}: DiagnosticTableHeaderProps) { + const headerCellClass = cn( + "flex-1 min-w-0 flex items-center gap-2", + "bg-[#f8fafc] px-2 py-[7.5px]", + "text-sm font-semibold leading-[21px] tracking-[0.07px]", + "text-[#020617] whitespace-nowrap", + ) + + return ( +
+ {showSuspectedCause && ( +
Suspected Cause
+ )} + {showConfidence &&
Confidence
} + {showRationale &&
Rationale
} + {showRecommendedAction && ( +
Recommended Action
+ )} +
+ ) +} + +export interface DiagnosticValueCardProps + extends React.HTMLAttributes { + suspectedCause: string + confidence: number + confidenceLevel: ConfidenceLevel + rationale: string + recommendedAction: string + onActionClick?: () => void +} + +export function DiagnosticValueCard({ + suspectedCause, + confidence, + confidenceLevel, + rationale, + recommendedAction, + onActionClick, + className, + ...props +}: DiagnosticValueCardProps) { + const cellClass = cn( + "flex-1 min-w-0 flex items-center gap-2", + "px-2 py-[7.5px]", + "text-sm font-normal leading-[21px] tracking-[0.07px]", + "text-[#020617]", + ) + + return ( +
+
+

{suspectedCause}

+
+ + + +
+

{rationale}

+
+ +
+ +
+
+ ) +} + +export interface DiagnosticItem { + id: string + suspectedCause: string + confidence: number + confidenceLevel: ConfidenceLevel + rationale: string + recommendedAction: string +} + +export interface DiagnosticReportCardProps + extends React.HTMLAttributes { + title?: string + items: DiagnosticItem[] + onActionClick?: (itemId: string) => void +} + +export function DiagnosticReportCard({ + title = "Diagnostic Report With Actionables", + items, + onActionClick, + className, + ...props +}: DiagnosticReportCardProps) { + return ( +
+
+

+ {title} +

+
+ +
+ + +
+ {items.map((item) => ( + onActionClick?.(item.id)} + /> + ))} +
+
+
+ ) +} + +interface HAXDiagnosticReportProps { + title?: string + items: DiagnosticItem[] + onActionClick?: (itemId: string) => void +} + +export function HAXDiagnosticReport({ + title, + items, + onActionClick, +}: HAXDiagnosticReportProps) { + return ( +
+ +
+ ) +} + +export default DiagnosticReportCard diff --git a/hax/artifacts/diagnostic-report/index.ts b/hax/artifacts/diagnostic-report/index.ts new file mode 100644 index 0000000..2c1c402 --- /dev/null +++ b/hax/artifacts/diagnostic-report/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2025 Cisco Systems, Inc. and its affiliates + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +export { HAXDiagnosticReport, DiagnosticReportCard } from "./diagnostic-report" +export { useDiagnosticReportAction } from "./action" +export type { DiagnosticReportArtifact, DiagnosticItem } from "./types" +export { DiagnosticReportArtifactZod, DiagnosticItemZod } from "./types" +export { DIAGNOSTIC_REPORT_DESCRIPTION } from "./description" diff --git a/hax/artifacts/diagnostic-report/types.ts b/hax/artifacts/diagnostic-report/types.ts new file mode 100644 index 0000000..9a07299 --- /dev/null +++ b/hax/artifacts/diagnostic-report/types.ts @@ -0,0 +1,42 @@ +/* + * Copyright 2025 Cisco Systems, Inc. and its affiliates + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { z } from "zod" + +export const DiagnosticItemZod = z.object({ + id: z.string().describe("Unique identifier for the diagnostic item"), + suspectedCause: z.string().describe("Description of the potential cause"), + confidence: z.number().min(0).max(100).describe("Confidence percentage 0-100"), + confidenceLevel: z + .enum(["high", "medium", "low"]) + .describe("Confidence category: high (70-100%), medium (40-69%), low (0-39%)"), + rationale: z.string().describe("Explanation connecting evidence to the suspected cause"), + recommendedAction: z.string().describe("Actionable next step to investigate or resolve"), +}) + +export const DiagnosticReportArtifactZod = z.object({ + id: z.string(), + type: z.literal("diagnostic-report"), + data: z.object({ + title: z.string().optional().describe("Title for the diagnostic report"), + items: z.array(DiagnosticItemZod).describe("Diagnostic items ordered by confidence"), + }), +}) + +export type DiagnosticReportArtifact = z.infer +export type DiagnosticItem = z.infer