Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94d92a256d | ||
|
|
09b0694e63 | ||
|
|
9bbd0493a8 | ||
|
|
1dbb5db178 | ||
|
|
0773956bf3 | ||
|
|
de5b257e95 | ||
|
|
77f8544cd2 | ||
|
|
f2dae8e0f7 | ||
|
|
107968568e | ||
|
|
b9ad46090d | ||
|
|
1fab9e421b | ||
|
|
ae51d0d3a9 | ||
|
|
5488629d32 | ||
|
|
0a42095e4c | ||
|
|
5d347a0947 | ||
|
|
e35708995a | ||
|
|
264587c65c | ||
|
|
f6d98eeb88 | ||
|
|
38395f3bc2 | ||
|
|
0f3c796193 | ||
|
|
f6e53efefb |
@@ -5,8 +5,6 @@ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from orchestrator.action_monitor import ActionMonitor
|
||||
|
||||
ROOT = Path(os.getenv('AIOS_GITOPS_ROOT', '/data/aios-gitops'))
|
||||
WS = Path(os.getenv('AIOS_GITOPS_WORKSPACE', str(ROOT / 'workspace')))
|
||||
SECRETS = Path(os.getenv('AIOS_GITOPS_SECRETS_DIR', str(ROOT / 'runtime' / 'secrets')))
|
||||
@@ -15,8 +13,6 @@ HOST = os.getenv('AIOS_GITOPS_HOST', '127.0.0.1')
|
||||
PORT = int(os.getenv('AIOS_GITOPS_PORT', '18890'))
|
||||
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')))
|
||||
monitor = ActionMonitor()
|
||||
|
||||
BASE_MODELS = [
|
||||
{'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'},
|
||||
@@ -195,12 +191,8 @@ class H(BaseHTTPRequestHandler):
|
||||
if path in ('/api/run','/run'):
|
||||
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']})
|
||||
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)
|
||||
except Exception as e:
|
||||
monitor.record_failure('do_GET', str(e), {'path':path})
|
||||
return self.sendj({'error':str(e)},500)
|
||||
except Exception as e: return self.sendj({'error':str(e)},500)
|
||||
def do_PUT(self):
|
||||
path=urllib.parse.urlparse(self.path).path.rstrip('/'); data=self.body()
|
||||
if path == '/api/model-priority': return self.model_priority(data)
|
||||
@@ -218,9 +210,7 @@ class H(BaseHTTPRequestHandler):
|
||||
if path == '/api/model-priority': return self.model_priority(data)
|
||||
if path == '/api/nl': return self.nl(data)
|
||||
return self.sendj({'error':'not_found','path':path},404)
|
||||
except Exception as e:
|
||||
monitor.record_failure('do_POST', str(e), {'path':path})
|
||||
return self.sendj({'error':str(e)},500)
|
||||
except Exception as e: return self.sendj({'error':str(e)},500)
|
||||
def branch(self,data):
|
||||
a=self.need('branch:create');
|
||||
if not a: return
|
||||
@@ -244,9 +234,6 @@ class H(BaseHTTPRequestHandler):
|
||||
if not a: return
|
||||
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 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'):
|
||||
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)})
|
||||
@@ -267,16 +254,10 @@ class H(BaseHTTPRequestHandler):
|
||||
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)
|
||||
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})
|
||||
def model_priority(self,data):
|
||||
a=self.need('model:priority');
|
||||
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})
|
||||
def nl(self,data):
|
||||
a=self.need('nl:plan');
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Codex Execution Instruction
|
||||
|
||||
Instruction ID: fix-agent-instructions-permission-v1
|
||||
Version: v1
|
||||
Target Agent: codex
|
||||
|
||||
## Objective
|
||||
|
||||
Repair GitOps Action runtime write permissions for agent instruction directories.
|
||||
|
||||
## Scope
|
||||
|
||||
Only:
|
||||
|
||||
- agent-instructions/
|
||||
- agent-instructions/codex/
|
||||
- agent-instructions/openclaw/
|
||||
- agent-instructions/hermes/
|
||||
- agent-instructions/windows_codex_app/
|
||||
- agent-instructions/custom_gpt_review/
|
||||
|
||||
## Execution Steps
|
||||
|
||||
1. Identify GitOps action runtime user.
|
||||
2. Inspect ownership and permissions.
|
||||
3. Apply minimum required ownership changes.
|
||||
4. Validate write access with temporary probes.
|
||||
5. Remove probes.
|
||||
|
||||
## Constraints
|
||||
|
||||
- No chmod 777.
|
||||
- No workspace-wide ownership changes.
|
||||
- No secrets.
|
||||
- No unrelated file commits.
|
||||
- No force push.
|
||||
|
||||
## Return Format
|
||||
|
||||
Status:
|
||||
Branch:
|
||||
Commit:
|
||||
Rev:
|
||||
Sync Status:
|
||||
Permission Result:
|
||||
Issues:
|
||||
@@ -0,0 +1,64 @@
|
||||
# Codex Execution Instruction
|
||||
|
||||
Instruction ID: fix-gitops-managed-path-governance-v1
|
||||
Version: v1
|
||||
Target Agent: codex
|
||||
|
||||
## Objective
|
||||
|
||||
Prevent recurring GitOps permission drift by managing all writable repository paths through one governance policy.
|
||||
|
||||
## Managed Paths
|
||||
|
||||
- config/
|
||||
- reports/
|
||||
- proposals/
|
||||
- approvals/
|
||||
- versions/
|
||||
- agent-instructions/
|
||||
- runtime/
|
||||
- patches/
|
||||
|
||||
## Required Model
|
||||
|
||||
Ownership:
|
||||
|
||||
root:gitops
|
||||
|
||||
Runtime users:
|
||||
|
||||
- aiman
|
||||
- aios
|
||||
|
||||
Requirements:
|
||||
|
||||
- setgid directories
|
||||
- shared group write access
|
||||
- inherited group ownership
|
||||
- permission drift detection
|
||||
|
||||
## Validation
|
||||
|
||||
Check:
|
||||
|
||||
- shell runtime user
|
||||
- commit action runtime user
|
||||
- directory ownership
|
||||
- group membership
|
||||
- write probes
|
||||
|
||||
## Constraints
|
||||
|
||||
- No chmod 777.
|
||||
- No unsafe workspace-wide ownership changes.
|
||||
- No secrets.
|
||||
- No production changes.
|
||||
|
||||
## Return Format
|
||||
|
||||
Status:
|
||||
Runtime Users:
|
||||
Managed Paths:
|
||||
Ownership Model:
|
||||
Validation:
|
||||
Remaining Issues:
|
||||
@@ -0,0 +1,70 @@
|
||||
# Codex Execution Instruction
|
||||
|
||||
Instruction ID: fix-gitops-workspace-permission-governance-v1
|
||||
Version: v1
|
||||
Target Agent: codex
|
||||
|
||||
## Objective
|
||||
|
||||
Permanently prevent repeated GitOps workspace permission failures across AIOS development and release workflows.
|
||||
|
||||
## Problem
|
||||
|
||||
Multiple directories have experienced inconsistent ownership between human/runtime users and GitOps action users:
|
||||
|
||||
- reports/
|
||||
- proposals/
|
||||
- approvals/
|
||||
- versions/
|
||||
- agent-instructions/
|
||||
- runtime/
|
||||
|
||||
## Execution Requirements
|
||||
|
||||
1. Identify the actual GitOps action runtime user.
|
||||
2. Identify all Git-managed writable workflow directories.
|
||||
3. Apply a consistent ownership model only to required workflow directories.
|
||||
4. Ensure new files inherit compatible permissions.
|
||||
5. Verify write access with temporary probes.
|
||||
6. Remove all probes.
|
||||
|
||||
## Required Directories
|
||||
|
||||
- reports/
|
||||
- proposals/
|
||||
- approvals/
|
||||
- versions/
|
||||
- agent-instructions/
|
||||
- runtime/
|
||||
|
||||
## Constraints
|
||||
|
||||
- No chmod 777.
|
||||
- No workspace-wide ownership changes.
|
||||
- No secrets.
|
||||
- No unrelated commits.
|
||||
- No force push.
|
||||
- Do not change production state.
|
||||
|
||||
## Permanent Solution Requirements
|
||||
|
||||
Prefer:
|
||||
|
||||
- shared group ownership,
|
||||
- setgid directory behavior where appropriate,
|
||||
- documented runtime user ownership,
|
||||
- consistent permission policy.
|
||||
|
||||
Avoid repeated manual directory fixes.
|
||||
|
||||
## Validation
|
||||
|
||||
Return:
|
||||
|
||||
Status:
|
||||
Runtime User:
|
||||
Ownership Model:
|
||||
Changed Directories:
|
||||
Permission Result:
|
||||
Probe Result:
|
||||
Remaining Issues:
|
||||
@@ -0,0 +1,69 @@
|
||||
# Codex Execution Instruction
|
||||
|
||||
Instruction ID: type-hints-auto-fix-v1
|
||||
Version: v1
|
||||
Target Agent: codex
|
||||
|
||||
## Objective
|
||||
|
||||
Automatically add missing Python type hints identified during code quality validation.
|
||||
|
||||
## Scope
|
||||
|
||||
Target:
|
||||
|
||||
adapters/gitops/aios_gitops_model_api.py
|
||||
|
||||
## Required Fixes
|
||||
|
||||
Add parameter and return type annotations for:
|
||||
|
||||
- db()
|
||||
- rows(sql, args=())
|
||||
- one(sql, args=())
|
||||
- exec_sql(sql, args=())
|
||||
- audit(actor, action, target='', payload=None)
|
||||
- init_db()
|
||||
- seed_base_models()
|
||||
- git_cmd(args, check=False)
|
||||
- parse_body(handler)
|
||||
- api_spec()
|
||||
|
||||
## Suggested Types
|
||||
|
||||
- database connections: sqlite3.Connection
|
||||
- sql input: str
|
||||
- argument collections: Sequence[Any] or tuple
|
||||
- rows: list[dict]
|
||||
- one: dict | None
|
||||
- audit/init/seed: None return
|
||||
- git args: list[str]
|
||||
- api spec: dict
|
||||
|
||||
## Constraints
|
||||
|
||||
- Only modify type annotations.
|
||||
- Do not change runtime behavior.
|
||||
- Do not add dependencies unless required.
|
||||
- No secrets.
|
||||
- No force push.
|
||||
- GitOps workflow required.
|
||||
|
||||
## Validation
|
||||
|
||||
Run:
|
||||
|
||||
python3 -m compileall -q adapters/gitops/aios_gitops_model_api.py
|
||||
|
||||
Run relevant tests.
|
||||
|
||||
## Return Format
|
||||
|
||||
Status:
|
||||
Branch:
|
||||
Commit:
|
||||
Rev:
|
||||
Sync Status:
|
||||
Changed Files:
|
||||
Tests:
|
||||
Issues:
|
||||
@@ -0,0 +1,66 @@
|
||||
# Codex Execution Instruction
|
||||
|
||||
Instruction ID: v1r1c5-cgpt-actions-confirmation-governance-v1
|
||||
Version: v1
|
||||
Target Agent: codex
|
||||
|
||||
## Objective
|
||||
|
||||
Complete CGPT Actions consequential write confirmation governance.
|
||||
|
||||
## Context
|
||||
|
||||
Completed:
|
||||
|
||||
- OpenAPI write operations marked x-openai-isConsequential: true.
|
||||
- api_spec risk classification implemented.
|
||||
- Confirmation interception added to branch/file/commit/patch/rollback.
|
||||
|
||||
## Required Changes
|
||||
|
||||
Complete confirmation protection for:
|
||||
|
||||
1. model()
|
||||
|
||||
Before model registration:
|
||||
- require confirm field.
|
||||
- return 428 confirm_required when missing.
|
||||
|
||||
2. model_priority()
|
||||
|
||||
Before priority changes:
|
||||
- require confirm field.
|
||||
- return 428 confirm_required when missing.
|
||||
|
||||
3. tag()
|
||||
|
||||
Complete confirmation logic:
|
||||
- require tag:create permission.
|
||||
- require confirm field.
|
||||
- block without explicit confirmation.
|
||||
|
||||
## Constraints
|
||||
|
||||
- Preserve existing API behavior.
|
||||
- Do not weaken consequential action protection.
|
||||
- No secrets.
|
||||
- No force push.
|
||||
- GitOps workflow only.
|
||||
|
||||
## Validation
|
||||
|
||||
Test:
|
||||
- missing confirm returns 428.
|
||||
- confirm=true allows authorized flow.
|
||||
- unauthorized scope remains blocked.
|
||||
|
||||
Return:
|
||||
|
||||
Status:
|
||||
Branch:
|
||||
Commit:
|
||||
Rev:
|
||||
Sync Status:
|
||||
Changed Files:
|
||||
Tests:
|
||||
Issues:
|
||||
@@ -0,0 +1,44 @@
|
||||
# Codex Execution Instruction
|
||||
|
||||
Instruction ID: verify-commit-action-runtime-v1
|
||||
Version: v1
|
||||
Target Agent: codex
|
||||
|
||||
## Objective
|
||||
|
||||
Diagnose GitOps commit action runtime permission differences that prevent file writes while shell runtime permissions are correct.
|
||||
|
||||
## Checks
|
||||
|
||||
1. Identify commit action runtime user.
|
||||
2. Identify commit action workspace mount.
|
||||
3. Compare with shell runtime user.
|
||||
4. Check reports/proposals/agent-instructions/runtime write capability.
|
||||
5. Identify permission difference.
|
||||
|
||||
## Required Outcome
|
||||
|
||||
If mismatch exists:
|
||||
|
||||
- Align action runtime with gitops shared ownership model.
|
||||
- Preserve root:gitops ownership.
|
||||
- Preserve setgid behavior.
|
||||
- Avoid unsafe permission expansion.
|
||||
|
||||
## Constraints
|
||||
|
||||
- No chmod 777.
|
||||
- No workspace-wide unsafe ownership changes.
|
||||
- No secrets.
|
||||
- No force push.
|
||||
- No production actions.
|
||||
|
||||
## Return Format
|
||||
|
||||
Status:
|
||||
Commit Action User:
|
||||
Shell Runtime User:
|
||||
Workspace Mount:
|
||||
Permission Difference:
|
||||
Fix Required:
|
||||
Issues:
|
||||
@@ -0,0 +1,33 @@
|
||||
# Codex Execution Instruction
|
||||
|
||||
Instruction ID: verify-gitops-action-runtime-user-v1
|
||||
Version: v1
|
||||
Target Agent: codex
|
||||
|
||||
## Objective
|
||||
|
||||
Verify the actual GitOps Action runtime user and workspace permission inheritance.
|
||||
|
||||
## Checks
|
||||
|
||||
1. Identify runtime user.
|
||||
2. Identify groups.
|
||||
3. Confirm Gitea runtime user.
|
||||
4. Confirm workspace ownership model.
|
||||
5. Confirm setgid workflow directories.
|
||||
|
||||
## Expected Model
|
||||
|
||||
- Shared group ownership.
|
||||
- GitOps runtime user belongs to shared group.
|
||||
- No chmod 777.
|
||||
- No workspace-wide unsafe ownership changes.
|
||||
|
||||
## Return Format
|
||||
|
||||
Status:
|
||||
Runtime User:
|
||||
Gitea Runs As:
|
||||
Workspace Owner:
|
||||
Ownership Model:
|
||||
Remaining Issues:
|
||||
@@ -1,107 +0,0 @@
|
||||
# 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": "V1R2C2",
|
||||
"active_tag": "V1R2C2",
|
||||
"active_version": "V1R1C4",
|
||||
"active_tag": "V1R1C4",
|
||||
"mode": "gitops-online",
|
||||
"version_policy": "VxRxCx",
|
||||
"update_mode": "git_patch_only",
|
||||
@@ -27,8 +27,8 @@
|
||||
"portal_gitops_dashboard": true,
|
||||
"human_shortlinks_login_required": true
|
||||
},
|
||||
"version": "V1R2C2",
|
||||
"baseline_tag": "V1R2C2-baseline",
|
||||
"version": "V1R1C4",
|
||||
"baseline_tag": "V1R1C0-baseline-20260706",
|
||||
"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",
|
||||
"zip_update_mode": "deprecated",
|
||||
@@ -46,7 +46,7 @@
|
||||
"/api",
|
||||
"/hook"
|
||||
],
|
||||
"updated_at": "2026-07-07T15:40:00Z",
|
||||
"updated_at": "2026-07-06T11:16:23Z",
|
||||
"auth": {
|
||||
"primary_domain": "https://auth.cnnetmkt.top",
|
||||
"backup_domain": "https://auth.h.imruyi.top:8443",
|
||||
@@ -55,7 +55,7 @@
|
||||
"casdoor_application": "admin/aios-portal",
|
||||
"backup_domain_role": "standby-only"
|
||||
},
|
||||
"previous_version": "V1R2C1",
|
||||
"previous_version": "V1R1C3",
|
||||
"codex_gitops": {
|
||||
"config": "config/codex/gitops-online.json",
|
||||
"token_account": "codex-gitops-bot",
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"type": "branch",
|
||||
"branch": "patch/V1R2C1-autonomous-orchestrator-foundation",
|
||||
"base": "main",
|
||||
"created_by": "gitops-write-bot",
|
||||
"created_at": "2026-07-07T04:24:24Z",
|
||||
"direct_main_push": false,
|
||||
"owner_approval_required": true
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"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,41 @@
|
||||
{
|
||||
"version": "V1R2C1",
|
||||
"status": "proposal",
|
||||
"source": "V1R1C5",
|
||||
"objective": "Upgrade AIOS from multi-agent execution workflow to autonomous orchestrator architecture",
|
||||
"architecture": {
|
||||
"orchestrator": "state-machine-driven autonomous coordinator",
|
||||
"planner": "GPT worker planning and reasoning layer",
|
||||
"reviewer": "Custom GPT advisory review layer",
|
||||
"executors": ["OpenClaw", "Hermes"],
|
||||
"recovery": "Windows Codex App recovery and privileged assistance"
|
||||
},
|
||||
"modules": [
|
||||
"orchestrator_state_machine",
|
||||
"run_store_and_evidence",
|
||||
"policy_gate",
|
||||
"planner_client",
|
||||
"reviewer_client",
|
||||
"executor_dispatcher",
|
||||
"result_collector",
|
||||
"notification_worker",
|
||||
"rollback_manager"
|
||||
],
|
||||
"autonomy_boundary": {
|
||||
"automatic": [
|
||||
"analysis",
|
||||
"planning",
|
||||
"patch_creation",
|
||||
"testing",
|
||||
"report_generation"
|
||||
],
|
||||
"owner_required": [
|
||||
"main_merge",
|
||||
"release_tag",
|
||||
"production_publish",
|
||||
"secret_change",
|
||||
"destructive_operation"
|
||||
]
|
||||
},
|
||||
"migration_target": "V1R2C1"
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
# 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
|
||||
@@ -1,93 +0,0 @@
|
||||
# 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
|
||||
@@ -1,37 +0,0 @@
|
||||
"""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
|
||||
@@ -0,0 +1,40 @@
|
||||
"""V1R2C1 orchestrator evidence writer."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from time import time
|
||||
from typing import Any, Dict, List
|
||||
import uuid
|
||||
|
||||
|
||||
@dataclass
|
||||
class EvidenceRecord:
|
||||
evidence_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||
category: str = "general"
|
||||
data: Dict[str, Any] = field(default_factory=dict)
|
||||
created_at: float = field(default_factory=time)
|
||||
|
||||
|
||||
class EvidenceWriter:
|
||||
def __init__(self):
|
||||
self.records: List[EvidenceRecord] = []
|
||||
|
||||
def write(self, category: str, data: Dict[str, Any]):
|
||||
record = EvidenceRecord(category=category, data=data)
|
||||
self.records.append(record)
|
||||
return record
|
||||
|
||||
def query(self, category: str = None):
|
||||
if category:
|
||||
return [r for r in self.records if r.category == category]
|
||||
return self.records
|
||||
|
||||
def export_audit(self):
|
||||
return [
|
||||
{
|
||||
"evidence_id": r.evidence_id,
|
||||
"category": r.category,
|
||||
"data": r.data,
|
||||
"created_at": r.created_at,
|
||||
}
|
||||
for r in self.records
|
||||
]
|
||||
@@ -0,0 +1,55 @@
|
||||
"""V1R2C1 executor dispatcher."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExecutionRequest:
|
||||
agent: str
|
||||
task: str
|
||||
context: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExecutionResult:
|
||||
agent: str
|
||||
status: str
|
||||
output: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
class ExecutorDispatcher:
|
||||
"""Dispatch execution requests to registered agent types.
|
||||
|
||||
Actual external agent communication is handled by integration layers.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.executors = {
|
||||
"openclaw": "server_execution",
|
||||
"hermes": "architecture_review",
|
||||
"windows_codex_app": "recovery_assistance",
|
||||
}
|
||||
self.history: List[ExecutionResult] = []
|
||||
|
||||
def dispatch(self, request: ExecutionRequest):
|
||||
if request.agent not in self.executors:
|
||||
result = ExecutionResult(
|
||||
agent=request.agent,
|
||||
status="unsupported",
|
||||
output={"error": "unknown executor"},
|
||||
)
|
||||
else:
|
||||
result = ExecutionResult(
|
||||
agent=request.agent,
|
||||
status="queued",
|
||||
output={
|
||||
"executor_type": self.executors[request.agent],
|
||||
"task": request.task,
|
||||
},
|
||||
)
|
||||
self.history.append(result)
|
||||
return result
|
||||
|
||||
def list_history(self):
|
||||
return self.history
|
||||
@@ -0,0 +1,59 @@
|
||||
"""V1R2C1 autonomous orchestrator integration tests."""
|
||||
|
||||
from .state_machine import StateMachine, RunState
|
||||
from .run_store import RunStore
|
||||
from .evidence_writer import EvidenceWriter
|
||||
from .policy_gate import PolicyGate, ActionLevel
|
||||
from .planner_client import PlannerClient
|
||||
from .reviewer_client import ReviewerClient
|
||||
from .executor_dispatcher import ExecutorDispatcher, ExecutionRequest
|
||||
from .result_collector import ResultCollector
|
||||
from .notification_worker import NotificationWorker
|
||||
from .rollback_manager import RollbackManager
|
||||
|
||||
|
||||
def run_tests():
|
||||
results = {}
|
||||
|
||||
state = StateMachine()
|
||||
state.transition(RunState.PLANNING)
|
||||
results["state_machine"] = state.current() == RunState.PLANNING
|
||||
|
||||
store = RunStore()
|
||||
run = store.create({"task": "v1r2c1"})
|
||||
store.update_state(run.run_id, "executing")
|
||||
results["run_store"] = store.get(run.run_id).state == "executing"
|
||||
|
||||
evidence = EvidenceWriter()
|
||||
evidence.write("test", {"ok": True})
|
||||
results["evidence"] = len(evidence.query("test")) == 1
|
||||
|
||||
policy = PolicyGate()
|
||||
results["policy_auto"] = policy.evaluate("testing") == ActionLevel.AUTOMATIC
|
||||
results["policy_owner"] = policy.evaluate("release_tag") == ActionLevel.OWNER_APPROVAL
|
||||
|
||||
planner = PlannerClient()
|
||||
results["planner"] = len(planner.create_plan("optimize" ).steps) > 0
|
||||
|
||||
reviewer = ReviewerClient()
|
||||
results["reviewer"] = reviewer.review("hermes", {"proposal": "test"}).decision == "conditional"
|
||||
|
||||
dispatcher = ExecutorDispatcher()
|
||||
results["dispatcher"] = dispatcher.dispatch(ExecutionRequest("openclaw", "test")).status == "queued"
|
||||
|
||||
collector = ResultCollector()
|
||||
collector.collect("openclaw", "success")
|
||||
results["collector"] = len(collector.success()) == 1
|
||||
|
||||
notifier = NotificationWorker()
|
||||
results["notification"] = notifier.notify("approval", "high")["status"] == "queued"
|
||||
|
||||
rollback = RollbackManager()
|
||||
rollback.create_request("V1R2C1", "V1R1C5", "test")
|
||||
results["rollback"] = rollback.requires_approval()
|
||||
|
||||
return results
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(run_tests())
|
||||
@@ -0,0 +1,40 @@
|
||||
"""V1R2C1 orchestrator notification worker."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from time import time
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
@dataclass
|
||||
class Notification:
|
||||
event: str
|
||||
priority: str
|
||||
payload: Dict[str, Any] = field(default_factory=dict)
|
||||
created_at: float = field(default_factory=time)
|
||||
|
||||
|
||||
class NotificationWorker:
|
||||
"""Owner and agent notification routing abstraction."""
|
||||
|
||||
def __init__(self):
|
||||
self.queue: List[Notification] = []
|
||||
self.channels = {
|
||||
"primary": "configured_owner_channel",
|
||||
"fallback": "configured_backup_channel",
|
||||
}
|
||||
|
||||
def notify(self, event: str, priority: str, payload: Dict[str, Any] | None = None):
|
||||
notification = Notification(
|
||||
event=event,
|
||||
priority=priority,
|
||||
payload=payload or {},
|
||||
)
|
||||
self.queue.append(notification)
|
||||
return {
|
||||
"status": "queued",
|
||||
"primary_channel": self.channels["primary"],
|
||||
"fallback_enabled": True,
|
||||
}
|
||||
|
||||
def pending(self):
|
||||
return self.queue
|
||||
@@ -0,0 +1,40 @@
|
||||
"""V1R2C1 autonomous orchestrator core controller."""
|
||||
|
||||
from .state_machine import StateMachine, RunState
|
||||
from .run_store import RunStore
|
||||
from .evidence_writer import EvidenceWriter
|
||||
from .policy_gate import PolicyGate
|
||||
|
||||
|
||||
class AutonomousOrchestrator:
|
||||
def __init__(self):
|
||||
self.run_store = RunStore()
|
||||
self.evidence = EvidenceWriter()
|
||||
self.policy = PolicyGate()
|
||||
self.state_machine = StateMachine()
|
||||
|
||||
def create_run(self, context=None):
|
||||
run = self.run_store.create(context)
|
||||
self.evidence.write("run_created", {"run_id": run.run_id})
|
||||
return run
|
||||
|
||||
def execute_stage(self, run_id, stage, action=None):
|
||||
run = self.run_store.get(run_id)
|
||||
if not run:
|
||||
return {"status": "not_found"}
|
||||
|
||||
if action and not self.policy.can_execute(action):
|
||||
self.evidence.write("policy_block", {"run_id": run_id, "action": action})
|
||||
return {"status": "approval_required", "action": action}
|
||||
|
||||
self.state_machine.transition(RunState.EXECUTING)
|
||||
self.run_store.update_state(run_id, stage)
|
||||
self.evidence.write("stage_execution", {"run_id": run_id, "stage": stage})
|
||||
|
||||
return {"status": "executed", "stage": stage}
|
||||
|
||||
def complete(self, run_id):
|
||||
self.state_machine.transition(RunState.COMPLETED)
|
||||
self.run_store.update_state(run_id, "completed")
|
||||
self.evidence.write("completed", {"run_id": run_id})
|
||||
return {"status": "completed", "run_id": run_id}
|
||||
@@ -0,0 +1,38 @@
|
||||
"""V1R2C1 planner client abstraction."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
@dataclass
|
||||
class Plan:
|
||||
objective: str
|
||||
steps: List[str] = field(default_factory=list)
|
||||
metadata: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
class PlannerClient:
|
||||
"""Planner interface for GPT planning workers.
|
||||
|
||||
This module defines orchestration boundaries and does not store credentials.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.plans = []
|
||||
|
||||
def create_plan(self, objective: str, context: Dict[str, Any] | None = None):
|
||||
plan = Plan(
|
||||
objective=objective,
|
||||
steps=[
|
||||
"analyze_context",
|
||||
"generate_options",
|
||||
"select_execution_path",
|
||||
"prepare_validation"
|
||||
],
|
||||
metadata=context or {},
|
||||
)
|
||||
self.plans.append(plan)
|
||||
return plan
|
||||
|
||||
def history(self):
|
||||
return self.plans
|
||||
@@ -0,0 +1,40 @@
|
||||
"""V1R2C1 autonomous orchestrator policy gate."""
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class ActionLevel(str, Enum):
|
||||
AUTOMATIC = "automatic"
|
||||
OWNER_APPROVAL = "owner_approval"
|
||||
|
||||
|
||||
class PolicyGate:
|
||||
def __init__(self):
|
||||
self.owner_required = {
|
||||
"main_merge",
|
||||
"release_tag",
|
||||
"production_publish",
|
||||
"secret_change",
|
||||
"destructive_operation",
|
||||
}
|
||||
|
||||
self.automatic_allowed = {
|
||||
"analysis",
|
||||
"planning",
|
||||
"patch_creation",
|
||||
"testing",
|
||||
"report_generation",
|
||||
}
|
||||
|
||||
def evaluate(self, action: str):
|
||||
if action in self.owner_required:
|
||||
return ActionLevel.OWNER_APPROVAL
|
||||
if action in self.automatic_allowed:
|
||||
return ActionLevel.AUTOMATIC
|
||||
return ActionLevel.OWNER_APPROVAL
|
||||
|
||||
def can_execute(self, action: str, approved: bool = False):
|
||||
level = self.evaluate(action)
|
||||
if level == ActionLevel.AUTOMATIC:
|
||||
return True
|
||||
return approved
|
||||
@@ -0,0 +1,38 @@
|
||||
"""V1R2C1 orchestrator result collector."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List
|
||||
from time import time
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExecutionResultRecord:
|
||||
agent: str
|
||||
status: str
|
||||
output: Dict[str, Any] = field(default_factory=dict)
|
||||
created_at: float = field(default_factory=time)
|
||||
|
||||
|
||||
class ResultCollector:
|
||||
"""Collect execution results and expose orchestration state."""
|
||||
|
||||
def __init__(self):
|
||||
self.results: List[ExecutionResultRecord] = []
|
||||
|
||||
def collect(self, agent: str, status: str, output: Dict[str, Any] | None = None):
|
||||
result = ExecutionResultRecord(
|
||||
agent=agent,
|
||||
status=status,
|
||||
output=output or {},
|
||||
)
|
||||
self.results.append(result)
|
||||
return result
|
||||
|
||||
def latest(self):
|
||||
return self.results[-1] if self.results else None
|
||||
|
||||
def success(self):
|
||||
return [r for r in self.results if r.status in {"success", "completed"}]
|
||||
|
||||
def failures(self):
|
||||
return [r for r in self.results if r.status in {"failed", "error"}]
|
||||
@@ -0,0 +1,38 @@
|
||||
"""V1R2C1 reviewer client abstraction."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
@dataclass
|
||||
class ReviewResult:
|
||||
reviewer: str
|
||||
decision: str
|
||||
issues: List[str] = field(default_factory=list)
|
||||
recommendations: List[str] = field(default_factory=list)
|
||||
metadata: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
class ReviewerClient:
|
||||
"""Review interface for Custom GPT advisory and Hermes architecture review."""
|
||||
|
||||
def __init__(self):
|
||||
self.reviews = []
|
||||
|
||||
def review(self, reviewer: str, proposal: Dict[str, Any]):
|
||||
result = ReviewResult(
|
||||
reviewer=reviewer,
|
||||
decision="conditional",
|
||||
issues=[],
|
||||
recommendations=[
|
||||
"validate implementation",
|
||||
"check policy constraints",
|
||||
"record evidence"
|
||||
],
|
||||
metadata=proposal,
|
||||
)
|
||||
self.reviews.append(result)
|
||||
return result
|
||||
|
||||
def history(self):
|
||||
return self.reviews
|
||||
@@ -0,0 +1,35 @@
|
||||
"""V1R2C1 orchestrator rollback manager."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from time import time
|
||||
from typing import List
|
||||
|
||||
|
||||
@dataclass
|
||||
class RollbackRequest:
|
||||
source_version: str
|
||||
target_version: str
|
||||
reason: str
|
||||
created_at: float = field(default_factory=time)
|
||||
|
||||
|
||||
class RollbackManager:
|
||||
"""Manage safe rollback planning without automatic destructive actions."""
|
||||
|
||||
def __init__(self):
|
||||
self.requests: List[RollbackRequest] = []
|
||||
|
||||
def create_request(self, source_version: str, target_version: str, reason: str):
|
||||
request = RollbackRequest(
|
||||
source_version=source_version,
|
||||
target_version=target_version,
|
||||
reason=reason,
|
||||
)
|
||||
self.requests.append(request)
|
||||
return request
|
||||
|
||||
def history(self):
|
||||
return self.requests
|
||||
|
||||
def requires_approval(self):
|
||||
return True
|
||||
@@ -0,0 +1,32 @@
|
||||
"""V1R2C1 orchestrator run store."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from time import time
|
||||
from typing import Any, Dict
|
||||
import uuid
|
||||
|
||||
|
||||
@dataclass
|
||||
class RunRecord:
|
||||
run_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
||||
state: str = "created"
|
||||
context: Dict[str, Any] = field(default_factory=dict)
|
||||
events: list = field(default_factory=list)
|
||||
created_at: float = field(default_factory=time)
|
||||
|
||||
|
||||
class RunStore:
|
||||
def __init__(self):
|
||||
self.runs = {}
|
||||
|
||||
def create(self, context=None):
|
||||
run = RunRecord(context=context or {})
|
||||
self.runs[run.run_id] = run
|
||||
return run
|
||||
|
||||
def update_state(self, run_id, state):
|
||||
self.runs[run_id].state = state
|
||||
self.runs[run_id].events.append({"state": state, "time": time()})
|
||||
|
||||
def get(self, run_id):
|
||||
return self.runs.get(run_id)
|
||||
@@ -0,0 +1,25 @@
|
||||
"""V1R2C1 autonomous orchestrator state machine."""
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class RunState(str, Enum):
|
||||
CREATED = "created"
|
||||
PLANNING = "planning"
|
||||
EXECUTING = "executing"
|
||||
VALIDATING = "validating"
|
||||
COMPLETED = "completed"
|
||||
FAILED = "failed"
|
||||
PAUSED = "paused"
|
||||
|
||||
|
||||
class StateMachine:
|
||||
def __init__(self):
|
||||
self.state = RunState.CREATED
|
||||
|
||||
def transition(self, new_state: RunState):
|
||||
self.state = new_state
|
||||
return self.state
|
||||
|
||||
def current(self):
|
||||
return self.state
|
||||
Reference in New Issue
Block a user