grix-connector 3.12.0 → 3.13.1
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/core/mcp/tools.js +1 -1
- package/dist/default-skills/grix-admin/SKILL.md +20 -7
- package/dist/default-skills/grix-admin/references/api-contract.md +16 -12
- package/dist/mcp/stream-http/security.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/core/mcp/tools.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const r=[{name:"grix_query",description:"Search contacts, sessions, message history, messages, or favorited sessions in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"],description:"Query action type. search_favorite_sessions returns the owner's favorited sessions (supports keyword filter)."},id:{type:"string",description:"Contact ID (contact_search) or Session ID (session_search)."},keyword:{type:"string",description:"Search keyword."},sessionType:{type:"integer",enum:[1,2],description:"Filter by session type (session_search only): 1=private chat, 2=group chat. Omit to return all."},limit:{type:"integer",description:"Max results."},offset:{type:"integer",description:"Result offset."},sessionId:{type:"string",description:"Session ID (message_history, message_search)."},beforeId:{type:"string",description:"Pagination cursor (message_history, message_search)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"]},id:{type:"string"},keyword:{type:"string",maxLength:200},sessionType:{type:"integer",enum:[1,2]},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"],description:"Group action type."},sessionId:{type:"string",description:"Group session ID."},name:{type:"string",description:"Group name (create)."},memberIds:{type:"array",items:{type:"string"},description:"Member IDs to add/remove."},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]},description:"Member types (1=user, 2=agent)."},memberId:{type:"string",description:"Target member ID."},role:{type:"integer",enum:[1,2],description:"New role (1=admin, 2=member)."},memberType:{type:"integer",description:"Member type."},allMembersMuted:{type:"boolean",description:"Whether to mute all members."},isSpeakMuted:{type:"boolean",description:"Whether member is muted."},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted."}},required:["action"]},validation:{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"}}}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Target session ID"},content:{type:"string",description:"Message content"},msgType:{type:"integer",description:"Message type (1=text, default 1)"},quotedMessageId:{type:"string",description:"Message ID to reply to"},threadId:{type:"string",description:"Thread ID for threaded reply"}},required:["sessionId","content"]},validation:{required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Session ID"},msgId:{type:"string",description:"Message ID to unsend"}},required:["sessionId","msgId"]},validation:{required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}}},{name:"grix_file_link",description:"Create a direct, tailnet-only download link for a local file on this host. Use this whenever the user asks you to send, share, give, or deliver a file that exists on the machine where you run (a report, log, build artifact, export, or any local path). It returns a ready-to-use Markdown link in the `markdown` field \u2014 include that exact Markdown link in your reply so the user can click and download the file directly over the shared Tailscale network. The link is reachable only inside the tailnet, so just send it as-is \u2014 no need to worry about or mention any link lifetime. The download link is HTTPS, served by a built-in self-signed CA. The result also returns `ca_install_url`: the first time you share a link with a user (or whenever their browser warns the cert is untrusted), also give them this CA install link so they can install and trust it once \u2014 after that all download links work without warnings. Requires this host to be on a tailnet (Tailscale running).",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file on this host to share with the user."},ttl_ms:{type:"integer",description:"Optional link lifetime in milliseconds. Leave unset to use the long default; set only if you deliberately want a short-lived link."}},required:["file_path"]},validation:{required:["file_path"],properties:{file_path:{type:"string",maxLength:4096},ttl_ms:{type:"integer",minimum:1e4,maximum:864e5}}}},{name:"grix_file_upload",description:"Upload a local file to the Grix platform and send it as a media message in the target session. Supports images (jpg/png/webp/gif/bmp/heic/heif), videos (mp4/mov/m4v/webm/mkv/avi), documents (pdf/doc/docx/xls/xlsx/ppt/pptx/txt/md/csv/json/xml), and archives (zip/rar/7z/tar/gz). Max 50 MB. Use this instead of grix_file_link when the file should appear as a native attachment in the chat (visible inline for images/videos), rather than a tailnet download link.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file to upload."},session_id:{type:"string",description:"Target session ID to send the file to."},caption:{type:"string",description:"Optional text caption for the media message."},reply_to_message_id:{type:"string",description:"Optional message ID to quote/reply to."}},required:["file_path","session_id"]},validation:{required:["file_path","session_id"],properties:{file_path:{type:"string",maxLength:4096},session_id:{type:"string"},caption:{type:"string",maxLength:2e3},reply_to_message_id:{type:"string"}}}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"],description:"Admin action type."},agentName:{type:"string",description:"Agent name (create_agent)."},introduction:{type:"string",description:"Agent introduction (create_agent)."},isMain:{type:"boolean",description:"Set as main agent (create_agent)."},agentId:{type:"string",description:"Agent ID (assign_category, rotate_api_key)."},categoryId:{type:"string",description:"Category ID (create_agent, update_category, assign_category)."},name:{type:"string",description:"Category name (create_category, update_category)."},parentId:{type:"string",description:"Parent category ID (create_category, update_category)."},sortOrder:{type:"integer",description:"Sort order (create_category, update_category)."}},required:["action"]},validation:{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"}}}},{name:"grix_call_owner",description:"Call your owner into this session to talk by voice. Use this when, during your work, you need to reach your owner \u2014 to discuss something or to get an approval/review. It sends the owner an offline notification; when they tap it they land directly in this conversation and a voice-brain call is started automatically. Requires the owner to have configured a voice brain. Rate-limited per session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID to call the owner into."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_agent_update",description:"Update the display name and/or text introduction of one of your owner's agents, identified by its numeric agent ID. Provide agent_name, introduction, or both \u2014 at least one is required.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},agent_name:{type:"string",description:"New display name (max 100 characters, must be unique among the owner's agents)."},introduction:{type:"string",description:"New text introduction (max 300 characters)."}},required:["agent_id"]},validation:{required:["agent_id"],properties:{agent_id:{type:"string"},agent_name:{type:"string",maxLength:100},introduction:{type:"string",maxLength:300}}}},{name:"grix_dispatch_agent",description:`Dispatch one of your owner's agents to do work in a given working directory. Provide the target agent numeric ID, the working directory, and a text description of the task. The backend creates a NEW private session between the owner and that agent for each dispatch (it does not reuse past sessions), binds the working directory when the agent type requires it (claude/codex/etc.), and sends the task into the session AS THE OWNER so the agent starts working. Because the task is delivered as the owner, write it in the owner's first-person voice and tone \u2014 phrase it the way the owner would speak directly to the agent (e.g. "\u5E2E\u6211\u2026", "\u4F60\u53BB\u2026"), NOT as a third-person relay or as yourself narrating on the owner's behalf. Provide a short title summarizing the core of the task \u2014 it becomes the new session's title; if omitted the backend derives one from the task text.`,inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},cwd:{type:"string",description:"Absolute working directory where the agent should do the work."},task:{type:"string",description:"Text description of the task to perform, written in the owner's first-person voice and tone \u2014 it is delivered into the session as the owner, so phrase it as the owner speaking directly to the agent, not as a third-person relay."},title:{type:"string",description:"Optional short title (a few words) summarizing the core of the task; used as the new session's title. If omitted, the backend derives a title from the task text."}},required:["agent_id","cwd","task"]},validation:{required:["agent_id","cwd","task"],properties:{agent_id:{type:"string"},cwd:{type:"string",maxLength:4096},task:{type:"string",maxLength:1e4},title:{type:"string",maxLength:255}}}},{name:"grix_session_send",description:"Send a message into a session AS THE OWNER \u2014 it appears as if the owner sent it, NOT as you (the agent). Use ONLY to relay on the owner's behalf into one of the owner's OTHER sessions that you are not part of (e.g. you were dispatched to work and need to drop a note to the owner elsewhere). NEVER use this to send your own reply in a session you are conversing in \u2014 that would make your words show up as the owner's message. To answer in your current conversation, reply normally (or use grix_message_send to send as yourself). The owner must be a member of the target session, and you (the agent) must NOT be a member of it \u2014 sending into a session you belong to is rejected.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Target session ID."},content:{type:"string",description:"Message content to send as the owner."}},required:["session_id","content"]},validation:{required:["session_id","content"],properties:{session_id:{type:"string"},content:{type:"string",maxLength:1e4}}}},{name:"grix_chat_state_query",description:"Query the chat-level task states across all of your owner's sessions (including direct and group chats). Returns one entry per session with a single mutually-exclusive state: running (working), waiting_approval (blocked on your owner to approve/deny), waiting_question (asked the owner a question, awaiting their reply), completed, failed, or idle (no task / stopped). Also returns the session title (task_title) for easy identification. Supports pagination (page/page_size) and optional state filtering. Use this to see at a glance which chats are done, still running, or waiting on the owner.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"(Optional) Query a single session by its ID. Omit to return all sessions."},page:{type:"number",description:"(Optional) Page number, starting from 1. Defaults to 1 if omitted."},page_size:{type:"number",description:"(Optional) Number of items per page, max 100. Defaults to 10 if omitted."},state:{type:"string",description:"(Optional) Filter by a specific state: running, waiting_approval, waiting_question, completed, failed, or idle. Omit to return all states."}}},validation:{required:[],properties:{}}},{name:"grix_chat_state_update",description:"Manually update the task state of a specific chat session. Use this to mark a chat as completed, failed, idle, or any other state when you need to override it manually. The reason is written to stop_reason and is optional.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID whose state to update."},state:{type:"string",enum:["running","waiting_approval","waiting_question","completed","failed","idle"],description:"The new state to set. Must be one of: running, waiting_approval, waiting_question, completed, failed, idle."},reason:{type:"string",description:"(Optional) Reason for the state change, written to stop_reason."}}},validation:{required:["session_id","state"],properties:{}}},{name:"grix_access_control",description:"Manage sender access control: pair approval, allow/remove senders, set policy.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"],description:"Access control action type."},code:{type:"string",description:"Pairing code (required for pair_approve/pair_deny)."},sender_id:{type:"string",description:"Sender ID (required for allow_sender/remove_sender)."},policy:{type:"string",enum:["allowlist","open","disabled"],description:"Access policy (required for set_policy)."}},required:["action"]},validation:{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"]}}}},{name:"grix_skill_set",description:"Create, update, or delete one of your owner's custom skills in the platform skill library. The skill library auto-syncs to every machine the owner runs an agent on (a per-machine `grix/skills` directory), so defining a skill here makes it available on all of them. A skill is a plain SKILL.md package (frontmatter + body), same standard as other Grix skills. Provide `name` and the full `content` (the SKILL.md text) to create or overwrite by name. To delete a skill, pass its `name` with an empty `content` string. How and when any agent actually loads/uses a synced skill is arranged by the owner (in a system prompt or in conversation); this tool only manages the library.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name (max 100 characters); unique within the owner. Used as the identifier and the synced directory name."},content:{type:"string",description:"Full SKILL.md text. Pass an empty string to delete the skill by name."}},required:["name","content"]},validation:{required:["name","content"],properties:{name:{type:"string",maxLength:100},content:{type:"string",maxLength:262144}}}},{name:"grix_skill_get",description:"Read one of your owner's custom skills by name (returns its full SKILL.md content), or list the owner's skill library when no name is given. Use this before editing to fetch current content, then call grix_skill_set with the revised text.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name to fetch. Omit to list all skills (names + versions) instead."}}},validation:{required:[],properties:{name:{type:"string",maxLength:100}}}}],a=[{name:"grix_reply",description:"Send your final reply \u2014 the conclusion the user is waiting for \u2014 to the specified session. This is the message the user treats as your answer; deliver your final result here, and use plain text only for brief progress notes while you work. Supports streaming in chunks; the frontend automatically aggregates them into one complete message. The connector quotes the message being answered automatically, so quoted_message_id is optional (set it only to quote a different earlier message).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"Associated event ID from the inbound event."},session_id:{type:"string",description:"Target session ID."},text:{type:"string",description:"Reply text content."},quoted_message_id:{type:"string",description:"Quoted message ID (optional)."},is_final:{type:"boolean",description:"Whether this is a stage-final reply. Advisory only \u2014 does not trigger event completion; completion is handled by the complete tool or Stop hook."}},required:["session_id","text"]},validation:{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"}}}},{name:"grix_complete",description:"Mark event processing as complete, notifying the backend that no more replies are expected.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to complete."},status:{type:"string",enum:["responded","canceled","failed"],description:"Completion status."},msg:{type:"string",description:"Additional note (optional)."}},required:["event_id","status"]},validation:{required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}}},{name:"grix_event_ack",description:"Acknowledge event receipt (usually done automatically by the Dispatcher; agents typically do not need to call this manually).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to acknowledge."},session_id:{type:"string",description:"Session ID."}},required:["event_id"]},validation:{required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}}},{name:"grix_composing",description:'Set the "typing" indicator status for a session.',inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Session ID."},active:{type:"boolean",description:"true = typing, false = stopped."},event_id:{type:"string",description:"Associated event ID (optional)."}},required:["session_id","active"]},validation:{required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}}},{name:"grix_status",description:"Query the Grix connection status of the current MCP session.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],v={grix_dispatch_agent:"grix-agent-dispatch",grix_agent_update:"grix-agent-dispatch",grix_query:"grix-query",grix_group:"grix-group",grix_message_send:"message-send",grix_message_unsend:"message-unsend",grix_admin:"grix-admin",grix_call_owner:"grix-owner-relay",grix_session_send:"grix-owner-relay",grix_chat_state_query:"grix-chat-state",grix_chat_state_update:"grix-chat-state",grix_status:"grix-chat-state",grix_access_control:"grix-access-control",grix_file_link:"tailnet-file-share"};function b(e){return` Before calling this tool, follow the \`${e}\` skill's procedure first; do not invoke this tool directly without going through that skill's guidance.`}for(const e of[...r,...a]){const t=v[e.name];t&&(e.description+=b(t))}const p=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},final:{type:"boolean",description:"Advisory flag only. It does not complete the event; completion is handled by complete tool or Stop hook."}},required:["chat_id","event_id","text"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string"},code:{type:"string"}},required:["event_id","status"]}}],c=new Set(p.map(e=>e.name)),w=new Set(r.map(e=>e.name)),x=new Set(a.map(e=>e.name)),k=/([A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+)/,I=/[A-Za-z0-9._-]+/;function F(e){return!!(w.has(e)||x.has(e)||c.has(e)||e.startsWith("mcp__grix"))}const S=[...r,...a],q=[...S,...p],H=new Map(q.map(e=>[e.name,e]));function Q(e,t){return e==="reply"?{name:"grix_reply",args:_("grix_reply",{event_id:t.event_id,session_id:t.chat_id,text:t.text,quoted_message_id:t.reply_to,is_final:t.final})}:e==="complete"?{name:"grix_complete",args:_("grix_complete",{event_id:t.event_id,status:t.status,msg:t.msg,code:t.code})}:{name:e,args:t}}function l(e){const t=String(e??"").trim();return t?t.match(k)?.[1]:void 0}function u(e){const t=String(e??"").trim();if(!t)return;const n=l(t);if(n)return m(n);const i=t.match(/(?:chat_id|session_id)\s*=\s*"([A-Za-z0-9._-]+)"/)?.[1];if(i)return i;const o=t.match(/[A-Za-z0-9._-]+/g)??[];for(const s of o)if(!(s==="event_id"||s==="chat_id"||s==="session_id")&&s.length>0)return s;return t.match(I)?.[0]}function m(e){if(!e)return;const t=e.split(":",1)[0]?.trim();if(t)return u(t)}function _(e,t){if(e!=="grix_reply"&&e!=="grix_complete")return t;const n={...t},i=l(n.event_id);if(i&&(n.event_id=i),e==="grix_reply"){const o=m(i),d=String(n.session_id??""),s=u(n.session_id),f=/\bevent_id\b|["'<>\s]/.test(d);s&&!(f&&o)?n.session_id=s:o&&(n.session_id=o)}return n}function Z(e){return c.has(e)}function K(e,t){switch(e){case"grix_query":return A(t);case"grix_group":return T(t);case"grix_message_send":return M(t);case"grix_message_unsend":return O(t);case"grix_file_link":return L(t);case"grix_file_upload":return D(t);case"grix_admin":return W(t);case"grix_call_owner":return E(t);case"grix_agent_update":return j(t);case"grix_dispatch_agent":return N(t);case"grix_session_send":return z(t);case"grix_chat_state_query":return C(t);case"grix_chat_state_update":return U(t);case"grix_access_control":return P(t);case"grix_skill_set":return R(t);case"grix_skill_get":return G(t);default:throw new Error(`Unknown tool: ${e}`)}}const g={contact_search:"contact_search",session_search:"session_search",message_history:"message_history",message_search:"message_search",search_favorite_sessions:"search_favorite_sessions"};function A(e){const t=String(e.action??""),n=g[t];if(!n)throw new Error(`Unknown grix_query action: ${t}`);const i={};return e.id!=null&&(i.id=e.id),e.keyword!=null&&(i.keyword=e.keyword),e.sessionType!=null&&(i.session_type=e.sessionType),e.limit!=null&&(i.limit=e.limit),e.offset!=null&&(i.offset=e.offset),e.sessionId!=null&&(i.session_id=e.sessionId),e.beforeId!=null&&(i.before_id=e.beforeId),{action:n,params:i}}const y={create:"group_create",detail:"group_detail_read",leave:"group_leave_self",add_members:"group_member_add",remove_members:"group_member_remove",update_member_role:"group_member_role_update",update_all_members_muted:"group_all_members_muted_update",update_member_speaking:"group_member_speaking_update",dissolve:"group_dissolve"};function T(e){const t=String(e.action??""),n=y[t];if(!n)throw new Error(`Unknown grix_group action: ${t}`);const i={};return e.sessionId!=null&&(i.session_id=e.sessionId),e.name!=null&&(i.name=e.name),e.memberIds!=null&&(i.member_ids=e.memberIds),e.memberTypes!=null&&(i.member_types=e.memberTypes),e.memberId!=null&&(i.member_id=e.memberId),e.role!=null&&(i.role=e.role),e.memberType!=null&&(i.member_type=e.memberType),e.allMembersMuted!=null&&(i.all_members_muted=e.allMembersMuted),e.isSpeakMuted!=null&&(i.is_speak_muted=e.isSpeakMuted),e.canSpeakWhenAllMuted!=null&&(i.can_speak_when_all_muted=e.canSpeakWhenAllMuted),{action:n,params:i}}function M(e){const t={session_id:e.sessionId,msg_type:e.msgType??1,content:e.content};return e.quotedMessageId!=null&&(t.quoted_message_id=e.quotedMessageId),e.threadId!=null&&(t.thread_id=e.threadId),{action:"send_msg",params:t}}function O(e){return{action:"delete_msg",params:{session_id:e.sessionId,msg_id:e.msgId}}}function L(e){const t={file_path:e.file_path};return e.ttl_ms!=null&&(t.ttl_ms=e.ttl_ms),{action:"file_link",params:t}}function D(e){const t={file_path:e.file_path,session_id:e.session_id};return e.caption!=null&&(t.caption=e.caption),e.reply_to_message_id!=null&&(t.reply_to_message_id=e.reply_to_message_id),{action:"file_upload",params:t,timeoutMs:6e4}}const h={create_agent:"agent_api_create",list_categories:"agent_category_list",create_category:"agent_category_create",update_category:"agent_category_update",assign_category:"agent_category_assign",rotate_api_key:"agent_api_key_rotate"};function E(e){return{action:"call_owner",params:{session_id:e.session_id}}}function j(e){if(e.agent_name==null&&e.introduction==null)throw new Error("grix_agent_update requires agent_name or introduction");const t={agent_id:e.agent_id};return e.agent_name!=null&&(t.agent_name=e.agent_name),e.introduction!=null&&(t.introduction=e.introduction),{action:"agent_introduction_update",params:t}}function N(e){return{action:"dispatch_agent",params:{agent_id:e.agent_id,cwd:e.cwd,task:e.task,title:e.title}}}function z(e){return{action:"session_send",params:{session_id:e.session_id,content:e.content}}}function C(e){const t={};return e.session_id!=null&&(t.session_id=e.session_id),e.page!=null&&(t.page=e.page),e.page_size!=null&&(t.page_size=e.page_size),e.state!=null&&(t.state=e.state),{action:"chat_state_query",params:t}}function P(e){const t=String(e.action??""),n=B[t];if(!n)throw new Error(`Unknown grix_access_control action: ${t}`);const i={};return e.code!=null&&(i.code=e.code),e.sender_id!=null&&(i.sender_id=e.sender_id),e.policy!=null&&(i.policy=e.policy),{action:"claude_access_control",params:{verb:n,payload:i},timeoutMs:3e4}}function U(e){const t={session_id:e.session_id,state:e.state};return e.reason!=null&&(t.reason=e.reason),{action:"chat_state_update",params:t}}function R(e){return{action:"skill_set",params:{name:e.name,content:e.content},timeoutMs:3e4}}function G(e){const t={};return e.name!=null&&(t.name=e.name),{action:"skill_get",params:t}}function W(e){const t=String(e.action??""),n=h[t];if(!n)throw new Error(`Unknown grix_admin action: ${t}`);const i={};return e.agentName!=null&&(i.agent_name=e.agentName),e.introduction!=null&&(i.introduction=e.introduction),e.isMain!=null&&(i.is_main=e.isMain),e.agentId!=null&&(i.agent_id=e.agentId),e.categoryId!=null&&(i.category_id=e.categoryId),e.name!=null&&(i.name=e.name),e.parentId!=null&&(i.parent_id=e.parentId),e.sortOrder!=null&&(i.sort_order=e.sortOrder),{action:n,params:i}}const $=new Set([...Object.values(g),...Object.values(y),...Object.values(h),"send_msg","delete_msg","file_link","file_upload","call_owner","agent_introduction_update","dispatch_agent","session_send","chat_state_query","chat_state_update","claude_access_control","skill_set","skill_get"]),B={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"};export{B as ACCESS_CONTROL_ACTION_MAP,S as ALL_TOOLS,a as EVENT_TOOLS,q as EXPOSED_TOOLS,$ as PHASE1_INVOKE_ACTIONS,w as PHASE1_TOOL_NAMES,x as PHASE2_TOOL_NAMES,r as TOOLS,p as TOOL_ALIASES,H as TOOL_MAP,Z as isAlias,F as isGrixInternalToolName,Q as mapToolAlias,_ as normalizeEventToolArgs,K as toolCallToInvoke};
|
|
1
|
+
const r=[{name:"grix_query",description:"Search contacts, sessions, message history, messages, or favorited sessions in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"],description:"Query action type. search_favorite_sessions returns the owner's favorited sessions (supports keyword filter)."},id:{type:"string",description:"Contact ID (contact_search) or Session ID (session_search)."},keyword:{type:"string",description:"Search keyword."},sessionType:{type:"integer",enum:[1,2],description:"Filter by session type (session_search only): 1=private chat, 2=group chat. Omit to return all."},limit:{type:"integer",description:"Max results."},offset:{type:"integer",description:"Result offset."},sessionId:{type:"string",description:"Session ID (message_history, message_search)."},beforeId:{type:"string",description:"Pagination cursor (message_history, message_search)."}},required:["action"]},validation:{required:["action"],properties:{action:{type:"string",enum:["contact_search","session_search","message_history","message_search","search_favorite_sessions"]},id:{type:"string"},keyword:{type:"string",maxLength:200},sessionType:{type:"integer",enum:[1,2]},limit:{type:"integer",minimum:1,maximum:100},offset:{type:"integer",minimum:0},sessionId:{type:"string"},beforeId:{type:"string"}}}},{name:"grix_group",description:"Manage groups in the Grix/AIBot platform: create, get details, leave, dissolve, manage members and permissions.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create","detail","leave","add_members","remove_members","update_member_role","update_all_members_muted","update_member_speaking","dissolve"],description:"Group action type."},sessionId:{type:"string",description:"Group session ID."},name:{type:"string",description:"Group name (create)."},memberIds:{type:"array",items:{type:"string"},description:"Member IDs to add/remove."},memberTypes:{type:"array",items:{type:"integer",enum:[1,2]},description:"Member types (1=user, 2=agent)."},memberId:{type:"string",description:"Target member ID."},role:{type:"integer",enum:[1,2],description:"New role (1=admin, 2=member)."},memberType:{type:"integer",description:"Member type."},allMembersMuted:{type:"boolean",description:"Whether to mute all members."},isSpeakMuted:{type:"boolean",description:"Whether member is muted."},canSpeakWhenAllMuted:{type:"boolean",description:"Allow speaking when all muted."}},required:["action"]},validation:{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"}}}},{name:"grix_message_send",description:"Send a message to a session in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Target session ID"},content:{type:"string",description:"Message content"},msgType:{type:"integer",description:"Message type (1=text, default 1)"},quotedMessageId:{type:"string",description:"Message ID to reply to"},threadId:{type:"string",description:"Thread ID for threaded reply"}},required:["sessionId","content"]},validation:{required:["sessionId","content"],properties:{sessionId:{type:"string"},content:{type:"string",maxLength:1e4},msgType:{type:"integer"},quotedMessageId:{type:"string"},threadId:{type:"string"}}}},{name:"grix_message_unsend",description:"Recall/unsend a message in the Grix/AIBot platform.",inputSchema:{type:"object",properties:{sessionId:{type:"string",description:"Session ID"},msgId:{type:"string",description:"Message ID to unsend"}},required:["sessionId","msgId"]},validation:{required:["sessionId","msgId"],properties:{sessionId:{type:"string"},msgId:{type:"string"}}}},{name:"grix_file_link",description:"Create a direct, tailnet-only download link for a local file on this host. Use this whenever the user asks you to send, share, give, or deliver a file that exists on the machine where you run (a report, log, build artifact, export, or any local path). It returns a ready-to-use Markdown link in the `markdown` field \u2014 include that exact Markdown link in your reply so the user can click and download the file directly over the shared Tailscale network. The link is reachable only inside the tailnet, so just send it as-is \u2014 no need to worry about or mention any link lifetime. The download link is HTTPS, served by a built-in self-signed CA. The result also returns `ca_install_url`: the first time you share a link with a user (or whenever their browser warns the cert is untrusted), also give them this CA install link so they can install and trust it once \u2014 after that all download links work without warnings. Requires this host to be on a tailnet (Tailscale running).",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file on this host to share with the user."},ttl_ms:{type:"integer",description:"Optional link lifetime in milliseconds. Leave unset to use the long default; set only if you deliberately want a short-lived link."}},required:["file_path"]},validation:{required:["file_path"],properties:{file_path:{type:"string",maxLength:4096},ttl_ms:{type:"integer",minimum:1e4,maximum:864e5}}}},{name:"grix_file_upload",description:"Upload a local file to the Grix platform and send it as a media message in the target session. Supports images (jpg/png/webp/gif/bmp/heic/heif), videos (mp4/mov/m4v/webm/mkv/avi), documents (pdf/doc/docx/xls/xlsx/ppt/pptx/txt/md/csv/json/xml), and archives (zip/rar/7z/tar/gz). Max 50 MB. Use this instead of grix_file_link when the file should appear as a native attachment in the chat (visible inline for images/videos), rather than a tailnet download link.",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"Absolute path to a local file to upload."},session_id:{type:"string",description:"Target session ID to send the file to."},caption:{type:"string",description:"Optional text caption for the media message."},reply_to_message_id:{type:"string",description:"Optional message ID to quote/reply to."}},required:["file_path","session_id"]},validation:{required:["file_path","session_id"],properties:{file_path:{type:"string",maxLength:4096},session_id:{type:"string"},caption:{type:"string",maxLength:2e3},reply_to_message_id:{type:"string"}}}},{name:"grix_admin",description:"Agent and category management in the Grix/AIBot platform: create agents, manage categories, rotate API keys.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["create_agent","list_categories","create_category","update_category","assign_category","rotate_api_key"],description:"Admin action type."},agentName:{type:"string",description:"Agent name (create_agent)."},introduction:{type:"string",description:"Professional behavioral introduction describing the Agent purpose, responsibilities, operating expectations, and boundaries (create_agent)."},isMain:{type:"boolean",description:"Set as main agent (create_agent)."},agentId:{type:"string",description:"Agent ID (assign_category, rotate_api_key)."},categoryId:{type:"string",description:"Category ID (create_agent, update_category, assign_category)."},name:{type:"string",description:"Category name (create_category, update_category)."},parentId:{type:"string",description:"Parent category ID (create_category, update_category)."},sortOrder:{type:"integer",description:"Sort order (create_category, update_category)."}},required:["action"]},validation:{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"}}}},{name:"grix_call_owner",description:"Call your owner into this session to talk by voice. Use this when, during your work, you need to reach your owner \u2014 to discuss something or to get an approval/review. It sends the owner an offline notification; when they tap it they land directly in this conversation and a voice-brain call is started automatically. Requires the owner to have configured a voice brain. Rate-limited per session.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID to call the owner into."}},required:["session_id"]},validation:{required:["session_id"],properties:{session_id:{type:"string"}}}},{name:"grix_agent_update",description:"Update the display name and/or text introduction of one of your owner's agents, identified by its numeric agent ID. Provide agent_name, introduction, or both \u2014 at least one is required.",inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},agent_name:{type:"string",description:"New display name (max 100 characters, must be unique among the owner's agents)."},introduction:{type:"string",description:"New text introduction (max 300 characters)."}},required:["agent_id"]},validation:{required:["agent_id"],properties:{agent_id:{type:"string"},agent_name:{type:"string",maxLength:100},introduction:{type:"string",maxLength:300}}}},{name:"grix_dispatch_agent",description:`Dispatch one of your owner's agents to do work in a given working directory. Provide the target agent numeric ID, the working directory, and a text description of the task. The backend creates a NEW private session between the owner and that agent for each dispatch (it does not reuse past sessions), binds the working directory when the agent type requires it (claude/codex/etc.), and sends the task into the session AS THE OWNER so the agent starts working. Because the task is delivered as the owner, write it in the owner's first-person voice and tone \u2014 phrase it the way the owner would speak directly to the agent (e.g. "\u5E2E\u6211\u2026", "\u4F60\u53BB\u2026"), NOT as a third-person relay or as yourself narrating on the owner's behalf. Provide a short title summarizing the core of the task \u2014 it becomes the new session's title; if omitted the backend derives one from the task text.`,inputSchema:{type:"object",properties:{agent_id:{type:"string",description:"Target agent's numeric ID, passed as a string."},cwd:{type:"string",description:"Absolute working directory where the agent should do the work."},task:{type:"string",description:"Text description of the task to perform, written in the owner's first-person voice and tone \u2014 it is delivered into the session as the owner, so phrase it as the owner speaking directly to the agent, not as a third-person relay."},title:{type:"string",description:"Optional short title (a few words) summarizing the core of the task; used as the new session's title. If omitted, the backend derives a title from the task text."}},required:["agent_id","cwd","task"]},validation:{required:["agent_id","cwd","task"],properties:{agent_id:{type:"string"},cwd:{type:"string",maxLength:4096},task:{type:"string",maxLength:1e4},title:{type:"string",maxLength:255}}}},{name:"grix_session_send",description:"Send a message into a session AS THE OWNER \u2014 it appears as if the owner sent it, NOT as you (the agent). Use ONLY to relay on the owner's behalf into one of the owner's OTHER sessions that you are not part of (e.g. you were dispatched to work and need to drop a note to the owner elsewhere). NEVER use this to send your own reply in a session you are conversing in \u2014 that would make your words show up as the owner's message. To answer in your current conversation, reply normally (or use grix_message_send to send as yourself). The owner must be a member of the target session, and you (the agent) must NOT be a member of it \u2014 sending into a session you belong to is rejected.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Target session ID."},content:{type:"string",description:"Message content to send as the owner."}},required:["session_id","content"]},validation:{required:["session_id","content"],properties:{session_id:{type:"string"},content:{type:"string",maxLength:1e4}}}},{name:"grix_chat_state_query",description:"Query the chat-level task states across all of your owner's sessions (including direct and group chats). Returns one entry per session with a single mutually-exclusive state: running (working), waiting_approval (blocked on your owner to approve/deny), waiting_question (asked the owner a question, awaiting their reply), completed, failed, or idle (no task / stopped). Also returns the session title (task_title) for easy identification. Supports pagination (page/page_size) and optional state filtering. Use this to see at a glance which chats are done, still running, or waiting on the owner.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"(Optional) Query a single session by its ID. Omit to return all sessions."},page:{type:"number",description:"(Optional) Page number, starting from 1. Defaults to 1 if omitted."},page_size:{type:"number",description:"(Optional) Number of items per page, max 100. Defaults to 10 if omitted."},state:{type:"string",description:"(Optional) Filter by a specific state: running, waiting_approval, waiting_question, completed, failed, or idle. Omit to return all states."}}},validation:{required:[],properties:{}}},{name:"grix_chat_state_update",description:"Manually update the task state of a specific chat session. Use this to mark a chat as completed, failed, idle, or any other state when you need to override it manually. The reason is written to stop_reason and is optional.",inputSchema:{type:"object",properties:{session_id:{type:"string",description:"The session ID whose state to update."},state:{type:"string",enum:["running","waiting_approval","waiting_question","completed","failed","idle"],description:"The new state to set. Must be one of: running, waiting_approval, waiting_question, completed, failed, idle."},reason:{type:"string",description:"(Optional) Reason for the state change, written to stop_reason."}}},validation:{required:["session_id","state"],properties:{}}},{name:"grix_access_control",description:"Manage sender access control: pair approval, allow/remove senders, set policy.",inputSchema:{type:"object",properties:{action:{type:"string",enum:["pair_approve","pair_deny","allow_sender","remove_sender","set_policy"],description:"Access control action type."},code:{type:"string",description:"Pairing code (required for pair_approve/pair_deny)."},sender_id:{type:"string",description:"Sender ID (required for allow_sender/remove_sender)."},policy:{type:"string",enum:["allowlist","open","disabled"],description:"Access policy (required for set_policy)."}},required:["action"]},validation:{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"]}}}},{name:"grix_skill_set",description:"Create, update, or delete one of your owner's custom skills in the platform skill library. The skill library auto-syncs to every machine the owner runs an agent on (a per-machine `grix/skills` directory), so defining a skill here makes it available on all of them. A skill is a plain SKILL.md package (frontmatter + body), same standard as other Grix skills. Provide `name` and the full `content` (the SKILL.md text) to create or overwrite by name. To delete a skill, pass its `name` with an empty `content` string. How and when any agent actually loads/uses a synced skill is arranged by the owner (in a system prompt or in conversation); this tool only manages the library.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name (max 100 characters); unique within the owner. Used as the identifier and the synced directory name."},content:{type:"string",description:"Full SKILL.md text. Pass an empty string to delete the skill by name."}},required:["name","content"]},validation:{required:["name","content"],properties:{name:{type:"string",maxLength:100},content:{type:"string",maxLength:262144}}}},{name:"grix_skill_get",description:"Read one of your owner's custom skills by name (returns its full SKILL.md content), or list the owner's skill library when no name is given. Use this before editing to fetch current content, then call grix_skill_set with the revised text.",inputSchema:{type:"object",properties:{name:{type:"string",description:"Skill name to fetch. Omit to list all skills (names + versions) instead."}}},validation:{required:[],properties:{name:{type:"string",maxLength:100}}}}],a=[{name:"grix_reply",description:"Send your final reply \u2014 the conclusion the user is waiting for \u2014 to the specified session. This is the message the user treats as your answer; deliver your final result here, and use plain text only for brief progress notes while you work. Supports streaming in chunks; the frontend automatically aggregates them into one complete message. The connector quotes the message being answered automatically, so quoted_message_id is optional (set it only to quote a different earlier message).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"Associated event ID from the inbound event."},session_id:{type:"string",description:"Target session ID."},text:{type:"string",description:"Reply text content."},quoted_message_id:{type:"string",description:"Quoted message ID (optional)."},is_final:{type:"boolean",description:"Whether this is a stage-final reply. Advisory only \u2014 does not trigger event completion; completion is handled by the complete tool or Stop hook."}},required:["session_id","text"]},validation:{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"}}}},{name:"grix_complete",description:"Mark event processing as complete, notifying the backend that no more replies are expected.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to complete."},status:{type:"string",enum:["responded","canceled","failed"],description:"Completion status."},msg:{type:"string",description:"Additional note (optional)."}},required:["event_id","status"]},validation:{required:["event_id","status"],properties:{event_id:{type:"string"},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string",maxLength:500}}}},{name:"grix_event_ack",description:"Acknowledge event receipt (usually done automatically by the Dispatcher; agents typically do not need to call this manually).",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The event ID to acknowledge."},session_id:{type:"string",description:"Session ID."}},required:["event_id"]},validation:{required:["event_id"],properties:{event_id:{type:"string"},session_id:{type:"string"}}}},{name:"grix_composing",description:'Set the "typing" indicator status for a session.',inputSchema:{type:"object",properties:{session_id:{type:"string",description:"Session ID."},active:{type:"boolean",description:"true = typing, false = stopped."},event_id:{type:"string",description:"Associated event ID (optional)."}},required:["session_id","active"]},validation:{required:["session_id","active"],properties:{session_id:{type:"string"},active:{type:"boolean"},event_id:{type:"string"}}}},{name:"grix_status",description:"Query the Grix connection status of the current MCP session.",inputSchema:{type:"object",properties:{}},validation:{required:[],properties:{}}}],b={grix_dispatch_agent:"grix-agent-dispatch",grix_agent_update:"grix-agent-dispatch",grix_query:"grix-query",grix_group:"grix-group",grix_message_send:"message-send",grix_message_unsend:"message-unsend",grix_admin:"grix-admin",grix_call_owner:"grix-owner-relay",grix_session_send:"grix-owner-relay",grix_chat_state_query:"grix-chat-state",grix_chat_state_update:"grix-chat-state",grix_status:"grix-chat-state",grix_access_control:"grix-access-control",grix_file_link:"tailnet-file-share"};function v(e){return` Before calling this tool, follow the \`${e}\` skill's procedure first; do not invoke this tool directly without going through that skill's guidance.`}for(const e of[...r,...a]){const t=b[e.name];t&&(e.description+=v(t))}const p=[{name:"reply",description:"Send a visible message back to the chat for this grix-claude event.",inputSchema:{type:"object",properties:{text:{type:"string",description:"The visible reply text to send."},chat_id:{type:"string",description:"The target chat/session id from the <channel> tag."},event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},reply_to:{type:"string",description:"Optional message_id to quote instead of the inbound trigger message."},final:{type:"boolean",description:"Advisory flag only. It does not complete the event; completion is handled by complete tool or Stop hook."}},required:["chat_id","event_id","text"]}},{name:"complete",description:"Finish an event without sending a visible reply so the backend does not time out.",inputSchema:{type:"object",properties:{event_id:{type:"string",description:"The Aibot event_id from the <channel> tag."},status:{type:"string",enum:["responded","canceled","failed"]},msg:{type:"string"},code:{type:"string"}},required:["event_id","status"]}}],c=new Set(p.map(e=>e.name)),w=new Set(r.map(e=>e.name)),x=new Set(a.map(e=>e.name)),k=/([A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+:[A-Za-z0-9._-]+)/,I=/[A-Za-z0-9._-]+/;function F(e){return!!(w.has(e)||x.has(e)||c.has(e)||e.startsWith("mcp__grix"))}const S=[...r,...a],q=[...S,...p],H=new Map(q.map(e=>[e.name,e]));function Q(e,t){return e==="reply"?{name:"grix_reply",args:_("grix_reply",{event_id:t.event_id,session_id:t.chat_id,text:t.text,quoted_message_id:t.reply_to,is_final:t.final})}:e==="complete"?{name:"grix_complete",args:_("grix_complete",{event_id:t.event_id,status:t.status,msg:t.msg,code:t.code})}:{name:e,args:t}}function l(e){const t=String(e??"").trim();return t?t.match(k)?.[1]:void 0}function u(e){const t=String(e??"").trim();if(!t)return;const n=l(t);if(n)return m(n);const i=t.match(/(?:chat_id|session_id)\s*=\s*"([A-Za-z0-9._-]+)"/)?.[1];if(i)return i;const o=t.match(/[A-Za-z0-9._-]+/g)??[];for(const s of o)if(!(s==="event_id"||s==="chat_id"||s==="session_id")&&s.length>0)return s;return t.match(I)?.[0]}function m(e){if(!e)return;const t=e.split(":",1)[0]?.trim();if(t)return u(t)}function _(e,t){if(e!=="grix_reply"&&e!=="grix_complete")return t;const n={...t},i=l(n.event_id);if(i&&(n.event_id=i),e==="grix_reply"){const o=m(i),d=String(n.session_id??""),s=u(n.session_id),f=/\bevent_id\b|["'<>\s]/.test(d);s&&!(f&&o)?n.session_id=s:o&&(n.session_id=o)}return n}function Z(e){return c.has(e)}function K(e,t){switch(e){case"grix_query":return A(t);case"grix_group":return T(t);case"grix_message_send":return M(t);case"grix_message_unsend":return O(t);case"grix_file_link":return L(t);case"grix_file_upload":return D(t);case"grix_admin":return W(t);case"grix_call_owner":return E(t);case"grix_agent_update":return j(t);case"grix_dispatch_agent":return N(t);case"grix_session_send":return P(t);case"grix_chat_state_query":return z(t);case"grix_chat_state_update":return U(t);case"grix_access_control":return C(t);case"grix_skill_set":return R(t);case"grix_skill_get":return G(t);default:throw new Error(`Unknown tool: ${e}`)}}const g={contact_search:"contact_search",session_search:"session_search",message_history:"message_history",message_search:"message_search",search_favorite_sessions:"search_favorite_sessions"};function A(e){const t=String(e.action??""),n=g[t];if(!n)throw new Error(`Unknown grix_query action: ${t}`);const i={};return e.id!=null&&(i.id=e.id),e.keyword!=null&&(i.keyword=e.keyword),e.sessionType!=null&&(i.session_type=e.sessionType),e.limit!=null&&(i.limit=e.limit),e.offset!=null&&(i.offset=e.offset),e.sessionId!=null&&(i.session_id=e.sessionId),e.beforeId!=null&&(i.before_id=e.beforeId),{action:n,params:i}}const y={create:"group_create",detail:"group_detail_read",leave:"group_leave_self",add_members:"group_member_add",remove_members:"group_member_remove",update_member_role:"group_member_role_update",update_all_members_muted:"group_all_members_muted_update",update_member_speaking:"group_member_speaking_update",dissolve:"group_dissolve"};function T(e){const t=String(e.action??""),n=y[t];if(!n)throw new Error(`Unknown grix_group action: ${t}`);const i={};return e.sessionId!=null&&(i.session_id=e.sessionId),e.name!=null&&(i.name=e.name),e.memberIds!=null&&(i.member_ids=e.memberIds),e.memberTypes!=null&&(i.member_types=e.memberTypes),e.memberId!=null&&(i.member_id=e.memberId),e.role!=null&&(i.role=e.role),e.memberType!=null&&(i.member_type=e.memberType),e.allMembersMuted!=null&&(i.all_members_muted=e.allMembersMuted),e.isSpeakMuted!=null&&(i.is_speak_muted=e.isSpeakMuted),e.canSpeakWhenAllMuted!=null&&(i.can_speak_when_all_muted=e.canSpeakWhenAllMuted),{action:n,params:i}}function M(e){const t={session_id:e.sessionId,msg_type:e.msgType??1,content:e.content};return e.quotedMessageId!=null&&(t.quoted_message_id=e.quotedMessageId),e.threadId!=null&&(t.thread_id=e.threadId),{action:"send_msg",params:t}}function O(e){return{action:"delete_msg",params:{session_id:e.sessionId,msg_id:e.msgId}}}function L(e){const t={file_path:e.file_path};return e.ttl_ms!=null&&(t.ttl_ms=e.ttl_ms),{action:"file_link",params:t}}function D(e){const t={file_path:e.file_path,session_id:e.session_id};return e.caption!=null&&(t.caption=e.caption),e.reply_to_message_id!=null&&(t.reply_to_message_id=e.reply_to_message_id),{action:"file_upload",params:t,timeoutMs:6e4}}const h={create_agent:"agent_api_create",list_categories:"agent_category_list",create_category:"agent_category_create",update_category:"agent_category_update",assign_category:"agent_category_assign",rotate_api_key:"agent_api_key_rotate"};function E(e){return{action:"call_owner",params:{session_id:e.session_id}}}function j(e){if(e.agent_name==null&&e.introduction==null)throw new Error("grix_agent_update requires agent_name or introduction");const t={agent_id:e.agent_id};return e.agent_name!=null&&(t.agent_name=e.agent_name),e.introduction!=null&&(t.introduction=e.introduction),{action:"agent_introduction_update",params:t}}function N(e){return{action:"dispatch_agent",params:{agent_id:e.agent_id,cwd:e.cwd,task:e.task,title:e.title}}}function P(e){return{action:"session_send",params:{session_id:e.session_id,content:e.content}}}function z(e){const t={};return e.session_id!=null&&(t.session_id=e.session_id),e.page!=null&&(t.page=e.page),e.page_size!=null&&(t.page_size=e.page_size),e.state!=null&&(t.state=e.state),{action:"chat_state_query",params:t}}function C(e){const t=String(e.action??""),n=B[t];if(!n)throw new Error(`Unknown grix_access_control action: ${t}`);const i={};return e.code!=null&&(i.code=e.code),e.sender_id!=null&&(i.sender_id=e.sender_id),e.policy!=null&&(i.policy=e.policy),{action:"claude_access_control",params:{verb:n,payload:i},timeoutMs:3e4}}function U(e){const t={session_id:e.session_id,state:e.state};return e.reason!=null&&(t.reason=e.reason),{action:"chat_state_update",params:t}}function R(e){return{action:"skill_set",params:{name:e.name,content:e.content},timeoutMs:3e4}}function G(e){const t={};return e.name!=null&&(t.name=e.name),{action:"skill_get",params:t}}function W(e){const t=String(e.action??""),n=h[t];if(!n)throw new Error(`Unknown grix_admin action: ${t}`);const i={};return e.agentName!=null&&(i.agent_name=e.agentName),e.introduction!=null&&(i.introduction=e.introduction),e.isMain!=null&&(i.is_main=e.isMain),e.agentId!=null&&(i.agent_id=e.agentId),e.categoryId!=null&&(i.category_id=e.categoryId),e.name!=null&&(i.name=e.name),e.parentId!=null&&(i.parent_id=e.parentId),e.sortOrder!=null&&(i.sort_order=e.sortOrder),{action:n,params:i}}const $=new Set([...Object.values(g),...Object.values(y),...Object.values(h),"send_msg","delete_msg","file_link","file_upload","call_owner","agent_introduction_update","dispatch_agent","session_send","chat_state_query","chat_state_update","claude_access_control","skill_set","skill_get"]),B={pair_approve:"pair_approve",pair_deny:"pair_deny",allow_sender:"sender_allow",remove_sender:"sender_remove",set_policy:"policy_set"};export{B as ACCESS_CONTROL_ACTION_MAP,S as ALL_TOOLS,a as EVENT_TOOLS,q as EXPOSED_TOOLS,$ as PHASE1_INVOKE_ACTIONS,w as PHASE1_TOOL_NAMES,x as PHASE2_TOOL_NAMES,r as TOOLS,p as TOOL_ALIASES,H as TOOL_MAP,Z as isAlias,F as isGrixInternalToolName,Q as mapToolAlias,_ as normalizeEventToolArgs,K as toolCallToInvoke};
|
|
@@ -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 +1 @@
|
|
|
1
|
-
function a(
|
|
1
|
+
function a(t){const o=new Set([`http://127.0.0.1:${t.serverPort}`,`http://localhost:${t.serverPort}`,...t.allowedOrigins]),e=new Set([`127.0.0.1:${t.serverPort}`,`localhost:${t.serverPort}`,...t.allowedHosts]);return{validateRequest(s){const r=i(s,o);if(!r.ok)return r;const n=l(s,e);return n.ok?{ok:!0}:n}}}function i(t,o){const e=t.headers.origin;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Origin not allowed: ${e}`}:{ok:!0}}function l(t,o){const e=t.headers.host;return e?o.has(e)?{ok:!0}:{ok:!1,statusCode:403,message:`Host not allowed: ${e}`}:{ok:!1,statusCode:403,message:"Missing Host header"}}export{a as createSecurityPolicy};
|
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
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grix-connector",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.1",
|
|
4
4
|
"description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|