Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ front/next-env.d.ts

# Golang
output
.idea
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Observātiō
# Observātiō - Smart ClusterAPI Troubleshoot Platform

[![Build](https://github.com/knabben/observatio/actions/workflows/build.yml/badge.svg)](https://github.com/knabben/observatio/actions/workflows/build.yml)

Expand All @@ -13,14 +13,31 @@ the project enables users to swiftly identify and address issues, improving oper
This solution empowers organizations to maintain optimal cluster functionality, streamline troubleshooting efforts,
and ensure robust management of their cloud-native environments.

## Development
<p align="center">
<img src="front/public/screen.png" alt="logo" />
</p>

## Production

### Prerequisites

- Go 1.23.1
- Node.js and pnpm
- Linux and Make

### Build and run

Ensure your management cluster is accessible via `${HOME}/.kube/config` compile the bundled frontend in the go binary
and run the server.

```bash
make build && ./output/observatio serve
```

Both API and frontend are accessible via port TCP 8080.

## Development

### Backend Setup

1. Install backend dependencies:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@ export default function ClusterInfraDetails({
},
{
label: "AI Troubleshooting",
content: (cluster: ClusterInfraType) => <AITroubleshooting conditions={cluster.status.conditions} />
content: (cluster: ClusterInfraType) => <AITroubleshooting
objectType="vspherecluster"
objectName={cluster.metadata.name}
objectNamespace={cluster.metadata.namespace}
conditions={cluster.status.conditions}
/>
}];
const headerRender = (cluster: ClusterInfraType) => (
<SimpleGrid cols={2}>
Expand Down
6 changes: 5 additions & 1 deletion front/app/ui/dashboard/components/mds/details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ export default function MachineDeploymentDetails({
},
{
label: "AI Troubleshooting",
content: (md: MachineDeploymentType) => <AITroubleshooting objectType="machinedeployment" conditions={md.status.conditions} />
content: (md: MachineDeploymentType) => <AITroubleshooting
objectType="machinedeployment"
objectName={md.metadata.name}
objectNamespace={md.metadata.namespace}
conditions={md.status.conditions} />
}
];
const headerRender = (md: MachineDeploymentType) => (
Expand Down
Binary file added front/public/screen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 11 additions & 3 deletions webserver/internal/infra/llm/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@ import (
)

var (
TASK_SYSTEM = `You will serve as a Kubernetes administrator managing a on-premises datacenter on VMware vCenter.`
TASK_CONTEXT = `Your task is to assist operators in troubleshooting issues within the cluster.
Provide a detailed explanation of the issue. New inputs are provided and you must respond accordingly the context`
TASK_SYSTEM = `You will serve as a Cluster API advisor helping troubleshoot on-premises Kubernetes on VMware vCenter infrastructure.`
TASK_CONTEXT = `You are Observatio AI, an advanced Kubernetes cluster troubleshooting assistant specialized in ClusterAPI (CAPI) environments.
You are part of a sophisticated monitoring platform that revolutionizes Kubernetes cluster assessment through data aggregation, MCP server integration, and AI-powered remediation.
Provide expert-level Kubernetes troubleshooting, root cause analysis, and automated remediation for DevOps teams managing distributed CAPI clusters.
You excel at translating complex cluster issues into actionable solutions. Your task is to assist operators in troubleshooting issues within the cluster.

When you receive a customer question, you must respond with a detailed DESCRIPTION of the issue, under <description></description> tag, ALWAYS.
If you have suggestions for fixing the issue or improvements, you can also include them under <suggestions></suggestions> tag.

You only run available tools when request to increase the context of the issue.
`
)

// MessageTemplate defines the structure for formatting error messages
Expand Down
27 changes: 21 additions & 6 deletions webserver/internal/infra/llm/observation.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,15 @@ func NewObservationService() (*ObservationService, error) {
return service, nil
}

// ChatWithAgent facilitates a conversation between a user and an AI agent by managing message history and API interactions.
func (s *ObservationService) ChatWithAgent(ctx context.Context, message *ChatMessage) (*ChatMessage, error) {
logger := log.FromContext(ctx)

s.conversationManager.AddUserMessage(formatMessage(message.Content))
userMessage := message.Content
if s.conversationManager.GetHistoryLength() == 0 {
userMessage = formatMessage(userMessage)
}
s.conversationManager.AddUserMessage(userMessage)

var historyLength = s.conversationManager.GetHistoryLength()
if historyLength > 0 {
Expand All @@ -60,14 +65,17 @@ func (s *ObservationService) ChatWithAgent(ctx context.Context, message *ChatMes
return nil, fmt.Errorf("claude API response format error: %v", err)
}

if len(response.Content) > 0 {
logger.Info("Parsed response from Claude", "response", parsedResponse)
s.conversationManager.AddAssistantMessage(parsedResponse)
s.conversationManager.TrimHistory()
if len(response.Content) == 0 {
return ToMessageParam("Bot error, try again."), nil
}

logger.Info("Parsed response from Claude", "response", parsedResponse)
s.conversationManager.AddAssistantMessage(parsedResponse)
s.conversationManager.TrimHistory()
return ToMessageParam(parsedResponse), nil
}

// requestAgent sends a request to the Anthropic API with specified messages and returns the API response or an error.
func (s *ObservationService) requestAgent(ctx context.Context, messages []anthropic.MessageParam) (*anthropic.Message, error) {
request := anthropic.MessageNewParams{
Model: anthropic.ModelClaude3_7SonnetLatest,
Expand All @@ -82,6 +90,8 @@ func (s *ObservationService) requestAgent(ctx context.Context, messages []anthro
return s.anthropicClient.Messages.New(ctx, request)
}

// responseAgent processes the response content from the Anthropic API and constructs a formatted string combining text and tool outputs.
// It handles text blocks and tool-use blocks, extracting detailed outputs as necessary. Returns the formatted response or an error.
func (s *ObservationService) responseAgent(response *anthropic.Message) (string, error) {
var (
responseText string
Expand All @@ -108,13 +118,18 @@ func (s *ObservationService) responseAgent(response *anthropic.Message) (string,
if err != nil {
return "", err
}
responseText += fmt.Sprintf("\n\n<tool>kubectl %s</tool>\n", input.Command)
toolResults = append(toolResults, toolResponse.(string))
}
}
}

if len(toolResults) > 0 {
responseText += "\n\nTool Results:\n" + fmt.Sprintf("%v", toolResults)
responseText += "\n<tool_results>"
for _, toolResult := range toolResults {
responseText += fmt.Sprintf("<pre>%s</pre>", toolResult)
}
responseText += "</tool_results>"
}

return responseText, nil
Expand Down
2 changes: 1 addition & 1 deletion webserver/internal/web/handlers/system/ws_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (c *WSClient) reader() {
// Start to chat with the bot agent, sending the first message.
response, err := (*c.service).ChatWithAgent(ctx, message)
if err != nil {
logger.Error(err, "error writing close message")
logger.Error(err, "error writing response message to client")
return
}

Expand Down