Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b013313
refactor(aiops): extract shared chat protocol and runtime design (#499)
singchia Oct 14, 2026
fe15dbd
fix(aiops): unify safe skill and host-file tool catalogs (#498)
singchia Oct 14, 2026
40665b4
fix(aiops): inherit web permissions and revoke stale tools (#499)
singchia Oct 14, 2026
2cd3bda
refactor(aiops): retire legacy loop and unify runtime wiring (#499)
singchia Oct 14, 2026
ad63664
fix(aiops): preserve skill requirements and migrate incident prechecks
singchia Oct 14, 2026
322b35a
fix(aiops): validate tool updates and preserve turn schema snapshots
singchia Oct 14, 2026
be50bab
fix(aiops): snapshot background tools before starting investigations
singchia Oct 14, 2026
0ed33ea
refactor(architecture): enforce domain boundaries and isolate shared …
singchia Oct 16, 2026
70586b5
docs(aiops): track capability acceptance and remaining live checks
singchia Oct 16, 2026
673b2d2
chore(aiops): reconcile unified runtime with latest bootstrap layout
singchia Oct 16, 2026
449d070
test(aiops): include workflow adapters in runtime regression target
singchia Oct 16, 2026
afd8111
fix(aiops): retire legacy approval execution and invalidate stale req…
singchia Oct 16, 2026
781fc1f
docs(aiops): propose isolated v2 and v3 runtime selection
singchia Oct 16, 2026
039bac1
fix(aiops): clarify approval wait timeout outcomes
singchia Oct 16, 2026
cc25f29
docs(aiops): trace v1 history and limit runtime selection to settings
singchia Oct 16, 2026
ee61997
refactor(aiops): isolate release runtimes as v1 v2 and v3
singchia Oct 16, 2026
a038e52
fix(agenttrace): preserve runtime instrumentation scope matching
singchia Oct 16, 2026
8b1c1db
refactor(aiops): route execution through version-independent contracts
singchia Oct 16, 2026
d3a6601
fix(aiops): remove implicit tool execution timeout
singchia Oct 16, 2026
250e5e8
fix(aiops): extend built-in tool execution budgets
singchia Oct 16, 2026
a912e6e
fix(skills): allow five minutes for journal reads
singchia Oct 16, 2026
6f9fc4e
feat(aiops): persist runtime ownership for new sessions
singchia Oct 16, 2026
b138a6b
feat(aiops): bind approvals to their originating runtime
singchia Oct 16, 2026
b855180
feat(aiops): complete v3 dynamic capabilities and reliable search
singchia Oct 17, 2026
45ec9ad
chore(aiops): sync main timeout fixes into v3 runtime
singchia Oct 17, 2026
d9f24e4
feat(aiops): wire dual runtimes and validate dynamic capability lifec…
singchia Oct 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ jobs:
if: steps.changes.outputs.docs_only != 'true'
run: make lint-proto

- name: Architecture boundaries
if: steps.changes.outputs.docs_only != 'true'
run: |
make tools-arch
make arch-lint test-arch-policy

- name: go build
if: steps.changes.outputs.docs_only != 'true'
run: go build ./...
Expand Down
114 changes: 68 additions & 46 deletions .go-arch-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
# - 同一 BC 内部 service 层禁止越过 biz 直接 import 同 BC 的 data 层
# (go-arch-lint v3 支持以独立组件 + deps 表达,见下方 iam_service / manager_service 等)
#
# ADR-005 枢轴备注:iam 下只剩 user 子域(org/membership 已删);data 目录
# 由 mysql/ 重命名为 sqlite/。组件 glob 使用 `**`,无需逐级更新。
# v1.19.0 / schema v3。检查生产代码的 import 边界;测试允许组装真实 fixture。
# deepScan 的实现类型流分析会把构造函数注入判为反向依赖;项目允许
# 消费方接口 + cmd 装配,因此不启用该模式,禁止 import 的规则仍完整执行。

version: 3
workdir: .

allow:
depOnAnyVendor: true
deepScan: false

components:
iam_service: { in: internal/iam/service/** }
iam_biz: { in: internal/iam/biz/** }
Expand All @@ -28,81 +33,98 @@ components:

edgeagent_service: { in: internal/edgeagent/service/** }
edgeagent_biz: { in: internal/edgeagent/biz/** }
edgeagent_data: { in: internal/edgeagent/data/** }
edgeagent_model: { in: internal/edgeagent/model/** }

observability_preview: { in: scripts/agent-observability/** }
test_harness: { in: tests/** }
shared_skill: { in: internal/skill/** }
edgeagent_runtime:
in:
- internal/edgeagent/bash/**
- internal/edgeagent/cmdpolicy/**
- internal/edgeagent/collector/**
- internal/edgeagent/config/**
- internal/edgeagent/dpapi/**
- internal/edgeagent/enrollment/**
- internal/edgeagent/edgedirs/**
- internal/edgeagent/host_files/**
- internal/edgeagent/install/**
- internal/edgeagent/k8s/**
- internal/edgeagent/operator/**
- internal/edgeagent/packetcapture/**
- internal/edgeagent/plugins/**
- internal/edgeagent/restart_service/**
- internal/edgeagent/skill/**
- internal/edgeagent/streamrouter/**
- internal/edgeagent/supervisorhealth/**
- internal/edgeagent/upgradebundle/**
- internal/edgeagent/upgrademachine/**
- internal/edgeagent/webshell/**

shared_pkg: { in: internal/pkg/** }
api: { in: api/** }
cmd: { in: cmd/** }
cmd_manager: { in: cmd/ongrid/** }
cmd_edge: { in: [cmd/ongrid-edge/**, cmd/ongrid-edge-supervisor/**] }

# 允许依赖的正向清单(未列出 = 禁止)
deps:
observability_preview:
mayDependOn: [manager_biz, manager_server, shared_pkg]
test_harness:
anyProjectDeps: true
# ---------------- iam BC ----------------
iam_server:
mayDependOn: [iam_service, iam_biz, iam_model, shared_pkg, api]
mayDependOn: [iam_server, iam_service, iam_biz, iam_model, shared_pkg, api]
iam_service:
# 关键:service 不得直接依赖 iam_data(必须走 biz)
mayDependOn: [iam_biz, iam_model, shared_pkg, api]
mayDependOn: [iam_service, iam_biz, iam_model, shared_pkg, api]
iam_biz:
mayDependOn: [iam_model, shared_pkg]
iam_data:
mayDependOn: [iam_biz, iam_model, shared_pkg]
iam_data:
mayDependOn: [iam_data, iam_biz, iam_model, shared_pkg]
iam_model:
mayDependOn: [shared_pkg]
mayDependOn: [iam_model, shared_pkg]

# ---------------- manager BC ----------------
manager_server:
mayDependOn: [manager_service, manager_biz, manager_model, shared_pkg, api]
mayDependOn: [manager_server, manager_service, manager_biz, manager_model, shared_pkg, api]
manager_service:
mayDependOn: [manager_biz, manager_model, shared_pkg, api]
mayDependOn: [manager_service, manager_biz, manager_model, shared_pkg, shared_skill, api]
manager_biz:
mayDependOn: [manager_model, shared_pkg]
mayDependOn: [manager_biz, manager_model, shared_pkg, shared_skill]
manager_data:
mayDependOn: [manager_biz, manager_model, shared_pkg]
mayDependOn: [manager_data, manager_biz, manager_model, shared_pkg]
manager_model:
mayDependOn: [shared_pkg]
mayDependOn: [manager_model, shared_pkg]

# ---------------- edgeagent BC ----------------
edgeagent_service:
mayDependOn: [edgeagent_biz, edgeagent_model, shared_pkg, api]
mayDependOn: [edgeagent_service, edgeagent_biz, edgeagent_model, shared_pkg, api]
edgeagent_biz:
mayDependOn: [edgeagent_model, shared_pkg]
edgeagent_data:
mayDependOn: [edgeagent_biz, edgeagent_model, shared_pkg]
mayDependOn: [edgeagent_biz, edgeagent_model, edgeagent_runtime, shared_skill, shared_pkg]
edgeagent_model:
mayDependOn: [shared_pkg]
mayDependOn: [edgeagent_model, shared_pkg]

edgeagent_runtime:
mayDependOn: [edgeagent_runtime, edgeagent_biz, edgeagent_model, shared_pkg, shared_skill, api]
shared_skill:
mayDependOn: [shared_skill, shared_pkg]

# ---------------- 共享 ----------------
shared_pkg:
# 不得依赖任何 BC(业务无关)
mayDependOn: []
mayDependOn: [shared_pkg]
anyVendorDeps: true
api:
mayDependOn: []
anyVendorDeps: true

# ---------------- 装配层 ----------------
# cmd/ongrid 装配 iam + manager,cmd/ongrid-edge 装配 edgeagent;
# go-arch-lint v3 无"按子目录分 cmd"的原生表达,这里合并授权,
# 由人工 review 与 CODEOWNERS 把住"cmd/ongrid-edge 不 import iam/manager"。
cmd:
mayDependOn:
- iam_server
- iam_service
- iam_biz
- iam_data
- iam_model
- manager_server
- manager_service
- manager_biz
- manager_data
- manager_model
- edgeagent_service
- edgeagent_biz
- edgeagent_data
- edgeagent_model
- shared_pkg
- api
# Manager 与 Edge 分别装配,禁止两个入口互相 import 对方业务域。
cmd_manager:
mayDependOn: [cmd_manager, iam_server, iam_service, iam_biz, iam_data, iam_model, manager_server, manager_service, manager_biz, manager_data, manager_model, shared_pkg, shared_skill, api]
cmd_edge:
mayDependOn: [cmd_edge, edgeagent_service, edgeagent_biz, edgeagent_model, edgeagent_runtime, shared_pkg, shared_skill, api]

# 注:go-arch-lint 的 schema 字段(version / components / deps)按 v3
# 主流文档书写;若 CI 报 schema 错,按实际版本微调字段名即可。
commonComponents: []
excludeFiles: []
# 包内测试允许组装真实存储/跨域 fixture;生产文件仍严格执行分层。
excludeFiles:
- "_test\\.go$"
18 changes: 15 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,17 @@ test-e2e-live: ## E2E live mode(用 tests/e2e/secrets.local.env 打通真实
lint: ## 运行 golangci-lint
golangci-lint run

arch-lint: ## 运行 go-arch-lint(校验 BC 边界)
@command -v go-arch-lint >/dev/null 2>&1 || { echo "go-arch-lint not installed; skipping"; exit 0; }
go-arch-lint check
ARCH_LINT ?= go-arch-lint
.PHONY: tools-arch test-arch-policy
tools-arch: ## 安装固定版本的架构检查工具
go install github.com/fe3dback/go-arch-lint@v1.19.0

arch-lint: ## 校验生产代码 BC 边界(缺少工具时明确失败)
@command -v $(ARCH_LINT) >/dev/null 2>&1 || { echo "go-arch-lint not installed; run make tools-arch" >&2; exit 1; }
$(ARCH_LINT) check

test-arch-policy: ## 验证架构规则确实拒绝跨域和跨层 import
python3 scripts/test-arch-policy.py --binary $(ARCH_LINT)

# ----------------------------------------------------------------------------
# proto
Expand Down Expand Up @@ -903,3 +911,7 @@ test-web-ci-platform: ## Run the serial platform frontend CI tests (requires npm
src/components/ChatLayout.test.tsx src/components/Sidebar.test.tsx \
src/components/icons/Provider.test.tsx src/pages/kubernetes/edgeAttachments.test.ts \
src/pages/kubernetes/registryCommands.test.ts

.PHONY: test-agent-runtime
test-agent-runtime: ## 统一 Agent runtime 回归(tools 依赖 Linux cmdpolicy)
go test -race ./internal/manager/biz/aiops/... ./internal/manager/biz/approval ./internal/manager/service/aiops ./internal/manager/server/aiops ./internal/manager/biz/imbridge ./internal/manager/service/imbridge ./internal/manager/service/flow ./internal/manager/biz/report ./internal/manager/biz/alert/investigator ./internal/manager/biz/marketplace ./internal/manager/biz/agenttrace ./internal/manager/service/skill ./internal/skill/... ./cmd/ongrid
2 changes: 2 additions & 0 deletions api/manager/aiops/v1/aiops.proto
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ message ChatSession {
string provider = 8 [json_name = "provider"];
string model = 9 [json_name = "model"];
APMSourceScope apm_source = 10 [json_name = "apm_source"];
// Server-assigned execution version. Empty for unclassified historical sessions.
string runtime_version = 11 [json_name = "runtime_version"];
}

// ToolCall 一次 LLM 发起的工具调用(OpenAI tool_calls 的投影)。
Expand Down
26 changes: 26 additions & 0 deletions api/manager/approval/v1/approval.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
syntax = "proto3";
package ongrid.manager.approval.v1;
import "google/protobuf/timestamp.proto";
option go_package = "github.com/ongridio/ongrid/api/gen/manager/approval/v1;approvalv1";

// Approval is the read-only record returned by the existing approval inbox.
// Runtime ownership is assigned by the producer, never by the approver.
message Approval {
string id = 1;
string kind = 2;
string title = 3;
string summary = 4;
string payload = 5;
string source = 6;
string session_id = 7;
string status = 8;
uint64 proposed_by = 9;
optional uint64 approved_by = 10;
optional string reason = 11;
optional string result = 12;
google.protobuf.Timestamp created_at = 13;
google.protobuf.Timestamp decided_at = 14;
google.protobuf.Timestamp executed_at = 15;
// Empty for historical or non-runtime proposals; never inferred at approval.
string runtime_version = 16;
}
31 changes: 31 additions & 0 deletions api/manager/setting/v1/setting.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ package ongrid.manager.setting.v1;
option go_package = "github.com/ongridio/ongrid/api/gen/manager/setting/v1;settingv1";

// SettingService 管理管理员可编辑的运行时配置。
// agent.runtime_version accepts "release" (follow this release default) or
// "v3" or "v2" (pin new sessions). v1 is no longer supported and is rejected.
// Existing sessions retain their runtime; legacy unversioned sessions stay v3.
// Read/write via the existing system-settings category/key API.
// Legacy platform.auto_apm_enabled values are retained but no longer affect discovery.
service SettingService {
// ApplyBuiltInObservabilityLimits saves storage limits and recreates only
Expand All @@ -28,6 +32,9 @@ service SettingService {
// ValidateWebSearchConfiguration 使用未落库的 provider 配置执行最小查询。
// HTTP 实现:POST /api/v1/integrations/websearch/test。
rpc ValidateWebSearchConfiguration(ValidateWebSearchConfigurationRequest) returns (ValidateWebSearchConfigurationResponse);
// POST /api/v1/integrations/websearch/validate-and-save; admin only.
// Validates primary and backup, then atomically saves the complete draft.
rpc ValidateAndSaveWebSearchConfiguration(ValidateAndSaveWebSearchConfigurationRequest) returns (ValidateAndSaveWebSearchConfigurationResponse);
// ValidateLLMConfiguration 使用未落库的草稿配置发起最小模型请求,
// 返回可机器识别的失败原因。HTTP 实现:
// POST /api/v1/integrations/llm/test。
Expand Down Expand Up @@ -96,11 +103,18 @@ message ValidateTempoConfigurationResponse {
string status = 1 [json_name = "status"];
}

// websearch settings also accept fallback_provider (empty disables fallback),
// searxng_engines (comma-separated names), request_timeout_seconds (2..60),
// and total_timeout_seconds (5..120). Fallback requires explicit admin selection.
message ValidateWebSearchConfigurationRequest {
string provider = 1 [json_name = "provider"];
string searxng_url = 2 [json_name = "searxng_url"];
string tavily_api_key = 3 [json_name = "tavily_api_key"];
string brave_api_key = 4 [json_name = "brave_api_key"];
string fallback_provider = 5 [json_name = "fallback_provider"];
string searxng_engines = 6 [json_name = "searxng_engines"];
string request_timeout_seconds = 7 [json_name = "request_timeout_seconds"];
string total_timeout_seconds = 8 [json_name = "total_timeout_seconds"];
}

message ValidateWebSearchConfigurationResponse {
Expand All @@ -109,6 +123,23 @@ message ValidateWebSearchConfigurationResponse {
string sample = 3 [json_name = "sample"];
}

message ValidateAndSaveWebSearchConfigurationRequest {
string provider = 1 [json_name = "provider"];
string searxng_url = 2 [json_name = "searxng_url"];
string tavily_api_key = 3 [json_name = "tavily_api_key"];
string brave_api_key = 4 [json_name = "brave_api_key"];
string fallback_provider = 5 [json_name = "fallback_provider"];
string searxng_engines = 6 [json_name = "searxng_engines"];
string request_timeout_seconds = 7 [json_name = "request_timeout_seconds"];
string total_timeout_seconds = 8 [json_name = "total_timeout_seconds"];
}

message ValidateAndSaveWebSearchConfigurationResponse {
string status = 1 [json_name = "status"];
string provider = 2 [json_name = "provider"];
string sample = 3 [json_name = "sample"];
}

message ValidateLLMConfigurationRequest {
// provider 是稳定提供商 ID:openai / anthropic / zhipu / gemini /
// deepseek / kimi / custom。
Expand Down
Loading
Loading