Compare commits
1 Commits
obs-detail
...
feat/brows
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
748f60c11e |
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v2
|
||||||
- run: |
|
- run: |
|
||||||
# Add Docker's official GPG key:
|
# Add Docker's official GPG key:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -69,11 +69,6 @@ Now you can access and manage your agents at [http://localhost:8080](http://loca
|
|||||||
|
|
||||||
Still having issues? see this Youtube video: https://youtu.be/HtVwIxW3ePg
|
Still having issues? see this Youtube video: https://youtu.be/HtVwIxW3ePg
|
||||||
|
|
||||||
## Videos
|
|
||||||
|
|
||||||
[](https://youtu.be/HtVwIxW3ePg)
|
|
||||||
[](https://youtu.be/v82rswGJt_M)
|
|
||||||
|
|
||||||
## 📚🆕 Local Stack Family
|
## 📚🆕 Local Stack Family
|
||||||
|
|
||||||
🆕 LocalAI is now part of a comprehensive suite of AI tools designed to work together:
|
🆕 LocalAI is now part of a comprehensive suite of AI tools designed to work together:
|
||||||
@@ -185,6 +180,14 @@ Good (relatively small) models that have been tested are:
|
|||||||
- **✓ Effortless Setup**: Simple Docker compose setups and pre-built binaries.
|
- **✓ Effortless Setup**: Simple Docker compose setups and pre-built binaries.
|
||||||
- **✓ Feature-Rich**: From planning to multimodal capabilities, connectors for Slack, MCP support, LocalAGI has it all.
|
- **✓ Feature-Rich**: From planning to multimodal capabilities, connectors for Slack, MCP support, LocalAGI has it all.
|
||||||
|
|
||||||
|
## 🌐 The Local Ecosystem
|
||||||
|
|
||||||
|
LocalAGI is part of the powerful Local family of privacy-focused AI tools:
|
||||||
|
|
||||||
|
- [**LocalAI**](https://github.com/mudler/LocalAI): Run Large Language Models locally.
|
||||||
|
- [**LocalRecall**](https://github.com/mudler/LocalRecall): Retrieval-Augmented Generation with local storage.
|
||||||
|
- [**LocalAGI**](https://github.com/mudler/LocalAGI): Deploy intelligent AI agents securely and privately.
|
||||||
|
|
||||||
## 🌟 Screenshots
|
## 🌟 Screenshots
|
||||||
|
|
||||||
### Powerful Web UI
|
### Powerful Web UI
|
||||||
|
|||||||
@@ -180,12 +180,6 @@ func (a *Agent) Execute(j *types.Job) *types.JobResult {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if j.Obs != nil {
|
if j.Obs != nil {
|
||||||
if len(j.ConversationHistory) > 0 {
|
|
||||||
m := j.ConversationHistory[len(j.ConversationHistory)-1]
|
|
||||||
j.Obs.Creation = &types.Creation{ ChatCompletionMessage: &m }
|
|
||||||
a.observer.Update(*j.Obs)
|
|
||||||
}
|
|
||||||
|
|
||||||
j.Result.AddFinalizer(func(ccm []openai.ChatCompletionMessage) {
|
j.Result.AddFinalizer(func(ccm []openai.ChatCompletionMessage) {
|
||||||
j.Obs.Completion = &types.Completion{
|
j.Obs.Completion = &types.Completion{
|
||||||
Conversation: ccm,
|
Conversation: ccm,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Creation struct {
|
type Creation struct {
|
||||||
ChatCompletionMessage *openai.ChatCompletionMessage `json:"chat_completion_message,omitempty"`
|
|
||||||
ChatCompletionRequest *openai.ChatCompletionRequest `json:"chat_completion_request,omitempty"`
|
ChatCompletionRequest *openai.ChatCompletionRequest `json:"chat_completion_request,omitempty"`
|
||||||
FunctionDefinition *openai.FunctionDefinition `json:"function_definition,omitempty"`
|
FunctionDefinition *openai.FunctionDefinition `json:"function_definition,omitempty"`
|
||||||
FunctionParams ActionParams `json:"function_params,omitempty"`
|
FunctionParams ActionParams `json:"function_params,omitempty"`
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import hljs from 'highlight.js/lib/core';
|
|
||||||
import json from 'highlight.js/lib/languages/json';
|
|
||||||
import 'highlight.js/styles/monokai.css';
|
|
||||||
|
|
||||||
hljs.registerLanguage('json', json);
|
|
||||||
|
|
||||||
export default function CollapsibleRawSections({ container }) {
|
|
||||||
const [showCreation, setShowCreation] = useState(false);
|
|
||||||
const [showProgress, setShowProgress] = useState(false);
|
|
||||||
const [showCompletion, setShowCompletion] = useState(false);
|
|
||||||
const [copied, setCopied] = useState({ creation: false, progress: false, completion: false });
|
|
||||||
|
|
||||||
const handleCopy = (section, data) => {
|
|
||||||
navigator.clipboard.writeText(JSON.stringify(data, null, 2));
|
|
||||||
setCopied(prev => ({ ...prev, [section]: true }));
|
|
||||||
setTimeout(() => setCopied(prev => ({ ...prev, [section]: false })), 1200);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{/* Creation Section */}
|
|
||||||
{container.creation && (
|
|
||||||
<div>
|
|
||||||
<h4 style={{ display: 'flex', alignItems: 'center' }}>
|
|
||||||
<span
|
|
||||||
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', flex: 1 }}
|
|
||||||
onClick={() => setShowCreation(v => !v)}
|
|
||||||
>
|
|
||||||
<i className={`fas fa-chevron-${showCreation ? 'down' : 'right'}`} style={{ marginRight: 6 }} />
|
|
||||||
Creation
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
title="Copy Creation JSON"
|
|
||||||
onClick={e => { e.stopPropagation(); handleCopy('creation', container.creation); }}
|
|
||||||
style={{ marginLeft: 8, border: 'none', background: 'none', cursor: 'pointer', color: '#ccc' }}
|
|
||||||
>
|
|
||||||
{copied.creation ? <span style={{ color: '#6f6' }}>Copied!</span> : <i className="fas fa-copy" />}
|
|
||||||
</button>
|
|
||||||
</h4>
|
|
||||||
{showCreation && (
|
|
||||||
<pre className="hljs"><code>
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(container.creation || {}, null, 2), { language: 'json' }).value }} />
|
|
||||||
</code></pre>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* Progress Section */}
|
|
||||||
{container.progress && container.progress.length > 0 && (
|
|
||||||
<div>
|
|
||||||
<h4 style={{ display: 'flex', alignItems: 'center' }}>
|
|
||||||
<span
|
|
||||||
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', flex: 1 }}
|
|
||||||
onClick={() => setShowProgress(v => !v)}
|
|
||||||
>
|
|
||||||
<i className={`fas fa-chevron-${showProgress ? 'down' : 'right'}`} style={{ marginRight: 6 }} />
|
|
||||||
Progress
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
title="Copy Progress JSON"
|
|
||||||
onClick={e => { e.stopPropagation(); handleCopy('progress', container.progress); }}
|
|
||||||
style={{ marginLeft: 8, border: 'none', background: 'none', cursor: 'pointer', color: '#ccc' }}
|
|
||||||
>
|
|
||||||
{copied.progress ? <span style={{ color: '#6f6' }}>Copied!</span> : <i className="fas fa-copy" />}
|
|
||||||
</button>
|
|
||||||
</h4>
|
|
||||||
{showProgress && (
|
|
||||||
<pre className="hljs"><code>
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(container.progress || {}, null, 2), { language: 'json' }).value }} />
|
|
||||||
</code></pre>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* Completion Section */}
|
|
||||||
{container.completion && (
|
|
||||||
<div>
|
|
||||||
<h4 style={{ display: 'flex', alignItems: 'center' }}>
|
|
||||||
<span
|
|
||||||
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', flex: 1 }}
|
|
||||||
onClick={() => setShowCompletion(v => !v)}
|
|
||||||
>
|
|
||||||
<i className={`fas fa-chevron-${showCompletion ? 'down' : 'right'}`} style={{ marginRight: 6 }} />
|
|
||||||
Completion
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
title="Copy Completion JSON"
|
|
||||||
onClick={e => { e.stopPropagation(); handleCopy('completion', container.completion); }}
|
|
||||||
style={{ marginLeft: 8, border: 'none', background: 'none', cursor: 'pointer', color: '#ccc' }}
|
|
||||||
>
|
|
||||||
{copied.completion ? <span style={{ color: '#6f6' }}>Copied!</span> : <i className="fas fa-copy" />}
|
|
||||||
</button>
|
|
||||||
</h4>
|
|
||||||
{showCompletion && (
|
|
||||||
<pre className="hljs"><code>
|
|
||||||
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(container.completion || {}, null, 2), { language: 'json' }).value }} />
|
|
||||||
</code></pre>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,181 +1,4 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import CollapsibleRawSections from '../components/CollapsibleRawSections';
|
|
||||||
|
|
||||||
function ObservableSummary({ observable }) {
|
|
||||||
// --- CREATION SUMMARIES ---
|
|
||||||
const creation = observable?.creation || {};
|
|
||||||
// ChatCompletionRequest summary
|
|
||||||
let creationChatMsg = '';
|
|
||||||
// Prefer chat_completion_message if present (for jobs/top-level containers)
|
|
||||||
if (creation?.chat_completion_message && creation.chat_completion_message.content) {
|
|
||||||
creationChatMsg = creation.chat_completion_message.content;
|
|
||||||
} else {
|
|
||||||
const messages = creation?.chat_completion_request?.messages;
|
|
||||||
if (Array.isArray(messages) && messages.length > 0) {
|
|
||||||
const lastMsg = messages[messages.length - 1];
|
|
||||||
creationChatMsg = lastMsg?.content || '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// FunctionDefinition summary
|
|
||||||
let creationFunctionDef = '';
|
|
||||||
if (creation?.function_definition?.name) {
|
|
||||||
creationFunctionDef = `Function: ${creation.function_definition.name}`;
|
|
||||||
}
|
|
||||||
// FunctionParams summary
|
|
||||||
let creationFunctionParams = '';
|
|
||||||
if (creation?.function_params && Object.keys(creation.function_params).length > 0) {
|
|
||||||
creationFunctionParams = `Params: ${JSON.stringify(creation.function_params)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- COMPLETION SUMMARIES ---
|
|
||||||
const completion = observable?.completion || {};
|
|
||||||
// ChatCompletionResponse summary
|
|
||||||
let completionChatMsg = '';
|
|
||||||
const chatCompletion = completion?.chat_completion_response;
|
|
||||||
if (
|
|
||||||
chatCompletion &&
|
|
||||||
Array.isArray(chatCompletion.choices) &&
|
|
||||||
chatCompletion.choices.length > 0
|
|
||||||
) {
|
|
||||||
const lastChoice = chatCompletion.choices[chatCompletion.choices.length - 1];
|
|
||||||
// Prefer tool_call summary if present
|
|
||||||
let toolCallSummary = '';
|
|
||||||
const toolCalls = lastChoice?.message?.tool_calls;
|
|
||||||
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
||||||
toolCallSummary = toolCalls.map(tc => {
|
|
||||||
let args = '';
|
|
||||||
// For OpenAI-style, arguments are in tc.function.arguments, function name in tc.function.name
|
|
||||||
if (tc.function && tc.function.arguments) {
|
|
||||||
try {
|
|
||||||
args = typeof tc.function.arguments === 'string' ? tc.function.arguments : JSON.stringify(tc.function.arguments);
|
|
||||||
} catch (e) {
|
|
||||||
args = '[Unserializable arguments]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const toolName = tc.function?.name || tc.name || 'unknown';
|
|
||||||
return `Tool call: ${toolName}(${args})`;
|
|
||||||
}).join('\n');
|
|
||||||
}
|
|
||||||
completionChatMsg = lastChoice?.message?.content || '';
|
|
||||||
// Attach toolCallSummary to completionChatMsg for rendering
|
|
||||||
if (toolCallSummary) {
|
|
||||||
completionChatMsg = { toolCallSummary, message: completionChatMsg };
|
|
||||||
}
|
|
||||||
// Else, it's just a string
|
|
||||||
|
|
||||||
}
|
|
||||||
// Conversation summary
|
|
||||||
let completionConversation = '';
|
|
||||||
if (Array.isArray(completion?.conversation) && completion.conversation.length > 0) {
|
|
||||||
const lastConv = completion.conversation[completion.conversation.length - 1];
|
|
||||||
completionConversation = lastConv?.content ? `${lastConv.content}` : '';
|
|
||||||
}
|
|
||||||
// ActionResult summary
|
|
||||||
let completionActionResult = '';
|
|
||||||
if (completion?.action_result) {
|
|
||||||
completionActionResult = `Action Result: ${String(completion.action_result).slice(0, 100)}`;
|
|
||||||
}
|
|
||||||
// AgentState summary
|
|
||||||
let completionAgentState = '';
|
|
||||||
if (completion?.agent_state) {
|
|
||||||
completionAgentState = `Agent State: ${JSON.stringify(completion.agent_state)}`;
|
|
||||||
}
|
|
||||||
// Error summary
|
|
||||||
let completionError = '';
|
|
||||||
if (completion?.error) {
|
|
||||||
completionError = `Error: ${completion.error}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only show if any summary is present
|
|
||||||
if (!creationChatMsg && !creationFunctionDef && !creationFunctionParams &&
|
|
||||||
!completionChatMsg && !completionConversation && !completionActionResult && !completionAgentState && !completionError) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 2, margin: '2px 0 0 0' }}>
|
|
||||||
{/* CREATION */}
|
|
||||||
{creationChatMsg && (
|
|
||||||
<div title={creationChatMsg} style={{ display: 'flex', alignItems: 'center', color: '#cfc', fontSize: 14 }}>
|
|
||||||
<i className="fas fa-comment-dots" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{creationChatMsg}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{creationFunctionDef && (
|
|
||||||
<div title={creationFunctionDef} style={{ display: 'flex', alignItems: 'center', color: '#cfc', fontSize: 14 }}>
|
|
||||||
<i className="fas fa-code" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{creationFunctionDef}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{creationFunctionParams && (
|
|
||||||
<div title={creationFunctionParams} style={{ display: 'flex', alignItems: 'center', color: '#fc9', fontSize: 14 }}>
|
|
||||||
<i className="fas fa-sliders-h" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{creationFunctionParams}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* COMPLETION */}
|
|
||||||
{/* COMPLETION: Tool call summary if present */}
|
|
||||||
{completionChatMsg && typeof completionChatMsg === 'object' && completionChatMsg.toolCallSummary && (
|
|
||||||
<div
|
|
||||||
title={completionChatMsg.toolCallSummary}
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
color: '#ffd966', // Distinct color for tool calls
|
|
||||||
fontSize: 14,
|
|
||||||
marginTop: 2,
|
|
||||||
whiteSpace: 'pre-line',
|
|
||||||
wordBreak: 'break-all',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fas fa-tools" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ whiteSpace: 'pre-line', display: 'block' }}>{completionChatMsg.toolCallSummary}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{/* COMPLETION: Message content if present */}
|
|
||||||
{completionChatMsg && ((typeof completionChatMsg === 'object' && completionChatMsg.message) || typeof completionChatMsg === 'string') && (
|
|
||||||
<div
|
|
||||||
title={typeof completionChatMsg === 'object' ? completionChatMsg.message : completionChatMsg}
|
|
||||||
style={{
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
color: '#8fc7ff',
|
|
||||||
fontSize: 14,
|
|
||||||
marginTop: 2,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<i className="fas fa-robot" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{typeof completionChatMsg === 'object' ? completionChatMsg.message : completionChatMsg}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{completionConversation && (
|
|
||||||
<div title={completionConversation} style={{ display: 'flex', alignItems: 'center', color: '#b8e2ff', fontSize: 14 }}>
|
|
||||||
<i className="fas fa-comments" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{completionConversation}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{completionActionResult && (
|
|
||||||
<div title={completionActionResult} style={{ display: 'flex', alignItems: 'center', color: '#ffd700', fontSize: 14 }}>
|
|
||||||
<i className="fas fa-bolt" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{completionActionResult}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{completionAgentState && (
|
|
||||||
<div title={completionAgentState} style={{ display: 'flex', alignItems: 'center', color: '#ffb8b8', fontSize: 14 }}>
|
|
||||||
<i className="fas fa-brain" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{completionAgentState}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{completionError && (
|
|
||||||
<div title={completionError} style={{ display: 'flex', alignItems: 'center', color: '#f66', fontSize: 14 }}>
|
|
||||||
<i className="fas fa-exclamation-triangle" style={{ marginRight: 6, flex: '0 0 auto' }}></i>
|
|
||||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', display: 'block' }}>{completionError}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
import { useParams, Link } from 'react-router-dom';
|
import { useParams, Link } from 'react-router-dom';
|
||||||
import hljs from 'highlight.js/lib/core';
|
import hljs from 'highlight.js/lib/core';
|
||||||
import json from 'highlight.js/lib/languages/json';
|
import json from 'highlight.js/lib/languages/json';
|
||||||
@@ -184,7 +7,7 @@ import 'highlight.js/styles/monokai.css';
|
|||||||
hljs.registerLanguage('json', json);
|
hljs.registerLanguage('json', json);
|
||||||
|
|
||||||
function AgentStatus() {
|
function AgentStatus() {
|
||||||
const [showStatus, setShowStatus] = useState(false);
|
const [showStatus, setShowStatus] = useState(true);
|
||||||
const { name } = useParams();
|
const { name } = useParams();
|
||||||
const [statusData, setStatusData] = useState(null);
|
const [statusData, setStatusData] = useState(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@@ -271,16 +94,17 @@ function AgentStatus() {
|
|||||||
setObservableMap(prevMap => {
|
setObservableMap(prevMap => {
|
||||||
const prev = prevMap[data.id] || {};
|
const prev = prevMap[data.id] || {};
|
||||||
const updated = {
|
const updated = {
|
||||||
...data,
|
|
||||||
...prev,
|
...prev,
|
||||||
|
...data,
|
||||||
|
creation: data.creation,
|
||||||
|
progress: data.progress,
|
||||||
|
completion: data.completion,
|
||||||
};
|
};
|
||||||
// Events can be received out of order
|
// Events can be received out of order
|
||||||
if (data.creation)
|
if (data.creation)
|
||||||
updated.creation = data.creation;
|
updated.creation = data.creation;
|
||||||
if (data.completion)
|
if (data.completion)
|
||||||
updated.completion = data.completion;
|
updated.completion = data.completion;
|
||||||
if ((data.progress?.length ?? 0) > (prev.progress?.length ?? 0))
|
|
||||||
updated.progress = data.progress;
|
|
||||||
if (data.parent_id && !prevMap[data.parent_id])
|
if (data.parent_id && !prevMap[data.parent_id])
|
||||||
prevMap[data.parent_id] = {
|
prevMap[data.parent_id] = {
|
||||||
id: data.parent_id,
|
id: data.parent_id,
|
||||||
@@ -428,16 +252,11 @@ function AgentStatus() {
|
|||||||
setExpandedCards(new Map(expandedCards).set(container.id, newExpanded));
|
setExpandedCards(new Map(expandedCards).set(container.id, newExpanded));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', gap: '10px', alignItems: 'center', maxWidth: '90%' }}>
|
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
|
||||||
<i className={`fas fa-${container.icon || 'robot'}`} style={{ verticalAlign: '-0.125em' }}></i>
|
<i className={`fas fa-${container.icon || 'robot'}`} style={{ verticalAlign: '-0.125em' }}></i>
|
||||||
<span style={{ width: '100%' }}>
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
|
|
||||||
<span>
|
<span>
|
||||||
<span className='stat-label'>{container.name}</span>#<span className='stat-label'>{container.id}</span>
|
<span className='stat-label'>{container.name}</span>#<span className='stat-label'>{container.id}</span>
|
||||||
</span>
|
</span>
|
||||||
<ObservableSummary observable={container} />
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||||
<i
|
<i
|
||||||
@@ -460,22 +279,17 @@ function AgentStatus() {
|
|||||||
const isExpanded = expandedCards.get(childKey);
|
const isExpanded = expandedCards.get(childKey);
|
||||||
return (
|
return (
|
||||||
<div key={`${container.id}-child-${child.id}`} className='card' style={{ background: '#222', marginBottom: '0.5em' }}>
|
<div key={`${container.id}-child-${child.id}`} className='card' style={{ background: '#222', marginBottom: '0.5em' }}>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', cursor: 'hand', maxWidth: '100%' }}
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', cursor: 'pointer' }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const newExpanded = !expandedCards.get(childKey);
|
const newExpanded = !expandedCards.get(childKey);
|
||||||
setExpandedCards(new Map(expandedCards).set(childKey, newExpanded));
|
setExpandedCards(new Map(expandedCards).set(childKey, newExpanded));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex', maxWidth: '90%', gap: '10px', alignItems: 'center' }}>
|
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
|
||||||
<i className={`fas fa-${child.icon || 'robot'}`} style={{ verticalAlign: '-0.125em' }}></i>
|
<i className={`fas fa-${child.icon || 'robot'}`} style={{ verticalAlign: '-0.125em' }}></i>
|
||||||
<span style={{ width: '100%' }}>
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
|
|
||||||
<span>
|
<span>
|
||||||
<span className='stat-label'>{child.name}</span>#<span className='stat-label'>{child.id}</span>
|
<span className='stat-label'>{child.name}</span>#<span className='stat-label'>{child.id}</span>
|
||||||
</span>
|
</span>
|
||||||
<ObservableSummary observable={child} />
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||||
<i
|
<i
|
||||||
@@ -489,14 +303,60 @@ function AgentStatus() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: isExpanded ? 'block' : 'none' }}>
|
<div style={{ display: isExpanded ? 'block' : 'none' }}>
|
||||||
<CollapsibleRawSections container={child} />
|
{child.creation && (
|
||||||
|
<div>
|
||||||
|
<h5>Creation:</h5>
|
||||||
|
<pre className="hljs"><code>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(child.creation || {}, null, 2), { language: 'json' }).value }}></div>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{child.progress && child.progress.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h5>Progress:</h5>
|
||||||
|
<pre className="hljs"><code>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(child.progress || {}, null, 2), { language: 'json' }).value }}></div>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{child.completion && (
|
||||||
|
<div>
|
||||||
|
<h5>Completion:</h5>
|
||||||
|
<pre className="hljs"><code>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(child.completion || {}, null, 2), { language: 'json' }).value }}></div>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<CollapsibleRawSections container={container} />
|
{container.creation && (
|
||||||
|
<div>
|
||||||
|
<h4>Creation:</h4>
|
||||||
|
<pre className="hljs"><code>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(container.creation || {}, null, 2), { language: 'json' }).value }}></div>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{container.progress && container.progress.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<h4>Progress:</h4>
|
||||||
|
<pre className="hljs"><code>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(container.progress || {}, null, 2), { language: 'json' }).value }}></div>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{container.completion && (
|
||||||
|
<div>
|
||||||
|
<h4>Completion:</h4>
|
||||||
|
<pre className="hljs"><code>
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: hljs.highlight(JSON.stringify(container.completion || {}, null, 2), { language: 'json' }).value }}></div>
|
||||||
|
</code></pre>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user