Skip to content

Commit 15f579b

Browse files
committed
feat(agents,templates): synchronize multi-slot agent models and harden industry template integration
- Establish model_config, model_config2, and model_config3 as authoritative source of truth for slots 1, 2, and 3 - Serialize full multi-slot configs and active slot in server-rs AgentResponse - Prioritize modelConfig in domain normalizers and buildAgentFormState with friendly name resolution - Bind Node_Model_Slots and ModelSlotConfig to authoritative slot configs with custom fallback options - Preserve hyperparameters on partial slot updates in Ops_Dashboard and Org_Chart - Implement 11 industry template improvements (structured receipts, SHA-256 lockfile checks, rollback/uninstall, caching catalog proxy)
1 parent 6b1b77f commit 15f579b

20 files changed

Lines changed: 1486 additions & 254 deletions

docs/API_REFERENCE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ Sec-WebSocket-Protocol: bearer.<NEURAL_TOKEN>
107107
| `POST` | `/v1/engine/pre-pr` | `routes::deploy::trigger_pre_pr` | Protected |
108108
| `POST` | `/v1/engine/shutdown` | `routes::engine_control::shutdown_engine` | Protected |
109109
| `POST` | `/v1/engine/speak` | `routes::audio::text_to_speech` | Protected |
110+
| `GET` | `/v1/engine/templates/catalog` | `routes::templates::get_template_catalog` | Protected |
110111
| `POST` | `/v1/engine/templates/install` | `routes::templates::install_template` | Protected |
112+
| `GET` | `/v1/engine/templates/installed` | `routes::templates::list_installed_templates` | Protected |
113+
| `DELETE` | `/v1/engine/templates/{id}` | `routes::templates::uninstall_template` | Protected |
111114
| `POST` | `/v1/engine/transcribe` | `routes::audio::transcribe_audio` | Protected |
112115
| `GET` | `/v1/engine/ws` | `routes::ws::ws_handler` | Protected (WS Subprotocol) |
113116

docs/openapi.yaml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,29 @@ paths:
16821682
application/json:
16831683
schema:
16841684
$ref: '#/components/schemas/ProblemDetails'
1685+
/v1/engine/templates/catalog:
1686+
get:
1687+
tags: [engine]
1688+
summary: "Get template catalog"
1689+
responses:
1690+
"200":
1691+
description: Success
1692+
content:
1693+
application/json:
1694+
schema:
1695+
$ref: '#/components/schemas/GenericResponse'
1696+
"401":
1697+
description: Unauthorized
1698+
content:
1699+
application/json:
1700+
schema:
1701+
$ref: '#/components/schemas/ProblemDetails'
1702+
"403":
1703+
description: Forbidden
1704+
content:
1705+
application/json:
1706+
schema:
1707+
$ref: '#/components/schemas/ProblemDetails'
16851708
/v1/engine/templates/install:
16861709
post:
16871710
tags: [engine]
@@ -1711,6 +1734,63 @@ paths:
17111734
application/json:
17121735
schema:
17131736
$ref: '#/components/schemas/ProblemDetails'
1737+
/v1/engine/templates/installed:
1738+
get:
1739+
tags: [engine]
1740+
summary: "List installed templates"
1741+
responses:
1742+
"200":
1743+
description: Success
1744+
content:
1745+
application/json:
1746+
schema:
1747+
$ref: '#/components/schemas/GenericResponse'
1748+
"401":
1749+
description: Unauthorized
1750+
content:
1751+
application/json:
1752+
schema:
1753+
$ref: '#/components/schemas/ProblemDetails'
1754+
"403":
1755+
description: Forbidden
1756+
content:
1757+
application/json:
1758+
schema:
1759+
$ref: '#/components/schemas/ProblemDetails'
1760+
/v1/engine/templates/{id}:
1761+
delete:
1762+
tags: [engine]
1763+
summary: "Uninstall template"
1764+
parameters:
1765+
- name: id
1766+
in: path
1767+
required: true
1768+
schema: { type: string }
1769+
responses:
1770+
"200":
1771+
description: Success
1772+
content:
1773+
application/json:
1774+
schema:
1775+
$ref: '#/components/schemas/GenericResponse'
1776+
"401":
1777+
description: Unauthorized
1778+
content:
1779+
application/json:
1780+
schema:
1781+
$ref: '#/components/schemas/ProblemDetails'
1782+
"403":
1783+
description: Forbidden
1784+
content:
1785+
application/json:
1786+
schema:
1787+
$ref: '#/components/schemas/ProblemDetails'
1788+
"404":
1789+
description: Not Found
1790+
content:
1791+
application/json:
1792+
schema:
1793+
$ref: '#/components/schemas/ProblemDetails'
17141794
/v1/engine/transcribe:
17151795
post:
17161796
tags: [engine]

server-rs/src/router.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,18 @@ fn build_engine_protected_routes(app_state: Arc<AppState>) -> Router<Arc<AppStat
470470
"/engine/templates/install",
471471
post(routes::templates::install_template),
472472
)
473+
.route(
474+
"/engine/templates/installed",
475+
get(routes::templates::list_installed_templates),
476+
)
477+
.route(
478+
"/engine/templates/catalog",
479+
get(routes::templates::get_template_catalog),
480+
)
481+
.route(
482+
"/engine/templates/{id}",
483+
axum::routing::delete(routes::templates::uninstall_template),
484+
)
473485
.route("/api/pull", post(routes::model_manager::ollama_proxy_pull))
474486
// --- MCP Bridge Endpoints ---
475487
.route("/mcp/sse", get(crate::agent::mcp::transport::mcp_sse_handler))

server-rs/src/routes/agent.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,32 @@ pub struct AgentResponse {
4646
pub department: String,
4747
pub status: String,
4848
pub model: String,
49+
#[serde(skip_serializing_if = "Option::is_none")]
50+
pub model_id: Option<String>,
51+
pub model_config: crate::agent::types::ModelConfig,
52+
#[serde(skip_serializing_if = "Option::is_none")]
53+
pub model_2: Option<String>,
54+
#[serde(skip_serializing_if = "Option::is_none")]
55+
pub model_config2: Option<crate::agent::types::ModelConfig>,
56+
#[serde(skip_serializing_if = "Option::is_none")]
57+
pub model_3: Option<String>,
58+
#[serde(skip_serializing_if = "Option::is_none")]
59+
pub model_config3: Option<crate::agent::types::ModelConfig>,
60+
#[serde(skip_serializing_if = "Option::is_none")]
61+
pub active_model_slot: Option<i32>,
4962
pub provider: String,
5063
pub budget_usd: f64,
5164
pub cost_usd: f64,
5265
pub is_healthy: bool,
5366
pub is_bankrupt: bool,
5467
pub skills: Vec<String>,
68+
pub workflows: Vec<String>,
69+
pub mcp_tools: Vec<String>,
70+
#[serde(skip_serializing_if = "Option::is_none")]
71+
pub theme_color: Option<String>,
72+
pub requires_oversight: bool,
73+
#[serde(skip_serializing_if = "Option::is_none")]
74+
pub current_task: Option<String>,
5575
pub created_at: Option<chrono::DateTime<chrono::Utc>>,
5676
pub version: u32,
5777
}
@@ -71,12 +91,24 @@ impl From<&EngineAgent> for AgentResponse {
7191
department: agent.identity.department.clone(),
7292
status: agent.health.status.clone(),
7393
model: model_name,
94+
model_id: agent.models.model_id.clone(),
95+
model_config: agent.models.model.clone(),
96+
model_2: agent.models.model_2.clone(),
97+
model_config2: agent.models.model_config2.clone(),
98+
model_3: agent.models.model_3.clone(),
99+
model_config3: agent.models.model_config3.clone(),
100+
active_model_slot: agent.models.active_model_slot,
74101
provider: agent.models.model.provider.to_string(),
75102
budget_usd: agent.economics.budget_usd,
76103
cost_usd: agent.economics.cost_usd,
77104
is_healthy: agent.health.failure_count < 5,
78105
is_bankrupt: agent.economics.cost_usd >= agent.economics.budget_usd && agent.economics.budget_usd > 0.0,
79106
skills: agent.capabilities.skills.clone(),
107+
workflows: agent.capabilities.workflows.clone(),
108+
mcp_tools: agent.capabilities.mcp_tools.clone(),
109+
theme_color: agent.identity.theme_color.clone(),
110+
requires_oversight: agent.requires_oversight,
111+
current_task: agent.state.current_task.clone(),
80112
created_at: agent.created_at,
81113
version: agent.version,
82114
}

0 commit comments

Comments
 (0)