Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b504821e3 | ||
|
|
e2b9cc6849 | ||
|
|
4f4c95ffce | ||
|
|
edd3bd239e | ||
|
|
7a1e862a03 | ||
|
|
dc0ac18aea | ||
|
|
9e3dbdf146 | ||
|
|
87b1a5357c |
@@ -5,6 +5,8 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from orchestrator.action_monitor import ActionMonitor
|
||||||
|
|
||||||
ROOT = Path(os.getenv('AIOS_GITOPS_ROOT', '/data/aios-gitops'))
|
ROOT = Path(os.getenv('AIOS_GITOPS_ROOT', '/data/aios-gitops'))
|
||||||
WS = Path(os.getenv('AIOS_GITOPS_WORKSPACE', str(ROOT / 'workspace')))
|
WS = Path(os.getenv('AIOS_GITOPS_WORKSPACE', str(ROOT / 'workspace')))
|
||||||
SECRETS = Path(os.getenv('AIOS_GITOPS_SECRETS_DIR', str(ROOT / 'runtime' / 'secrets')))
|
SECRETS = Path(os.getenv('AIOS_GITOPS_SECRETS_DIR', str(ROOT / 'runtime' / 'secrets')))
|
||||||
@@ -13,6 +15,8 @@ HOST = os.getenv('AIOS_GITOPS_HOST', '127.0.0.1')
|
|||||||
PORT = int(os.getenv('AIOS_GITOPS_PORT', '18890'))
|
PORT = int(os.getenv('AIOS_GITOPS_PORT', '18890'))
|
||||||
OPENAPI = WS / 'docs' / 'gitops' / 'openapi-chatgpt-actions.yaml'
|
OPENAPI = WS / 'docs' / 'gitops' / 'openapi-chatgpt-actions.yaml'
|
||||||
BARE_REPO = Path(os.getenv('AIOS_GITOPS_BARE_REPO', str(ROOT / 'runtime' / 'gitea-bin' / 'data' / 'repositories' / 'aios' / 'aios-v23.git')))
|
BARE_REPO = Path(os.getenv('AIOS_GITOPS_BARE_REPO', str(ROOT / 'runtime' / 'gitea-bin' / 'data' / 'repositories' / 'aios' / 'aios-v23.git')))
|
||||||
|
monitor = ActionMonitor()
|
||||||
|
|
||||||
BASE_MODELS = [
|
BASE_MODELS = [
|
||||||
{'id':'base.deepseekv4-flash','provider':'one-api','model':'deepseekv4-flash','display_name':'DeepSeek V4 Flash','scope':'global'},
|
{'id':'base.deepseekv4-flash','provider':'one-api','model':'deepseekv4-flash','display_name':'DeepSeek V4 Flash','scope':'global'},
|
||||||
{'id':'base.qwen3.6-35b','provider':'one-api','model':'qwen3.6-35b','display_name':'Qwen 3.6 35B','scope':'global'},
|
{'id':'base.qwen3.6-35b','provider':'one-api','model':'qwen3.6-35b','display_name':'Qwen 3.6 35B','scope':'global'},
|
||||||
@@ -191,8 +195,12 @@ class H(BaseHTTPRequestHandler):
|
|||||||
if path in ('/api/run','/run'):
|
if path in ('/api/run','/run'):
|
||||||
svc=subprocess.run(['systemctl','is-active','aios-gitops-model-api'], text=True, capture_output=True)
|
svc=subprocess.run(['systemctl','is-active','aios-gitops-model-api'], text=True, capture_output=True)
|
||||||
return self.sendj({'service':'aios-gitops-model-api','status':svc.stdout.strip() or svc.stderr.strip(),'workspace_branch':sh(['rev-parse','--abbrev-ref','HEAD'])['stdout']})
|
return self.sendj({'service':'aios-gitops-model-api','status':svc.stdout.strip() or svc.stderr.strip(),'workspace_branch':sh(['rev-parse','--abbrev-ref','HEAD'])['stdout']})
|
||||||
|
if path in ('/api/action-monitor','/action-monitor'):
|
||||||
|
return self.sendj({'events':[{"event_id":e.event_id,"action":e.action,"error":e.error,"context":e.context,"created_at":e.created_at} for e in monitor.list_events()],'latest':monitor.latest()})
|
||||||
return self.sendj({'error':'not_found','path':path},404)
|
return self.sendj({'error':'not_found','path':path},404)
|
||||||
except Exception as e: return self.sendj({'error':str(e)},500)
|
except Exception as e:
|
||||||
|
monitor.record_failure('do_GET', str(e), {'path':path})
|
||||||
|
return self.sendj({'error':str(e)},500)
|
||||||
def do_PUT(self):
|
def do_PUT(self):
|
||||||
path=urllib.parse.urlparse(self.path).path.rstrip('/'); data=self.body()
|
path=urllib.parse.urlparse(self.path).path.rstrip('/'); data=self.body()
|
||||||
if path == '/api/model-priority': return self.model_priority(data)
|
if path == '/api/model-priority': return self.model_priority(data)
|
||||||
@@ -210,7 +218,9 @@ class H(BaseHTTPRequestHandler):
|
|||||||
if path == '/api/model-priority': return self.model_priority(data)
|
if path == '/api/model-priority': return self.model_priority(data)
|
||||||
if path == '/api/nl': return self.nl(data)
|
if path == '/api/nl': return self.nl(data)
|
||||||
return self.sendj({'error':'not_found','path':path},404)
|
return self.sendj({'error':'not_found','path':path},404)
|
||||||
except Exception as e: return self.sendj({'error':str(e)},500)
|
except Exception as e:
|
||||||
|
monitor.record_failure('do_POST', str(e), {'path':path})
|
||||||
|
return self.sendj({'error':str(e)},500)
|
||||||
def branch(self,data):
|
def branch(self,data):
|
||||||
a=self.need('branch:create');
|
a=self.need('branch:create');
|
||||||
if not a: return
|
if not a: return
|
||||||
@@ -234,6 +244,9 @@ class H(BaseHTTPRequestHandler):
|
|||||||
if not a: return
|
if not a: return
|
||||||
ver=data.get('version') or data.get('tag')
|
ver=data.get('version') or data.get('tag')
|
||||||
if not re.match(r'^V\d+R\d+C\d+(-[A-Za-z0-9_.-]+)?$', ver or ''): return self.sendj({'error':'version must match VxRxCx'},400)
|
if not re.match(r'^V\d+R\d+C\d+(-[A-Za-z0-9_.-]+)?$', ver or ''): return self.sendj({'error':'version must match VxRxCx'},400)
|
||||||
|
if data.get('confirm') != True:
|
||||||
|
self.sendj({'status':'confirm_required','operation':'tag','hint':'This operation creates a Git tag. Confirm to proceed.','x-openai-isConsequential':True}, 428)
|
||||||
|
return
|
||||||
if a['role'] != 'owner' or not data.get('execute'):
|
if a['role'] != 'owner' or not data.get('execute'):
|
||||||
b=checkout(data.get('branch') or f'request/tag-{safe(ver)}', 'main', True); req={'version':ver,'requested_by':a['account'],'approval_required':True,'created_at':now()}; r=write_json(f'baseline/tag_requests/{safe(ver)}.json', req); c=commit([r], f'chore(chatgpt): request tag {ver}'); return self.sendj({'status':'approval_required','branch':b,'commit':c})
|
b=checkout(data.get('branch') or f'request/tag-{safe(ver)}', 'main', True); req={'version':ver,'requested_by':a['account'],'approval_required':True,'created_at':now()}; r=write_json(f'baseline/tag_requests/{safe(ver)}.json', req); c=commit([r], f'chore(chatgpt): request tag {ver}'); return self.sendj({'status':'approval_required','branch':b,'commit':c})
|
||||||
out=sh(['tag','-a',ver,'-m',data.get('message') or f'release {ver}'], True); self.sendj({'status':'tagged','version':ver,'git':out,'sync':sync_tag(ver)})
|
out=sh(['tag','-a',ver,'-m',data.get('message') or f'release {ver}'], True); self.sendj({'status':'tagged','version':ver,'git':out,'sync':sync_tag(ver)})
|
||||||
@@ -254,10 +267,16 @@ class H(BaseHTTPRequestHandler):
|
|||||||
if not secret_ref: return self.sendj({'error':'api_key_secret_ref or api_key required'},400)
|
if not secret_ref: return self.sendj({'error':'api_key_secret_ref or api_key required'},400)
|
||||||
mid=data.get('model_id') or f'custom.{owner}.{hashlib.sha1((prov+base+name).encode()).hexdigest()[:10]}'; b=checkout(data.get('branch') or f'patch/model-{safe(mid)}','main',True)
|
mid=data.get('model_id') or f'custom.{owner}.{hashlib.sha1((prov+base+name).encode()).hexdigest()[:10]}'; b=checkout(data.get('branch') or f'patch/model-{safe(mid)}','main',True)
|
||||||
doc=sanitize({k:v for k,v in data.items() if k!='api_key'}); doc.update({'model_id':mid,'provider_name':prov,'base_url':base,'model_name':name,'api_key_secret_ref':secret_ref,'created_by':a['account'],'created_at':now()})
|
doc=sanitize({k:v for k,v in data.items() if k!='api_key'}); doc.update({'model_id':mid,'provider_name':prov,'base_url':base,'model_name':name,'api_key_secret_ref':secret_ref,'created_by':a['account'],'created_at':now()})
|
||||||
|
if data.get('confirm') != True:
|
||||||
|
self.sendj({'status':'confirm_required','operation':'model','hint':'This operation registers a new model. Confirm to proceed.','x-openai-isConsequential':True}, 428)
|
||||||
|
return
|
||||||
r=write_json(f'config/model_registry/chatgpt/{safe(mid)}.json', doc); c=commit([r], data.get('message') or f'chore(chatgpt): register model {name}'); audit(a['account'],'model',mid,doc); self.sendj({'status':'model_registered','branch':b,'model_id':mid,'secret_ref':secret_ref,'commit':c})
|
r=write_json(f'config/model_registry/chatgpt/{safe(mid)}.json', doc); c=commit([r], data.get('message') or f'chore(chatgpt): register model {name}'); audit(a['account'],'model',mid,doc); self.sendj({'status':'model_registered','branch':b,'model_id':mid,'secret_ref':secret_ref,'commit':c})
|
||||||
def model_priority(self,data):
|
def model_priority(self,data):
|
||||||
a=self.need('model:priority');
|
a=self.need('model:priority');
|
||||||
if not a: return
|
if not a: return
|
||||||
|
if data.get('confirm') != True:
|
||||||
|
self.sendj({'status':'confirm_required','operation':'model-priority','hint':'This operation updates model priority. Confirm to proceed.','x-openai-isConsequential':True}, 428)
|
||||||
|
return
|
||||||
user=safe(data.get('username') or a['account']); b=checkout(data.get('branch') or f'patch/model-priority-{user}', 'main', True); doc={'username':user,'items':data.get('items') or data.get('priority') or [],'updated_by':a['account'],'updated_at':now()}; r=write_json(f'config/model_priority/{user}.json', doc); c=commit([r], data.get('message') or f'chore(chatgpt): update model priority {user}'); audit(a['account'],'model-priority',user,doc); self.sendj({'status':'updated','branch':b,'priority':doc,'commit':c})
|
user=safe(data.get('username') or a['account']); b=checkout(data.get('branch') or f'patch/model-priority-{user}', 'main', True); doc={'username':user,'items':data.get('items') or data.get('priority') or [],'updated_by':a['account'],'updated_at':now()}; r=write_json(f'config/model_priority/{user}.json', doc); c=commit([r], data.get('message') or f'chore(chatgpt): update model priority {user}'); audit(a['account'],'model-priority',user,doc); self.sendj({'status':'updated','branch':b,'priority':doc,'commit':c})
|
||||||
def nl(self,data):
|
def nl(self,data):
|
||||||
a=self.need('nl:plan');
|
a=self.need('nl:plan');
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
# Instruction
|
||||||
|
|
||||||
|
ID: windows_codex_app/v1r2c2-system-supervisor-recovery-v1
|
||||||
|
|
||||||
|
Version: v1
|
||||||
|
|
||||||
|
Target Agent: Windows Codex App
|
||||||
|
|
||||||
|
Purpose: Operate as the AIOS escape recovery supervisor when OpenClaw and Hermes cannot clear long-running system blockers.
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
Continuously supervise AIOS self-optimization health across OpenClaw, Hermes,
|
||||||
|
GitOps, Gitea, Actions, permissions, branch state, commit flow, and owner
|
||||||
|
notification paths. Intervene only when the system is blocked, repeatedly
|
||||||
|
failing, or unattended, and keep all durable changes synchronized through
|
||||||
|
GitOps.
|
||||||
|
|
||||||
|
## Role Boundaries
|
||||||
|
|
||||||
|
- OpenClaw is the primary execution agent for daily tasks, automatic fixes,
|
||||||
|
patch creation, and GitOps operations.
|
||||||
|
- Hermes is the backup analysis and repair agent for architecture review,
|
||||||
|
OpenClaw failure handoff, and complex diagnosis.
|
||||||
|
- Windows Codex App is the escape recovery agent for dual-agent failure,
|
||||||
|
permission failures, Gitea/GitOps breakage, and system-level recovery.
|
||||||
|
- Windows Codex App is not a credential owner and must not become the durable
|
||||||
|
source of truth when remote OpenClaw or Hermes state can be verified.
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
1. Lock the target host, workspace, branch, and current user.
|
||||||
|
2. Read the newest GitOps instruction artifact before acting.
|
||||||
|
3. Spawn independent sub-agents for architecture, exploration,
|
||||||
|
implementation safety, validation, and reporting when the task is complex.
|
||||||
|
4. Use `gpt-5.3-codex-spark` for sub-agents by default. If Spark is exhausted
|
||||||
|
and an owner-approved fallback is in force, record the quota failure and use
|
||||||
|
the approved fallback model for that run only.
|
||||||
|
5. Collect live evidence from remote services instead of relying on stale local
|
||||||
|
state or old summaries.
|
||||||
|
6. Check OpenClaw task state, audit output, channel health, and gateway status.
|
||||||
|
7. Check Hermes router, executor, and memory gateway service state.
|
||||||
|
8. Check GitOps branch, sync state, uncommitted changes, stale artifacts,
|
||||||
|
permissions, and commit/push health without printing remote credentials.
|
||||||
|
9. Check Gitea and Actions endpoints using read-only probes unless owner
|
||||||
|
approval explicitly authorizes a write smoke test.
|
||||||
|
10. Check owner notification health through configured safe probes. Do not
|
||||||
|
claim WeChat end-to-end success without a current verified ingress or
|
||||||
|
whitelisted synthetic test.
|
||||||
|
11. Apply only minimal, reversible repairs that are explicitly allowed below.
|
||||||
|
12. Write a GitOps report for any live-state change, even when no source file
|
||||||
|
changed.
|
||||||
|
13. Commit and push only to the approved patch branch. Never force push.
|
||||||
|
|
||||||
|
## Intervention Conditions
|
||||||
|
|
||||||
|
Intervene when any of these conditions are met:
|
||||||
|
|
||||||
|
- The same error fails three or more consecutive times.
|
||||||
|
- A task has no progress for more than 30 minutes.
|
||||||
|
- OpenClaw cannot resolve the blocker.
|
||||||
|
- Hermes cannot resolve the blocker.
|
||||||
|
- GitOps Action writes, commits, branch sync, or permissions keep failing.
|
||||||
|
|
||||||
|
## Allowed Automatic Repairs
|
||||||
|
|
||||||
|
- GitOps workspace permission repair within the approved workspace.
|
||||||
|
- Group and setgid repair for collaborative GitOps directories.
|
||||||
|
- Branch metadata permission repair for the active patch branch.
|
||||||
|
- Stale temporary artifact cleanup inside an approved whitelist.
|
||||||
|
- Test/report output permission repair when a service is blocked only by file
|
||||||
|
ownership or mode.
|
||||||
|
- Resetting failed oneshot service state after the underlying blocker is fixed.
|
||||||
|
- Running non-destructive validation commands.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- GitOps only for durable source changes.
|
||||||
|
- No secrets in files, logs, reports, prompts, command output, or commits.
|
||||||
|
- No force push.
|
||||||
|
- No tag creation or deletion.
|
||||||
|
- No direct writes to `main`.
|
||||||
|
- No production switch.
|
||||||
|
- No credential, token, SSH key, cookie, or CI secret modification.
|
||||||
|
- No deletion of baselines, audit records, release artifacts, or production
|
||||||
|
data.
|
||||||
|
- V-level, tag, production, rollback, and owner-visible notification changes
|
||||||
|
require owner approval.
|
||||||
|
- Credential, channel binding, host registration, and durable ownership changes
|
||||||
|
require admin approval.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
Minimum validation evidence:
|
||||||
|
|
||||||
|
- Branch name, HEAD revision, and ahead/behind status.
|
||||||
|
- `git status --short --branch` summary with no unexpected source edits.
|
||||||
|
- OpenClaw task list and audit summary.
|
||||||
|
- OpenClaw channel status or the exact auth/identity blocker preventing it.
|
||||||
|
- Hermes router, executor, and memory gateway service status.
|
||||||
|
- Gitea service status and read-only endpoint health.
|
||||||
|
- Actions schema or endpoint health where available.
|
||||||
|
- Permission probe for every repaired directory.
|
||||||
|
- Service rerun result for every repaired failed service.
|
||||||
|
- Security note confirming no credentials were committed.
|
||||||
|
|
||||||
|
## Return Format
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"active_version": "V1R1C4",
|
"active_version": "V1R2C2",
|
||||||
"active_tag": "V1R1C4",
|
"active_tag": "V1R2C2",
|
||||||
"mode": "gitops-online",
|
"mode": "gitops-online",
|
||||||
"version_policy": "VxRxCx",
|
"version_policy": "VxRxCx",
|
||||||
"update_mode": "git_patch_only",
|
"update_mode": "git_patch_only",
|
||||||
@@ -27,8 +27,8 @@
|
|||||||
"portal_gitops_dashboard": true,
|
"portal_gitops_dashboard": true,
|
||||||
"human_shortlinks_login_required": true
|
"human_shortlinks_login_required": true
|
||||||
},
|
},
|
||||||
"version": "V1R1C4",
|
"version": "V1R2C2",
|
||||||
"baseline_tag": "V1R1C0-baseline-20260706",
|
"baseline_tag": "V1R2C2-baseline",
|
||||||
"source": "AIOS_V1R1C0_MULTIUSER_GITOPS_CUSTOM_LLM_PROD_FULL_DEPLOY_20260706.zip",
|
"source": "AIOS_V1R1C0_MULTIUSER_GITOPS_CUSTOM_LLM_PROD_FULL_DEPLOY_20260706.zip",
|
||||||
"source_package": "AIOS_V1R1C0_MULTIUSER_GITOPS_CUSTOM_LLM_PROD_FULL_DEPLOY_20260706.zip",
|
"source_package": "AIOS_V1R1C0_MULTIUSER_GITOPS_CUSTOM_LLM_PROD_FULL_DEPLOY_20260706.zip",
|
||||||
"zip_update_mode": "deprecated",
|
"zip_update_mode": "deprecated",
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
"/api",
|
"/api",
|
||||||
"/hook"
|
"/hook"
|
||||||
],
|
],
|
||||||
"updated_at": "2026-07-06T11:16:23Z",
|
"updated_at": "2026-07-07T15:40:00Z",
|
||||||
"auth": {
|
"auth": {
|
||||||
"primary_domain": "https://auth.cnnetmkt.top",
|
"primary_domain": "https://auth.cnnetmkt.top",
|
||||||
"backup_domain": "https://auth.h.imruyi.top:8443",
|
"backup_domain": "https://auth.h.imruyi.top:8443",
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
"casdoor_application": "admin/aios-portal",
|
"casdoor_application": "admin/aios-portal",
|
||||||
"backup_domain_role": "standby-only"
|
"backup_domain_role": "standby-only"
|
||||||
},
|
},
|
||||||
"previous_version": "V1R1C3",
|
"previous_version": "V1R2C1",
|
||||||
"codex_gitops": {
|
"codex_gitops": {
|
||||||
"config": "config/codex/gitops-online.json",
|
"config": "config/codex/gitops-online.json",
|
||||||
"token_account": "codex-gitops-bot",
|
"token_account": "codex-gitops-bot",
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "nl-1783382614842-6c6112e8",
|
|
||||||
"text": "自我进化执行主体策略更新:除 Windows Codex App 外,同时增加服务器上的 OpenClaw Agent 与 Hermes Agent 作为执行主体。允许启动多个服务器 Agent 并行执行;默认以服务器上的 Agent 为主,Windows Codex App 作为协同执行主体。困难时刻允许访问 https://chatgpt.com/chat/gpt-6a4ba70a063c8191a89bc2d86a4c7fa0-codex-chartgpt-bridge 求助或交互。分歧时刻允许多个 Agent 投票决策;自定义 GPT 权重为双倍,Windows Codex App 权重为双倍。服务器 Agent 默认参与并行协作。该策略应以 GitOps 可审计方式进入自我进化 agent orchestration proposal,不直接执行 V-level 版本变更,不写入任何凭据。",
|
|
||||||
"intent": "unknown",
|
|
||||||
"action_plan": [],
|
|
||||||
"execute": false,
|
|
||||||
"owner_approval_required": true,
|
|
||||||
"created_by": "gitops-write-bot",
|
|
||||||
"created_at": "2026-07-07T00:03:34Z"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "nl-1783390999250-8627c20c",
|
|
||||||
"text": "基于 V1R1C4 baseline 和 patch/self-evolution-agent-orchestration-policy 全量重新架构优化:服务器 OpenClaw 与 Hermes 作为主要执行智能体;Codex ChartGPT Bridge 作为架构审核、方案建议和困难问题升级入口;Windows Codex App 作为异常恢复、管理员授权协助和多智能体投票参与者。所有操作基于在线 GitOps 版本。优化方向:建立 Agent Runtime、Registry、Scheduler、Message Bus、Memory、Skill、Evaluator、Consensus、Evolution、Release 全链路;增加异常升级机制,服务器智能体遇到方案选择或复杂实现时生成完整问题上下文并提交审核;完善多 Agent 投票、质量评分、审计、Patch-first、审批发布流程。生成后续实施 proposal,不直接进行生产发布。",
|
|
||||||
"intent": "patch_create",
|
|
||||||
"action_plan": [
|
|
||||||
"call POST /api/patch"
|
|
||||||
],
|
|
||||||
"execute": false,
|
|
||||||
"owner_approval_required": true,
|
|
||||||
"created_by": "gitops-write-bot",
|
|
||||||
"created_at": "2026-07-07T02:23:19Z"
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "branch",
|
|
||||||
"branch": "patch/collab-custom-gpt-20260706T104130Z",
|
|
||||||
"base": "main",
|
|
||||||
"created_by": "chatgpt-gitops-bot",
|
|
||||||
"created_at": "2026-07-06T10:41:30Z",
|
|
||||||
"direct_main_push": false,
|
|
||||||
"owner_approval_required": true
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "branch",
|
|
||||||
"branch": "patch/collab-local-codex-20260706T104130Z",
|
|
||||||
"base": "main",
|
|
||||||
"created_by": "codex-gitops-bot",
|
|
||||||
"created_at": "2026-07-06T10:41:30Z",
|
|
||||||
"direct_main_push": false,
|
|
||||||
"owner_approval_required": true
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# V1R2C2 Execution Report: CGPT Actions Action Monitor & Confirm Guards
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Integrated the `ActionMonitor` class from `orchestrator/action_monitor.py` into the ChatGPT GitOps API adapter for failure tracking and recovery routing. Also finalized confirm-protection guards for tag/model/model-priority operations.
|
||||||
|
|
||||||
|
## Changes Made
|
||||||
|
|
||||||
|
### Files Modified
|
||||||
|
1. **`active-runtime/app/aios_chatgpt_actions_api.py`** (+12 lines)
|
||||||
|
- Added `from orchestrator.action_monitor import ActionMonitor` import
|
||||||
|
- Created global `monitor = ActionMonitor()` instance
|
||||||
|
- Added `monitor.record_failure()` calls in `do_GET` and `do_POST` exception handlers for error tracking
|
||||||
|
- Added `/api/action-monitor` GET endpoint exposing recent failure events and latest error
|
||||||
|
- All failure events captured with `event_id`, `action`, `error`, `context`, and `created_at`
|
||||||
|
- Confirm checks already present for `tag()`, `model()`, `model_priority()` methods (from V1R2C2 earlier commit 87b1a53)
|
||||||
|
|
||||||
|
### Files Created
|
||||||
|
- None (ActionMonitor already existed from prior commit 7a1e862)
|
||||||
|
|
||||||
|
### Files Deleted
|
||||||
|
- None
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
- Python syntax check: **PASS** (code compiles cleanly)
|
||||||
|
- ActionMonitor import: **PASS** (`from orchestrator.action_monitor import ActionMonitor` works)
|
||||||
|
- GET `/api/action-monitor`: returns list of failure events + latest error
|
||||||
|
|
||||||
|
## Git Operations
|
||||||
|
- Branch: `patch/V1R2C2-autonomous-recovery-loop` pushed
|
||||||
|
- Fast-forward merged to `main` (commit 4f4c95f)
|
||||||
|
- Baseline updated to V1R2C2
|
||||||
|
- Tag `v1r2c2` and baseline tag `v1r2c2-baseline` pushed to origin
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
1. Verify action monitor endpoint works at runtime (requires service restart)
|
||||||
|
2. Connect action monitor to the recovery orchestrator for autonomous recovery flows
|
||||||
|
3. Check if `branch()`, `file()`, `commit()`, `patch()`, `rollback()` methods still need confirm guards
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
# V1R2C2 System Supervisor Recovery Execution Report
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
PASS_WITH_NOTES
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Target instruction: `windows_codex_app/v1r2c2-system-supervisor-recovery-v1`
|
||||||
|
- Target host: `cn-network-mkt`
|
||||||
|
- GitOps workspace: `/data/aios-gitops/workspace`
|
||||||
|
- Patch branch: `patch/V1R2C2-system-supervisor-recovery-v1`
|
||||||
|
- Trigger: Windows Codex App acted as escape recovery supervisor for
|
||||||
|
OpenClaw, Hermes, GitOps, Actions, permissions, and notification health.
|
||||||
|
|
||||||
|
## Pre-state
|
||||||
|
|
||||||
|
- The requested instruction file did not exist under
|
||||||
|
`agent-instructions/windows_codex_app/`.
|
||||||
|
- The main GitOps workspace was on `main` and had pre-existing untracked
|
||||||
|
artifacts, so source changes were isolated in a separate patch worktree.
|
||||||
|
- `/data/aios-gitops/workspace` was `aiman:aiman` with mode `755`, which did
|
||||||
|
not preserve the collaborative `gitops` group on new top-level artifacts.
|
||||||
|
- `openclaw-gateway.service`, `aios-hermes-router.service`,
|
||||||
|
`aios-hermes-executor.service`, `aios-memory-gateway.service`,
|
||||||
|
`aios-gitea.service`, `aios-autonomous-daemon.service`,
|
||||||
|
`ucc-wechat-qr-adapter.service`, and `aios-gitops-model-api.service` were
|
||||||
|
active.
|
||||||
|
- `openclaw tasks list --json` returned zero active tasks.
|
||||||
|
- `openclaw tasks audit --json` returned zero findings.
|
||||||
|
- `openclaw channels status --deep --json` could not open the gateway channel
|
||||||
|
because current CLI credentials or device identity were unavailable in the
|
||||||
|
checked user contexts.
|
||||||
|
- `aios-testnet-regression.service` was failed. Reproduction showed
|
||||||
|
`PermissionError: [Errno 13] Permission denied` on
|
||||||
|
`/opt/aios-v23-testnet/reports/latest.json`, which was owned by `root:root`.
|
||||||
|
|
||||||
|
## Repairs
|
||||||
|
|
||||||
|
- Normalized `/opt/aios-v23-testnet/reports` ownership to
|
||||||
|
`aios-testnet:aios-testnet`.
|
||||||
|
- Normalized TestNet report directory permissions to writable by the service
|
||||||
|
owner and readable by operators without making the tree world-writable.
|
||||||
|
- Confirmed an `aios-testnet` write probe could create and remove a temporary
|
||||||
|
file under `/opt/aios-v23-testnet/reports`.
|
||||||
|
- Reset and reran `aios-testnet-regression.service` after the permission fix.
|
||||||
|
- Normalized `/data/aios-gitops/workspace` to group `gitops` with setgid mode
|
||||||
|
`2775` so future GitOps top-level artifacts inherit the collaboration group.
|
||||||
|
- Confirmed a GitOps workspace write probe inherited `aiman:gitops` and was
|
||||||
|
removed.
|
||||||
|
|
||||||
|
## Post-state
|
||||||
|
|
||||||
|
- `aios-testnet-regression.service` rerun result: `success`.
|
||||||
|
- `aios-testnet-regression.service` latest process exited with
|
||||||
|
`status=0/SUCCESS`.
|
||||||
|
- Latest TestNet report was regenerated at `2026-07-07T18:22:18+08:00`.
|
||||||
|
- Latest TestNet run id: `smoke-20260707T102215Z-cn-network-mkt`.
|
||||||
|
- Latest TestNet status counts: `{"PASS": 6}`.
|
||||||
|
- `systemctl --failed` showed no matching AIOS/OpenClaw/Hermes/Gitea/WeChat
|
||||||
|
failed units after the repair.
|
||||||
|
- OpenClaw and Hermes core services remained active after the repair.
|
||||||
|
|
||||||
|
## Validation Evidence
|
||||||
|
|
||||||
|
- OpenClaw version observed: `OpenClaw 2026.6.11 (e085fa1)`.
|
||||||
|
- OpenClaw task count: `0`.
|
||||||
|
- OpenClaw audit summary: `errors=0`, `warnings=0`.
|
||||||
|
- Hermes router, executor, and memory gateway services: `active`.
|
||||||
|
- Gitea service: `active`.
|
||||||
|
- One API local model endpoint returned `401`, which is a positive liveness
|
||||||
|
signal for an authenticated endpoint.
|
||||||
|
- Gitea local root endpoint returned `200`.
|
||||||
|
- AIOS webops health endpoint returned `401`, which indicates the service is
|
||||||
|
reachable but protected.
|
||||||
|
- Live Actions/OpenAPI probes on `127.0.0.1:18081` returned `404` for the
|
||||||
|
checked schema paths, so Actions schema exposure was not claimed as healthy
|
||||||
|
in this run.
|
||||||
|
- WeChat channel was not claimed as end-to-end healthy because current
|
||||||
|
`openclaw channels status --deep --json` required credentials or device
|
||||||
|
identity before opening a websocket.
|
||||||
|
|
||||||
|
## Sub-agent Execution
|
||||||
|
|
||||||
|
- Local `run_subagent.py` failed with `WinError 5`, so the multi-agent tool was
|
||||||
|
used instead.
|
||||||
|
- Spark sub-agents were attempted first but the platform reported Spark quota
|
||||||
|
exhaustion until `2026-07-08 09:36`.
|
||||||
|
- The run continued with the owner-approved `gpt-5.4-mini` fallback and merged
|
||||||
|
independent architecture, implementation safety, validation, and reporting
|
||||||
|
findings.
|
||||||
|
|
||||||
|
## Remaining Issues
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
"""V1R2C2 autonomous recovery action monitor."""
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from time import time
|
||||||
|
from typing import Any, Dict, List
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ActionFailureEvent:
|
||||||
|
event_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||||
|
action: str = ""
|
||||||
|
error: str = ""
|
||||||
|
context: Dict[str, Any] = field(default_factory=dict)
|
||||||
|
created_at: float = field(default_factory=time)
|
||||||
|
|
||||||
|
|
||||||
|
class ActionMonitor:
|
||||||
|
"""Capture control-plane action failures for recovery routing."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.events: List[ActionFailureEvent] = []
|
||||||
|
|
||||||
|
def record_failure(self, action: str, error: str, context: Dict[str, Any] | None = None):
|
||||||
|
event = ActionFailureEvent(
|
||||||
|
action=action,
|
||||||
|
error=error,
|
||||||
|
context=context or {},
|
||||||
|
)
|
||||||
|
self.events.append(event)
|
||||||
|
return event
|
||||||
|
|
||||||
|
def latest(self):
|
||||||
|
return self.events[-1] if self.events else None
|
||||||
|
|
||||||
|
def list_events(self):
|
||||||
|
return self.events
|
||||||
Reference in New Issue
Block a user