From f46380230fa862e7b771f7bcd63f429737b6a2a0 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Tue, 28 Jul 2026 14:52:20 -0300 Subject: [PATCH 01/10] Issue #1184 Quick Fix, changing section titles to "Default values for request parameters" --- .../src/components/configuration_page/Agents/BaseParams.jsx | 2 +- .../src/components/configuration_page/Agents/ContextBroker.jsx | 2 +- .../src/components/configuration_page/Agents/EvolutionAgent.jsx | 2 +- .../src/components/configuration_page/Agents/InferenceAgent.jsx | 2 +- .../src/components/configuration_page/Agents/LinkCreation.jsx | 2 +- .../src/components/configuration_page/Agents/QueryAgent.jsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx b/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx index 5a17758e..f6eb0714 100644 --- a/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx @@ -46,7 +46,7 @@ export default function BaseParametersPanel() { {SpecificParamComponent && ( - Parameters + Default values for request parameters )} diff --git a/das-dashboard/src/components/configuration_page/Agents/ContextBroker.jsx b/das-dashboard/src/components/configuration_page/Agents/ContextBroker.jsx index 7421abef..1ba44df4 100644 --- a/das-dashboard/src/components/configuration_page/Agents/ContextBroker.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/ContextBroker.jsx @@ -50,7 +50,7 @@ export default function ContextBrokerPanel() { {ParamsComponent && ( - Parameters + Default values for request parameters )} diff --git a/das-dashboard/src/components/configuration_page/Agents/EvolutionAgent.jsx b/das-dashboard/src/components/configuration_page/Agents/EvolutionAgent.jsx index 623612a9..d8060de4 100644 --- a/das-dashboard/src/components/configuration_page/Agents/EvolutionAgent.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/EvolutionAgent.jsx @@ -48,7 +48,7 @@ export default function EvolutionAgentPanel() { {ParamsComponent && ( - Parameters + Default values for request parameters )} diff --git a/das-dashboard/src/components/configuration_page/Agents/InferenceAgent.jsx b/das-dashboard/src/components/configuration_page/Agents/InferenceAgent.jsx index e1e8f682..0bfa917e 100644 --- a/das-dashboard/src/components/configuration_page/Agents/InferenceAgent.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/InferenceAgent.jsx @@ -47,7 +47,7 @@ export default function InferenceAgentPanel() { {ParamsComponent && ( - Parameters + Default values for request parameters )} diff --git a/das-dashboard/src/components/configuration_page/Agents/LinkCreation.jsx b/das-dashboard/src/components/configuration_page/Agents/LinkCreation.jsx index 26ae5d71..e418c309 100644 --- a/das-dashboard/src/components/configuration_page/Agents/LinkCreation.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/LinkCreation.jsx @@ -53,7 +53,7 @@ export default function LinkCreationAgentPanel() { {ParamsComponent && ( - Parameters + Default values for request parameters )} diff --git a/das-dashboard/src/components/configuration_page/Agents/QueryAgent.jsx b/das-dashboard/src/components/configuration_page/Agents/QueryAgent.jsx index d32985d9..c2954705 100644 --- a/das-dashboard/src/components/configuration_page/Agents/QueryAgent.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/QueryAgent.jsx @@ -48,7 +48,7 @@ export default function QueryAgentPanel() { {ParamsComponent && ( - Parameters + Default values for request parameters )} From c28ab291ac2f7cd88d57acfd7b397fdce23740d1 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Tue, 28 Jul 2026 15:08:43 -0300 Subject: [PATCH 02/10] Issue #1185 removed "Agent params" sub-section, added query base parameters to "Agents" --- .../components/configuration_page/Agents/agentRegistry.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js b/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js index 2897c43f..642b223f 100644 --- a/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js +++ b/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js @@ -9,6 +9,7 @@ export const AGENT_GROUPS = [ { label: "Agents", items: [ + { key: "base_query", label: "Base Query", paramsKey: "base_query" }, { key: "query", label: "Query Agent", paramsKey: "query" }, { key: "link_creation", label: "Link Creation Agent", paramsKey: "link_creation" }, { key: "inference", label: "Inference Agent", paramsKey: "inference" }, @@ -23,12 +24,6 @@ export const AGENT_GROUPS = [ { key: "context", label: "Context Broker", paramsKey: "context" }, { key: "atomdb", label: "AtomDB Broker", paramsKey: null } ] - }, - { - label: "Agent Params", - items: [ - { key: "base_query", label: "Base Parameters", paramsKey: "base_query" } - ] } ] From c398c89bbb844cd1bafb9805955c1c5c997e37c2 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Tue, 28 Jul 2026 18:09:57 -0300 Subject: [PATCH 03/10] Adjustments on dashboard front-end and backend --- .../backend/shared/builders/agents_builder.py | 19 ++++++++++- .../internal/configuration_constants.py | 4 ++- .../shared/mappers/nested_config_mapper.py | 9 +++++ .../Agents/AgentConnectionFields.jsx | 7 ++-- .../Agents/AgentsParams/BaseParams.jsx | 13 ++++++- .../configuration_page/Agents/BaseParams.jsx | 1 + .../Agents/CommandRouter.jsx | 34 ++++++++++++++++--- .../Agents/agentRegistry.js | 2 +- .../ConfigurationPreview.jsx | 2 ++ .../configuration_page/configFormUtils.js | 9 +++++ 10 files changed, 90 insertions(+), 10 deletions(-) diff --git a/das-dashboard/backend/shared/builders/agents_builder.py b/das-dashboard/backend/shared/builders/agents_builder.py index dcc123d2..588029ad 100644 --- a/das-dashboard/backend/shared/builders/agents_builder.py +++ b/das-dashboard/backend/shared/builders/agents_builder.py @@ -24,6 +24,7 @@ class AgentsBuilder: "endpoint_port", "ports_range_start", "ports_range_end", + "http_api_port", }) EXCLUDED_PARAM_KEYS = CONNECTION_KEYS | UI_CONNECTION_KEYS @@ -33,6 +34,7 @@ class AgentsBuilder: "max_bundle_size", "attention_update", "attention_correlation", + "attention_focus_strictness", "unique_assignment_flag", "use_link_template_cache", "populate_metta_mapping", @@ -103,7 +105,7 @@ def build_agent(self, agent_key: str, agent: dict) -> dict: return self._build_attention(agent, label) if agent_key == "command_router": - return self._build_connection_only(agent, label) + return self._build_command_router(agent, label) if agent_key == "atomdb": return self._build_connection_only(agent, label) @@ -183,6 +185,21 @@ def _build_attention(cls, agent: dict, label: str) -> dict: _require(agent, "endpoint", label=label) return {"endpoint": _get(agent, "endpoint")} + @classmethod + def _build_command_router(cls, agent: dict, label: str) -> dict: + _require(agent, "endpoint", "ports_range", "http_api_port", label=label) + + router_host = str(_get(agent, "endpoint")).split(":", 1)[0] + http_api_endpoint = f"{router_host}:{_get(agent, 'http_api_port')}" + + return { + "endpoint": _get(agent, "endpoint"), + "ports_range": _get(agent, "ports_range"), + "http_api": { + "endpoint": http_api_endpoint, + }, + } + @classmethod def _build_connection_only(cls, agent: dict, label: str) -> dict: _require(agent, "endpoint", "ports_range", label=label) diff --git a/das-dashboard/backend/shared/internal/configuration_constants.py b/das-dashboard/backend/shared/internal/configuration_constants.py index ef76c917..00937e3f 100644 --- a/das-dashboard/backend/shared/internal/configuration_constants.py +++ b/das-dashboard/backend/shared/internal/configuration_constants.py @@ -13,7 +13,7 @@ "environment", ) -AGENTS_SCHEMA_VERSION = "1.0" +AGENTS_SCHEMA_VERSION = "1.0.1" LOADERS = { "metta": {"image": "trueagi/das:1.0.0-metta-parser"}, @@ -131,6 +131,7 @@ "unique_assignment_flag": False, "attention_update": 0, "attention_correlation": 0, + "attention_focus_strictness": 0, "max_bundle_size": 1000, "max_answers": 0, "use_link_template_cache": False, @@ -191,6 +192,7 @@ "agents.command_router": { "endpoint": "0.0.0.0:40008", "ports_range": "48000:48999", + "http_api_port": 40009, }, "environment": { "jupyter_endpoint": "0.0.0.0:40019", diff --git a/das-dashboard/backend/shared/mappers/nested_config_mapper.py b/das-dashboard/backend/shared/mappers/nested_config_mapper.py index a4a33163..ad16e11f 100644 --- a/das-dashboard/backend/shared/mappers/nested_config_mapper.py +++ b/das-dashboard/backend/shared/mappers/nested_config_mapper.py @@ -64,6 +64,15 @@ def _agents_to_flat(agents: dict) -> dict: flat[f"agents.{agent_key}"] = entry + if agent_key == "command_router": + http_api = section.get("http_api") or {} + _, http_port = split_endpoint( + http_api.get("endpoint"), + DEFAULT_ENDPOINT_HOST, + 40009, + ) + entry["http_api_port"] = http_port + return flat @staticmethod diff --git a/das-dashboard/src/components/configuration_page/Agents/AgentConnectionFields.jsx b/das-dashboard/src/components/configuration_page/Agents/AgentConnectionFields.jsx index b88add17..5669425b 100644 --- a/das-dashboard/src/components/configuration_page/Agents/AgentConnectionFields.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/AgentConnectionFields.jsx @@ -3,7 +3,7 @@ import { FieldGrid } from "./Agents.styled" import { parsePortValue } from "../configFormUtils" import { ipv4Field, portField } from "../formValidation" -export function AgentConnectionFields({ form, withPortRange = true }) { +export function AgentConnectionFields({ form, withPortRange = true, onChange }) { return ( <> @@ -13,7 +13,10 @@ export function AgentConnectionFields({ form, withPortRange = true }) { size="small" required defaultValue={form.current.endpoint_ip} - onChange={(e) => { form.current.endpoint_ip = e.target.value }} + onChange={(e) => { + form.current.endpoint_ip = e.target.value + onChange?.() + }} {...ipv4Field} /> + { + formRef.current.attention_focus_strictness = Number(e.target.value) + }} + /> diff --git a/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx b/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx index f6eb0714..03f112e1 100644 --- a/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx @@ -23,6 +23,7 @@ export default function BaseParametersPanel() { max_bundle_size: getAgentParam(getDefaults(), "base_query", "max_bundle_size", 1000), attention_update: getAgentParam(getDefaults(), "base_query", "attention_update", 0), attention_correlation: getAgentParam(getDefaults(), "base_query", "attention_correlation", 0), + attention_focus_strictness: getAgentParam(getDefaults(), "base_query", "attention_focus_strictness", 0), unique_assignment_flag: getAgentParam(getDefaults(), "base_query", "unique_assignment_flag", false), use_link_template_cache: getAgentParam(getDefaults(), "base_query", "use_link_template_cache", false), populate_metta_mapping: getAgentParam(getDefaults(), "base_query", "populate_metta_mapping", false), diff --git a/das-dashboard/src/components/configuration_page/Agents/CommandRouter.jsx b/das-dashboard/src/components/configuration_page/Agents/CommandRouter.jsx index c70f6859..e282ac1a 100644 --- a/das-dashboard/src/components/configuration_page/Agents/CommandRouter.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/CommandRouter.jsx @@ -1,7 +1,8 @@ -import { useRef } from "react" +import { useRef, useState } from "react" +import { TextField } from "@mui/material" import { useConfig } from "../../global_providers/ConfigurationProvider" import { useToast } from "../../global_providers/ToastProvider" -import { buildAgentPayload, initAgentConnection } from "../configFormUtils" +import { buildAgentPayload, initCommandRouterForm, parsePortValue } from "../configFormUtils" import { ConfigForm } from "../ConfigForm" import { getAgentByKey } from "./agentRegistry" import { AgentConnectionFields } from "./AgentConnectionFields" @@ -11,15 +12,18 @@ import { AgentTitle, ConfigSection, ConfigSectionTitle, + FieldGrid, SaveButton } from "./Agents.styled" +import { portField } from "../formValidation" export default function CommandRouterPanel() { const { updateField, getDefaults } = useConfig() const { showToast } = useToast() const agent = getAgentByKey("command_router") - const form = useRef(initAgentConnection(getDefaults(), "command_router")) + const form = useRef(initCommandRouterForm(getDefaults())) + const [, refreshView] = useState(0) const handleSave = () => { updateField("agents.command_router", buildAgentPayload(form.current)) @@ -35,7 +39,29 @@ export default function CommandRouterPanel() { Connection - + refreshView((n) => n + 1)} /> + + + { + form.current.http_api_port = parsePortValue(event.target.value) + }} + {...portField} + /> + diff --git a/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js b/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js index 642b223f..d1213bc8 100644 --- a/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js +++ b/das-dashboard/src/components/configuration_page/Agents/agentRegistry.js @@ -34,10 +34,10 @@ export function getAgentByKey(key) { } export const AGENT_COMPONENTS = { + base_query: BaseQueryParams, query: QueryParams, link_creation: LinkCreationParams, evolution: EvolutionParams, context: ContextParams, - base_query: BaseQueryParams, inference: InferenceParams, } diff --git a/das-dashboard/src/components/configuration_page/ConfigurationPreview.jsx b/das-dashboard/src/components/configuration_page/ConfigurationPreview.jsx index a9815193..6a3a7f94 100644 --- a/das-dashboard/src/components/configuration_page/ConfigurationPreview.jsx +++ b/das-dashboard/src/components/configuration_page/ConfigurationPreview.jsx @@ -52,6 +52,8 @@ const FIELD_LABELS = { context: "Context", attention_update: "Attention Update", attention_correlation: "Attention Correlation", + attention_focus_strictness: "Attention Focus Strictness", + http_api_port: "HTTP API Port", query_interval: "Query Interval", query_timeout: "Query Timeout", use_metta_as_query_tokens: "Use MeTTa as Query Tokens", diff --git a/das-dashboard/src/components/configuration_page/configFormUtils.js b/das-dashboard/src/components/configuration_page/configFormUtils.js index f142d8e4..fcfd66af 100644 --- a/das-dashboard/src/components/configuration_page/configFormUtils.js +++ b/das-dashboard/src/components/configuration_page/configFormUtils.js @@ -70,6 +70,15 @@ export function initAgentConnection(sectionDefaults, agentKey) { } } +export function initCommandRouterForm(sectionDefaults, agentKey = "command_router") { + const defaults = sectionDefaults?.[`agents.${agentKey}`] || {} + + return { + ...initAgentConnection(sectionDefaults, agentKey), + http_api_port: defaults.http_api_port ?? 40009 + } +} + export function getAgentParam(sectionDefaults, agentKey, param, fallback) { const section = sectionDefaults?.[`agents.${agentKey}`] return section?.[param] ?? fallback From cc8907e11bfa4302778f617bdfb673cef44bb686 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Wed, 29 Jul 2026 10:21:44 -0300 Subject: [PATCH 04/10] Adding extra params to the defaults --- .../backend/shared/builders/agents_builder.py | 6 +++++- .../backend/shared/internal/configuration_constants.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/das-dashboard/backend/shared/builders/agents_builder.py b/das-dashboard/backend/shared/builders/agents_builder.py index 588029ad..bf6811cf 100644 --- a/das-dashboard/backend/shared/builders/agents_builder.py +++ b/das-dashboard/backend/shared/builders/agents_builder.py @@ -1,5 +1,8 @@ from shared.builders.builder_helpers import _get, _require -from shared.internal.configuration_constants import AGENTS_SCHEMA_VERSION +from shared.internal.configuration_constants import ( + AGENTS_SCHEMA_VERSION, + COMMAND_ROUTER_HTTP_API_DEFAULTS, +) class AgentsBuilder: @@ -197,6 +200,7 @@ def _build_command_router(cls, agent: dict, label: str) -> dict: "ports_range": _get(agent, "ports_range"), "http_api": { "endpoint": http_api_endpoint, + **COMMAND_ROUTER_HTTP_API_DEFAULTS, }, } diff --git a/das-dashboard/backend/shared/internal/configuration_constants.py b/das-dashboard/backend/shared/internal/configuration_constants.py index 00937e3f..315c1db6 100644 --- a/das-dashboard/backend/shared/internal/configuration_constants.py +++ b/das-dashboard/backend/shared/internal/configuration_constants.py @@ -15,6 +15,16 @@ AGENTS_SCHEMA_VERSION = "1.0.1" +# Temporary defaults until http_api extras are dropped from the DAS schema. +COMMAND_ROUTER_HTTP_API_DEFAULTS = { + "thread_pool_size": 4, + "max_concurrent_executions": 100, + "max_queued_executions": 500, + "max_events_per_execution": 100000, + "stream_items_per_chunk": 100, + "execution_retention_ms": 900000, +} + LOADERS = { "metta": {"image": "trueagi/das:1.0.0-metta-parser"}, "morkdb": {"image": "trueagi/das:mork-loader-1.1.0"}, From 3b147f810d39f6b464681515930814e71f74ae69 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Wed, 29 Jul 2026 12:49:52 -0300 Subject: [PATCH 05/10] Forcing '0.0' as default value because of type validation --- .../backend/services/config_services.py | 3 + .../backend/shared/builders/agents_builder.py | 6 +- .../internal/configuration_constants.py | 2 +- .../Agents/AgentsParams/BaseParams.jsx | 2 +- .../configuration_page/Agents/BaseParams.jsx | 2 +- .../src/pages/setup_das/SetupDas.jsx | 4 +- das-dashboard/src/utils/FileSaver.js | 88 ++++++++----------- 7 files changed, 52 insertions(+), 55 deletions(-) diff --git a/das-dashboard/backend/services/config_services.py b/das-dashboard/backend/services/config_services.py index 1b5b4261..f0060c17 100644 --- a/das-dashboard/backend/services/config_services.py +++ b/das-dashboard/backend/services/config_services.py @@ -54,6 +54,9 @@ async def save_config(self, configuration_entries: ConfigurationEntriesDto) -> d return { "message": message, "content": nested_config, + # Pre-serialized with Python so floats like 0.0 survive browser download + # (JS JSON.stringify turns 0.0 into 0, which DAS rejects for doubles). + "content_text": json.dumps(nested_config, indent=2), "remote_hosts": remote_hosts, "hosts": self.web_config.map_dashboard_hosts(), } diff --git a/das-dashboard/backend/shared/builders/agents_builder.py b/das-dashboard/backend/shared/builders/agents_builder.py index bf6811cf..1d436985 100644 --- a/das-dashboard/backend/shared/builders/agents_builder.py +++ b/das-dashboard/backend/shared/builders/agents_builder.py @@ -181,7 +181,11 @@ def _split_connection_and_params(cls, agent: dict) -> tuple[dict, dict]: def _build_base_query(cls, agent: dict, label: str) -> dict: normalized = cls._normalize_base_query(agent) _require(normalized, *cls._BASE_QUERY_PARAMS, label=label) - return {"params": dict(normalized)} + params = dict(normalized) + params["attention_focus_strictness"] = float( + params.get("attention_focus_strictness", 0.0) + ) + return {"params": params} @classmethod def _build_attention(cls, agent: dict, label: str) -> dict: diff --git a/das-dashboard/backend/shared/internal/configuration_constants.py b/das-dashboard/backend/shared/internal/configuration_constants.py index 315c1db6..c39ca08e 100644 --- a/das-dashboard/backend/shared/internal/configuration_constants.py +++ b/das-dashboard/backend/shared/internal/configuration_constants.py @@ -141,7 +141,7 @@ "unique_assignment_flag": False, "attention_update": 0, "attention_correlation": 0, - "attention_focus_strictness": 0, + "attention_focus_strictness": 0.0, "max_bundle_size": 1000, "max_answers": 0, "use_link_template_cache": False, diff --git a/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx b/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx index 804b6d64..8eda2d8f 100644 --- a/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx @@ -58,7 +58,7 @@ export default function BaseQueryParams({ formRef }) { defaultValue={formRef.current.attention_focus_strictness} {...selectionRateField} onChange={(e) => { - formRef.current.attention_focus_strictness = Number(e.target.value) + formRef.current.attention_focus_strictness = Number(e.target.value) || 0.0 }} /> diff --git a/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx b/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx index 03f112e1..813f580a 100644 --- a/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/BaseParams.jsx @@ -23,7 +23,7 @@ export default function BaseParametersPanel() { max_bundle_size: getAgentParam(getDefaults(), "base_query", "max_bundle_size", 1000), attention_update: getAgentParam(getDefaults(), "base_query", "attention_update", 0), attention_correlation: getAgentParam(getDefaults(), "base_query", "attention_correlation", 0), - attention_focus_strictness: getAgentParam(getDefaults(), "base_query", "attention_focus_strictness", 0), + attention_focus_strictness: getAgentParam(getDefaults(), "base_query", "attention_focus_strictness", 0.0), unique_assignment_flag: getAgentParam(getDefaults(), "base_query", "unique_assignment_flag", false), use_link_template_cache: getAgentParam(getDefaults(), "base_query", "use_link_template_cache", false), populate_metta_mapping: getAgentParam(getDefaults(), "base_query", "populate_metta_mapping", false), diff --git a/das-dashboard/src/pages/setup_das/SetupDas.jsx b/das-dashboard/src/pages/setup_das/SetupDas.jsx index c4a25121..dc7ab845 100644 --- a/das-dashboard/src/pages/setup_das/SetupDas.jsx +++ b/das-dashboard/src/pages/setup_das/SetupDas.jsx @@ -102,8 +102,8 @@ export default function SetupDasPage() { severity: "success" }) - if (response?.content) { - setSavedConfigContent(response.content) + if (response?.content_text || response?.content) { + setSavedConfigContent(response.content_text || response.content) setOpenSaveCopyDialog(true) } diff --git a/das-dashboard/src/utils/FileSaver.js b/das-dashboard/src/utils/FileSaver.js index ae1259ad..ae335f5a 100644 --- a/das-dashboard/src/utils/FileSaver.js +++ b/das-dashboard/src/utils/FileSaver.js @@ -1,57 +1,47 @@ -import axios from "axios" - -export async function saveFileWithPicker(data){ - - try{ - - const options = { - suggestedName: "config.json", - types: [ - { - description: ".json", - accept: {"application/json": [".json"]} - } - ] - }; - - const fileHandle = await window.showSaveFilePicker(options); - - const writableFileStream = await fileHandle.createWritable(); - - await writableFileStream.write( - new Blob([JSON.stringify(data, null, 2)], { type: "application/json" }) - ) - - await writableFileStream.close(); +export async function saveFileWithPicker(data) { + const payload = typeof data === "string" ? data : JSON.stringify(data, null, 2) + + try { + const options = { + suggestedName: "config.json", + types: [ + { + description: ".json", + accept: { "application/json": [".json"] } + } + ] } - catch (err) { - console.error('Error saving config.json', err.name, err.message) - throw err - } + const fileHandle = await window.showSaveFilePicker(options) + const writableFileStream = await fileHandle.createWritable() -} + await writableFileStream.write( + new Blob([payload], { type: "application/json" }) + ) -export default async function saveFile(data){ + await writableFileStream.close() + } catch (err) { + console.error("Error saving config.json", err.name, err.message) + throw err + } +} - try{ - const handle = await saveFileWithPicker(data) +export default async function saveFile(data) { + try { + await saveFileWithPicker(data) + } catch (err) { + if (err.name === "AbortError") { + return } - catch (err) { - if (err.name === "AbortError"){ - return - } - else{ - saveFileFallback(data) - } - } - + saveFileFallback(data) + } } -export async function saveFileFallback(data){ - const blob = new Blob([JSON.stringify(data, null, 2)]) - const a = document.createElement("a") - a.href = URL.createObjectURL(blob) - a.download = "config.json" - a.click() -} \ No newline at end of file +export async function saveFileFallback(data) { + const payload = typeof data === "string" ? data : JSON.stringify(data, null, 2) + const blob = new Blob([payload], { type: "application/json" }) + const a = document.createElement("a") + a.href = URL.createObjectURL(blob) + a.download = "config.json" + a.click() +} From 47738d72b05290321a36bd78254d3d267ae23fdd Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Wed, 29 Jul 2026 13:01:49 -0300 Subject: [PATCH 06/10] adding new parameters to das-cli config validator and fixing config load bug that was cleaning the file when having an error --- das-cli/src/commands/config/config_cli.py | 14 +++++- .../config/config_sections/agents_params.py | 6 +++ .../config/config_sections/normalize_file.py | 47 +++++++++++++++++++ das-cli/src/common/config/core.py | 15 +++++- das-cli/src/common/config/store.py | 33 ++++++++++--- das-cli/src/common/settings.py | 23 ++++++++- das-cli/src/settings/config.py | 2 +- .../integration/fixtures/config/simple.json | 14 +++++- 8 files changed, 141 insertions(+), 13 deletions(-) diff --git a/das-cli/src/commands/config/config_cli.py b/das-cli/src/commands/config/config_cli.py index 3cc7c00a..8e6c0a2e 100644 --- a/das-cli/src/commands/config/config_cli.py +++ b/das-cli/src/commands/config/config_cli.py @@ -73,9 +73,21 @@ def __init__( def _set_file_path(self, save_path) -> None: self._settings.set_path(save_path) - self._settings.rewind() + load_error = getattr(self._settings._store, "_load_error", None) + if load_error is not None: + raise ValueError( + f"Could not load configuration from '{save_path}': {load_error}. " + "The file was left unchanged. Fix the JSON and try again." + ) from load_error + + if not self._settings.exists(): + raise ValueError( + f"Configuration file at '{save_path}' is empty. " + "The file was left unchanged." + ) + verify_populate_missing_values(self._settings, save_path) self.stdout( diff --git a/das-cli/src/commands/config/config_sections/agents_params.py b/das-cli/src/commands/config/config_sections/agents_params.py index 85da3d79..d51aff32 100644 --- a/das-cli/src/commands/config/config_sections/agents_params.py +++ b/das-cli/src/commands/config/config_sections/agents_params.py @@ -5,6 +5,7 @@ "unique_assignment_flag": False, "attention_update": 0, "attention_correlation": 0, + "attention_focus_strictness": 0.0, "max_bundle_size": 1000, "max_answers": 0, "use_link_template_cache": False, @@ -81,6 +82,11 @@ def setup_base_query_params(settings: Settings): default=BASE_QUERY_DEFAULTS["attention_correlation"], type=int, ), + "attention_focus_strictness": Command.prompt( + "Attention focus strictness", + default=BASE_QUERY_DEFAULTS["attention_focus_strictness"], + type=float, + ), "max_bundle_size": Command.prompt( "Max bundle size", default=BASE_QUERY_DEFAULTS["max_bundle_size"], diff --git a/das-cli/src/commands/config/config_sections/normalize_file.py b/das-cli/src/commands/config/config_sections/normalize_file.py index 4aa9a1bf..abd065eb 100644 --- a/das-cli/src/commands/config/config_sections/normalize_file.py +++ b/das-cli/src/commands/config/config_sections/normalize_file.py @@ -1,6 +1,8 @@ import getpass +from copy import deepcopy from typing import Any, Dict, List +from common.config.core import get_core_defaults_dict from common.docker import RemoteContextManager from common.docker.remote_context_manager import Server from common.settings import Settings @@ -44,8 +46,53 @@ def normalize_servers( return updated_nodes +def _fill_missing_values(current: Any, defaults: Any) -> Any: + """Add keys present in defaults but missing in current; never overwrite user values.""" + if not isinstance(defaults, dict): + return current if current is not None else deepcopy(defaults) + + result = dict(current) if isinstance(current, dict) else {} + for key, default_value in defaults.items(): + if key not in result: + result[key] = deepcopy(default_value) + else: + result[key] = _fill_missing_values(result[key], default_value) + return result + + +def _defaults_for_config(content: Dict[str, Any]) -> Dict[str, Any]: + """Return schema defaults trimmed to the active atomdb type (same rules as validation).""" + expected = get_core_defaults_dict() + atomdb_type = content.get("atomdb", {}).get("type") + atomdb_section = expected["atomdb"] + + if atomdb_type != "adapterdb": + atomdb_section.pop("adapterdb", None) + + if atomdb_type != "remotedb": + atomdb_section.pop("remote_peers", None) + + if atomdb_type != "morkdb": + atomdb_section.pop("mongodb", None) + atomdb_section.pop("morkdb", None) + + if atomdb_type != "redismongodb": + atomdb_section.pop("mongodb", None) + atomdb_section.pop("redis", None) + + return expected + + def verify_populate_missing_values(settings: Settings, path: str) -> None: content: Dict[str, Any] = settings.get_content() + content = _fill_missing_values(content, _defaults_for_config(content)) + + base_query_params = content.get("agents", {}).get("base_query", {}).get("params") + if isinstance(base_query_params, dict) and "attention_focus_strictness" in base_query_params: + base_query_params["attention_focus_strictness"] = float( + base_query_params["attention_focus_strictness"] + ) + current_user = getpass.getuser() context_manager = RemoteContextManager() diff --git a/das-cli/src/common/config/core.py b/das-cli/src/common/config/core.py index 084172b3..8296d20e 100644 --- a/das-cli/src/common/config/core.py +++ b/das-cli/src/common/config/core.py @@ -94,6 +94,7 @@ def get_core_defaults_dict() -> Dict[str, Any]: "unique_assignment_flag": False, "attention_update": 0, "attention_correlation": 0, + "attention_focus_strictness": 0.0, "max_bundle_size": 1000, "max_answers": 0, "use_link_template_cache": False, @@ -159,7 +160,19 @@ def get_core_defaults_dict() -> Dict[str, Any]: }, }, "atomdb": {"endpoint": "localhost:40007", "ports_range": "47000:47999"}, - "command_router": {"endpoint": "localhost:40008", "ports_range": "48000:48999"}, + "command_router": { + "endpoint": "localhost:40008", + "ports_range": "48000:48999", + "http_api": { + "endpoint": "localhost:40009", + "thread_pool_size": 4, + "max_concurrent_executions": 100, + "max_queued_executions": 500, + "max_events_per_execution": 100000, + "stream_items_per_chunk": 100, + "execution_retention_ms": 900000 + } + }, }, "environment": {"jupyter": {"endpoint": "localhost:40019"}}, } diff --git a/das-cli/src/common/config/store.py b/das-cli/src/common/config/store.py index eb5e60b4..86f15468 100644 --- a/das-cli/src/common/config/store.py +++ b/das-cli/src/common/config/store.py @@ -87,6 +87,7 @@ def __init__(self, env_file_path: str): self._content: Dict[str, Any] = {} self._new_content: Dict[str, Any] = {} self._overwrite_mode = False + self._load_error: Exception | None = None self.rewind() def get_content(self) -> dict: @@ -102,21 +103,41 @@ def set_path(self, new_file_path: str) -> None: self._file_path = new_file_path def save_path(self) -> None: - env_file = open(self._env_path, "w") - env_file.write(f"configpath={self._file_path}\n") + os.makedirs(os.path.dirname(self._env_path), exist_ok=True) + with open(self._env_path, "w", encoding="utf-8") as env_file: + env_file.write(f"configpath={self._file_path}\n") def get_dir_path(self) -> str: return os.path.dirname(self._file_path) + def file_exists(self) -> bool: + return bool(self._file_path) and os.path.isfile(self._file_path) + def exists(self) -> bool: - return len(self.get_content().items()) > 0 + return isinstance(self.get_content(), dict) and len(self.get_content()) > 0 def rewind(self): + self._new_content = {} try: - with open(self._file_path, "r") as f: - self._content = json.load(f) - except (FileNotFoundError, json.JSONDecodeError): + with open(self._file_path, "r", encoding="utf-8") as f: + loaded = json.load(f) + if not isinstance(loaded, dict): + raise json.JSONDecodeError( + "Configuration root must be a JSON object", + doc=str(self._file_path), + pos=0, + ) + self._content = loaded + self._load_error = None + except FileNotFoundError as error: + self._content = {} + self._load_error = error + except json.JSONDecodeError as error: + self._content = {} + self._load_error = error + except OSError as error: self._content = {} + self._load_error = error return self diff --git a/das-cli/src/common/settings.py b/das-cli/src/common/settings.py index 57cec5ce..6a94574a 100644 --- a/das-cli/src/common/settings.py +++ b/das-cli/src/common/settings.py @@ -81,9 +81,28 @@ def validate_configuration_file(self): self.raise_on_version_mismatch() def raise_on_missing_file(self): - if not self.exists(): + path = self.get_path() + store = self._store + load_error = getattr(store, "_load_error", None) + + if hasattr(store, "file_exists") and not store.file_exists(): raise FileNotFoundError( - "Configuration file not found. You can run the command 'config set' to create a configuration file or point to an existing file." + f"Configuration file not found at '{path}'. " + "Run 'das-cli config set --file ' to point to an existing file, " + "or 'das-cli config set' to create one." + ) + + if load_error is not None: + raise ValueError( + f"Configuration file at '{path}' could not be loaded: {load_error}. " + "Fix the JSON and try again." + ) from load_error + + if not self.exists(): + raise ValueError( + f"Configuration file at '{path}' is empty. " + "Restore a valid DAS config JSON, then run " + "'das-cli config set --file '." ) def raise_on_version_mismatch(self): diff --git a/das-cli/src/settings/config.py b/das-cli/src/settings/config.py index eecdb9e6..e1c51bcc 100644 --- a/das-cli/src/settings/config.py +++ b/das-cli/src/settings/config.py @@ -51,5 +51,5 @@ DAS_MORK_LOADER_IMAGE_NAME = "trueagi/das" DAS_MORK_LOADER_IMAGE_VERSION = "mork-loader-1.1.0" -DAS_IMAGE_VERSION = "1.1.0-rc" +DAS_IMAGE_VERSION = "1.2.0-rc" DAS_IMAGE_NAME = "trueagi/das" diff --git a/das-cli/tests/integration/fixtures/config/simple.json b/das-cli/tests/integration/fixtures/config/simple.json index 87116082..c9c8f8e5 100644 --- a/das-cli/tests/integration/fixtures/config/simple.json +++ b/das-cli/tests/integration/fixtures/config/simple.json @@ -38,7 +38,7 @@ } }, "agents": { - "schema_version": "1.0", + "schema_version": "1.0.1", "attention": { "endpoint": "localhost:40001" }, @@ -47,6 +47,7 @@ "unique_assignment_flag": false, "attention_update": 0, "attention_correlation": 0, + "attention_focus_strictness": 0.0, "max_bundle_size": 1000, "max_answers": 0, "use_link_template_cache": false, @@ -117,7 +118,16 @@ }, "command_router": { "endpoint": "localhost:40008", - "ports_range": "48000:48999" + "ports_range": "48000:48999", + "http_api": { + "endpoint": "localhost:40009", + "thread_pool_size": 4, + "max_concurrent_executions": 100, + "max_queued_executions": 500, + "max_events_per_execution": 100000, + "stream_items_per_chunk": 100, + "execution_retention_ms": 900000 + } } }, "environment": { From 2326ab8b02668e6a19fef9bbbfb8810aa19dcf37 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Wed, 29 Jul 2026 14:26:08 -0300 Subject: [PATCH 07/10] CodeRabbit changes + changing focusStrictness to slider --- das-cli/src/commands/config/config_cli.py | 2 +- .../config/config_sections/normalize_file.py | 26 ++++++++++- das-cli/src/common/config/store.py | 5 +- das-cli/src/common/settings.py | 8 +++- .../backend/shared/builders/agents_builder.py | 7 ++- .../backend/shared/utils/path_utils.py | 37 ++++++++++++++- .../Agents/AgentsParams/BaseParams.jsx | 46 +++++++++++++------ 7 files changed, 109 insertions(+), 22 deletions(-) diff --git a/das-cli/src/commands/config/config_cli.py b/das-cli/src/commands/config/config_cli.py index 8e6c0a2e..c28011df 100644 --- a/das-cli/src/commands/config/config_cli.py +++ b/das-cli/src/commands/config/config_cli.py @@ -75,7 +75,7 @@ def _set_file_path(self, save_path) -> None: self._settings.set_path(save_path) self._settings.rewind() - load_error = getattr(self._settings._store, "_load_error", None) + load_error = self._settings.get_load_error() if load_error is not None: raise ValueError( f"Could not load configuration from '{save_path}': {load_error}. " diff --git a/das-cli/src/commands/config/config_sections/normalize_file.py b/das-cli/src/commands/config/config_sections/normalize_file.py index abd065eb..c202490a 100644 --- a/das-cli/src/commands/config/config_sections/normalize_file.py +++ b/das-cli/src/commands/config/config_sections/normalize_file.py @@ -62,8 +62,9 @@ def _fill_missing_values(current: Any, defaults: Any) -> Any: def _defaults_for_config(content: Dict[str, Any]) -> Dict[str, Any]: """Return schema defaults trimmed to the active atomdb type (same rules as validation).""" - expected = get_core_defaults_dict() - atomdb_type = content.get("atomdb", {}).get("type") + expected = deepcopy(get_core_defaults_dict()) + default_atomdb_type = expected.get("atomdb", {}).get("type", "redismongodb") + atomdb_type = content.get("atomdb", {}).get("type") or default_atomdb_type atomdb_section = expected["atomdb"] if atomdb_type != "adapterdb": @@ -80,6 +81,27 @@ def _defaults_for_config(content: Dict[str, Any]) -> Dict[str, Any]: atomdb_section.pop("mongodb", None) atomdb_section.pop("redis", None) + adapterdb = atomdb_section.get("adapterdb") + if adapterdb: + backend = adapterdb.get("atomdb_backend") + if backend: + backend_type = ( + content.get("atomdb", {}) + .get("adapterdb", {}) + .get("atomdb_backend", {}) + .get("type") + ) or backend.get("type") + + if backend_type != "redismongodb": + backend.pop("redis", None) + backend.pop("mongodb", None) + + if backend_type != "morkdb": + backend.pop("morkdb", None) + + if backend_type != "inmemorydb": + backend.pop("inmemorydb", None) + return expected diff --git a/das-cli/src/common/config/store.py b/das-cli/src/common/config/store.py index 86f15468..7055ed48 100644 --- a/das-cli/src/common/config/store.py +++ b/das-cli/src/common/config/store.py @@ -132,7 +132,7 @@ def rewind(self): except FileNotFoundError as error: self._content = {} self._load_error = error - except json.JSONDecodeError as error: + except (json.JSONDecodeError, UnicodeDecodeError) as error: self._content = {} self._load_error = error except OSError as error: @@ -141,6 +141,9 @@ def rewind(self): return self + def get_load_error(self) -> Exception | None: + return self._load_error + def enable_overwrite_mode(self): self._overwrite_mode = True self._content = {} diff --git a/das-cli/src/common/settings.py b/das-cli/src/common/settings.py index 6a94574a..09a55b94 100644 --- a/das-cli/src/common/settings.py +++ b/das-cli/src/common/settings.py @@ -80,10 +80,16 @@ def validate_configuration_file(self): self.raise_on_missing_file() self.raise_on_version_mismatch() + def get_load_error(self) -> Exception | None: + store = self._store + if hasattr(store, "get_load_error"): + return store.get_load_error() + return getattr(store, "_load_error", None) + def raise_on_missing_file(self): path = self.get_path() store = self._store - load_error = getattr(store, "_load_error", None) + load_error = self.get_load_error() if hasattr(store, "file_exists") and not store.file_exists(): raise FileNotFoundError( diff --git a/das-dashboard/backend/shared/builders/agents_builder.py b/das-dashboard/backend/shared/builders/agents_builder.py index 1d436985..fa87de68 100644 --- a/das-dashboard/backend/shared/builders/agents_builder.py +++ b/das-dashboard/backend/shared/builders/agents_builder.py @@ -3,6 +3,7 @@ AGENTS_SCHEMA_VERSION, COMMAND_ROUTER_HTTP_API_DEFAULTS, ) +from shared.utils.path_utils import replace_endpoint_port class AgentsBuilder: @@ -196,8 +197,10 @@ def _build_attention(cls, agent: dict, label: str) -> dict: def _build_command_router(cls, agent: dict, label: str) -> dict: _require(agent, "endpoint", "ports_range", "http_api_port", label=label) - router_host = str(_get(agent, "endpoint")).split(":", 1)[0] - http_api_endpoint = f"{router_host}:{_get(agent, 'http_api_port')}" + http_api_endpoint = replace_endpoint_port( + _get(agent, "endpoint"), + _get(agent, "http_api_port"), + ) return { "endpoint": _get(agent, "endpoint"), diff --git a/das-dashboard/backend/shared/utils/path_utils.py b/das-dashboard/backend/shared/utils/path_utils.py index 2be600d3..17a1e3f0 100644 --- a/das-dashboard/backend/shared/utils/path_utils.py +++ b/das-dashboard/backend/shared/utils/path_utils.py @@ -1,6 +1,39 @@ -def split_endpoint(endpoint: str, default_host: str = "localhost", default_port: int = 40020) -> tuple[str, int]: +def split_endpoint( + endpoint: str, + default_host: str = "localhost", + default_port: int = 40020, +) -> tuple[str, int]: if not endpoint: return default_host, default_port - host, _, port = str(endpoint).partition(":") + value = str(endpoint).strip() + + if value.startswith("["): + close = value.find("]") + if close != -1: + host = value[1:close] or default_host + port_part = value[close + 1 :] + if port_part.startswith(":"): + port_part = port_part[1:] + return host, int(port_part) if port_part else default_port + + host, separator, port = value.rpartition(":") + if not separator: + return value or default_host, default_port + return host or default_host, int(port) if port else default_port + + +def replace_endpoint_port( + endpoint: str, + new_port: int | str, + default_host: str = "localhost", +) -> str: + """Replace only the port, preserving bracketed IPv6 hosts like [::1]:40008.""" + value = str(endpoint or "").strip() + host, _ = split_endpoint(value, default_host, 0) + + if value.startswith("["): + return f"[{host}]:{new_port}" + + return f"{host}:{new_port}" diff --git a/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx b/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx index 8eda2d8f..7dfa68b6 100644 --- a/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx +++ b/das-dashboard/src/components/configuration_page/Agents/AgentsParams/BaseParams.jsx @@ -1,8 +1,14 @@ -import { TextField, Switch, FormControlLabel } from "@mui/material" +import { useState } from "react" +import { TextField, Switch, FormControlLabel, Slider, Box, Typography } from "@mui/material" import { FieldGrid, SwitchGrid } from "../Agents.styled" -import { numberField, selectionRateField } from "../../formValidation" +import { numberField } from "../../formValidation" +import { palette } from "../../../../pages/setup_das/SetupDasStyled" export default function BaseQueryParams({ formRef }) { + const [focusStrictness, setFocusStrictness] = useState( + Number(formRef.current.attention_focus_strictness) || 0 + ) + return ( <> @@ -50,17 +56,31 @@ export default function BaseQueryParams({ formRef }) { formRef.current.attention_correlation = Number(e.target.value) }} /> - { - formRef.current.attention_focus_strictness = Number(e.target.value) || 0.0 - }} - /> + + + + Attention Focus Strictness + + + {focusStrictness.toFixed(1)} + + + { + setFocusStrictness(value) + formRef.current.attention_focus_strictness = value + }} + sx={{ + color: palette.accent, + "& .MuiSlider-rail": { opacity: 0.35 } + }} + /> + From d7491e329cb41a288d8c72ba73b495962c43dffe Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Wed, 29 Jul 2026 14:37:40 -0300 Subject: [PATCH 08/10] revert version to 1.1.0 --- das-cli/src/settings/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/das-cli/src/settings/config.py b/das-cli/src/settings/config.py index e1c51bcc..eecdb9e6 100644 --- a/das-cli/src/settings/config.py +++ b/das-cli/src/settings/config.py @@ -51,5 +51,5 @@ DAS_MORK_LOADER_IMAGE_NAME = "trueagi/das" DAS_MORK_LOADER_IMAGE_VERSION = "mork-loader-1.1.0" -DAS_IMAGE_VERSION = "1.2.0-rc" +DAS_IMAGE_VERSION = "1.1.0-rc" DAS_IMAGE_NAME = "trueagi/das" From ebdb0c4521be8436b43a6dee7a46a785186208c4 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Wed, 29 Jul 2026 14:40:01 -0300 Subject: [PATCH 09/10] make lint --- das-cli/src/commands/config/config_cli.py | 3 +-- .../src/commands/config/config_sections/normalize_file.py | 5 +---- das-cli/src/commands/system/system_cli.py | 4 +--- das-cli/src/common/command.py | 4 ++-- das-cli/src/common/config/core.py | 4 ++-- .../common/container_manager/system_containers_manager.py | 4 ++-- das-cli/src/common/prompt_types.py | 1 + 7 files changed, 10 insertions(+), 15 deletions(-) diff --git a/das-cli/src/commands/config/config_cli.py b/das-cli/src/commands/config/config_cli.py index c28011df..25c3d193 100644 --- a/das-cli/src/commands/config/config_cli.py +++ b/das-cli/src/commands/config/config_cli.py @@ -84,8 +84,7 @@ def _set_file_path(self, save_path) -> None: if not self._settings.exists(): raise ValueError( - f"Configuration file at '{save_path}' is empty. " - "The file was left unchanged." + f"Configuration file at '{save_path}' is empty. " "The file was left unchanged." ) verify_populate_missing_values(self._settings, save_path) diff --git a/das-cli/src/commands/config/config_sections/normalize_file.py b/das-cli/src/commands/config/config_sections/normalize_file.py index c202490a..9cecc975 100644 --- a/das-cli/src/commands/config/config_sections/normalize_file.py +++ b/das-cli/src/commands/config/config_sections/normalize_file.py @@ -86,10 +86,7 @@ def _defaults_for_config(content: Dict[str, Any]) -> Dict[str, Any]: backend = adapterdb.get("atomdb_backend") if backend: backend_type = ( - content.get("atomdb", {}) - .get("adapterdb", {}) - .get("atomdb_backend", {}) - .get("type") + content.get("atomdb", {}).get("adapterdb", {}).get("atomdb_backend", {}).get("type") ) or backend.get("type") if backend_type != "redismongodb": diff --git a/das-cli/src/commands/system/system_cli.py b/das-cli/src/commands/system/system_cli.py index 96b9db18..fe27f336 100644 --- a/das-cli/src/commands/system/system_cli.py +++ b/das-cli/src/commands/system/system_cli.py @@ -44,10 +44,9 @@ class SystemStatus(Command): help="Sets how many seconds of cooldown before updating the metrics again.", default=2, required=False, - ) + ), ] - @inject def __init__( self, @@ -218,7 +217,6 @@ def machine_loop(): latest_machine.clear() latest_machine.update(data) - except Exception as e: print(f"[machine_loop] {e}") diff --git a/das-cli/src/common/command.py b/das-cli/src/common/command.py index 3e703dcb..c681f32f 100644 --- a/das-cli/src/common/command.py +++ b/das-cli/src/common/command.py @@ -331,11 +331,11 @@ def _remote_run(self, kwargs, remote_kwargs): command = f"{prefix} {command_path} {extra_args} {remote_context}".strip() try: - + if "config" not in command_path: self._check_remote_config(remote_kwargs) - # Ignores this check when a config command is called, prevents command from breaking when user is setting up configuration across multiple remote machines. + # Ignores this check when a config command is called, prevents command from breaking when user is setting up configuration across multiple remote machines. Connection(**remote_kwargs).run(command, pty=False) except Exception as e: diff --git a/das-cli/src/common/config/core.py b/das-cli/src/common/config/core.py index 8296d20e..1598874f 100644 --- a/das-cli/src/common/config/core.py +++ b/das-cli/src/common/config/core.py @@ -170,8 +170,8 @@ def get_core_defaults_dict() -> Dict[str, Any]: "max_queued_executions": 500, "max_events_per_execution": 100000, "stream_items_per_chunk": 100, - "execution_retention_ms": 900000 - } + "execution_retention_ms": 900000, + }, }, }, "environment": {"jupyter": {"endpoint": "localhost:40019"}}, diff --git a/das-cli/src/common/container_manager/system_containers_manager.py b/das-cli/src/common/container_manager/system_containers_manager.py index 0a4eff9f..85df96e3 100644 --- a/das-cli/src/common/container_manager/system_containers_manager.py +++ b/das-cli/src/common/container_manager/system_containers_manager.py @@ -145,9 +145,9 @@ def _parse_container_stats(self, stats: dict) -> dict: cpu_percent = self._calculate_cpu_percent(stats) memory_usage = stats.get("memory_stats", {}).get("usage", 0) - + memory_mb = round( - memory_usage / (1024 ** 3), + memory_usage / (1024**3), 2, ) diff --git a/das-cli/src/common/prompt_types.py b/das-cli/src/common/prompt_types.py index a2e91d1c..fac88e4a 100644 --- a/das-cli/src/common/prompt_types.py +++ b/das-cli/src/common/prompt_types.py @@ -15,6 +15,7 @@ def _is_remote_invocation(ctx) -> bool: params = ctx.params return bool(params.get("remote") or params.get("host") or params.get("user")) + class ReachableIpAddress(ParamType): name = "reachable ip address" From a033b33573d4843b1855f171688e46903c25d5a8 Mon Sep 17 00:00:00 2001 From: "rafael.levi" Date: Wed, 29 Jul 2026 15:47:13 -0300 Subject: [PATCH 10/10] fixing test setup --- das-cli/tests/agents_integration/conftest.py | 12 +++++++- das-cli/tests/integration/libs/errors.bash | 2 +- das-cli/tests/integration/libs/utils.bash | 32 ++++++++++++++++++-- das-cli/tests/integration/test_das_peer.bats | 3 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/das-cli/tests/agents_integration/conftest.py b/das-cli/tests/agents_integration/conftest.py index f7b0c1c3..f8f7e5d6 100644 --- a/das-cli/tests/agents_integration/conftest.py +++ b/das-cli/tests/agents_integration/conftest.py @@ -38,8 +38,18 @@ def setup_environment(): env_path = os.path.join(home_folder, ".das", ".env") target_path = os.path.join(home_folder, ".das", "config.json") source_path = os.path.abspath("tests/integration/fixtures/config/simple.json") - + os.makedirs(os.path.dirname(target_path), exist_ok=True) + + if os.path.isdir(target_path): + try: + shutil.rmtree(target_path) + except PermissionError as error: + raise RuntimeError( + f"{target_path} is a directory (often created by Docker when the file is missing). " + f"Run: sudo rm -rf {target_path}" + ) from error + shutil.copy(source_path, target_path) with open(env_path, mode="w+") as f: f.write(f"configpath={target_path}") diff --git a/das-cli/tests/integration/libs/errors.bash b/das-cli/tests/integration/libs/errors.bash index 7a6cbb56..d64c10e5 100644 --- a/das-cli/tests/integration/libs/errors.bash +++ b/das-cli/tests/integration/libs/errors.bash @@ -1,4 +1,4 @@ -export FILE_NOT_FOUND_ERROR="[FileNotFoundError] Configuration file not found. You can run the command 'config set' to create a configuration file or point to an existing file." +export FILE_NOT_FOUND_ERROR="[FileNotFoundError] Configuration file not found at" export VALUE_ERROR_MSG="[ValueError] Your configuration file doesn't have all the entries this version of das-cli requires. You can call 'das-cli config set' and hit to every prompt in order to re-use the configuration you currently have in your config file and set the new ones to safe default values." export DOCKER_CONTAINER_MISSING="[DockerContainerNotFoundError]" export PORT_IN_USE_ERROR="[PortBindingError] Port on localhost are already in use." \ No newline at end of file diff --git a/das-cli/tests/integration/libs/utils.bash b/das-cli/tests/integration/libs/utils.bash index edc8934f..6e03120b 100644 --- a/das-cli/tests/integration/libs/utils.bash +++ b/das-cli/tests/integration/libs/utils.bash @@ -115,7 +115,26 @@ function set_config() { } function unset_config() { - rm -f "$das_config_file" "$das_env_file" + if [ -d "$das_config_file" ]; then + rm -rf "$das_config_file" 2>/dev/null || { + echo "ERROR: $das_config_file is a directory (often created by Docker when the file is missing)." + echo "Run: sudo rm -rf $das_config_file" + return 1 + } + else + rm -f "$das_config_file" + fi + rm -f "$das_env_file" +} + +function _ensure_config_path_is_file() { + if [ -d "$das_config_file" ]; then + rm -rf "$das_config_file" 2>/dev/null || { + echo "ERROR: $das_config_file is a directory (often created by Docker when the file is missing)." + echo "Run: sudo rm -rf $das_config_file" + return 1 + } + fi } function set_log() { @@ -140,10 +159,17 @@ function use_config() { local config="$1" local config_source="${test_fixtures_dir}/config/${config}.json" + [ -f "${config_source}" ] || { + echo "Config '${config_source}' does not exist" + return 1 + } + mkdir -p "${das_config_dir}" - + + _ensure_config_path_is_file || return 1 + cp -f "${config_source}" "${das_config_file}" - + chmod 644 "${das_config_file}" set_env_config_path "${das_config_file}" diff --git a/das-cli/tests/integration/test_das_peer.bats b/das-cli/tests/integration/test_das_peer.bats index 78dcaee8..f45cdaa5 100644 --- a/das-cli/tests/integration/test_das_peer.bats +++ b/das-cli/tests/integration/test_das_peer.bats @@ -4,6 +4,7 @@ load 'libs/bats-support/load' load 'libs/bats-assert/load' load 'libs/utils' load 'libs/docker' +load 'libs/errors' setup() { use_config "simple" @@ -22,7 +23,7 @@ setup() { for cmd in "${cmds[@]}"; do run das-cli dbms-adapter das-peer $cmd - assert_output "[FileNotFoundError] Configuration file not found in ${das_config_file}. You can run the command \`config set\` to create a configuration file." + assert_output --partial "$FILE_NOT_FOUND_ERROR" done }