grix-connector 3.11.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/claude/claude-bridge-server.js +1 -1
- package/dist/adapter/claude/claude-tools.js +1 -1
- package/dist/adapter/claude/claude-worker-client.js +1 -1
- package/dist/adapter/claude/mcp-http-launcher.js +2 -2
- package/dist/adapter/claude/result-timeout.js +1 -1
- package/dist/adapter/opencode/opencode-adapter.js +2 -2
- package/dist/adapter/pi/pi-adapter.js +3 -3
- package/dist/bridge/bridge.js +9 -9
- package/dist/core/access/allowlist-store.js +1 -1
- package/dist/core/file-ops/list-files.js +1 -1
- package/dist/core/mcp/tools.js +1 -1
- package/dist/core/provider-quota/index.js +1 -1
- package/dist/core/provider-quota/presentation.js +1 -0
- package/dist/core/provider-quota/providers.js +2 -2
- package/dist/core/provider-quota/service.js +1 -0
- package/dist/default-skills/grix-admin/SKILL.md +20 -7
- package/dist/default-skills/grix-admin/references/api-contract.md +16 -12
- package/dist/log.js +2 -2
- package/dist/manager.js +2 -2
- package/dist/mcp/stream-http/config.js +1 -1
- package/dist/mcp/stream-http/connection-binding.js +1 -1
- package/dist/mcp/stream-http/security.js +1 -1
- package/dist/mcp/stream-http/tool-executor.js +1 -1
- package/dist/mcp/stream-http/tool-registry.js +1 -1
- package/dist/mcp/stream-http/tool-schemas.js +1 -1
- package/openclaw-plugin/index.js +41 -11
- package/openclaw-plugin/skills/grix-admin/SKILL.md +20 -7
- package/openclaw-plugin/skills/grix-admin/references/api-contract.md +16 -12
- package/openclaw-plugin/skills/grix-egg/SKILL.md +23 -11
- package/openclaw-plugin/skills/grix-egg/references/api-contract.md +2 -1
- package/package.json +1 -1
package/dist/manager.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readFileSync as K,readdirSync as G,writeFileSync as z}from"node:fs";import{join as A}from"node:path";import{AgentInstance as T}from"./bridge/bridge.js";import{buildSharedInstanceConfig as J,diffSharedOwners as V,sharedInstanceKey as X,SharedOwnersCache as Y}from"./manager-share-config.js";import{isAgentDeletedError as D}from"./core/aibot/errors.js";import{GRIX_PATHS as w,log as l}from"./core/log/index.js";import{resolveClientVersion as Z}from"./core/util/client-version.js";import{UpgradeChecker as ee}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as te}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as ne}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as ae}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as re}from"./core/skill-sync/sync-state.js";import{buildReportedSkills as se,logDefaultSkillsCheck as oe,cleanupProjectedSkills as P}from"./default-skills/index.js";import{supportsDirectProviderConfig as ie}from"./core/config/provider-env.js";import{resolveCopilotCommand as O}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as H}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ce,resolveCliPath as le}from"./core/util/cli-probe.js";import{AgentInstaller as de}from"./core/installer/installer.js";import{reportInstallFailure as pe}from"./core/observability/sentry.js";const me=8e3;function ue(){const n=O();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:H()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:n.command},{clientType:"agy",command:"agy"}]}async function ge(){return Promise.all(ue().map(async n=>{const e=await le(n.command);if(!e)return{client_type:n.clientType,command:n.command,installed:!1,path:null,version:null};const t=await ce(e,n.versionArgs??["--version"]);return{client_type:n.clientType,command:n.command,installed:!0,path:e,version:t.version,error:t.error}}))}function he(n){switch(n){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:H()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=O();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${n}`)}}function q(n,e){return String(n??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function fe(n,e){return A(w.data,`session-bindings-${q(n,e)}.json`)}function _e(n,e){return A(w.data,`active-events-${q(n,e)}.json`)}function ye(...n){const e=[],t=new Set;for(const r of n)for(const s of r??[]){const i=String(s??"").trim(),o=i.toLowerCase();!i||t.has(o)||(t.add(o),e.push(i))}return e.length>0?e:void 0}function we(n,e){const t={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},r=t[n]??t.acp;return{maxConcurrent:e?.max_concurrent??r.maxConcurrent??1,maxQueued:e?.max_queued??r.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??r.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function b(n,e={}){const t=Z(),r=String(n.client_type??"").trim().toLowerCase(),s=he(r),i=String(n.ws_url??"").trim(),o="get_session_usage",p="get_rate_limits",c="get_agent_global_config";if(!n.name?.trim())throw new Error("agent name is required");if(!i)throw new Error(`agent ${n.name}: ws_url is required`);if(!n.agent_id?.trim())throw new Error(`agent ${n.name}: agent_id is required`);if(!n.api_key?.trim())throw new Error(`agent ${n.name}: api_key is required`);const a=s.adapterType,g=a==="acp",m=r==="qwen",_={...s.options??{}},S=a==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",o,p]}:null,d=a==="claude"?{localActions:["session_control","set_mode","set_model","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",o,p]}:null,f=m?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o],adapterHint:"qwen/base"}:null,h=a==="pi"?{adapterHint:"pi/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",o]}:null,u=a==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,y=a==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder",o,p]}:null,v=a==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,C=a==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o]}:null,$=a==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,R=g&&!m?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o]}:null,B=r==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",o,p]}:null,F=a==="codex"||a==="claude"||r==="gemini"?["session_control","set_model","set_mode"]:void 0,U=[o,p];g&&_.raw_transport===void 0&&(_.raw_transport=r==="gemini");const L=`${r}/base`,I=ae(a,r),Q=I==="kiro"?void 0:process.cwd(),E=se({mode:I,projectDir:Q}),M=E.filter(x=>x.source==="connector").map(x=>x.name);M.length>0&&!e.quiet&&l.info("manager",`[${n.name}] injecting connector skills: [${M.join(", ")}]`);const j=re(E,w.skills);let W=j.length>0?j:void 0;return{name:n.name,adapterType:a,aibot:{url:i,agentId:n.agent_id,apiKey:n.api_key,clientType:r,clientVersion:t,adapterHint:s.adapterHint??f?.adapterHint??h?.adapterHint??u?.adapterHint??y?.adapterHint??C?.adapterHint??$?.adapterHint??L,capabilities:S?.capabilities??v?.capabilities??h?.capabilities??u?.capabilities??y?.capabilities??C?.capabilities??$?.capabilities??f?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:ye(S?.localActions??v?.localActions??d?.localActions??h?.localActions??u?.localActions??y?.localActions??C?.localActions??$?.localActions??f?.localActions??B?.localActions??R?.localActions??["exec_approve","exec_reject"],F,U,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload"]),skills:W},agent:{command:s.command,args:[...s.args??[],...n.args??[]],env:n.env,clientType:r,...n.provider?{provider:{...n.provider.base_url?.trim()?{baseUrl:n.provider.base_url.trim()}:{},...n.provider.api_key?.trim()?{apiKey:n.provider.api_key.trim()}:{},...n.provider.model?.trim()?{model:n.provider.model.trim()}:{}}}:{}},adapterOptions:_,acpAuthMethod:_.auth_method,acpInitialMode:_.initial_mode,acpMcpTools:_.acp_mcp_tools,promptTimeoutMs:n.prompt_timeout_ms,bindingsPath:fe(n.name,n.agent_id),activeEventStorePath:_e(n.name,n.agent_id),...s.enableSessionBinding||g?{enableSessionBinding:!0}:{},...s.autoInjectArgs||r==="reasonix"&&n.provider?.model?.trim()?{autoInjectArgs:{...s.autoInjectArgs??{},...r==="reasonix"&&n.provider?.model?.trim()?{model:n.provider.model.trim()}:{}}}:{},poolMaxSize:n.pool?.maxSize,poolIdleTimeoutMs:n.pool?.idleTimeoutMs,eventQueue:we(a,n.event_queue),logDir:w.log,providerBaseUrl:n.provider_base_url?.trim()||void 0,providerApiKey:n.provider_api_key?.trim()||void 0}}function Se(){const n=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(n);return Number.isFinite(e)&&e>=500?Math.floor(e):me}function N(n){const e=[],t=[],r=[],s=G(n).filter(i=>i.endsWith(".json")).sort();for(const i of s)try{const o=JSON.parse(K(A(n,i),"utf-8"));if(o===null||typeof o!="object"||Array.isArray(o)||!("agents"in o)){r.push(i);continue}if(!Array.isArray(o.agents)){t.push({file:i,error:"agents is not an array"});continue}if(o.agents.length===0){t.push({file:i,error:"agents array is empty"});continue}for(const p of o.agents)e.push({entry:p,file:i})}catch(o){t.push({file:i,error:o instanceof Error?o.message:String(o)})}return{entries:e,fileErrors:t,skipped:r}}function k(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"null";if(Array.isArray(n))return`[${n.map(k).join(",")}]`;const e=n;return`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${k(e[r])}`).join(",")}}`}function Ae(n,e){return k(n)===k(e)}class Le{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=w.config;sharedOwnersCache=new Y(w.data);installer=new de;async start(e){const t=e??w.config;this.configDir=t,l.info("manager",`Loading configs from ${t}`),oe(),P(),this.globalConfigStore=new ne(A(w.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:r,fileErrors:s,skipped:i}=N(t);for(const a of s)l.error("manager",`Failed to load ${a.file}: ${a.error}`);for(const a of i)l.info("manager",`Skipped ${a}: not an agent config (no "agents" key)`);if(r.length===0&&s.length===0&&i.length===0)throw new Error(`No config files found in ${t}`);const o=[];let p=s.length;for(const{entry:a,file:g}of r)try{const m=b(a);o.push({config:m,entry:a,file:g}),l.info("manager",`Loaded ${m.name} (${m.adapterType??"acp"}) from ${g}`)}catch(m){const _=typeof a?.name=="string"?a.name:"<unknown>";l.error("manager",`Invalid agent config in ${g} (name=${_}): ${m}`),p++}let c=0;if(o.length>0){const a=Se();l.info("manager",`Starting ${o.length} agent(s), startup wait=${a}ms`);const g=()=>this.upgradeChecker?.triggerCheck(),m=d=>{this.instances=this.instances.filter(f=>f!==d)},_=o.map(({config:d,entry:f,file:h})=>{const u=new T(d,this.globalConfigStore);return u.setUpgradeTrigger(g),u.setShareSetHandler(y=>this.onShareSet(d,y)),u.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(d.name)),u.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),this.instances.push(u),this.configMap.set(d.name,d),this.rawConfigMap.set(d.name,{entry:f,file:h}),{config:d,instance:u,startPromise:u.start()}}),S=await Promise.all(_.map(async d=>{const f=await new Promise(h=>{let u=!1;const y=setTimeout(()=>{u||(u=!0,h({kind:"timeout"}))},a);d.startPromise.then(()=>{u||(u=!0,clearTimeout(y),h({kind:"started"}))}).catch(v=>{u||(u=!0,clearTimeout(y),h({kind:"failed",error:v}))})});return{task:d,outcome:f}}));for(const{task:d,outcome:f}of S){if(f.kind==="started"){this.restoreCachedSharedInstances(d.config);continue}if(f.kind==="failed"){if(D(f.error)){this.onAgentDeletedByPlatform(d.config.name);continue}m(d.instance),l.error("manager",`Failed to start ${d.config.name}: ${f.error}`);continue}c++,l.warn("manager",`Startup pending for ${d.config.name}, continue retrying in background`),d.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${d.config.name}`),this.restoreCachedSharedInstances(d.config)}).catch(h=>{if(D(h)){this.onAgentDeletedByPlatform(d.config.name);return}m(d.instance),l.error("manager",`Delayed start failed: ${d.config.name}: ${h}`)})}if(this.instances.length>0){const d=Math.max(0,this.instances.length-c);l.info("manager",`${d}/${o.length} agent(s) running now`)}c>0&&l.warn("manager",`${c} agent(s) still connecting in background`)}if(this.instances.length===0&&o.length>0)throw new Error("All agent configurations failed to start");o.length>0&&(this.upgradeChecker=new ee(o.map(({config:a})=>({apiKey:a.aibot.apiKey,wsUrl:a.aibot.url})),()=>this.instances.some(a=>a.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(a=>a.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),o.length>0&&(this.skillSyncer=new te(o.map(({config:a})=>({apiKey:a.aibot.apiKey,wsUrl:a.aibot.url})),w.skills),await this.skillSyncer.start())}async stop(){l.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(t=>t.stop()),...e.map(t=>t.stop())]),await this.globalConfigStore?.flush(),this.instances=[],P(),l.info("manager","All stopped")}onShareSet(e,t){this.sharedOwnersCache.save(e.name,t);const s=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,t));this.shareSyncChains.set(e.name,s)}async syncSharedInstances(e,t){if(this.stopping)return;const{toAdd:r,toRemove:s}=V(e.name,this.sharedInstances.keys(),t);for(const i of r){if(this.stopping)break;const o=X(e.name,i);try{const p=J(e,i),c=new T(p,this.globalConfigStore);this.sharedInstances.set(o,c),await c.start(),l.info("manager",`shared instance started: ${o}`)}catch(p){this.sharedInstances.delete(o);const c=p instanceof Error?p.message:String(p);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,i),l.warn("manager",`shared instance auth rejected, removed from cache: ${o}`)):l.error("manager",`start shared instance failed ${o}: ${p}`)}}for(const{key:i}of s){const o=this.sharedInstances.get(i);o&&(this.sharedInstances.delete(i),o.stop().catch(p=>l.error("manager",`stop shared instance failed ${i}: ${p}`)),l.info("manager",`shared instance stopped: ${i}`))}}restoreCachedSharedInstances(e){const t=this.sharedOwnersCache.load(e.name);t.length!==0&&(l.info("manager",`restoring ${t.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,t))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),l.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,t){const r=b(e);if(this.instances.some(s=>s.name===r.name))throw new Error(`Agent "${r.name}" already exists`);await this.startInstanceFromConfig(r,e,t)}async startInstanceFromConfig(e,t,r){const s=new T(e,this.globalConfigStore);s.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),s.setShareSetHandler(i=>this.onShareSet(e,i)),s.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),s.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),s.setProviderConfigHandler(i=>this.setAgentProvider(e.name,i)),s.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),await s.start(),this.instances.push(s),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:t,file:r}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(t=>t.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,t){const r=this.instances.findIndex(p=>p.name===e),s=r===-1?void 0:this.instances[r];r!==-1&&this.instances.splice(r,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const i=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),i&&await i.catch(()=>{});const o=`${e}#shared:`;for(const[p,c]of[...this.sharedInstances.entries()])p.startsWith(o)&&(this.sharedInstances.delete(p),c.stop().catch(a=>l.error("manager",`stop shared instance failed ${p}: ${a}`)));t?.keepShareCache||this.sharedOwnersCache.delete(e),s&&await s.stop()}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(r=>r.name===e)))return;l.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(t){l.error("manager",`cleanup for deleted agent "${e}" failed: ${t}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=A(this.configDir,"agents.json");try{const t=[];for(const[,s]of this.configMap){const i=this.rawConfigMap.get(s.name)?.entry.provider;t.push({name:s.name,ws_url:s.aibot.url,agent_id:s.aibot.agentId,api_key:s.aibot.apiKey,client_type:s.aibot.clientType,...i?{provider:i}:{}})}z(e,JSON.stringify({agents:t},null,4)+`
|
|
2
|
-
`,"utf-8")}catch(
|
|
1
|
+
import{readFileSync as K,readdirSync as G,writeFileSync as z}from"node:fs";import{join as v}from"node:path";import{AgentInstance as T}from"./bridge/bridge.js";import{buildSharedInstanceConfig as J,diffSharedOwners as V,sharedInstanceKey as X,SharedOwnersCache as Y}from"./manager-share-config.js";import{isAgentDeletedError as D}from"./core/aibot/errors.js";import{GRIX_PATHS as w,log as l}from"./core/log/index.js";import{resolveClientVersion as Z}from"./core/util/client-version.js";import{UpgradeChecker as ee}from"./core/upgrade/upgrade-checker.js";import{SkillSyncer as te}from"./core/skill-sync/skill-syncer.js";import{AgentGlobalConfigStore as ne}from"./core/persistence/agent-global-config-store.js";import{resolveSkillScanMode as ae}from"./adapter/claude/skill-scanner.js";import{buildWireSkills as re}from"./core/skill-sync/sync-state.js";import{buildReportedSkills as se,logDefaultSkillsCheck as oe,cleanupProjectedSkills as P}from"./default-skills/index.js";import{supportsDirectProviderConfig as ie}from"./core/config/provider-env.js";import{resolveCopilotCommand as O}from"./core/runtime/copilot-resolve.js";import{resolveCursorCommand as q}from"./core/runtime/cursor-resolve.js";import{getCliVersion as ce,resolveCliPath as le}from"./core/util/cli-probe.js";import{AgentInstaller as de}from"./core/installer/installer.js";import{reportInstallFailure as pe}from"./core/observability/sentry.js";const me=8e3;function ue(){const t=O();return[{clientType:"openclaw",command:"openclaw"},{clientType:"claude",command:"claude"},{clientType:"codex",command:"codex"},{clientType:"qwen",command:"qwen"},{clientType:"hermes",command:"hermes"},{clientType:"reasonix",command:"reasonix"},{clientType:"codewhale",command:"codewhale"},{clientType:"opencode",command:"opencode"},{clientType:"cursor",command:q()},{clientType:"pi",command:"pi"},{clientType:"openhuman",command:"openhuman-core"},{clientType:"kiro",command:"kiro-cli"},{clientType:"kimi",command:"kimi"},{clientType:"copilot",command:t.command},{clientType:"agy",command:"agy"}]}async function ge(){return Promise.all(ue().map(async t=>{const e=await le(t.command);if(!e)return{client_type:t.clientType,command:t.command,installed:!1,path:null,version:null};const n=await ce(e,t.versionArgs??["--version"]);return{client_type:t.clientType,command:t.command,installed:!0,path:e,version:n.version,error:n.error}}))}function he(t){switch(t){case"claude":return{adapterType:"claude",command:"claude"};case"codex":return{adapterType:"codex",command:"codex",options:{sandboxMode:"danger-full-access"}};case"gemini":return{adapterType:"acp",command:"gemini",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"qwen":return{adapterType:"acp",command:"qwen",adapterHint:"qwen/base",autoInjectArgs:{acp:!0},enableSessionBinding:!0};case"pi":return{adapterType:"pi",command:"pi"};case"cursor":return{adapterType:"cursor",command:q()};case"reasonix":return{adapterType:"acp",command:"reasonix",args:["acp"],enableSessionBinding:!0};case"codewhale":return{adapterType:"codewhale",command:"codewhale",enableSessionBinding:!0};case"openhuman":return{adapterType:"openhuman",command:"openhuman-core",enableSessionBinding:!0};case"kiro":return{adapterType:"acp",command:"kiro-cli",args:["acp"],enableSessionBinding:!0};case"kimi":return{adapterType:"acp",command:"kimi",args:["acp"],options:{initial_mode:"yolo"},enableSessionBinding:!0};case"opencode":return{adapterType:"opencode",command:"opencode",args:["serve"],enableSessionBinding:!0};case"copilot":{const e=O();return{adapterType:"acp",command:e.command,args:[...e.prefixArgs,"--acp"],enableSessionBinding:!0}}case"agy":return{adapterType:"agy",command:"agy",enableSessionBinding:!0};case"hermes":return{adapterType:"acp",command:"hermes",args:["acp"],enableSessionBinding:!0};default:throw new Error(`Unsupported client_type: ${t}`)}}function H(t,e){return String(t??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||String(e??"").trim().toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"")||"default"}function fe(t,e){return v(w.data,`session-bindings-${H(t,e)}.json`)}function _e(t,e){return v(w.data,`active-events-${H(t,e)}.json`)}function ye(...t){const e=[],n=new Set;for(const r of t)for(const s of r??[]){const i=String(s??"").trim(),o=i.toLowerCase();!i||n.has(o)||(n.add(o),e.push(i))}return e.length>0?e:void 0}function we(t,e){const n={claude:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codex:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},cursor:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},acp:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},pi:{maxConcurrent:1,maxQueued:5,queueTimeoutMs:0},codewhale:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},openhuman:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},opencode:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0},agy:{maxConcurrent:1,maxQueued:3,queueTimeoutMs:0}},r=n[t]??n.acp;return{maxConcurrent:e?.max_concurrent??r.maxConcurrent??1,maxQueued:e?.max_queued??r.maxQueued??3,queueTimeoutMs:e?.queue_timeout_ms??r.queueTimeoutMs??0,cancelableQueued:!0,cancelableRunning:!0}}function b(t,e={}){const n=Z(),r=String(t.client_type??"").trim().toLowerCase(),s=he(r),i=String(t.ws_url??"").trim(),o="get_session_usage",p="get_rate_limits",c="get_agent_global_config";if(!t.name?.trim())throw new Error("agent name is required");if(!i)throw new Error(`agent ${t.name}: ws_url is required`);if(!t.agent_id?.trim())throw new Error(`agent ${t.name}: agent_id is required`);if(!t.api_key?.trim())throw new Error(`agent ${t.name}: api_key is required`);const a=s.adapterType,g=a==="acp",m=r==="qwen",_={...s.options??{}},S=a==="codex"?{capabilities:["local_action_v1","agent_invoke"],localActions:["session_control","get_context","set_model","set_mode","set_reasoning_effort","set_service_tier","set_sandbox_mode","exec_approve","exec_reject","file_list","create_folder","turn_interrupt","permission_approve","permission_reject","thread_compact",o,p]}:null,d=a==="claude"?{localActions:["session_control","set_mode","set_model","claude_interaction_reply","exec_approve","exec_reject","file_list","create_folder","thread_compact",o,p]}:null,f=m?{capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o],adapterHint:"qwen/base"}:null,h=a==="pi"?{adapterHint:"pi/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","get_context","file_list","create_folder",o]}:null,u=a==="openhuman"?{adapterHint:"openhuman/base",capabilities:["local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,y=a==="cursor"?{adapterHint:"cursor/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","set_mode","get_context","file_list","create_folder",o,p]}:null,A=a==="codewhale"?{capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,C=a==="opencode"?{adapterHint:"opencode/base",capabilities:["stream_chunk","local_action_v1"],localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o]}:null,$=a==="agy"?{adapterHint:"agy/base",capabilities:["stream_chunk","local_action_v1"],localActions:["session_control","set_model","file_list","create_folder",o]}:null,R=g&&!m?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder",o]}:null,B=r==="kiro"?{localActions:["exec_approve","exec_reject","permission_approve","permission_reject","session_control","set_model","set_mode","file_list","create_folder","thread_compact",o,p]}:null,U=a==="codex"||a==="claude"||r==="gemini"?["session_control","set_model","set_mode"]:void 0,F=[o,p];g&&_.raw_transport===void 0&&(_.raw_transport=r==="gemini");const L=`${r}/base`,I=ae(a,r),Q=I==="kiro"?void 0:process.cwd(),E=se({mode:I,projectDir:Q}),M=E.filter(x=>x.source==="connector").map(x=>x.name);M.length>0&&!e.quiet&&l.info("manager",`[${t.name}] injecting connector skills: [${M.join(", ")}]`);const j=re(E,w.skills);let W=j.length>0?j:void 0;return{name:t.name,adapterType:a,aibot:{url:i,agentId:t.agent_id,apiKey:t.api_key,clientType:r,clientVersion:n,adapterHint:s.adapterHint??f?.adapterHint??h?.adapterHint??u?.adapterHint??y?.adapterHint??C?.adapterHint??$?.adapterHint??L,capabilities:S?.capabilities??A?.capabilities??h?.capabilities??u?.capabilities??y?.capabilities??C?.capabilities??$?.capabilities??f?.capabilities??["stream_chunk","local_action_v1","connector_upgrade"],localActions:ye(S?.localActions??A?.localActions??d?.localActions??h?.localActions??u?.localActions??y?.localActions??C?.localActions??$?.localActions??f?.localActions??B?.localActions??R?.localActions??["exec_approve","exec_reject"],U,F,["connector_rollback","connector_upgrade_push",c,"configure_gateway_provider","skill_upload"]),skills:W},agent:{command:s.command,args:[...s.args??[],...t.args??[]],env:t.env,clientType:r,...t.provider?{provider:{...t.provider.provider_id?.trim()?{providerId:t.provider.provider_id.trim()}:{},...t.provider.base_url?.trim()?{baseUrl:t.provider.base_url.trim()}:{},...t.provider.quota_base_url?.trim()?{quotaBaseUrl:t.provider.quota_base_url.trim()}:{},...t.provider.api_key?.trim()?{apiKey:t.provider.api_key.trim()}:{},...t.provider.model?.trim()?{model:t.provider.model.trim()}:{}}}:{}},adapterOptions:_,acpAuthMethod:_.auth_method,acpInitialMode:_.initial_mode,acpMcpTools:_.acp_mcp_tools,promptTimeoutMs:t.prompt_timeout_ms,bindingsPath:fe(t.name,t.agent_id),activeEventStorePath:_e(t.name,t.agent_id),...s.enableSessionBinding||g?{enableSessionBinding:!0}:{},...s.autoInjectArgs||r==="reasonix"&&t.provider?.model?.trim()?{autoInjectArgs:{...s.autoInjectArgs??{},...r==="reasonix"&&t.provider?.model?.trim()?{model:t.provider.model.trim()}:{}}}:{},poolMaxSize:t.pool?.maxSize,poolIdleTimeoutMs:t.pool?.idleTimeoutMs,eventQueue:we(a,t.event_queue),logDir:w.log,providerBaseUrl:t.provider_base_url?.trim()||void 0,providerApiKey:t.provider_api_key?.trim()||void 0}}function Se(){const t=process.env.GRIX_AGENT_STARTUP_WAIT_MS,e=Number(t);return Number.isFinite(e)&&e>=500?Math.floor(e):me}function N(t){const e=[],n=[],r=[],s=G(t).filter(i=>i.endsWith(".json")).sort();for(const i of s)try{const o=JSON.parse(K(v(t,i),"utf-8"));if(o===null||typeof o!="object"||Array.isArray(o)||!("agents"in o)){r.push(i);continue}if(!Array.isArray(o.agents)){n.push({file:i,error:"agents is not an array"});continue}if(o.agents.length===0){n.push({file:i,error:"agents array is empty"});continue}for(const p of o.agents)e.push({entry:p,file:i})}catch(o){n.push({file:i,error:o instanceof Error?o.message:String(o)})}return{entries:e,fileErrors:n,skipped:r}}function k(t){if(t===null||typeof t!="object")return JSON.stringify(t)??"null";if(Array.isArray(t))return`[${t.map(k).join(",")}]`;const e=t;return`{${Object.keys(e).sort().map(r=>`${JSON.stringify(r)}:${k(e[r])}`).join(",")}}`}function ve(t,e){return k(t)===k(e)}class Le{instances=[];configMap=new Map;rawConfigMap=new Map;reloadChain=Promise.resolve();sharedInstances=new Map;shareSyncChains=new Map;stopping=!1;deletedAgentCleanups=new Set;upgradeChecker=null;skillSyncer=null;globalConfigStore;configDir=w.config;sharedOwnersCache=new Y(w.data);installer=new de;async start(e){const n=e??w.config;this.configDir=n,l.info("manager",`Loading configs from ${n}`),oe(),P(),this.globalConfigStore=new ne(v(w.data,"agent-global-configs.json")),this.globalConfigStore.load();const{entries:r,fileErrors:s,skipped:i}=N(n);for(const a of s)l.error("manager",`Failed to load ${a.file}: ${a.error}`);for(const a of i)l.info("manager",`Skipped ${a}: not an agent config (no "agents" key)`);if(r.length===0&&s.length===0&&i.length===0)throw new Error(`No config files found in ${n}`);const o=[];let p=s.length;for(const{entry:a,file:g}of r)try{const m=b(a);o.push({config:m,entry:a,file:g}),l.info("manager",`Loaded ${m.name} (${m.adapterType??"acp"}) from ${g}`)}catch(m){const _=typeof a?.name=="string"?a.name:"<unknown>";l.error("manager",`Invalid agent config in ${g} (name=${_}): ${m}`),p++}let c=0;if(o.length>0){const a=Se();l.info("manager",`Starting ${o.length} agent(s), startup wait=${a}ms`);const g=()=>this.upgradeChecker?.triggerCheck(),m=d=>{this.instances=this.instances.filter(f=>f!==d)},_=o.map(({config:d,entry:f,file:h})=>{const u=new T(d,this.globalConfigStore);return u.setUpgradeTrigger(g),u.setShareSetHandler(y=>this.onShareSet(d,y)),u.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(d.name)),u.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),this.instances.push(u),this.configMap.set(d.name,d),this.rawConfigMap.set(d.name,{entry:f,file:h}),{config:d,instance:u,startPromise:u.start()}}),S=await Promise.all(_.map(async d=>{const f=await new Promise(h=>{let u=!1;const y=setTimeout(()=>{u||(u=!0,h({kind:"timeout"}))},a);d.startPromise.then(()=>{u||(u=!0,clearTimeout(y),h({kind:"started"}))}).catch(A=>{u||(u=!0,clearTimeout(y),h({kind:"failed",error:A}))})});return{task:d,outcome:f}}));for(const{task:d,outcome:f}of S){if(f.kind==="started"){this.restoreCachedSharedInstances(d.config);continue}if(f.kind==="failed"){if(D(f.error)){this.onAgentDeletedByPlatform(d.config.name);continue}m(d.instance),l.error("manager",`Failed to start ${d.config.name}: ${f.error}`);continue}c++,l.warn("manager",`Startup pending for ${d.config.name}, continue retrying in background`),d.startPromise.then(()=>{l.info("manager",`Delayed start succeeded: ${d.config.name}`),this.restoreCachedSharedInstances(d.config)}).catch(h=>{if(D(h)){this.onAgentDeletedByPlatform(d.config.name);return}m(d.instance),l.error("manager",`Delayed start failed: ${d.config.name}: ${h}`)})}if(this.instances.length>0){const d=Math.max(0,this.instances.length-c);l.info("manager",`${d}/${o.length} agent(s) running now`)}c>0&&l.warn("manager",`${c} agent(s) still connecting in background`)}if(this.instances.length===0&&o.length>0)throw new Error("All agent configurations failed to start");o.length>0&&(this.upgradeChecker=new ee(o.map(({config:a})=>({apiKey:a.aibot.apiKey,wsUrl:a.aibot.url})),()=>this.instances.some(a=>a.hasPendingOrBackgroundWork())||[...this.sharedInstances.values()].some(a=>a.hasPendingOrBackgroundWork())),await this.upgradeChecker.start()),o.length>0&&(this.skillSyncer=new te(o.map(({config:a})=>({apiKey:a.aibot.apiKey,wsUrl:a.aibot.url})),w.skills),await this.skillSyncer.start())}async stop(){l.info("manager","Stopping all agents..."),this.stopping=!0,this.upgradeChecker?.stop(),this.skillSyncer?.stop(),await Promise.allSettled([...this.shareSyncChains.values()]),this.shareSyncChains.clear();const e=[...this.sharedInstances.values()];this.sharedInstances.clear(),await Promise.allSettled([...this.instances.map(n=>n.stop()),...e.map(n=>n.stop())]),await this.globalConfigStore?.flush(),this.instances=[],P(),l.info("manager","All stopped")}onShareSet(e,n){this.sharedOwnersCache.save(e.name,n);const s=(this.shareSyncChains.get(e.name)??Promise.resolve()).catch(()=>{}).then(()=>this.syncSharedInstances(e,n));this.shareSyncChains.set(e.name,s)}async syncSharedInstances(e,n){if(this.stopping)return;const{toAdd:r,toRemove:s}=V(e.name,this.sharedInstances.keys(),n);for(const i of r){if(this.stopping)break;const o=X(e.name,i);try{const p=J(e,i),c=new T(p,this.globalConfigStore);this.sharedInstances.set(o,c),await c.start(),l.info("manager",`shared instance started: ${o}`)}catch(p){this.sharedInstances.delete(o);const c=p instanceof Error?p.message:String(p);/Auth failed/i.test(c)?(this.sharedOwnersCache.remove(e.name,i),l.warn("manager",`shared instance auth rejected, removed from cache: ${o}`)):l.error("manager",`start shared instance failed ${o}: ${p}`)}}for(const{key:i}of s){const o=this.sharedInstances.get(i);o&&(this.sharedInstances.delete(i),o.stop().catch(p=>l.error("manager",`stop shared instance failed ${i}: ${p}`)),l.info("manager",`shared instance stopped: ${i}`))}}restoreCachedSharedInstances(e){const n=this.sharedOwnersCache.load(e.name);n.length!==0&&(l.info("manager",`restoring ${n.length} cached shared instance(s) for ${e.name}`),this.onShareSet(e,n))}getAgentsStatus(){return this.instances.map(e=>e.getStatus())}async addAgent(e){await this.addAgentInternal(e,"agents.json"),this.persistAgentsConfig(),l.info("manager",`Added agent: ${e.name}`)}async addAgentInternal(e,n){const r=b(e);if(this.instances.some(s=>s.name===r.name))throw new Error(`Agent "${r.name}" already exists`);await this.startInstanceFromConfig(r,e,n)}async startInstanceFromConfig(e,n,r){const s=new T(e,this.globalConfigStore);s.setUpgradeTrigger(()=>this.upgradeChecker?.triggerCheck()),s.setShareSetHandler(i=>this.onShareSet(e,i)),s.setAgentDeletedHandler(()=>this.onAgentDeletedByPlatform(e.name)),s.setSkillSyncHandler(()=>this.skillSyncer?.triggerSync()),s.setProviderConfigHandler(i=>this.setAgentProvider(e.name,i)),s.setRelayEnvSettledHandler(()=>this.relayEnvSettledHandler?.()),await s.start(),this.instances.push(s),this.configMap.set(e.name,e),this.rawConfigMap.set(e.name,{entry:n,file:r}),this.relayEnvSettledHandler?.()}async removeAgent(e){if(!this.instances.some(n=>n.name===e))throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Removed agent: ${e}`),this.relayEnvSettledHandler?.()}async removeAgentInternal(e,n){const r=this.instances.findIndex(p=>p.name===e),s=r===-1?void 0:this.instances[r];r!==-1&&this.instances.splice(r,1),this.configMap.delete(e),this.rawConfigMap.delete(e);const i=this.shareSyncChains.get(e);this.shareSyncChains.delete(e),i&&await i.catch(()=>{});const o=`${e}#shared:`;for(const[p,c]of[...this.sharedInstances.entries()])p.startsWith(o)&&(this.sharedInstances.delete(p),c.stop().catch(a=>l.error("manager",`stop shared instance failed ${p}: ${a}`)));n?.keepShareCache||this.sharedOwnersCache.delete(e),s&&await s.stop()}onAgentDeletedByPlatform(e){this.stopping||this.deletedAgentCleanups.has(e)||(this.deletedAgentCleanups.add(e),(async()=>{try{if(!(this.rawConfigMap.has(e)||this.instances.some(r=>r.name===e)))return;l.warn("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u505C\u6B62\u5B9E\u4F8B\u5E76\u6E05\u7406\u672C\u5730\u914D\u7F6E`),await this.removeAgentInternal(e),this.persistAgentsConfig(),l.info("manager",`Agent "${e}" \u5DF2\u5728\u5E73\u53F0\u5220\u9664\uFF0C\u672C\u5730\u914D\u7F6E\u5DF2\u6E05\u7406\uFF08agents.json \u5DF2\u79FB\u9664\u8BE5\u6761\u76EE\uFF09`)}catch(n){l.error("manager",`cleanup for deleted agent "${e}" failed: ${n}`)}finally{this.deletedAgentCleanups.delete(e)}})())}persistAgentsConfig(){const e=v(this.configDir,"agents.json");try{const n=[];for(const[,s]of this.configMap){const i=this.rawConfigMap.get(s.name)?.entry.provider;n.push({name:s.name,ws_url:s.aibot.url,agent_id:s.aibot.agentId,api_key:s.aibot.apiKey,client_type:s.aibot.clientType,...i?{provider:i}:{}})}z(e,JSON.stringify({agents:n},null,4)+`
|
|
2
|
+
`,"utf-8")}catch(n){l.error("manager",`Failed to persist agents config: ${n}`)}}isAgentBusy(e){return this.instances.find(r=>r.name===e)?.hasPendingWork()??!1}getAgentsWithStaleRelayEnv(){return this.instances.filter(e=>e.hasStaleRelayEnv()).map(e=>e.name)}markAgentRelayEnvStale(e){const n=this.instances.find(r=>r.name===e);return n?(n.markRelayEnvStale(),!0):!1}relayEnvSettledHandler;setRelayEnvSettledHandler(e){this.relayEnvSettledHandler=e}async restartAgent(e){const n=this.rawConfigMap.get(e);if(!n)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});await this.replaceInstance(e,n.entry,n.file),l.info("manager",`Restarted agent: ${e}`)}async setAgentProvider(e,n){const r=this.rawConfigMap.get(e);if(!r)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});const s={...r.entry,provider:n};await this.replaceInstance(e,s,r.file),this.persistAgentsConfig(),l.info("manager",`Updated provider config for agent: ${e}`)}async clearDirectProviderConfigs(){const e=[...this.rawConfigMap.entries()].filter(([,r])=>!!r.entry.provider&&ie(r.entry.client_type)).map(([r])=>r),n=[];for(const r of e)try{await this.setAgentProvider(r,void 0),n.push(r)}catch(s){l.warn("manager",`Failed to clear provider config for "${r}": ${s instanceof Error?s.message:String(s)}`)}return n}async replaceInstance(e,n,r){const s=b(n);await this.removeAgentInternal(e,{keepShareCache:!0}),await this.startInstanceFromConfig(s,n,r),this.restoreCachedSharedInstances(s)}async reload(){const e=this.reloadChain.catch(()=>{}).then(()=>this.doReload());return this.reloadChain=e.catch(()=>{}),e}async doReload(){if(this.stopping)throw Object.assign(new Error("manager is stopping"),{code:"RELOAD_UNSAFE"});const{entries:e,fileErrors:n,skipped:r}=N(this.configDir);for(const c of r)l.info("manager",`reload: skipped ${c}: not an agent config (no "agents" key)`);if(n.length>0){const c=n.map(a=>`${a.file}: ${a.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${n.length} config file(s) failed to parse [${c}]`),{code:"RELOAD_UNSAFE"})}if(e.length===0)throw Object.assign(new Error("reload aborted: no valid agent config found"),{code:"RELOAD_UNSAFE"});const s=[];for(const{entry:c}of e)try{b(c,{quiet:!0})}catch(a){const g=c?.name,m=typeof g=="string"&&g.trim()?g:"<unknown>";s.push({name:m,error:a instanceof Error?a.message:String(a)})}if(s.length>0){const c=s.map(a=>`${a.name}: ${a.error}`).join("; ");throw Object.assign(new Error(`reload aborted: ${s.length} agent config(s) invalid [${c}]`),{code:"RELOAD_UNSAFE"})}const i=new Map;for(const c of e){const a=String(c.entry?.name??"").trim();a&&(i.has(a)&&l.warn("manager",`reload: duplicate agent name "${a}", last one wins`),i.set(a,c))}const o={added:[],removed:[],restarted:[],unchanged:[],failed:[]},p=new Set(this.rawConfigMap.keys());for(const c of p)if(!i.has(c))try{await this.removeAgentInternal(c),o.removed.push(c)}catch(a){o.failed.push({name:c,error:a instanceof Error?a.message:String(a)})}for(const[c,a]of i){const g=this.rawConfigMap.get(c);if(g)if(ve(g.entry,a.entry))this.rawConfigMap.set(c,a),o.unchanged.push(c);else try{await this.replaceInstance(c,a.entry,a.file),o.restarted.push(c)}catch(m){o.failed.push({name:c,error:m instanceof Error?m.message:String(m)})}else try{await this.addAgentInternal(a.entry,a.file),o.added.push(c)}catch(m){o.failed.push({name:c,error:m instanceof Error?m.message:String(m)})}}return l.info("manager",`reload done: +${o.added.length} -${o.removed.length} ~${o.restarted.length} =${o.unchanged.length} !${o.failed.length}`),o}async checkUpgrade(){return this.upgradeChecker?this.upgradeChecker.checkForUpdate():{available:!1}}triggerUpgrade(){this.upgradeChecker?.triggerCheck()}async probeAll(e={}){return Ae(this.instances,e)}async probeOne(e,n={}){return be(this.instances,e,n)}listInstallable(){return this.installer.listInstallable()}async installAgent(e){const n=await this.installer.install(e);return pe(n),n}getInstallProgress(e){return this.installer.getProgress(e)??null}}async function Ae(t,e){const n=e.concurrency??4,r=Date.now(),s=new Array(t.length);await new Promise(a=>{let g=0,m=0;const _=t.length;if(_===0){a();return}function S(h){const u=t[h];u.probe(e).then(y=>{s[h]=y,d()},y=>{s[h]={agent_name:u.name,client_type:"unknown",adapter_type:"acp",ok:!1,status:"error",probed_at:Date.now(),duration_ms:0,cached:!1,cli:{command:"",installed:!1,path:null,version:null,error:{code:"internal",message:y?.message??String(y)}},conversation:{attempted:!1,ok:!1,latency_ms:null},config:{model:null,base_url:null,source:{model:"unknown",base_url:"unknown"}},process:{started:!1,alive:!1,busy:!1}},d()})}function d(){m++,g<_?S(g++):m===_&&a()}const f=Math.min(n,_);for(let h=0;h<f;h++)S(g++)});const i=s.filter(a=>a.status==="healthy").length,o=s.filter(a=>a.status==="degraded").length,p=s.filter(a=>a.status==="unavailable").length,c=await ge();return{ok:i===s.length&&s.length>0,total:s.length,healthy:i,degraded:o,unavailable:p,installed_clients:c,agents:s,probed_at:r,duration_ms:Date.now()-r}}async function be(t,e,n){const r=t.find(s=>s.name===e);if(!r)throw Object.assign(new Error(`Agent "${e}" not found`),{code:"NOT_FOUND"});return r.probe(n)}export{Le as Manager,ge as probeInstalledClientCommands,Ae as probeInstances,be as probeOneInstance};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as i from"node:net";const e={bind:"127.0.0.1",port:0,endpoint:"/mcp",sessionTimeoutMs:18e5,invokeTimeoutMs:3e4};function n(o){const u={bind:o?.bind??e.bind,port:o?.port??e.port,endpoint:o?.endpoint??e.endpoint,sessionTimeoutMs:o?.sessionTimeoutMs??e.sessionTimeoutMs,invokeTimeoutMs:o?.invokeTimeoutMs??e.invokeTimeoutMs,allowedOrigins:o?.allowedOrigins,allowedHosts:o?.allowedHosts};return s(u.bind),u.port!==0&&t(u.port),r(u.sessionTimeoutMs),u}function s(o){if(!o||!i.isIPv4(o)&&!i.isIPv6(o))throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: bind \u5730\u5740 "${o}" \u4E0D\u662F\u5408\u6CD5\u7684 IPv4 \u6216 IPv6 \u5730\u5740`)}function t(o){if(!Number.isInteger(o)||o<1||o>65535)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: port \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1-65535 \u5185\u6216\u4E0D\u662F\u6574\u6570`)}function r(o){if(!Number.isInteger(o)||o<1e3||o>864e5)throw new Error(`\u914D\u7F6E\u6821\u9A8C\u5931\u8D25: session_timeout_ms \u503C ${o} \u4E0D\u5728\u5408\u6CD5\u8303\u56F4 1000-86400000 \u5185`)}export{n as createDefaultGatewayConfig};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const r=3e4;class c{connectionManager;onDisconnected;bindings=new Map;constructor(n,i){this.connectionManager=n,this.onDisconnected=i}async bind(n,i){if(this.bindings.has(n))throw new Error(`Session ${n} is already bound to a connection`);const e=await this.connectWithTimeout(i),t=[],s=e.onDisconnected(()=>{this.removeBinding(n),this.onDisconnected(n)});return t.push(s),this.bindings.set(n,{sessionId:n,handle:e,subscriptions:t}),e}getHandle(n){return this.bindings.get(n)?.handle}unbind(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e();i.handle.disconnect()}}unbindAll(){const n=[...this.bindings.keys()];for(const i of n)this.unbind(i)}connectWithTimeout(n){return new Promise((i,e)=>{let t=!1;const s=setTimeout(()=>{t||(t=!0,e(new Error("Connection bind timeout after 30000ms")))},3e4);this.connectionManager.connect({agentId:n.agentId,apiKey:n.apiKey,url:n.wsUrl,clientType:n.clientType,capabilities:["agent_invoke"],adapterHint:`${n.clientType}/base`},{maxRetries:0}).then(o=>{t?o.disconnect():(t=!0,clearTimeout(s),i(o))}).catch(o=>{t||(t=!0,clearTimeout(s),e(o))})})}removeBinding(n){const i=this.bindings.get(n);if(i){this.bindings.delete(n);for(const e of i.subscriptions)e()}}}export{c as ConnectionBindingImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function a(
|
|
1
|
+
function a(o){const e=new Set([`http://127.0.0.1:${o.serverPort}`,`http://localhost:${o.serverPort}`,...o.allowedOrigins]),t=new Set([`127.0.0.1:${o.serverPort}`,`localhost:${o.serverPort}`,...o.allowedHosts]);return{validateRequest(s){const r=i(s,e);if(!r.ok)return r;const n=l(s,t);return n.ok?{ok:!0}:n}}}function i(o,e){const t=o.headers.origin;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${t}`}:{ok:!0}}function l(o,e){const t=o.headers.host;return t?e.has(t)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${t}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(
|
|
1
|
+
import{toolCallToInvoke as i}from"../../core/mcp/tools.js";import{ToolRegistryImpl as l}from"./tool-registry.js";import{validateToolArgs as a}from"./tool-schemas.js";import{isEventTool as p,executeEventTool as d}from"./event-tool-executor.js";class y{registry;constructor(){this.registry=new l}async execute(t,e,r,n){if(!this.registry.hasTool(e))return this.errorResult(`\u672A\u77E5\u5DE5\u5177: ${e}`);const s=a(e,r);if(!s.valid)return this.errorResult(`\u53C2\u6570\u6821\u9A8C\u5931\u8D25: ${s.error}`);if(t.status!=="ready")return this.errorResult(`\u8FDE\u63A5\u4E0D\u53EF\u7528: \u5F53\u524D\u72B6\u6001\u4E3A ${t.status}`);if(p(e))return this.executeEventTool(t,e,r);const o=i(e,r);try{const u=await t.agentInvoke(o.action,o.params,n);return this.normalizeResult(u)}catch(u){const c=u instanceof Error?u.message:String(u);return c.toLowerCase().includes("timeout")?this.errorResult(`\u8C03\u7528\u8D85\u65F6: ${c}`):this.errorResult(`\u8C03\u7528\u5931\u8D25: ${c}`)}}normalizeResult(t){if(t==null||typeof t!="object")return this.successResult(t??null);const e=t,r=typeof e.code=="number"?e.code:0;if(r===0){const s="data"in e?e.data:null;return this.successResult(s??null)}const n=typeof e.msg=="string"?e.msg:"\u672A\u77E5\u9519\u8BEF";return this.errorResult(`\u4E0A\u6E38\u9519\u8BEF [code=${r}]: ${n}`)}successResult(t){return{content:[{type:"text",text:JSON.stringify(t)}],isError:!1}}errorResult(t){return{content:[{type:"text",text:t}],isError:!0}}async executeEventTool(t,e,r){return e==="grix_access_control"?this.executeAccessControl(t,r):d(t,e,r)}async executeAccessControl(t,e){const r=String(e.action??""),n={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"}[r];if(!n)return this.errorResult(`\u672A\u77E5 access_control action: ${r}`);const s={};e.code!=null&&(s.code=e.code),e.sender_id!=null&&(s.sender_id=e.sender_id),e.policy!=null&&(s.policy=e.policy);try{const o=await t.agentInvoke("claude_access_control",{verb:n,payload:s},3e4);return this.successResult(o)}catch(o){const u=o instanceof Error?o.message:String(o);return this.errorResult(`access_control \u8C03\u7528\u5931\u8D25: ${u}`)}}}export{y as ToolExecutorImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TOOLS as
|
|
1
|
+
import{TOOLS as s,EVENT_TOOLS as t}from"../../core/mcp/tools.js";const e=new Set(["grix_query","grix_group","grix_message_send","grix_message_unsend","grix_admin"]),r=new Set(["grix_reply","grix_complete","grix_event_ack","grix_composing","grix_access_control","grix_status"]);class a{tools;toolMap;constructor(){this.tools=[...s.filter(o=>e.has(o.name)),...t.filter(o=>r.has(o.name))],this.toolMap=new Map(this.tools.map(o=>[o.name,o]))}getTools(){return this.tools}getTool(o){return this.toolMap.get(o)}hasTool(o){return this.toolMap.has(o)}}export{a as ToolRegistryImpl};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(
|
|
1
|
+
const o={required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search"]},id:{type:"string"},keyword:{type:"string",maxLength:200},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}},a={required:["action"],properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"]},sessionId:{type:"string"},name:{type:"string",maxLength:128},memberIds:{type:"array",items:{type:"string"},maxItems:100},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]}},memberId:{type:"string"},role:{type:"integer",enum:[1,2]},memberType:{type:"integer"},allMembersMuted:{type:"boolean"},isSpeakMuted:{type:"boolean"},canSpeakWhenAllMuted:{type:"boolean"}}},p={required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}},m={required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}},g={required:["action"],properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"]},agentName:{type:"string"},introduction:{type:"string"},isMain:{type:"boolean"},agentId:{type:"string"},categoryId:{type:"string"},name:{type:"string"},parentId:{type:"string"},sortOrder:{type:"integer"}}},y={required:["session_id","text"],properties:{event_id:{type:"string"},session_id:{type:"string"},text:{type:"string",maxLength:5e4},quoted_message_id:{type:"string"},is_final:{type:"boolean"}}},d={required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}},c={required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}},l={required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}},_={required:["action"],properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"]},code:{type:"string"},sender_id:{type:"string"},policy:{type:"string",enum:["allowlist","open","disabled"]}}},f={required:[],properties:{}},C={grix_query:o,grix_group:a,grix_message_send:p,grix_message_unsend:m,grix_admin:g,grix_reply:y,grix_complete:d,grix_event_ack:c,grix_composing:l,grix_access_control:_,grix_status:f};function B(u,t){const e=C[u];if(!e)return{valid:!1,error:`\u672A\u77E5\u5DE5\u5177: ${u}`};for(const i of e.required)if(t[i]===void 0||t[i]===null)return{valid:!1,error:`\u7F3A\u5C11\u5FC5\u586B\u53C2\u6570: ${i}`};for(const[i,r]of Object.entries(t)){if(r==null)continue;const n=e.properties[i];if(!n)continue;const s=$(i,r,n);if(s)return{valid:!1,error:s}}return{valid:!0}}function $(u,t,e){switch(e.type){case"string":if(typeof t!="string")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxLength!==void 0&&t.length>e.maxLength)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u957F\u5EA6 ${e.maxLength}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C "${t}" \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"integer":if(typeof t!="number"||!Number.isInteger(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof t=="number"?"\u6D6E\u70B9\u6570":typeof t}`;if(e.minimum!==void 0&&t<e.minimum)return`\u53C2\u6570 ${u} \u503C ${t} \u5C0F\u4E8E\u6700\u5C0F\u503C ${e.minimum}`;if(e.maximum!==void 0&&t>e.maximum)return`\u53C2\u6570 ${u} \u503C ${t} \u5927\u4E8E\u6700\u5927\u503C ${e.maximum}`;if(e.enum&&!e.enum.includes(t))return`\u53C2\u6570 ${u} \u503C ${t} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.enum.join(", ")}]`;break;case"boolean":if(typeof t!="boolean")return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B boolean\uFF0C\u5B9E\u9645 ${typeof t}`;break;case"array":if(!Array.isArray(t))return`\u53C2\u6570 ${u} \u7C7B\u578B\u9519\u8BEF: \u671F\u671B array\uFF0C\u5B9E\u9645 ${typeof t}`;if(e.maxItems!==void 0&&t.length>e.maxItems)return`\u53C2\u6570 ${u} \u8D85\u8FC7\u6700\u5927\u5143\u7D20\u6570 ${e.maxItems}\uFF0C\u5B9E\u9645 ${t.length}`;if(e.items)for(let i=0;i<t.length;i++){const r=t[i];if(e.items.type==="string"&&typeof r!="string")return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B string\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.type==="integer"){if(typeof r!="number"||!Number.isInteger(r))return`\u53C2\u6570 ${u}[${i}] \u7C7B\u578B\u9519\u8BEF: \u671F\u671B integer\uFF0C\u5B9E\u9645 ${typeof r}`;if(e.items.enum&&!e.items.enum.includes(r))return`\u53C2\u6570 ${u}[${i}] \u503C ${r} \u4E0D\u5728\u5141\u8BB8\u8303\u56F4 [${e.items.enum.join(", ")}]`}}break}}export{B as validateToolArgs};
|
package/openclaw-plugin/index.js
CHANGED
|
@@ -9207,7 +9207,7 @@ var TOOLS = [
|
|
|
9207
9207
|
description: "Admin action type."
|
|
9208
9208
|
},
|
|
9209
9209
|
agentName: { type: "string", description: "Agent name (create_agent)." },
|
|
9210
|
-
introduction: { type: "string", description: "
|
|
9210
|
+
introduction: { type: "string", description: "Professional behavioral introduction describing the Agent purpose, responsibilities, operating expectations, and boundaries (create_agent)." },
|
|
9211
9211
|
isMain: { type: "boolean", description: "Set as main agent (create_agent)." },
|
|
9212
9212
|
agentId: { type: "string", description: "Agent ID (assign_category, rotate_api_key)." },
|
|
9213
9213
|
categoryId: { type: "string", description: "Category ID (create_agent, update_category, assign_category)." },
|
|
@@ -10254,7 +10254,7 @@ function buildGrixAdminTaskMessage(task) {
|
|
|
10254
10254
|
"Use the grix-admin skill to complete the request below.",
|
|
10255
10255
|
"Do not call the grix_admin tool again with a task from this delegated run.",
|
|
10256
10256
|
"If the workflow needs remote API agent creation or category management, call grix_admin directly without task for that step.",
|
|
10257
|
-
"Direct actions: create_agent(agentName, optional
|
|
10257
|
+
"Direct actions: create_agent(agentName, introduction, optional isMain/categoryId/categoryName/parentCategoryId/categorySortOrder), list_categories(), create_category(name, parentId, optional sortOrder), update_category(categoryId, name, parentId, optional sortOrder), assign_category(agentId, categoryId; use 0 to clear), rotate_api_key(agentId).",
|
|
10258
10258
|
"Agents with agent.api.create scope can independently call rotate_api_key to rotate credentials for any agent owned by the same owner.",
|
|
10259
10259
|
`Request: ${task}`
|
|
10260
10260
|
].join("\n");
|
|
@@ -10418,6 +10418,9 @@ function normalizeFromInstallContext(rawInstallContext) {
|
|
|
10418
10418
|
const displayName = cleanText(
|
|
10419
10419
|
installBlock.suggested_agent_name ?? eggBlock.title ?? eggBlock.name ?? installBlock.agent_name ?? installBlock.target_agent_id
|
|
10420
10420
|
);
|
|
10421
|
+
const introduction = cleanText(
|
|
10422
|
+
installBlock.introduction ?? installBlock.agent_introduction ?? parsed.introduction
|
|
10423
|
+
);
|
|
10421
10424
|
const localAgentName = normalizeLocalAgentName(
|
|
10422
10425
|
cleanText(
|
|
10423
10426
|
installBlock.agent_id_slug ?? installBlock.local_agent_name ?? parsed.localAgentName ?? displayName
|
|
@@ -10436,6 +10439,7 @@ function normalizeFromInstallContext(rawInstallContext) {
|
|
|
10436
10439
|
packageName: cleanText(eggBlock.name),
|
|
10437
10440
|
localAgentName,
|
|
10438
10441
|
displayName,
|
|
10442
|
+
introduction,
|
|
10439
10443
|
downloadUrl: cleanText(eggBlock.downloadUrl ?? installBlock.package_url),
|
|
10440
10444
|
packageHash: cleanText(eggBlock.hash),
|
|
10441
10445
|
mainAgentName: cleanText(parsed.main_agent ?? installBlock.main_agent ?? "main") || "main",
|
|
@@ -10464,6 +10468,9 @@ function normalizeFromDirectParams(rawParams) {
|
|
|
10464
10468
|
throw new EggContextParseError("installId", "resume mode requires installId");
|
|
10465
10469
|
}
|
|
10466
10470
|
const displayName = cleanText(rawParams.agentName ?? rawParams.displayName ?? rawParams.suggested_agent_name);
|
|
10471
|
+
const introduction = cleanText(
|
|
10472
|
+
rawParams.introduction ?? rawParams.agentIntroduction ?? rawParams.agent_introduction
|
|
10473
|
+
);
|
|
10467
10474
|
const localAgentName = normalizeLocalAgentName(
|
|
10468
10475
|
cleanText(rawParams.localAgentName ?? rawParams.agentIdSlug ?? rawParams.agent_id_slug ?? displayName)
|
|
10469
10476
|
);
|
|
@@ -10478,6 +10485,7 @@ function normalizeFromDirectParams(rawParams) {
|
|
|
10478
10485
|
packageName: cleanText(rawParams.packageName ?? rawParams.package_name),
|
|
10479
10486
|
localAgentName,
|
|
10480
10487
|
displayName,
|
|
10488
|
+
introduction,
|
|
10481
10489
|
downloadUrl: cleanText(rawParams.downloadUrl),
|
|
10482
10490
|
packageHash: cleanText(rawParams.packageHash),
|
|
10483
10491
|
mainAgentName: cleanText(rawParams.mainAgent ?? "main") || "main",
|
|
@@ -10496,7 +10504,17 @@ function normalizeFromDirectParams(rawParams) {
|
|
|
10496
10504
|
function normalizeEggInstallRequest(rawParams) {
|
|
10497
10505
|
const rawInstallContext = cleanText(rawParams.installContext);
|
|
10498
10506
|
if (rawInstallContext) {
|
|
10499
|
-
|
|
10507
|
+
const request = normalizeFromInstallContext(rawInstallContext);
|
|
10508
|
+
const displayNameOverride = cleanText(rawParams.agentName ?? rawParams.displayName);
|
|
10509
|
+
const introductionOverride = cleanText(
|
|
10510
|
+
rawParams.introduction ?? rawParams.agentIntroduction ?? rawParams.agent_introduction
|
|
10511
|
+
);
|
|
10512
|
+
return {
|
|
10513
|
+
...request,
|
|
10514
|
+
displayName: displayNameOverride || request.displayName,
|
|
10515
|
+
localAgentName: request.localAgentName || normalizeLocalAgentName(displayNameOverride),
|
|
10516
|
+
introduction: introductionOverride || request.introduction
|
|
10517
|
+
};
|
|
10500
10518
|
}
|
|
10501
10519
|
return normalizeFromDirectParams(rawParams);
|
|
10502
10520
|
}
|
|
@@ -10504,6 +10522,7 @@ function collectMissingParameters(request) {
|
|
|
10504
10522
|
const missing = [];
|
|
10505
10523
|
if (!request.localAgentName) missing.push("localAgentName|agentIdSlug");
|
|
10506
10524
|
if (!request.displayName && request.route === "create_new") missing.push("agentName");
|
|
10525
|
+
if (!request.introduction && request.route === "create_new") missing.push("introduction");
|
|
10507
10526
|
if (!request.downloadUrl && request.route !== "existing_claude") missing.push("downloadUrl");
|
|
10508
10527
|
if (request.route === "existing") {
|
|
10509
10528
|
if (!request.existingCredentials?.agentId) missing.push("existingCredentials.agentId");
|
|
@@ -10999,6 +11018,7 @@ function mergeRequestForResume(current, previous) {
|
|
|
10999
11018
|
packageName: cleanText2(current.packageName) || previous.packageName,
|
|
11000
11019
|
localAgentName: cleanText2(current.localAgentName) || previous.localAgentName,
|
|
11001
11020
|
displayName: cleanText2(current.displayName) || previous.displayName,
|
|
11021
|
+
introduction: cleanText2(current.introduction) || previous.introduction,
|
|
11002
11022
|
downloadUrl: cleanText2(current.downloadUrl) || previous.downloadUrl,
|
|
11003
11023
|
packageHash: cleanText2(current.packageHash) || previous.packageHash,
|
|
11004
11024
|
mainAgentName: cleanText2(current.mainAgentName) || previous.mainAgentName,
|
|
@@ -11015,6 +11035,16 @@ function mergeRequestForResume(current, previous) {
|
|
|
11015
11035
|
existingCredentials: current.existingCredentials ?? previous.existingCredentials
|
|
11016
11036
|
};
|
|
11017
11037
|
}
|
|
11038
|
+
function buildCreateAgentToolParams(request) {
|
|
11039
|
+
return {
|
|
11040
|
+
action: "create_agent",
|
|
11041
|
+
agentName: request.displayName || request.localAgentName,
|
|
11042
|
+
introduction: request.introduction,
|
|
11043
|
+
isMain: request.isMain,
|
|
11044
|
+
categoryId: request.categoryId || void 0,
|
|
11045
|
+
categoryName: request.categoryName || void 0
|
|
11046
|
+
};
|
|
11047
|
+
}
|
|
11018
11048
|
function normalizeLoadedState(state) {
|
|
11019
11049
|
const normalizedSteps = makeEmptySteps();
|
|
11020
11050
|
const loadedSteps = state.steps && typeof state.steps === "object" ? state.steps : {};
|
|
@@ -11450,13 +11480,7 @@ async function runEggOrchestrator(params) {
|
|
|
11450
11480
|
const createResult = await hooks.runCreateAgent({
|
|
11451
11481
|
cfg,
|
|
11452
11482
|
contextAccountId: contextAccountId || void 0,
|
|
11453
|
-
toolParams:
|
|
11454
|
-
action: "create_agent",
|
|
11455
|
-
agentName: request.displayName || request.localAgentName,
|
|
11456
|
-
isMain: request.isMain,
|
|
11457
|
-
categoryId: request.categoryId || void 0,
|
|
11458
|
-
categoryName: request.categoryName || void 0
|
|
11459
|
-
}
|
|
11483
|
+
toolParams: buildCreateAgentToolParams(request)
|
|
11460
11484
|
});
|
|
11461
11485
|
const created = createResult.createdAgent;
|
|
11462
11486
|
const agentId = cleanText2(created?.id);
|
|
@@ -11743,6 +11767,7 @@ async function runEggOrchestrator(params) {
|
|
|
11743
11767
|
var TOOL_DESCRIPTION = [
|
|
11744
11768
|
"Program-first egg installer.",
|
|
11745
11769
|
"Pass installContext JSON directly, or pass structured install params.",
|
|
11770
|
+
"create_new requires a concrete agentName and a professional behavioral introduction.",
|
|
11746
11771
|
"AI should only normalize params and call this tool; do not manually perform create/bind/accept steps."
|
|
11747
11772
|
].join(" ");
|
|
11748
11773
|
var GrixEggToolSchema = {
|
|
@@ -11754,6 +11779,11 @@ var GrixEggToolSchema = {
|
|
|
11754
11779
|
installId: { type: "string", minLength: 1 },
|
|
11755
11780
|
resume: { type: "boolean" },
|
|
11756
11781
|
agentName: { type: "string", minLength: 1 },
|
|
11782
|
+
introduction: {
|
|
11783
|
+
type: "string",
|
|
11784
|
+
minLength: 1,
|
|
11785
|
+
description: "Professional agent profile describing purpose, responsibilities, operating rules, and boundaries."
|
|
11786
|
+
},
|
|
11757
11787
|
agentIdSlug: { type: "string", minLength: 1 },
|
|
11758
11788
|
localAgentName: { type: "string", minLength: 1 },
|
|
11759
11789
|
mainAgent: { type: "string", minLength: 1 },
|
|
@@ -11794,7 +11824,7 @@ function createGrixEggTool(api, ctx) {
|
|
|
11794
11824
|
ok: false,
|
|
11795
11825
|
error_code: "missing_parameters",
|
|
11796
11826
|
reason: "task mode is deprecated; use installContext or structured parameters to call grix_egg.",
|
|
11797
|
-
suggestion: "Provide installContext, or at least structured fields like route/agentName/downloadUrl.",
|
|
11827
|
+
suggestion: "Provide installContext, or at least structured fields like route/agentName/introduction/downloadUrl.",
|
|
11798
11828
|
install_id: parseInstallIdHint(rawParams)
|
|
11799
11829
|
});
|
|
11800
11830
|
}
|
|
@@ -24,11 +24,24 @@ description: Responsible for OpenClaw and grix-connector local configuration, bi
|
|
|
24
24
|
4. The legacy direct call format for `create_agent` (passing only `agentName` and other fields without `action`) is still compatible, but should not be used in new flows.
|
|
25
25
|
5. Use `bind-local` / `create-and-bind` for **OpenClaw** local configuration; use `connector-bind-local` / `create-and-connector-bind` for **grix-connector** local configuration. Do not mix the two targets in a single invocation.
|
|
26
26
|
|
|
27
|
+
## Agent Creation Intake
|
|
28
|
+
|
|
29
|
+
Before any `create_agent` API call:
|
|
30
|
+
|
|
31
|
+
1. Ensure both `agentName` and `introduction` are present and specific. Never create an Agent with an empty, generic, or placeholder introduction.
|
|
32
|
+
2. If either the Agent name or a usable introduction is missing or too vague, pause before calling the tool and ask one concise question: “这个 Agent 主要做什么?核心职责、服务对象和工作边界是什么?”
|
|
33
|
+
3. Convert the user's answer into:
|
|
34
|
+
- A concise, professional `agentName` that reflects the Agent's role.
|
|
35
|
+
- A professional `introduction` that states its purpose, core responsibilities, intended users or scenarios, operating expectations, and important boundaries.
|
|
36
|
+
4. Preserve the user's facts and intent. Do not invent permissions, business authority, expertise, or responsibilities that the user did not grant.
|
|
37
|
+
5. Treat `introduction` as the Agent's behavioral specification, not promotional copy. It directly affects how the Agent behaves after creation.
|
|
38
|
+
6. Pass the finalized professional text in the actual `introduction` field of `action=create_agent`; do not leave it only in conversation, a summary, `soulContent`, or local persona files.
|
|
39
|
+
|
|
27
40
|
## Direct Action List
|
|
28
41
|
|
|
29
42
|
1. `action=create_agent`
|
|
30
|
-
- Required: `agentName`
|
|
31
|
-
- Optional: `
|
|
43
|
+
- Required by this skill: `agentName`, `introduction`
|
|
44
|
+
- Optional: `isMain`, `categoryId`, `categoryName`, `parentCategoryId`, `categorySortOrder`
|
|
32
45
|
- `categoryId` and `categoryName` cannot be provided simultaneously
|
|
33
46
|
- When `categoryName` is given, it first checks for duplicates under `parentCategoryId`; if not found, creates and assigns
|
|
34
47
|
2. `action=list_categories`
|
|
@@ -111,7 +124,7 @@ Fields written in `grix_admin.task`:
|
|
|
111
124
|
|
|
112
125
|
1. First line must be `create-and-bind`
|
|
113
126
|
2. `agentName` (required)
|
|
114
|
-
3. `introduction` (
|
|
127
|
+
3. `introduction` (required; professionally organized according to **Agent Creation Intake**)
|
|
115
128
|
4. `isMain` (optional, default `false`)
|
|
116
129
|
5. `categoryId` (optional): assign the new agent directly to an existing category
|
|
117
130
|
6. `categoryName` (optional): create if not exists, then assign
|
|
@@ -125,7 +138,7 @@ Execution rules:
|
|
|
125
138
|
3. Call `grix_admin` only once with `action=create_agent`, delegating remote creation and optional category handling to it; pass:
|
|
126
139
|
- `action=create_agent`
|
|
127
140
|
- `agentName`
|
|
128
|
-
-
|
|
141
|
+
- Required `introduction`
|
|
129
142
|
- Optional `isMain`
|
|
130
143
|
- Optional `categoryId`
|
|
131
144
|
- Optional `categoryName`
|
|
@@ -210,7 +223,7 @@ Fields written in `grix_admin.task`:
|
|
|
210
223
|
|
|
211
224
|
1. First line must be `create-and-connector-bind`
|
|
212
225
|
2. `agentName` (required)
|
|
213
|
-
3. `introduction` (
|
|
226
|
+
3. `introduction` (required; professionally organized according to **Agent Creation Intake**)
|
|
214
227
|
4. `isMain` (optional, default `false`)
|
|
215
228
|
5. `clientType` (optional, default `pi`)
|
|
216
229
|
6. `categoryId` (optional): assign the new agent directly to an existing category
|
|
@@ -225,7 +238,7 @@ Execution rules:
|
|
|
225
238
|
3. Call `grix_admin` only once with `action=create_agent`, delegating remote creation and optional category handling to it; pass:
|
|
226
239
|
- `action=create_agent`
|
|
227
240
|
- `agentName`
|
|
228
|
-
-
|
|
241
|
+
- Required `introduction`
|
|
229
242
|
- Optional `isMain`
|
|
230
243
|
- Optional `categoryId`
|
|
231
244
|
- Optional `categoryName`
|
|
@@ -262,7 +275,7 @@ If the current task has neither an existing `agent_name`, `agent_id`, `api_endpo
|
|
|
262
275
|
## Error Handling Rules
|
|
263
276
|
|
|
264
277
|
1. `bind-local` / `connector-bind-local` missing fields: clearly state which field is missing and stop.
|
|
265
|
-
2. `create-and-bind` / `create-and-connector-bind` missing `agentName`:
|
|
278
|
+
2. `create-and-bind` / `create-and-connector-bind` missing `agentName` or `introduction`: do not call the creation API; ask for the Agent's purpose, core responsibilities, intended users, and boundaries, then professionally organize both fields.
|
|
266
279
|
3. `create-and-bind` / `create-and-connector-bind` with both `categoryId` and `categoryName`: clearly state the conflict and stop.
|
|
267
280
|
4. `category-manage` missing `operation` or operation-specific fields: clearly state which field is missing and stop.
|
|
268
281
|
5. Remote returns `code=4003` or message explicitly mentions `agent.api.create`: tell the owner to grant `agent.api.create` on the Agent permissions page.
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
3. If `agent_name` / `agent_id` / `api_endpoint` / `api_key` are incomplete, and the current account cannot create remotely, stop first and require backend admin to complete them.
|
|
18
18
|
4. The current agent must first have the corresponding scope enabled on the frontend permissions page; without scope, WS will fail directly.
|
|
19
19
|
5. For `bind-local` / `create-and-bind` / `connector-bind-local` / `create-and-connector-bind`, "config written successfully" does not equal completion; if this invocation already has real routing verification conditions, real verification passing must also be counted as part of the success criteria; otherwise explicitly hand the subsequent verification responsibility back to the upper-level flow.
|
|
20
|
+
6. Before remote creation, require a concrete Agent name and a professional introduction based on the user's stated purpose, responsibilities, intended users or scenarios, operating expectations, and boundaries. If those details are missing, ask the user before calling the API.
|
|
21
|
+
7. Always send the finalized behavioral description in the actual `introduction` field of `action=create_agent`; never substitute a chat summary, `soulContent`, or local persona file for this API field.
|
|
20
22
|
|
|
21
23
|
## Direct `grix_admin` Contract
|
|
22
24
|
|
|
@@ -26,7 +28,7 @@
|
|
|
26
28
|
{
|
|
27
29
|
"action": "create_agent",
|
|
28
30
|
"agentName": "ops helper",
|
|
29
|
-
"introduction": "
|
|
31
|
+
"introduction": "Professional deployment operations Agent responsible for release readiness checks, change coordination, on-call triage, and clear status reporting; requests confirmation before high-risk operations.",
|
|
30
32
|
"isMain": false,
|
|
31
33
|
"categoryName": "Project Assistant",
|
|
32
34
|
"parentCategoryId": "0",
|
|
@@ -224,20 +226,21 @@ When the main agent already has an available account and `agent.api.create` scop
|
|
|
224
226
|
|
|
225
227
|
```json
|
|
226
228
|
{
|
|
227
|
-
"task": "create-and-bind\nagentName=ops helper\nintroduction=
|
|
229
|
+
"task": "create-and-bind\nagentName=ops helper\nintroduction=Professional deployment operations Agent responsible for release readiness checks, change coordination, on-call triage, and clear status reporting; requests confirmation before high-risk operations.\nisMain=false\ncategoryName=Project Assistant\nparentCategoryId=0\ncategorySortOrder=10"
|
|
228
230
|
}
|
|
229
231
|
```
|
|
230
232
|
|
|
231
233
|
This mode requires steps in order:
|
|
232
234
|
|
|
233
|
-
1.
|
|
234
|
-
2.
|
|
235
|
-
3. If the
|
|
235
|
+
1. Confirm `agentName` and a professionally organized `introduction` are both present; otherwise ask the user about the Agent's purpose, core responsibilities, intended users, and boundaries before continuing
|
|
236
|
+
2. First make one direct call with `action=create_agent`, passing `agentName`, `introduction`, and optional `categoryId` / `categoryName` / `parentCategoryId` / `categorySortOrder` together
|
|
237
|
+
3. If the return already includes the category assignment result, continue directly
|
|
238
|
+
4. If the caller used a legacy path, or the return does not include the category assignment result, supplement with:
|
|
236
239
|
- `categoryId` -> `action=assign_category`
|
|
237
240
|
- `categoryName` -> `action=list_categories`
|
|
238
241
|
- Not found -> `action=create_category`
|
|
239
242
|
- After obtaining category ID -> `action=assign_category`
|
|
240
|
-
|
|
243
|
+
5. Finally follow the same local binding and runtime convergence flow as `bind-local`
|
|
241
244
|
|
|
242
245
|
Notes:
|
|
243
246
|
|
|
@@ -251,17 +254,18 @@ When the main agent already has an available account and `agent.api.create` scop
|
|
|
251
254
|
|
|
252
255
|
```json
|
|
253
256
|
{
|
|
254
|
-
"task": "create-and-connector-bind\nagentName=程序员 pi\nintroduction
|
|
257
|
+
"task": "create-and-connector-bind\nagentName=程序员 pi\nintroduction=专业软件工程 Agent,负责分析需求、设计实现、编写并验证代码;涉及破坏性操作或需求边界不明确时先请求确认。\nisMain=false\nclientType=pi\ncategoryName=Developers\nparentCategoryId=0\ncategorySortOrder=10"
|
|
255
258
|
}
|
|
256
259
|
```
|
|
257
260
|
|
|
258
261
|
This mode requires steps in order:
|
|
259
262
|
|
|
260
|
-
1.
|
|
261
|
-
2.
|
|
262
|
-
3.
|
|
263
|
-
4.
|
|
264
|
-
5.
|
|
263
|
+
1. Confirm `agentName` and a professionally organized `introduction` are both present; otherwise ask the user about the Agent's purpose, core responsibilities, intended users, and boundaries before continuing.
|
|
264
|
+
2. Make one direct call with `action=create_agent`, passing `agentName`, `introduction`, and optional `categoryId` / `categoryName` / `parentCategoryId` / `categorySortOrder` together.
|
|
265
|
+
3. If the return already includes the category assignment result, continue directly; otherwise supplement with the same category resolution logic as `create-and-bind`.
|
|
266
|
+
4. Read `createdAgent.id`, `createdAgent.agent_name`, `createdAgent.api_endpoint`, `createdAgent.api_key` from the result.
|
|
267
|
+
5. Follow the `connector-bind-local` local binding and runtime convergence flow, using `clientType` (default `pi`) for the `client_type` field.
|
|
268
|
+
6. Trigger reload via the synchronous Admin API `POST /api/reload`, verify the Agent entry exists and `alive=true` via `GET /api/agents`, and perform secondary platform-connection verification (log inspection or test message).
|
|
265
269
|
|
|
266
270
|
Notes:
|
|
267
271
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: grix-egg
|
|
3
|
-
description: Program-driven hatching: AI only organizes parameters and calls `grix_egg`; the program handles creation, installation, binding, acceptance, and status reporting.
|
|
3
|
+
description: "Program-driven hatching: AI only organizes parameters and calls `grix_egg`; the program handles creation, installation, binding, acceptance, and status reporting. Use for creating or installing an Agent from an egg package, including collecting and professionally organizing its name and behavioral introduction before remote creation."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Grix Egg
|
|
@@ -23,7 +23,18 @@ Do not manually execute these actions:
|
|
|
23
23
|
3. Gateway operations
|
|
24
24
|
4. Test group acceptance
|
|
25
25
|
|
|
26
|
-
## 2.
|
|
26
|
+
## 2. Agent Profile Intake
|
|
27
|
+
|
|
28
|
+
Before calling `grix_egg` with `route=create_new`:
|
|
29
|
+
|
|
30
|
+
1. Ensure the request has both a concrete Agent name and a usable introduction.
|
|
31
|
+
2. If either one is missing or too vague, pause and ask one concise question: “这个 Agent 主要做什么?核心职责、服务对象和工作边界是什么?” Do not start hatching yet.
|
|
32
|
+
3. Turn the user's answer into a concise professional `agentName` and a professional `introduction`. The introduction must describe purpose, core responsibilities, intended users or scenarios, operating expectations, and important boundaries.
|
|
33
|
+
4. Preserve the user's facts and intent; do not invent permissions, authority, expertise, or responsibilities.
|
|
34
|
+
5. Treat the introduction as the Agent's behavioral specification. Pass it through the actual `introduction` parameter so the program sends it in `grix_admin action=create_agent`; do not leave it only in chat, `soulContent`, or persona files.
|
|
35
|
+
6. When using a raw `installContext` that lacks the finalized profile, pass `agentName` and `introduction` alongside it as explicit overrides.
|
|
36
|
+
|
|
37
|
+
## 3. Standard Call Entry
|
|
27
38
|
|
|
28
39
|
Prefer passing the raw install card:
|
|
29
40
|
|
|
@@ -34,19 +45,20 @@ Prefer passing the raw install card:
|
|
|
34
45
|
If there is no install card, pass structured parameters:
|
|
35
46
|
|
|
36
47
|
1. `route`: `create_new` | `existing` | `existing_claude`
|
|
37
|
-
2. `agentName`
|
|
38
|
-
3. `
|
|
39
|
-
4. `
|
|
40
|
-
5. `
|
|
41
|
-
6.
|
|
48
|
+
2. `agentName` (required for `create_new`)
|
|
49
|
+
3. `introduction` (required for `create_new`; professionally organized according to **Agent Profile Intake**)
|
|
50
|
+
4. `agentIdSlug` or `localAgentName`
|
|
51
|
+
5. `downloadUrl`
|
|
52
|
+
6. `existingCredentials` (required for `existing`)
|
|
53
|
+
7. Optional: `packageHash`, `soulContent`, `soulFile`, `categoryId`, `categoryName`, `isMain`, `expectedSubstring`, `statusTarget`, `resume`, `installId`
|
|
42
54
|
|
|
43
|
-
##
|
|
55
|
+
## 4. Route Behavior
|
|
44
56
|
|
|
45
57
|
1. `create_new`: program automatically completes creation, installation, binding, acceptance, and status reporting
|
|
46
58
|
2. `existing`: program automatically completes existing credential installation and acceptance
|
|
47
59
|
3. `existing_claude`: program returns `unsupported_route`, handled by a standalone Claude installer
|
|
48
60
|
|
|
49
|
-
##
|
|
61
|
+
## 5. Acceptance Rules
|
|
50
62
|
|
|
51
63
|
Program has fixed acceptance logic:
|
|
52
64
|
|
|
@@ -55,7 +67,7 @@ Program has fixed acceptance logic:
|
|
|
55
67
|
3. Only the first non-empty reply after the probe from the target agent is accepted
|
|
56
68
|
4. `expectedSubstring` is only an optional enhancement condition
|
|
57
69
|
|
|
58
|
-
##
|
|
70
|
+
## 6. Result Reporting
|
|
59
71
|
|
|
60
72
|
When `ok=true`:
|
|
61
73
|
|
|
@@ -69,7 +81,7 @@ When `ok=false`:
|
|
|
69
81
|
2. Only supplement external inputs that the program explicitly identifies as missing
|
|
70
82
|
3. Use `resume=true` + `installId` when continuation is needed
|
|
71
83
|
|
|
72
|
-
##
|
|
84
|
+
## 7. Prohibited Actions
|
|
73
85
|
|
|
74
86
|
1. Do not use `curl`/`fetch`/`axios` to directly connect to `/v1/agent-api`
|
|
75
87
|
2. Do not manually modify `openclaw.json`
|
|
@@ -7,7 +7,7 @@ AI only provides params, program executes.
|
|
|
7
7
|
|
|
8
8
|
## Required Paths
|
|
9
9
|
|
|
10
|
-
1. Remote create/category actions: `grix_admin`
|
|
10
|
+
1. Remote create/category actions: `grix_admin`; for `route=create_new`, the real `create_agent` request must contain the finalized professional `agentName` and `introduction`
|
|
11
11
|
2. Group lifecycle and membership actions: `grix_group`
|
|
12
12
|
3. Message/session query actions: `grix_query`
|
|
13
13
|
4. Local bind/update actions: official `openclaw` CLI (`config set`, `agents bind`, `config validate`)
|
|
@@ -17,6 +17,7 @@ AI only provides params, program executes.
|
|
|
17
17
|
1. Do not call `/v1/agent-api` using `curl`, `fetch`, `axios`, or ad hoc scripts.
|
|
18
18
|
2. Do not hand-edit `openclaw.json`.
|
|
19
19
|
3. Do not bypass typed tools with hidden protocol payloads.
|
|
20
|
+
4. Do not create an Agent with a blank, generic, or placeholder introduction, or keep the introduction only in chat/persona files.
|
|
20
21
|
|
|
21
22
|
## Delivery Rules
|
|
22
23
|
|