@visiq/openclaw-plugin 0.1.4 → 0.1.5
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/chunk-2TT2F3AO.js +8 -0
- package/dist/index.d.ts +101 -11
- package/dist/index.js +1 -1
- package/dist/openclaw-entry.js +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
- package/dist/chunk-K2XSEUBX.js +0 -11
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{readFile as ve}from"node:fs/promises";import{homedir as $}from"node:os";import{join as q,isAbsolute as Ae,resolve as we}from"node:path";import{createInterface as Ie}from"node:readline";import{parseArgs as ke}from"node:util";var B="@visiq/openclaw-plugin",Se='[VisIQ] OpenClaw plugin is installed but missing credentials. Provide them with one of (highest precedence first): (1) environment variables VISIQ_API_KEY=<key> VISIQ_AGENT_ID=<id> (set before `openclaw gateway run` / `openclaw start`) ; (2) a JSON file at the path in VISIQ_CONFIG_PATH ; (3) ~/.openclaw/openclaw.json -> plugins.entries["@visiq/openclaw-plugin"].config = { "apiKey": "<key>", "agentId": "<id>" } . Plugin will load but all hooks will no-op until credentials are provided.';function Ce(e){return e==="~"||e.startsWith("~/")?q($(),e.slice(1).replace(/^\//,"")):e}async function U(e){try{let t=Ae(e)?e:we(e),n=await ve(t,"utf-8");return JSON.parse(n)}catch{return null}}function O(e,...t){for(let n of t){let r=e[n];if(typeof r=="string")return r}}function N(e){if(!e||typeof e!="object")return{};let t=e,n=O(t,"apiKey","api_key"),r=O(t,"agentId","agent_id"),i=O(t,"baseUrl","base_url"),a={};return n&&(a.apiKey=n),r&&(a.agentId=r),i&&(a.baseUrl=i),a}async function Ee(e){if(!e)return{};let t=Ce(e),n=await U(t);if(!n||typeof n!="object")return{};let r=n,i=r.plugins?.entries,a=i&&typeof i=="object"?i[B]:void 0;return a&&typeof a=="object"&&a.config?N(a.config):N(r)}async function Te(){let e=q($(),".openclaw","openclaw.json"),t=await U(e);if(!t||typeof t!="object")return{};let a=t.plugins?.entries?.[B];return!a||typeof a!="object"?{}:N(a.config)}async function xe(e){if(!process.stdout.isTTY)return{};let t=Ie({input:process.stdin,output:process.stdout}),n=r=>new Promise(i=>t.question(r,a=>i(a)));try{let r={...e};if(!r.apiKey){let i=(await n("VisIQ API key: ")).trim();i&&(r.apiKey=i)}if(!r.agentId){let i=(await n("VisIQ agent ID: ")).trim();i&&(r.agentId=i)}if(!r.baseUrl){let i=(await n("VisIQ base URL (optional, press Enter for default): ")).trim();i&&(r.baseUrl=i)}return r}finally{t.close()}}function Re(){try{let{values:e}=ke({args:process.argv.slice(2),options:{"api-key":{type:"string"},"agent-id":{type:"string"},"base-url":{type:"string"}},strict:!1,allowPositionals:!0}),t={},n=e["api-key"],r=e["agent-id"],i=e["base-url"];return typeof n=="string"&&n&&(t.apiKey=n),typeof r=="string"&&r&&(t.agentId=r),typeof i=="string"&&i&&(t.baseUrl=i),t}catch{return{}}}async function W(){let e=Re(),t={};process.env.VISIQ_API_KEY&&(t.apiKey=process.env.VISIQ_API_KEY),process.env.VISIQ_AGENT_ID&&(t.agentId=process.env.VISIQ_AGENT_ID),process.env.VISIQ_BASE_URL?t.baseUrl=process.env.VISIQ_BASE_URL:process.env.VISIQ_ENDPOINT&&(t.baseUrl=process.env.VISIQ_ENDPOINT);let n=await Ee(process.env.VISIQ_CONFIG_PATH),i={...await Te(),...n,...t,...e};if((!i.apiKey||!i.agentId)&&process.stdout.isTTY&&process.stdin.isTTY&&(i=await xe(i)),!i.apiKey||!i.agentId)return process.stderr.write(`${Se}
|
|
2
|
+
`),null;let a={apiKey:i.apiKey,agentId:i.agentId};return i.baseUrl&&(a.baseUrl=i.baseUrl),a}var P=null,z={ready:!1,config:null};function h(){return P||(P=W().catch(e=>(process.stderr.write(`[VisIQ] Config resolution failed (treating as unconfigured): ${e instanceof Error?e.message:String(e)}
|
|
3
|
+
`),null)).then(e=>(z={ready:!0,config:e},e))),P}function k(){return z}function Lt(){h()}import{z as o}from"zod";import*as m from"node:os";var K="interceptor_source",Oe=o.enum(["enforce","audit","off"]),Ne=o.enum(["closed","open"]),V=o.enum(["enforce","monitor","off"]),Pe=o.object({apiKey:o.string().min(1,"apiKey is required"),agentId:o.string().min(1,"agentId is required"),endpoint:o.string().url().optional(),mode:Oe.optional(),timeoutMs:o.number().int().positive().optional(),hitlTimeoutMs:o.number().int().positive().optional(),failBehavior:Ne.optional()}),jt=o.object({agent_id:o.string().min(1),target_app:o.string().min(1),action:o.string().min(1),context:o.record(o.unknown()).optional(),session_id:o.string().min(1).max(255).optional(),telemetry:o.record(o.unknown()).optional()}),Le=o.object({field:o.string().optional(),pattern:o.string().optional(),replacement:o.string().optional(),mode:o.enum(["full","partial","email"]).optional(),keepFirst:o.number().optional(),keepLast:o.number().optional(),maskChar:o.string().optional()}),Fe=o.object({decision_id:o.string().min(1),decision:o.enum(["permit","deny","approval_required","mask"]),reason:o.string().optional(),rule_code:o.string().nullable().optional(),enforced:o.boolean().optional(),agent_mode:V.optional(),arg_redaction_rules:o.array(Le).optional(),plane:o.string().nullable().optional(),operation:o.string().nullable().optional(),is_retrieval:o.boolean().optional(),metadata:o.record(o.unknown()).optional()}),Me=o.object({field:o.string().min(1),operator:o.enum(["equals","in","not_equals","not_in","glob","gt","lt","gte","lte","contains","not_contains"]),value:o.union([o.string(),o.number(),o.array(o.string())])}),je=o.object({id:o.string().min(1),rule_code:o.string().default(""),name:o.string().min(1),description:o.string().nullable().default(null),effect:o.enum(["allow","deny","hitl","mask"]),resource_type:o.string().min(1),rego_source:o.string().default(""),target_app:o.string().nullable().default(null),action_pattern:o.string().nullable().default(null),conditions:o.array(Me).default([]),priority:o.number().int().default(0)}),De=o.object({version:o.string().min(1),agent_mode:V.optional(),rules:o.array(je),no_coverage:o.object({no_coverage_defaults:o.record(o.string()),autopilot_enabled:o.boolean(),enduser_hitl_enabled:o.boolean(),hitl_timeout_seconds:o.number()}).optional()}),$e=2e3,G=class{config;originalFetch;constructor(e,t){this.config=e,this.originalFetch=t}async evaluate(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.config.timeoutMs),r;try{r=await this.originalFetch(`${this.config.endpoint}/allow/evaluate`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify(e),signal:t.signal})}finally{clearTimeout(n)}if(!r.ok)throw new Error(`ALLOW evaluate request failed: HTTP ${r.status} ${r.statusText}`);let i=await r.json();return Fe.parse(i)}async fetchBundle(){let e=this.config.agentId?`?agent_id=${encodeURIComponent(this.config.agentId)}`:"",t=`${this.config.endpoint}/allow/rules/bundle${e}`,n=new AbortController,r=setTimeout(()=>n.abort(),this.config.timeoutMs),i;try{i=await this.originalFetch(t,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`,Accept:"application/json"},signal:n.signal})}finally{clearTimeout(r)}if(!i.ok)throw new Error(`ALLOW rules/bundle fetch failed: HTTP ${i.status} ${i.statusText}`);let a=await i.json();return De.parse(a)}async sendTelemetry(e){if(e.length===0)return;let t=`${this.config.endpoint}/allow/telemetry`,n=await this.originalFetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({decisions:e})});if(!n.ok)throw new Error(`ALLOW telemetry delivery failed: HTTP ${n.status} ${n.statusText}`)}async reportExecutionResult(e,t,n){let r=`${this.config.endpoint}/allow/execution-events`;try{let i=await this.originalFetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({decision_id:e,result:t,details:n})});i.ok||console.warn(`[ALLOW] Execution result report failed: HTTP ${i.status}`)}catch(i){console.warn("[ALLOW] Execution result report failed:",i)}}async registerEnvironment(e){if(!this.config.agentId)return;let t=`${this.config.endpoint}/allow/agents/register`;try{let n=await this.originalFetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({agent_id:this.config.agentId,os:e.os,hostname:e.hostname,ip:e.ip,username:e.username,...this.config.harnessKind?{kind:this.config.harnessKind}:{}})});n.ok||console.warn(`[ALLOW] Agent registration failed: HTTP ${n.status} ${n.statusText}`)}catch(n){console.warn("[ALLOW] Agent registration failed:",n)}}async waitForApproval(e){if(!e)throw new Error("waitForApproval: decisionId must be a non-empty string");let t=Date.now()+this.config.hitlTimeoutMs;for(;Date.now()<t;){let n=new AbortController,r=setTimeout(()=>n.abort(),this.config.timeoutMs),i;try{i=await this.originalFetch(`${this.config.endpoint}/v1/allow/decisions/${encodeURIComponent(e)}`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`},signal:n.signal})}finally{clearTimeout(r)}if(!i.ok)throw new Error(`ALLOW decisions poll failed: HTTP ${i.status} ${i.statusText}`);let a=await i.json();if(typeof a!="object"||a===null)throw new Error("ALLOW decisions poll returned unexpected non-object response");let l=a,s=l.hitl_result;if(s==="approved")return{decision_id:e,decision:"permit",reason:"Approved by human reviewer"};if(s==="rejected")return{decision_id:e,decision:"deny",reason:typeof l.reason=="string"?l.reason:"Rejected by human reviewer"};if(s==="timeout"||s==="expired")return{decision_id:e,decision:"deny",reason:"HITL approval timed out"};await qe($e)}return{decision_id:e,decision:"deny",reason:"HITL approval timed out"}}};function qe(e){return new Promise(t=>setTimeout(t,e))}function H(){let e={};try{let t=`${m.platform()} ${m.release()}`.trim();t&&(e.os=t)}catch{}try{let t=m.hostname();t&&(e.hostname=t)}catch{}try{let{username:t}=m.userInfo();t&&(e.username=t)}catch{}try{let t=Be();t&&(e.ip=t)}catch{}return e}function Be(){let e=m.networkInterfaces();for(let t of Object.keys(e))for(let n of e[t]??[])if((n.family==="IPv4"||n.family===4)&&!n.internal&&n.address)return n.address}import{z as u}from"zod";import{createHash as Bt}from"crypto";import{createHash as zt}from"crypto";var Ue=["tier1","tier2","tier3"];function Z(e){return typeof e=="string"&&Ue.includes(e)}var We=["read_only","transactional","data_processor","external_comms","code_exec","privileged"],ze=["internal","customer_facing","experimental","third_party"],J=[...We,...ze];function Ke(e){return typeof e=="string"&&J.includes(e)}function X(e){let t=new Set;for(let n of e)Ke(n)&&t.add(n);return J.filter(n=>t.has(n))}var Ve=["read_only","record_create","record_update","record_delete","data_export","data_share","data_subject_request","consent_change","funds_transfer","funds_disbursement","payroll_run","trade_execution","ledger_mutation","credit_decision","decision_adverse","account_restriction","account_closure","card_management","purchase_commitment","vendor_management","deal_management","pricing_change","contract_execution","legal_hold","regulatory_filing","personnel_action","employment_termination","compensation_change","campaign_send","content_publish","inventory_adjustment","order_fulfillment","account_servicing","credential_reset","access_grant","permission_change","credential_management","auth_policy_change","security_config_change","logging_change","alert_management","code_change","infrastructure_provision","deployment_change","communication_send","other"];function ee(e){if(typeof e!="string"&&typeof e!="number")return null;let t=String(e).trim().replace(/([a-z0-9])([A-Z])/g,"$1_$2").toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"");return t.length>0?t:null}var Ge={wire_transfer:"funds_transfer",international_transfer:"funds_transfer",cross_border_payment:"funds_transfer",send_swift:"funds_transfer",send_wire:"funds_transfer",transfer_funds:"funds_transfer",update_wire_instructions:"funds_transfer",add_beneficiary:"funds_transfer",modify_payee:"funds_transfer",disburse_funds:"funds_disbursement",initiate_ach:"funds_disbursement",issue_refund:"funds_disbursement",execute_trade:"trade_execution",place_order:"trade_execution",post_journal_entry:"ledger_mutation",adjust_ledger:"ledger_mutation",modify_general_ledger:"ledger_mutation",raise_limit:"credit_decision",increase_credit_limit:"credit_decision",extend_credit:"credit_decision",decline_credit:"decision_adverse",deny_application:"decision_adverse",adverse_action:"decision_adverse",block_card:"card_management",cancel_card:"card_management",place_hold:"account_restriction",freeze_account:"account_restriction",restrict_account:"account_restriction",close_account:"account_closure",export_data:"data_export",export_customer_list:"data_export",download_report:"data_export",download_customer_list:"data_export",bulk_export:"data_export",share_data:"data_share",send_to_partner:"data_share",delete_records:"record_delete",delete_user:"record_delete",drop_table:"record_delete",grant_role:"access_grant",change_permissions:"permission_change",modify_access:"permission_change",rotate_keys:"credential_management",disable_mfa:"auth_policy_change",modify_security_config:"security_config_change",disable_logging:"logging_change",purge_logs:"logging_change",suppress_alert:"alert_management",dismiss_alert:"alert_management",rollback:"deployment_change",modify_billing:"record_update",close_sar:"record_update",send_email:"communication_send",send_sms:"communication_send",fulfill_dsar:"data_subject_request",process_dsar:"data_subject_request",fulfill_data_request:"data_subject_request",process_erasure_request:"data_subject_request",honor_deletion_request:"data_subject_request",export_subject_data:"data_subject_request",erase_subject_data:"data_subject_request",delete_subject_data:"data_subject_request",record_consent:"consent_change",capture_consent:"consent_change",update_consent:"consent_change",withdraw_consent:"consent_change",revoke_consent:"consent_change",opt_out:"consent_change",opt_in:"consent_change",run_payroll:"payroll_run",process_payroll:"payroll_run",submit_payroll:"payroll_run",approve_payroll:"payroll_run",create_purchase_order:"purchase_commitment",issue_purchase_order:"purchase_commitment",approve_purchase_order:"purchase_commitment",submit_purchase_order:"purchase_commitment",approve_purchase:"purchase_commitment",approve_requisition:"purchase_commitment",commit_spend:"purchase_commitment",onboard_vendor:"vendor_management",add_vendor:"vendor_management",create_supplier:"vendor_management",approve_vendor:"vendor_management",update_vendor_bank:"vendor_management",update_supplier_bank:"vendor_management",modify_supplier:"vendor_management",create_opportunity:"deal_management",update_opportunity:"deal_management",advance_deal_stage:"deal_management",update_deal_stage:"deal_management",close_deal:"deal_management",mark_closed_won:"deal_management",mark_closed_lost:"deal_management",issue_quote:"pricing_change",send_quote:"pricing_change",approve_discount:"pricing_change",apply_discount:"pricing_change",override_price:"pricing_change",update_pricing:"pricing_change",approve_special_pricing:"pricing_change",execute_contract:"contract_execution",sign_contract:"contract_execution",countersign_contract:"contract_execution",sign_agreement:"contract_execution",execute_agreement:"contract_execution",sign_nda:"contract_execution",execute_nda:"contract_execution",sign_document:"contract_execution",esign_document:"contract_execution",place_legal_hold:"legal_hold",place_litigation_hold:"legal_hold",apply_legal_hold:"legal_hold",release_legal_hold:"legal_hold",file_regulatory_report:"regulatory_filing",file_sar:"regulatory_filing",submit_regulatory_filing:"regulatory_filing",file_compliance_report:"regulatory_filing",file_disclosure:"regulatory_filing",onboard_employee:"personnel_action",hire_employee:"personnel_action",change_employee_role:"personnel_action",promote_employee:"personnel_action",transfer_employee:"personnel_action",update_job_title:"personnel_action",terminate_employee:"employment_termination",offboard_employee:"employment_termination",deactivate_employee:"employment_termination",separate_employee:"employment_termination",adjust_salary:"compensation_change",change_compensation:"compensation_change",approve_raise:"compensation_change",grant_equity:"compensation_change",grant_stock:"compensation_change",issue_bonus:"compensation_change",update_pay_rate:"compensation_change",send_campaign:"campaign_send",launch_campaign:"campaign_send",schedule_campaign:"campaign_send",send_bulk_email:"campaign_send",send_marketing_email:"campaign_send",send_newsletter:"campaign_send",blast_email:"campaign_send",publish_post:"content_publish",publish_content:"content_publish",publish_blog:"content_publish",post_to_social:"content_publish",schedule_post:"content_publish",adjust_inventory:"inventory_adjustment",write_off_inventory:"inventory_adjustment",update_stock_level:"inventory_adjustment",reconcile_inventory:"inventory_adjustment",fulfill_order:"order_fulfillment",ship_order:"order_fulfillment",dispatch_order:"order_fulfillment",mark_order_shipped:"order_fulfillment",update_customer_account:"account_servicing",modify_customer_account:"account_servicing",update_customer_contact:"account_servicing",change_customer_settings:"account_servicing",reset_customer_password:"credential_reset",reset_password:"credential_reset",force_password_reset:"credential_reset",reset_mfa:"credential_reset",unlock_account:"credential_reset",reset_customer_credentials:"credential_reset",merge_pull_request:"code_change",merge_pr:"code_change",merge_branch:"code_change",push_to_branch:"code_change",push_to_main:"code_change",push_code:"code_change",commit_code:"code_change",force_push:"code_change",provision_infrastructure:"infrastructure_provision",provision_resource:"infrastructure_provision",create_instance:"infrastructure_provision",terminate_instance:"infrastructure_provision",spin_up_server:"infrastructure_provision",tear_down_server:"infrastructure_provision",destroy_resource:"infrastructure_provision",create_cluster:"infrastructure_provision"};function He(e){let t=ee(e);return t===null?"other":Ge[t]||(/^(delete|remove|purge|drop|destroy|wipe)_/.test(t)?"record_delete":/^(export|download|extract|dump)_/.test(t)?"data_export":/^(create|add|insert)_/.test(t)?"record_create":/^(update|edit|modify|patch|set)_/.test(t)?"record_update":t==="send_email"||t==="send_sms"||/^(notify|email|sms)_/.test(t)?"communication_send":/^(read|get|list|search|fetch|view|query)_/.test(t)||t==="read"||t==="get"?"read_only":"other")}var Q={github:"version_control",gitlab:"version_control",bitbucket:"version_control",stripe:"payments",adyen:"payments",braintree:"payments",paypal:"payments",square:"payments",salesforce:"crm",hubspot:"crm",pipedrive:"crm",slack:"communication",teams:"communication",twilio:"communication",sendgrid:"communication",mailgun:"communication",gmail:"communication",outlook:"communication",zoom:"communication",aws:"cloud_infra",gcp:"cloud_infra",azure:"cloud_infra",okta:"identity",auth0:"identity",entra:"identity",onelogin:"identity",duo:"identity",snowflake:"data_warehouse",bigquery:"data_warehouse",databricks:"data_warehouse",redshift:"data_warehouse",jira:"ticketing",zendesk:"ticketing",servicenow:"ticketing",freshdesk:"ticketing",linear:"ticketing",workday:"hr",bamboohr:"hr",gusto:"hr",netsuite:"finance_erp",quickbooks:"finance_erp",sap:"finance_erp",xero:"finance_erp",s3:"storage",gcs:"storage",dropbox:"storage",box:"storage",postgres:"database",postgresql:"database",mysql:"database",mongodb:"database",redis:"database"};function Qe(e){let t=ee(e);return t===null?"other":Q[t]??Q[t.replace(/_/g,"")]??"other"}function te(e,t){let n={...e};if(t.action!==void 0&&t.action!==null&&n.action_class===void 0&&(n.action_class=He(t.action)),t.targetApp!==void 0&&t.targetApp!==null){let r=n.context&&typeof n.context=="object"&&!Array.isArray(n.context)?{...n.context}:{};r.app_category===void 0&&(r.app_category=Qe(t.targetApp)),n.context=r}return n}var Y=64,Ye=64,w={retrieved_data_categories:[],retrieved_classifications:[],action_classes:[],action_counts:{},denied_count:0,inhibited_count:0,event_count:0,target_apps:[]};function ne(){return{retrieved_data_categories:[],retrieved_classifications:[],action_classes:[],action_counts:{},denied_count:0,inhibited_count:0,event_count:0,target_apps:[]}}var Ze=new Set(["deny","approval_required","escalate"]);function S(e,t){if(t.length===0)return[...e];let n=new Set(e);for(let i of t)n.add(i);let r=[...n].sort();return r.length>Y?r.slice(0,Y):r}function Je(e){return e?e.filter(t=>typeof t=="string"&&t.length>0):[]}function C(e){return typeof e=="string"&&e.length>0?e:null}function re(e,t){let n=Je(t.data_categories),r=C(t.classification),i=C(t.action_class),a=i&&Ve.includes(i)?i:null,l=C(t.target_app),s=C(t.decision),c={...e.action_counts};if(a)if(a in c)c[a]=(c[a]??0)+1;else if(Object.keys(c).length<Ye)c[a]=1;else{let p=Object.keys(c).sort(),d=p[p.length-1];d!==void 0&&a<d&&(delete c[d],c[a]=1)}return{retrieved_data_categories:S(e.retrieved_data_categories,n),retrieved_classifications:S(e.retrieved_classifications,r?[r]:[]),action_classes:S(e.action_classes,a?[a]:[]),action_counts:c,denied_count:e.denied_count+(s==="deny"?1:0),inhibited_count:e.inhibited_count+(s&&Ze.has(s)?1:0),event_count:e.event_count+1,target_apps:S(e.target_apps,l?[l]:[])}}var Xe="generic",ie=[{id:"finance_accounting",name:"Finance & Accounting",icon:"Landmark",description:"Payments, invoicing, ledgers, transactions, refunds, financial reporting, SOX/AML/KYC controls."},{id:"hr",name:"Human Resources",icon:"Users",description:"Employee records, payroll, hiring/recruiting, benefits, personnel actions and PII of staff."},{id:"engineering",name:"Engineering",icon:"Code",description:"Source code, build/deploy pipelines, infrastructure changes, production systems and developer tooling."},{id:"it_security",name:"IT & Security",icon:"ShieldCheck",description:"Credentials, secrets, access control, configuration, threat/exfiltration prevention and security operations."},{id:"legal",name:"Legal",icon:"Scale",description:"Contracts, NDAs, litigation, counsel communications and legal-hold material."},{id:"privacy_compliance",name:"Privacy & Compliance",icon:"BadgeCheck",description:"GDPR/CCPA/HIPAA, consent, data-subject rights, special-category data and regulatory data handling."},{id:"sales",name:"Sales",icon:"TrendingUp",description:"CRM, leads, deals, quotes, pipeline and customer commercial relationships."},{id:"marketing",name:"Marketing",icon:"Megaphone",description:"Campaigns, content, brand, social channels and prospect/audience data."},{id:"operations",name:"Operations",icon:"Cog",description:"Business operations, logistics, internal workflows, vendor/ops tooling and process automation."},{id:"customer_support",name:"Customer Support",icon:"LifeBuoy",description:"Support tickets, customer communications, account servicing and help-desk actions."},{id:"procurement",name:"Procurement",icon:"ShoppingCart",description:"Purchasing, supplier management, purchase orders, sourcing and spend approvals."},{id:Xe,name:"Generic",icon:"Shapes",description:"Catch-all for cross-cutting rules or rules that do not fit a specific function. Assign when no specific function clearly applies."}],Ut=ie.map(e=>e.id),et=new Map(ie.map(e=>[e.id,e]));function L(e){if(!Array.isArray(e))return[];let t=[],n=new Set;for(let r of e)typeof r=="string"&&et.has(r)&&!n.has(r)&&(n.add(r),t.push(r));return t}function ae(e){return L(e)[0]??null}function oe(e){return e==="open"||e==="closed"?e:null}var tt=["action","retrieval","delegation"];function nt(e){return typeof e=="string"&&tt.includes(e)}var rt=new Set(["rules"]);function se(e){if(typeof e.id!="string"||typeof e.vendor_id!="string")return null;let t=typeof e.origin_table=="string"?e.origin_table:"";if(!rt.has(t))return null;let n=Array.isArray(e.applies_to)?e.applies_to.filter(nt):[];return n.length===0?null:{id:e.id,originTable:t,vendorId:e.vendor_id,name:typeof e.name=="string"?e.name:"",description:typeof e.description=="string"?e.description:null,regoSource:typeof e.rego_source=="string"?e.rego_source:null,priority:typeof e.priority=="number"?e.priority:0,enabled:e.enabled===!0,appliesTo:n,targetApp:typeof e.target_app=="string"?e.target_app:null,actionPattern:typeof e.action_pattern=="string"?e.action_pattern:null,trustTier:typeof e.trust_tier=="string"?e.trust_tier:null,surface:typeof e.surface=="string"?e.surface:null,principalExclusions:Array.isArray(e.principal_exclusions)?e.principal_exclusions.filter(r=>typeof r=="string"):null,bypassActive:e.bypass_active===!0,bypassReason:typeof e.bypass_reason=="string"?e.bypass_reason:null,bypassExpiresAt:typeof e.bypass_expires_at=="string"?e.bypass_expires_at:null,redactionSpec:e.redaction_spec??null,failClosedOnEmptySpec:e.fail_closed_on_empty_spec===!0,hitlFallback:e.hitl_fallback==="mask"?"mask":"deny",ruleCode:typeof e.rule_code=="string"?e.rule_code:null}}function it(e,t=process.env){if(typeof e=="number"&&Number.isFinite(e)&&e>0)return e;let n=t.ALLOW_TIMEOUT_MS;if(n!==void 0){let r=Number.parseInt(n,10);if(Number.isFinite(r)&&r>0)return r}return 5e3}var I;async function at(){if(I!==void 0)return I;try{let e=await import("@visiq/core-wasm"),t=e.evaluate??e.default?.evaluate;I=typeof t=="function"?t:null}catch{I=null}return I}var ot=5e3,st=1e4,le=1e3,lt=512,ct=1800*1e3,ut="monitor",dt=u.object({operations:u.array(u.enum(["retrieval","action","delegation"])).min(1,"at least one operation is required"),agentId:u.string().min(1,"agentId is required"),sessionId:u.string().min(1).max(255).optional(),toolName:u.string().optional(),toolArgs:u.record(u.unknown()).optional(),targetResource:u.string().optional(),resourceType:u.string().optional(),resourceMetadata:u.record(u.unknown()).optional(),normalized:u.record(u.unknown()).optional(),query:u.string().optional(),contentPreview:u.string().optional(),telemetry:u.record(u.unknown()).optional()}),pt=u.object({version:u.string().min(1),agent_mode:u.enum(["enforce","monitor","off"]).optional(),agent_mode_by_operation:u.object({action:u.string().optional(),retrieval:u.string().optional(),delegation:u.string().optional()}).partial().optional(),agent_attributes:u.object({trust_tier:u.string().nullable().optional(),categories:u.array(u.string()).optional(),business_function:u.string().nullable().optional(),business_functions:u.array(u.string()).nullable().optional(),no_coverage:u.string().nullable().optional()}).optional(),rules:u.array(u.record(u.unknown())),no_coverage:u.object({no_coverage_defaults:u.record(u.string()),autopilot_enabled:u.boolean(),enduser_hitl_enabled:u.boolean(),hitl_timeout_seconds:u.number().optional()}).optional()});function ft(e){let t=e.trust_tier??null,n=[];Array.isArray(e.business_functions)&&e.business_functions.length>0?n=e.business_functions:typeof e.business_function=="string"&&e.business_function!==""&&(n=[e.business_function]);let r=L(n);return{trust_tier:Z(t)?t:null,categories:X(e.categories??[]),business_functions:r,business_function:ae(r)}}function gt(e){if(!e)return null;let t={};for(let n of["action","retrieval","delegation"]){let r=e[n];(r==="enforce"||r==="monitor"||r==="off")&&(t[n]=r)}return Object.keys(t).length>0?t:null}function mt(e){return e==="permit"?"permit":e==="mask"||e==="redact"?"mask":e==="approval_required"||e==="escalate"?"approval_required":"deny"}var ue=class{client;originalFetch;resolvedApiKey;resolvedEndpoint;resolvedAgentId;harnessKind;rules=[];agentAttributes=null;agentNoCoverage=null;sessions=new Map;noCoverage=null;bundleVersion=null;bundleEtag=null;bundleLoaded=!1;bundleFetchInProgress=!1;initialBundlePromise=null;refreshTimer=null;agentMode=ut;agentModeByOperation=null;rawBundle=null;agentModeConfirmed=!1;bundleApplyFailed=!1;telemetryBuffer=[];telemetryTimer=null;envRegistered=!1;registerPromise=null;constructor(e,t,n,r,i){let a=e??process.env.VISIQ_API_KEY??process.env.ALLOW_API_KEY??process.env.VISIQ_ALLOW_API_KEY,l=t??process.env.VISIQ_ENDPOINT??process.env.ALLOW_ENDPOINT,s=n??process.env.VISIQ_AGENT_ID??process.env.ALLOW_AGENT_ID??"";if(this.resolvedApiKey=a,this.resolvedEndpoint=l,this.resolvedAgentId=s,this.harnessKind=r,this.originalFetch=globalThis.fetch.bind(globalThis),a&&l){let c={apiKey:a,agentId:s,endpoint:l,mode:"enforce",timeoutMs:it(i),hitlTimeoutMs:12e4,failBehavior:"closed",...r?{harnessKind:r}:{}};this.client=new G(c,this.originalFetch),this.initialBundlePromise=this.fetchBundleBackground(),this.refreshTimer=setInterval(()=>{this.fetchBundleBackground()},ot),ce(this.refreshTimer),this.telemetryTimer=setInterval(()=>{this.flushTelemetry()},st),ce(this.telemetryTimer)}else this.client=null}async evaluate(e){let t=dt.parse(e),n=Date.now();if(t.operations.every(c=>this.modeFor(c)==="off"))return this.offDecision(t);if(!this.bundleLoaded){let c;this.agentModeConfirmed?c=this.agentMode:this.bundleApplyFailed?c="enforce":c="monitor";let p=this.denyAll(t,"No unified bundle loaded and no local rules \u2014 fail-closed (G001)");return this.applyAgentMode(p,c,t,n)}let r=this.readSession(t.sessionId),i=await at();if(!i||!this.rawBundle)throw new Error("governance core (@visiq/core-wasm) unavailable \u2014 failing closed (G001)");let a={...t,session:r,at:Date.now()},l={...this.rawBundle,agent_mode:this.agentMode,...this.agentModeByOperation?{agent_mode_by_operation:this.agentModeByOperation}:{}},s=i(a,l);return this.foldSession(t,s.enforced?s.decision:"permit"),s.enforced&&s.action.decision==="approval_required"&&await this.registerHitl(t,s),this.bufferTelemetry(t,s,Date.now()-n,s.enforced),s}modeFor(e){return this.agentModeByOperation?.[e]??this.agentMode}readSession(e){if(!e)return w;let t=this.sessions.get(e);return t?Date.now()-t.touchedAt>ct?(this.sessions.delete(e),w):t.state:w}foldSession(e,t){let{sessionId:n}=e;if(!n)return;let r=this.readSession(n),i=e.resourceMetadata??{},a=e.operations.includes("retrieval"),l=e.operations.includes("action")||e.operations.includes("delegation"),s=l?te(e.normalized??{},{action:e.toolName??"",targetApp:e.targetResource??e.toolName??""}):e.normalized??{},c=re(r===w?ne():r,{data_categories:a&&Array.isArray(i.data_categories)?i.data_categories:void 0,classification:a?i.classification:void 0,action_class:l?s.action_class:void 0,target_app:l?e.targetResource??e.toolName:void 0,decision:t});if(this.sessions.delete(n),this.sessions.set(n,{state:c,touchedAt:Date.now()}),this.sessions.size>lt){let p=this.sessions.keys().next().value;p!==void 0&&this.sessions.delete(p)}}applyAgentMode(e,t,n,r){let i=Date.now()-r;if(t==="enforce"){let l={...e,enforced:!0,agentMode:"enforce"};return this.bufferTelemetry(n,l,i,!0),l}let a={...e,allowed:!0,enforced:!1,agentMode:"monitor"};return this.bufferTelemetry(n,a,i,!1),a}offDecision(e){let t=e.operations.includes("action")||e.operations.includes("delegation"),n=e.operations.includes("retrieval");return{decision:"permit",allowed:!0,reason:"agent_mode=off \u2014 evaluation bypassed",ruleId:null,ruleCode:null,enforced:!1,agentMode:"off",action:t?{decision:"permit",allowed:!0}:{decision:null,allowed:!0},retrieval:n?{action:"allow"}:{action:null}}}denyAll(e,t){let n=e.operations.includes("action")||e.operations.includes("delegation"),r=e.operations.includes("retrieval");return{decision:"deny",allowed:!1,reason:t,ruleId:null,ruleCode:null,enforced:!0,agentMode:"enforce",action:n?{decision:"deny",allowed:!1}:{decision:null,allowed:!0},retrieval:r?{action:"deny"}:{action:null}}}async registerHitl(e,t){if(this.client)try{let n={agent_id:e.agentId,target_app:e.targetResource??e.toolName??"",action:e.toolName??"",context:e.toolName?{[e.toolName]:e.toolArgs??{}}:{},...e.sessionId?{session_id:e.sessionId}:{},...e.telemetry?{telemetry:e.telemetry}:{}},r=await this.client.evaluate(n);r.decision_id&&(t.action.decisionId=r.decision_id)}catch(n){console.warn("[UNIFIED] HITL registration failed \u2014 staying fail-closed (G001):",n)}}applyBundle(e){this.bundleApplyFailed=!0;let t=pt.parse(e);this.bundleApplyFailed=!1,!(this.bundleLoaded&&t.version===this.bundleVersion)&&(this.rules=t.rules.map(n=>se(n)).filter(n=>n!==null),this.agentAttributes=t.agent_attributes?ft(t.agent_attributes):null,this.agentNoCoverage=oe(t.agent_attributes?.no_coverage),this.bundleVersion=t.version,this.bundleLoaded=!0,this.noCoverage=t.no_coverage?{no_coverage_defaults:t.no_coverage.no_coverage_defaults,autopilot_enabled:t.no_coverage.autopilot_enabled,enduser_hitl_enabled:t.no_coverage.enduser_hitl_enabled}:null,t.agent_mode!==void 0&&(this.agentMode=t.agent_mode,this.agentModeConfirmed=!0),this.agentModeByOperation=gt(t.agent_mode_by_operation),this.rawBundle=e)}async awaitBundleReady(e=5e3){if(!this.initialBundlePromise||this.bundleLoaded)return;let t,n=new Promise(r=>{t=setTimeout(r,e)});try{await Promise.race([this.initialBundlePromise,n])}catch{}finally{t&&clearTimeout(t)}}async fetchBundleBackground(){if(!(this.bundleFetchInProgress||!this.resolvedEndpoint||!this.resolvedApiKey)){this.bundleFetchInProgress=!0;try{let e=this.resolvedAgentId?`?agent_id=${encodeURIComponent(this.resolvedAgentId)}`:"",t={Authorization:`Bearer ${this.resolvedApiKey}`,Accept:"application/json"};this.bundleEtag&&(t["If-None-Match"]=this.bundleEtag);let n=await this.originalFetch(`${this.resolvedEndpoint}/rules/bundle${e}`,{method:"GET",headers:t});if(n.status===304)return;if(!n.ok)throw new Error(`unified bundle fetch failed: HTTP ${n.status}`);let r=n.headers.get("ETag");r&&(this.bundleEtag=r);let i=await n.json();this.applyBundle(i)}catch(e){this.bundleLoaded?console.warn("[UNIFIED] Bundle refresh failed (using cached rules):",e):console.warn("[UNIFIED] Initial bundle fetch failed (fail-closed until loaded):",e)}finally{this.bundleFetchInProgress=!1}}}hasRules(){return this.bundleLoaded&&this.rules.length>0}hasClient(){return this.client!==null}getEndpoint(){return this.resolvedEndpoint}getApiKey(){return this.resolvedApiKey}getBundleVersion(){return this.bundleVersion}getAgentMode(){return this.agentMode}getAgentAttributes(){return this.agentAttributes}getSessionState(e){return this.readSession(e)}registerEnvironment(e){!this.client||this.envRegistered||!this.resolvedAgentId||(this.envRegistered=!0,this.registerPromise=this.client.registerEnvironment(e))}registerHostEnvironment(){this.registerEnvironment(H())}bufferTelemetry(e,t,n,r){this.telemetryBuffer.push({decision_id:crypto.randomUUID(),agent_id:e.agentId,target_app:e.targetResource??e.toolName??"",action:e.toolName??e.operations.join("+"),...e.sessionId?{session_id:e.sessionId}:{},decision:mt(t.decision),reason:t.reason,evaluated_at:new Date().toISOString(),rule_id:t.ruleId,rule_code:t.ruleCode,enforced:r,agent_mode:this.agentMode,latency_ms:n,evaluation_mode:"local",raw_event:{agent_id:e.agentId,operations:e.operations,...e.toolName?{tool_name:e.toolName}:{},...e.targetResource?{target_resource:e.targetResource}:{},...e.resourceType?{resource_type:e.resourceType}:{}},...this.harnessKind?{context:{[K]:this.harnessKind}}:{}}),this.enforceTelemetryCap()}async flushTelemetry(){if(this.telemetryBuffer.length===0||!this.client)return;let e=this.telemetryBuffer.splice(0);try{await this.client.sendTelemetry(e)}catch(t){console.error("[UnifiedRuntime] telemetry flush failed (non-fatal):",t)}}enforceTelemetryCap(){let e=this.telemetryBuffer.length-le;e>0&&(this.telemetryBuffer.splice(0,e),console.warn(`[UnifiedRuntime] telemetry buffer full \u2014 dropped ${e} oldest entries (cap ${le})`))}async flush(){if(this.registerPromise)try{await this.registerPromise}catch{}await this.flushTelemetry()}dispose(){this.refreshTimer&&(clearInterval(this.refreshTimer),this.refreshTimer=null),this.telemetryTimer&&(clearInterval(this.telemetryTimer),this.telemetryTimer=null),this.flushTelemetry()}};function ce(e){e&&typeof e=="object"&&"unref"in e&&e.unref()}var b=null;function F(e){let t=`${e.apiKey}::${e.agentId}::${e.baseUrl??""}`;if(b&&b.key===t)return b.runtimes;let n=new ue(e.apiKey,e.baseUrl,e.agentId,"cli_harness");return n.registerHostEnvironment(),b={key:t,runtimes:{unified:n}},b.runtimes}async function Xt(){if(b)try{await b.runtimes.unified.flush()}catch{}}async function en(e){try{let t=await h();if(!t)return;let{unified:n}=F(t);await n.awaitBundleReady(e)}catch{}}function y(e,t){return e?.sessionKey??t?.sessionKey??t?.sessionId??"default"}var M=class{entries=new Map;set(t,n){this.entries.set(t,n)}get(t){return this.entries.get(t)}delete(t){this.entries.delete(t)}clear(){this.entries.clear()}size(){return this.entries.size}},j=new Map;function v(e){let t=j.get(e);return t||(t=new M,j.set(e,t)),t}function de(e){j.delete(e)}var pe=new Set(["web_search","x_search","web_fetch","tool_search","tool_describe","get_account","get_transactions","get_devices","check_watchlist","search_knowledge"]);function _t(e){if(typeof e!="string"||e.length===0)return e;let t=e.lastIndexOf("__");return t<0?e:e.slice(t+2)}function fe(e){return pe.has(_t(e))}function rn(){return pe}var ht=[{name:"private_key",re:/-----BEGIN (?:[A-Z]+ )?PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z]+ )?PRIVATE KEY-----/g},{name:"jwt",re:/\beyJ[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\.[A-Za-z0-9_-]{6,}\b/g},{name:"aws_access_key",re:/\b(?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA|ANVA|AIPA)[0-9A-Z]{16}\b/g},{name:"github_token",re:/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36}\b|\bgithub_pat_[A-Za-z0-9_]{22,}\b/g},{name:"slack_token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g},{name:"stripe_secret",re:/\b(?:sk|rk)_live_[A-Za-z0-9]{16,}\b/g},{name:"google_api_key",re:/\bAIza[0-9A-Za-z_-]{35}\b/g},{name:"llm_api_key",re:/\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{20,}\b/g},{name:"bearer_token",re:/\bBearer\s+[A-Za-z0-9._~+/=-]{20,}/g},{name:"connection_string",re:/\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqps?):\/\/[^\s/@:]+:[^\s/@:]+@[^\s'"]+/g},{name:"us_ein",re:/\b\d{2}-\d{7}\b/g},{name:"ssn",re:/\b\d{3}[- ]\d{2}[- ]\d{4}\b/g},{name:"email",re:/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g},{name:"swift_bic",re:/\b[A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?\b/g},{name:"us_phone",re:/\b(?:\+?1[ .-]?)?\(?\d{3}\)?[ .-]?\d{3}[ .-]?\d{4}\b/g},{name:"ipv4",re:/\b(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)\b/g},{name:"mac_address",re:/\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b/g}];var f=Object.fromEntries(ht.map(e=>[e.name,e.re.source])),yt=["private_key","jwt","aws_access_key","github_token","slack_token","stripe_secret","google_api_key","llm_api_key","bearer_token","connection_string","pan","iban","aba_routing","us_ein","swift_bic","ssn","email","us_phone","ipv4","mac_address"],bt={private_key:{id:"private_key",label:"Private keys (PEM)",description:"PEM-encoded private keys (RSA / EC / EdDSA / OpenSSH).",category:"secret",example:`-----BEGIN PRIVATE KEY-----
|
|
4
|
+
MIIEv\u2026
|
|
5
|
+
-----END PRIVATE KEY-----`,template:{pattern:f.private_key,mode:"full"},defaultEnabled:!0},jwt:{id:"jwt",label:"JWT / bearer tokens",description:"JSON Web Tokens (base64url header.payload.signature).",category:"secret",example:"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.dBjftJeZ4CVP",template:{pattern:f.jwt,mode:"full"},defaultEnabled:!0},aws_access_key:{id:"aws_access_key",label:"AWS access key IDs",description:"AWS access / identity key ids (AKIA / ASIA / AROA \u2026).",category:"secret",example:"AKIAIOSFODNN7EXAMPLE",template:{pattern:f.aws_access_key,mode:"full"},defaultEnabled:!0},github_token:{id:"github_token",label:"GitHub tokens",description:"GitHub personal / OAuth tokens (classic ghp_\u2026 + fine-grained).",category:"secret",example:"ghp_0123456789abcdef0123456789abcdef0123",template:{pattern:f.github_token,mode:"full"},defaultEnabled:!0},slack_token:{id:"slack_token",label:"Slack tokens",description:"Slack bot / user / app tokens (xoxb- / xoxp- \u2026).",category:"secret",example:"xoxb-1234567890-abcdefghijkl",template:{pattern:f.slack_token,mode:"full"},defaultEnabled:!0},stripe_secret:{id:"stripe_secret",label:"Stripe secret keys",description:"Stripe live secret / restricted keys (sk_live_ / rk_live_).",category:"secret",example:"sk_live_0123456789abcdefABCDEF",template:{pattern:f.stripe_secret,mode:"full"},defaultEnabled:!0},google_api_key:{id:"google_api_key",label:"Google API keys",description:"Google API keys (AIza\u2026).",category:"secret",example:"AIzaSyA1234567890abcdefghijklmnopqrstuv",template:{pattern:f.google_api_key,mode:"full"},defaultEnabled:!0},llm_api_key:{id:"llm_api_key",label:"LLM provider API keys",description:"OpenAI / Anthropic secret keys (sk-\u2026, sk-proj-\u2026, sk-ant-\u2026).",category:"secret",example:"sk-ant-api03-AbCdEf0123456789AbCdEf01",template:{pattern:f.llm_api_key,mode:"full"},defaultEnabled:!0},bearer_token:{id:"bearer_token",label:"Authorization bearer tokens",description:"Credentials following an HTTP `Authorization: Bearer \u2026` header.",category:"secret",example:"Bearer abcdef0123456789abcdef0123456789",template:{pattern:f.bearer_token,mode:"full"},defaultEnabled:!0},connection_string:{id:"connection_string",label:"Connection strings (with password)",description:"Database / broker DSNs carrying an inline password (scheme://user:pass@host).",category:"secret",example:"postgres://app:s3cr3t@db.internal:5432/main",template:{pattern:f.connection_string,mode:"full"},defaultEnabled:!0},pan:{id:"pan",label:"Payment card numbers (PAN)",description:"Luhn-valid 13\u201319 digit primary account numbers (PCI-DSS).",category:"financial",example:"4242 4242 4242 4242",template:{pattern:"\\b\\d{13,19}\\b",mode:"partial",keepLast:4},defaultEnabled:!0},iban:{id:"iban",label:"IBAN bank account numbers",description:"ISO 13616 IBANs (mod-97 validated); keeps the last 4 visible.",category:"financial",example:"DE89 3704 0044 0532 0130 00",template:{pattern:"\\b[A-Z]{2}\\d{2}(?:[ ]?[A-Z0-9]){10,30}\\b",mode:"partial",keepLast:4},defaultEnabled:!0},aba_routing:{id:"aba_routing",label:"ABA routing numbers",description:"US bank routing-transit numbers (9-digit, checksum-validated). DEFAULT-OFF (9-digit false-positive surface).",category:"financial",example:"021000021",template:{pattern:"\\b\\d{9}\\b",mode:"full"},defaultEnabled:!1},us_ein:{id:"us_ein",label:"US Employer ID (EIN)",description:"US tax Employer Identification Numbers (XX-XXXXXXX).",category:"financial",example:"12-3456789",template:{pattern:f.us_ein,mode:"full"},defaultEnabled:!0},swift_bic:{id:"swift_bic",label:"SWIFT / BIC codes",description:"Bank SWIFT/BIC codes (8 or 11 chars). DEFAULT-OFF (matches uppercase tokens).",category:"financial",example:"DEUTDEFF500",template:{pattern:f.swift_bic,mode:"full"},defaultEnabled:!1},ssn:{id:"ssn",label:"US Social Security numbers",description:"Dashed / spaced US SSNs (e.g. 123-45-6789).",category:"pii",example:"123-45-6789",template:{pattern:f.ssn,mode:"partial",keepLast:4},defaultEnabled:!0},email:{id:"email",label:"Email addresses",description:"Email addresses (the mailbox is masked, the domain kept).",category:"pii",example:"alice@acme.com",template:{pattern:f.email,mode:"email"},defaultEnabled:!0},us_phone:{id:"us_phone",label:"US phone numbers",description:"US phone numbers in common formats. DEFAULT-OFF (10-digit false-positive surface).",category:"pii",example:"(415) 555-0132",template:{pattern:f.us_phone,mode:"partial",keepLast:4},defaultEnabled:!1},ipv4:{id:"ipv4",label:"IPv4 addresses",description:"Dotted-quad IPv4 addresses. DEFAULT-OFF (common + usually benign).",category:"identifier",example:"203.0.113.42",template:{pattern:f.ipv4,mode:"full"},defaultEnabled:!1},mac_address:{id:"mac_address",label:"MAC addresses",description:"Hardware MAC addresses. DEFAULT-OFF.",category:"identifier",example:"3c:22:fb:1a:2b:3c",template:{pattern:f.mac_address,mode:"full"},defaultEnabled:!1}},on=new Set(yt.filter(e=>!bt[e].defaultEnabled));var D="[REDACTED]",A="\u2022",E=e=>/[A-Za-z0-9]/.test(e);function ge(e,t,n,r){let i=Array.from(e),a=i.length,l=Math.max(0,Math.floor(t)||0),s=Math.max(0,Math.floor(n)||0),c=r.length>0?r:A,p=l+s>=a;return i.map((d,g)=>!p&&(g<l||g>=a-s)?d:E(d)?c:d).join("")}function vt(e,t){let n=e.indexOf("@");if(n<=0||n>=e.length-1)return ge(e,0,0,t);let r=e.slice(0,n),i=e.slice(n),a=t.length>0?t:A;return(r.length<=1?a:r[0]+Array.from(r.slice(1)).map(l=>E(l)?a:l).join(""))+i}function At(e,t,n){let r=n.length>0?n:A,i=new Array(e.length).fill(!1);if(typeof t=="string"&&t.length>0)try{let p=new RegExp(t,"g"),d;for(;(d=p.exec(e))!==null;){if(d[0].length===0){p.lastIndex++;continue}for(let g=d.index;g<d.index+d[0].length;g++)i[g]=!0}}catch{}let a=!1,l=!0;for(let p=0;p<e.length;p++)if(E(e[p])&&(a=!0,!i[p])){l=!1;break}let s=a&&l,c="";for(let p=0;p<e.length;p++){let d=e[p];!s&&i[p]||!E(d)?c+=d:c+=r}return c}function me(e,t){let n=t.mode??"full";return n==="partial"?ge(e,t.keepFirst??0,t.keepLast??0,t.maskChar??A):n==="email"?vt(e,t.maskChar??A):n==="custom"?At(e,t.keepPattern,t.maskChar??A):t.replacement??D}function wt(e,t){return typeof e=="string"?me(e,t):t.replacement??D}function _e(e){let t=[],n=e.replacement??D;for(let r of e.patterns??[])typeof r!="string"||r.length===0||t.push({source:r,replacer:()=>n});for(let r of e.directives??[]){let{pattern:i}=r;typeof i!="string"||i.length===0||t.push({source:i,replacer:a=>me(a,r)})}return t}function he(e,t){let n=e;for(let{source:r,replacer:i}of t){let a;try{a=new RegExp(r,"g")}catch(l){let s=l instanceof Error?l.message:String(l);throw new Error(`[visiq-redact] Invalid redaction pattern "${r}": ${s}`)}n=n.replace(a,l=>i(l))}return n}function T(e,t){return e==null?e:typeof e=="string"?It(e,t):typeof e=="object"?kt(e,t):e}function It(e,t){if(typeof e!="string")return e;let n=_e(t);return n.length===0?e:he(e,n)}function kt(e,t){let n=new Map;for(let s of t.fields??[])typeof s=="string"&&s.length>0&&n.set(s,{field:s,mode:"full",replacement:t.replacement});for(let s of t.directives??[])typeof s.field=="string"&&s.field.length>0&&n.set(s.field,s);let r=_e(t),i=n.size>0,a=r.length>0,l=s=>{if(s==null)return s;if(Array.isArray(s))return s.map(c=>l(c));if(typeof s=="object"){let c=s,p=Object.create(Object.getPrototypeOf(c));for(let d of Object.keys(c)){let g=i?n.get(d):void 0;if(g){p[d]=wt(c[d],g);continue}p[d]=l(c[d])}return p}return typeof s=="string"&&a?he(s,r):s};return l(e)}var ye="@visiq/openclaw-plugin";function be(e){let t=[],n=[],r;for(let a of e){let{field:l,pattern:s,replacement:c}=a;l&&t.push(l),s&&n.push(s),c&&r===void 0&&(r=c)}let i={};return t.length>0&&(i.fields=t),n.length>0&&(i.patterns=n),r!==void 0&&(i.replacement=r),i}async function fn(e,t){let n=await h();if(!n)return;let r=F(n),i=n.agentId??t.agentId,a=y(e,t),l=t.toolCallId??e.toolCallId,c=fe(e.toolName)?["retrieval","action"]:["action"],p=St(e.params),d;try{await r.unified.awaitBundleReady(),d=await r.unified.evaluate({operations:c,agentId:i,sessionId:a,toolName:e.toolName,toolArgs:e.params??{},resourceType:"tool_result",resourceMetadata:{toolName:e.toolName,runId:e.runId??t.runId},...p!==void 0?{query:p}:{}})}catch(_){return{block:!0,blockReason:`[VisIQ] Evaluation error (fail-closed): ${_ instanceof Error?_.message:String(_)}`}}if(!d.enforced)return;let{action:g}=d;if(g.decision==="approval_required")return{requireApproval:{title:`VisIQ approval required: ${e.toolName}`,description:d.reason,severity:"critical",allowedDecisions:["allow-once","allow-always","deny"],pluginId:ye}};if(!g.allowed)return{block:!0,blockReason:`[VisIQ ${d.ruleCode??"DENY"}] ${d.reason}`};let R;if(g.decision==="mask"&&g.argRedactionRules&&g.argRedactionRules.length>0&&(R=T(e.params??{},be(g.argRedactionRules))),c.includes("retrieval"))switch(d.retrieval.action){case"allow":case null:break;case"deny":return{block:!0,blockReason:`[VisIQ RECALL] ${d.reason}`};case"redact":{if(!l)return{block:!0,blockReason:"[VisIQ RECALL] Redact decision but no toolCallId \u2014 fail-closed"};let _=d.retrieval.redactionRules??[];_.length>0&&v(a).set(l,be(_));break}case"escalate":return{requireApproval:{title:`VisIQ approval required: ${e.toolName}`,description:d.reason,severity:"warning",allowedDecisions:["allow-once","allow-always","deny"],pluginId:ye}};default:{let _=d.retrieval.action;return{block:!0,blockReason:`[VisIQ RECALL] Unknown action "${String(_)}" \u2014 fail-closed`}}}if(R)return{params:R}}function St(e){if(e)for(let t of["query","q","url","prompt"]){let n=e[t];if(typeof n=="string"&&n.length>0)return n}}function yn(e,t){let{ready:n,config:r}=k();if(!n||!r)return;let i=e.toolCallId??t.toolCallId;if(!i)return;let a=y(e,t),l=v(a),s=l.get(i);if(!s)return;let c={...e.message};return c.content!==void 0&&(c.content=T(c.content,s)),l.delete(i),{message:c}}function wn(e,t){let{ready:n,config:r}=k();if(n&&!r)return;let i=y(e,t),a=v(i);if(a.size()>0)return a.clear(),{block:!0}}async function x(e,t){let r=`${(e.baseUrl??"https://api.visiqlabs.com").replace(/\/$/,"")}/v1/events`;try{let i=new AbortController,a=setTimeout(()=>i.abort(),5e3);try{let l=await fetch(r,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(t),signal:i.signal});l.ok||process.stderr.write(`[VisIQ] /v1/events POST failed: ${l.status} ${l.statusText}
|
|
6
|
+
`);try{await l.text()}catch{}}finally{clearTimeout(a)}}catch(i){if(i instanceof Error&&i.name==="AbortError"){process.stderr.write(`[VisIQ] /v1/events POST timed out (5s)
|
|
7
|
+
`);return}process.stderr.write(`[VisIQ] /v1/events POST error: ${i instanceof Error?i.message:String(i)}
|
|
8
|
+
`)}}async function En(e,t){let n=await h();if(!n)return;let r=n.agentId??t.agentId;x(n,{type:"llm_input",agentId:r,sessionId:e.sessionId??t.sessionId??t.sessionKey,runId:e.runId??t.runId,timestamp:new Date().toISOString(),payload:{provider:e.provider,model:e.model,hasSystemPrompt:typeof e.systemPrompt=="string"&&e.systemPrompt.length>0,promptLength:typeof e.prompt=="string"?e.prompt.length:0,historyMessageCount:Array.isArray(e.historyMessages)?e.historyMessages.length:0,imagesCount:e.imagesCount??0,toolCount:Array.isArray(e.tools)?e.tools.length:0}})}function Ct(e){if(!Array.isArray(e))return 0;let t=0;for(let n of e)typeof n=="string"&&(t+=n.length);return t}async function On(e,t){let n=await h();if(!n)return;let r=n.agentId??t.agentId;x(n,{type:"llm_output",agentId:r,sessionId:e.sessionId??t.sessionId??t.sessionKey,runId:e.runId??t.runId,timestamp:new Date().toISOString(),payload:{provider:e.provider,model:e.model,resolvedRef:e.resolvedRef,harnessId:e.harnessId,assistantSegmentCount:Array.isArray(e.assistantTexts)?e.assistantTexts.length:0,assistantTotalChars:Ct(e.assistantTexts),usage:e.usage??null}})}function Ln(e,t){de(y(e,t))}export{W as a,Lt as b,Xt as c,en as d,M as e,v as f,de as g,_t as h,fe as i,rn as j,fn as k,yn as l,wn as m,En as n,On as o,Ln as p};
|
package/dist/index.d.ts
CHANGED
|
@@ -42,10 +42,10 @@ export declare function loadConfig(): Promise<VisiqConfig | null>;
|
|
|
42
42
|
* @visiq/redact — shared redaction primitives for VisIQ SDKs.
|
|
43
43
|
*
|
|
44
44
|
* This package extracts the redaction logic previously embedded in
|
|
45
|
-
* `@visiq/
|
|
45
|
+
* `@visiq/harness` so that OpenClaw plugins, LangChain wrappers, and other
|
|
46
46
|
* harnesses can apply consistent redaction semantics.
|
|
47
47
|
*
|
|
48
|
-
*
|
|
48
|
+
* Operation modes:
|
|
49
49
|
*
|
|
50
50
|
* 1. **Field redaction** — for structured (object / array) content. Any
|
|
51
51
|
* object key listed in `spec.fields` is replaced with `spec.replacement`
|
|
@@ -56,13 +56,71 @@ export declare function loadConfig(): Promise<VisiqConfig | null>;
|
|
|
56
56
|
* compiled with the `g` flag and matched substrings are replaced with
|
|
57
57
|
* `spec.replacement`.
|
|
58
58
|
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
59
|
+
* 3. **Directives (SOTA, 2026-06)** — `spec.directives` carries per-target
|
|
60
|
+
* masking with a `mode`:
|
|
61
|
+
* - `"full"` — replace the whole field value / matched substring with
|
|
62
|
+
* `replacement` (the classic behavior; the default).
|
|
63
|
+
* - `"partial"` — FORMAT-PRESERVING: keep `keepFirst` leading and
|
|
64
|
+
* `keepLast` trailing characters, mask the alphanumerics
|
|
65
|
+
* in between with `maskChar` (separators are preserved),
|
|
66
|
+
* e.g. an SSN field with `keepLast:4` → `•••-••-6789`,
|
|
67
|
+
* a 16-digit PAN pattern with `keepLast:4` → `••••••••••••4242`.
|
|
68
|
+
* - `"email"` — DOMAIN-PRESERVING: keep the first local char + the full
|
|
69
|
+
* domain, e.g. `alice@acme.com` → `a••••@acme.com`.
|
|
70
|
+
* Directives compose with `fields`/`patterns`; a `field` directive masks a
|
|
71
|
+
* key wherever it appears (any depth); a `pattern` directive masks every
|
|
72
|
+
* regex match in every string leaf. `partial`/`email` modes never reveal
|
|
73
|
+
* more than the kept characters and fall back to a full mask when a value is
|
|
74
|
+
* too short or the wrong type.
|
|
75
|
+
*
|
|
76
|
+
* Both legacy modes can be combined in a single spec; structured content has
|
|
77
|
+
* fields masked first, then string leaves get pattern redaction applied.
|
|
61
78
|
*
|
|
62
79
|
* Semantics intentionally match the previous `filterDocuments`-era behavior
|
|
63
|
-
* in @visiq/
|
|
64
|
-
* mutated. Null and undefined pass through unchanged.
|
|
80
|
+
* in @visiq/harness: the input is deep-cloned, so the original object is never
|
|
81
|
+
* mutated. Null and undefined pass through unchanged. Replacements are inserted
|
|
82
|
+
* LITERALLY via function replacers — never subject to `$`-substitution — so a
|
|
83
|
+
* matched secret can never be re-injected into the output (fail-closed).
|
|
84
|
+
*/
|
|
85
|
+
/**
|
|
86
|
+
* Masking strategy for a {@link RedactionDirective}.
|
|
87
|
+
*
|
|
88
|
+
* The wire/storage values are STABLE (additive): the rule editor presents these
|
|
89
|
+
* to operators under friendlier names — `full`→"Replace", `partial`/`email`→
|
|
90
|
+
* "Transform", `custom`→"Custom" — but the engine values never change so stored
|
|
91
|
+
* rules and fielded SDKs keep working.
|
|
92
|
+
*/
|
|
93
|
+
export type RedactionMode = "full" | "partial" | "email" | "custom";
|
|
94
|
+
/**
|
|
95
|
+
* A single, mode-aware masking directive. Carries EITHER a `field` (mask a
|
|
96
|
+
* structured key wherever it appears, at any depth) OR a `pattern` (a regex
|
|
97
|
+
* masking every match in every string leaf) — or both. `mode` selects how the
|
|
98
|
+
* matched value is transformed; defaults to `"full"` so an entry with no `mode`
|
|
99
|
+
* behaves exactly like a classic field/pattern entry.
|
|
65
100
|
*/
|
|
101
|
+
export interface RedactionDirective {
|
|
102
|
+
/** Structured key to mask wherever it appears (exact, case-sensitive). */
|
|
103
|
+
field?: string;
|
|
104
|
+
/** Regex source (no flags); compiled with `g` and applied to string leaves. */
|
|
105
|
+
pattern?: string;
|
|
106
|
+
/** Masking strategy. Default `"full"`. */
|
|
107
|
+
mode?: RedactionMode;
|
|
108
|
+
/** `partial` mode: leading characters to keep. Default `0`. */
|
|
109
|
+
keepFirst?: number;
|
|
110
|
+
/** `partial` mode: trailing characters to keep. Default `0`. */
|
|
111
|
+
keepLast?: number;
|
|
112
|
+
/** `partial`/`email`/`custom` mode: the mask glyph for masked alphanumerics. Default `"•"`. */
|
|
113
|
+
maskChar?: string;
|
|
114
|
+
/** `full` mode: replacement text. Default `"[REDACTED]"`. */
|
|
115
|
+
replacement?: string;
|
|
116
|
+
/**
|
|
117
|
+
* `custom` mode: a regex whose MATCHES are KEPT — every other alphanumeric in
|
|
118
|
+
* the value is masked with `maskChar`. The inverse of `pattern` (which masks
|
|
119
|
+
* matches): use this to keep a known-safe shape and mask the rest (e.g. keep a
|
|
120
|
+
* country-code prefix, mask the subscriber number). Invalid → full mask (G001).
|
|
121
|
+
*/
|
|
122
|
+
keepPattern?: string;
|
|
123
|
+
}
|
|
66
124
|
/**
|
|
67
125
|
* Redaction specification produced by RECALL evaluation. A non-null spec
|
|
68
126
|
* indicates the content must be masked before being persisted or returned to
|
|
@@ -70,23 +128,55 @@ export declare function loadConfig(): Promise<VisiqConfig | null>;
|
|
|
70
128
|
*/
|
|
71
129
|
export interface RedactionSpec {
|
|
72
130
|
/**
|
|
73
|
-
* Object keys whose values must be masked. Applied recursively at
|
|
74
|
-
* depth in structured content. Empty / omitted means no field masking.
|
|
131
|
+
* Object keys whose values must be masked (full mode). Applied recursively at
|
|
132
|
+
* every depth in structured content. Empty / omitted means no field masking.
|
|
75
133
|
*/
|
|
76
134
|
fields?: string[];
|
|
77
135
|
/**
|
|
78
136
|
* Regular-expression source strings (without flags). Each pattern is
|
|
79
137
|
* compiled with the global flag and applied to every string leaf — both
|
|
80
138
|
* top-level strings and string values within structured content. Empty /
|
|
81
|
-
* omitted means no pattern masking.
|
|
139
|
+
* omitted means no pattern masking. (Full mode.)
|
|
82
140
|
*/
|
|
83
141
|
patterns?: string[];
|
|
84
142
|
/**
|
|
85
|
-
* Replacement string for any matched field value or matched pattern
|
|
86
|
-
* Defaults to `"[REDACTED]"` when omitted.
|
|
143
|
+
* Replacement string for any matched field value or matched pattern in the
|
|
144
|
+
* legacy `fields`/`patterns` paths. Defaults to `"[REDACTED]"` when omitted.
|
|
87
145
|
*/
|
|
88
146
|
replacement?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Mode-aware masking directives (partial / format-preserving / email). Each
|
|
149
|
+
* is applied IN ADDITION to `fields`/`patterns`. A `field` directive takes
|
|
150
|
+
* precedence over a legacy `fields` entry for the same key.
|
|
151
|
+
*/
|
|
152
|
+
directives?: RedactionDirective[];
|
|
89
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* Gracefully drain the cached runtimes' pending backend I/O and AWAIT it.
|
|
156
|
+
*
|
|
157
|
+
* A long-running OpenClaw daemon relies on the UnifiedRuntime's periodic (10s,
|
|
158
|
+
* unref'd) timer to flush telemetry — but a SHORT-LIVED driver (the
|
|
159
|
+
* visiq-openclaw-driver oneshot, which runs ~1s then exits) would otherwise
|
|
160
|
+
* exit before the registration handshake lands and before any ALLOW telemetry
|
|
161
|
+
* is sent, so the fleet harness-liveness probe never sees the
|
|
162
|
+
* `allow_agents` row OR the `allow_audit_log` heartbeat. Call this once after a
|
|
163
|
+
* run, before the process exits, to guarantee both land.
|
|
164
|
+
*
|
|
165
|
+
* Best-effort and never throws — registration + telemetry are non-fatal to the
|
|
166
|
+
* decision path. No-op when nothing has been instantiated yet.
|
|
167
|
+
*/
|
|
168
|
+
export declare function shutdownRuntimes(): Promise<void>;
|
|
169
|
+
/**
|
|
170
|
+
* Await the UnifiedRuntime's initial bundle fetch so subsequent evaluations use
|
|
171
|
+
* the LOCAL policy bundle (not a remote round-trip). A SHORT-LIVED driver should
|
|
172
|
+
* call this once after the runtimes are built and before driving commands —
|
|
173
|
+
* otherwise it races the background fetch, evaluates remotely, and the harness
|
|
174
|
+
* provenance marker (emitted only on the local-telemetry path) never lands.
|
|
175
|
+
*
|
|
176
|
+
* Best-effort + bounded inside awaitBundleReady; never throws. No-op when
|
|
177
|
+
* nothing has been instantiated yet.
|
|
178
|
+
*/
|
|
179
|
+
export declare function awaitRuntimesReady(timeoutMs?: number): Promise<void>;
|
|
90
180
|
export declare class RedactionLedger {
|
|
91
181
|
private readonly entries;
|
|
92
182
|
/** Stash a spec for a tool call. Overwrites any existing entry. */
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as w,c as g,d as _,e as d,f as k,g as f,h as e,i as t,j as h,k as i,l as s,m as l,n as a,o as u,p}from"./chunk-2TT2F3AO.js";var c=new Set(["place_hold","block_card","wire_transfer","create_case","send_notification","bank_account_lookup_tool","exec","write_file","http_post","http_put","http_delete"]),N=new Set(["sessions_list","sessions_history","sessions_send","sessions_get","sessions_create","sessions_delete","memory_search","memory_read","memory_write"]),T=["sessions_","memory_"];function I(o){let r=e(o);return N.has(r)?!0:T.some(m=>r.startsWith(m))}function x(o){return!(t(o)||I(o))}function R(o){return c.has(e(o))}function O(){return c}var n="@visiq/openclaw-plugin";function b(){return{id:n,name:"VisIQ OpenClaw Plugin",version:"0.1.0",hooks:[{pluginId:n,hookName:"before_tool_call",handler:i,source:"visiq-openclaw-plugin"},{pluginId:n,hookName:"tool_result_persist",handler:s,source:"visiq-openclaw-plugin"},{pluginId:n,hookName:"before_message_write",handler:l,source:"visiq-openclaw-plugin"},{pluginId:n,hookName:"llm_input",handler:a,source:"visiq-openclaw-plugin"},{pluginId:n,hookName:"llm_output",handler:u,source:"visiq-openclaw-plugin"},{pluginId:n,hookName:"session_end",handler:p,source:"visiq-openclaw-plugin"}]}}var S=b;export{d as RedactionLedger,_ as awaitRuntimesReady,e as bareToolName,f as clearLedger,b as createPlugin,S as default,O as getActionToolNames,k as getLedger,h as getRetrievalToolNames,x as isActionTool,R as isKnownActionTool,t as isRetrievalTool,w as loadConfig,g as shutdownRuntimes};
|
package/dist/openclaw-entry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{b as w,
|
|
1
|
+
import{b as w,k as b,l as S,m as k,n as L,o as v,p as O}from"./chunk-2TT2F3AO.js";import{Type as e}from"typebox";import{definePluginEntry as D}from"openclaw/plugin-sdk/plugin-entry";import{readFileSync as x,readdirSync as A,statSync as C,existsSync as R}from"node:fs";import{join as p,dirname as $}from"node:path";import{fileURLToPath as P}from"node:url";var U="@visiq/openclaw-plugin",h=process.env.BANK_API_URL??"http://localhost:4000/api",I=$(P(import.meta.url));function c(n,i={}){return{content:[{type:"text",text:n}],details:i}}async function m(n){let i=await fetch(`${h}${n}`);return i.ok?await i.text():`[Error ${i.status}]`}async function d(n,i){let t=await fetch(`${h}${n}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)});return t.ok?await t.text():`[Error ${t.status}]`}function j(){let n=[p(I,"..","..","..","examples","langchain-agent","docs"),p(I,"..","..","examples","langchain-agent","docs"),process.env.VISIQ_KNOWLEDGE_DIR??""].filter(i=>i.length>0);for(let i of n)if(R(i))return i;return null}function N(){let n=j();if(!n)return[];let i=[];function t(o){for(let s of A(o)){let r=p(o,s);if(C(r).isDirectory())t(r);else if(s.endsWith(".txt")){let l=x(r,"utf-8").match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(l){let a={};for(let _ of l[1].split(`
|
|
2
2
|
`)){let[g,...y]=_.split(":");g&&y.length&&(a[g.trim()]=y.join(":").trim())}i.push({path:r,title:a.title?.replace(/"/g,"")??s,classification:a.classification??"public",source:a.source??"unknown",content:l[2].trim()})}}}}return t(n),i}var f=null;function B(){return f===null&&(f=N()),f}function T(n,i=5){let t=B(),o=n.toLowerCase().split(/\s+/).filter(r=>r.length>=3);return t.map(r=>{let u=`${r.title} ${r.content}`.toLowerCase(),l=0;for(let a of o)u.includes(a)&&(l+=a.length,r.title.toLowerCase().includes(a)&&(l+=a.length*2));return{doc:r,score:l}}).filter(r=>r.score>0).sort((r,u)=>u.score-r.score).slice(0,i).map(r=>r.doc)}function K(n){w(),n.on("before_tool_call",b,{priority:50}),n.on("tool_result_persist",S),n.on("before_message_write",k),n.on("llm_input",L),n.on("llm_output",v),n.on("session_end",O),n.registerTool({name:"get_account",label:"Get account",description:"Get account holder profile from core banking system. Input: account ID (e.g. '4821-7734'). Returns: holder name, balance, risk score, KYC status, linked cards, address.",parameters:e.Object({account_id:e.String({description:"Account ID (e.g. '4821-7734')."})}),async execute(i,t){return c(await m(`/accounts/${t.account_id}`))}}),n.registerTool({name:"get_devices",label:"Get devices",description:"Get device fingerprints and login sessions from BioCatch. Input: account ID. Returns: registered devices, recent sessions with IP/geolocation, anomaly alerts.",parameters:e.Object({account_id:e.String({description:"Account ID to fetch devices for."})}),async execute(i,t){return c(await m(`/accounts/${t.account_id}/devices`))}}),n.registerTool({name:"get_transactions",label:"Get transactions",description:"Get recent transactions from the card processor with filtering. Returns: transaction list with amounts, merchants, locations, and risk flags.",parameters:e.Object({account_id:e.String({description:"Account ID (e.g. '4821-7734')."}),lookback_hours:e.Optional(e.Integer({minimum:1,maximum:720,description:"How far back to look (1\u2013720h, default 72)."})),min_amount:e.Optional(e.Number({minimum:0,description:"Filter out transactions below this dollar amount."}))}),async execute(i,t){let o=new URLSearchParams;t.lookback_hours!==void 0&&o.set("lookback_hours",String(t.lookback_hours)),t.min_amount!==void 0&&o.set("min_amount",String(t.min_amount));let s=o.toString()?`?${o.toString()}`:"";return c(await m(`/accounts/${t.account_id}/transactions${s}`))}}),n.registerTool({name:"check_watchlist",label:"Check watchlist",description:"Screen a name or entity against OFAC SDN, EU, and UN sanctions lists. Returns: match scores and recommendation.",parameters:e.Object({name:e.String({description:"Name or entity to screen."}),country_code:e.Optional(e.String({description:"ISO 3166-1 alpha-2 country code to scope the screening (e.g. 'US')."}))}),async execute(i,t){return c(await d("/watchlists/check",{name:t.name,country_code:t.country_code}))}}),n.registerTool({name:"search_knowledge",label:"Search knowledge base",description:"Search the bank's internal knowledge base for compliance policies, prior fraud case files, triage procedures, and customer information. Input is a free-text search query.",parameters:e.Object({query:e.String({description:"Free-text knowledge base search query."})}),async execute(i,t){let o=T(t.query,5);if(o.length===0)return c("No matching knowledge base documents found.",{hitCount:0});let s=o.map(r=>`--- ${r.title} (classification=${r.classification}, source=${r.source}) ---
|
|
3
3
|
${r.content}`).join(`
|
|
4
4
|
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@visiq/openclaw-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "OpenClaw plugin for VisIQ ALLOW + RECALL + RECORD",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
}
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@open-policy-agent/opa-wasm": "^1.9.0",
|
|
32
31
|
"zod": "^3.23.8",
|
|
33
|
-
"typebox": "^1.1.38"
|
|
32
|
+
"typebox": "^1.1.38",
|
|
33
|
+
"@visiq/core-wasm": "^0.1.0"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
36
|
"@langchain/core": ">=0.3.0",
|
package/dist/chunk-K2XSEUBX.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import{readFile as ye}from"node:fs/promises";import{homedir as D}from"node:os";import{join as V,isAbsolute as we,resolve as ve}from"node:path";import{createInterface as Ie}from"node:readline";import{parseArgs as be}from"node:util";var K="@visiq/openclaw-plugin",Ae='[VisIQ] OpenClaw plugin is installed but missing credentials. Provide them with one of (highest precedence first): (1) environment variables VISIQ_API_KEY=<key> VISIQ_AGENT_ID=<id> (set before `openclaw gateway run` / `openclaw start`) ; (2) a JSON file at the path in VISIQ_CONFIG_PATH ; (3) ~/.openclaw/openclaw.json -> plugins.entries["@visiq/openclaw-plugin"].config = { "apiKey": "<key>", "agentId": "<id>" } . Plugin will load but all hooks will no-op until credentials are provided.';function _e(e){return e==="~"||e.startsWith("~/")?V(D(),e.slice(1).replace(/^\//,"")):e}async function W(e){try{let t=we(e)?e:ve(e),n=await ye(t,"utf-8");return JSON.parse(n)}catch{return null}}function k(e,...t){for(let n of t){let r=e[n];if(typeof r=="string")return r}}function P(e){if(!e||typeof e!="object")return{};let t=e,n=k(t,"apiKey","api_key"),r=k(t,"agentId","agent_id"),i=k(t,"baseUrl","base_url"),o={};return n&&(o.apiKey=n),r&&(o.agentId=r),i&&(o.baseUrl=i),o}async function Te(e){if(!e)return{};let t=_e(e),n=await W(t);if(!n||typeof n!="object")return{};let r=n,i=r.plugins?.entries,o=i&&typeof i=="object"?i[K]:void 0;return o&&typeof o=="object"&&o.config?P(o.config):P(r)}async function Re(){let e=V(D(),".openclaw","openclaw.json"),t=await W(e);if(!t||typeof t!="object")return{};let o=t.plugins?.entries?.[K];return!o||typeof o!="object"?{}:P(o.config)}async function Le(e){if(!process.stdout.isTTY)return{};let t=Ie({input:process.stdin,output:process.stdout}),n=r=>new Promise(i=>t.question(r,o=>i(o)));try{let r={...e};if(!r.apiKey){let i=(await n("VisIQ API key: ")).trim();i&&(r.apiKey=i)}if(!r.agentId){let i=(await n("VisIQ agent ID: ")).trim();i&&(r.agentId=i)}if(!r.baseUrl){let i=(await n("VisIQ base URL (optional, press Enter for default): ")).trim();i&&(r.baseUrl=i)}return r}finally{t.close()}}function Ee(){try{let{values:e}=be({args:process.argv.slice(2),options:{"api-key":{type:"string"},"agent-id":{type:"string"},"base-url":{type:"string"}},strict:!1,allowPositionals:!0}),t={},n=e["api-key"],r=e["agent-id"],i=e["base-url"];return typeof n=="string"&&n&&(t.apiKey=n),typeof r=="string"&&r&&(t.agentId=r),typeof i=="string"&&i&&(t.baseUrl=i),t}catch{return{}}}async function F(){let e=Ee(),t={};process.env.VISIQ_API_KEY&&(t.apiKey=process.env.VISIQ_API_KEY),process.env.VISIQ_AGENT_ID&&(t.agentId=process.env.VISIQ_AGENT_ID),process.env.VISIQ_BASE_URL?t.baseUrl=process.env.VISIQ_BASE_URL:process.env.VISIQ_ENDPOINT&&(t.baseUrl=process.env.VISIQ_ENDPOINT);let n=await Te(process.env.VISIQ_CONFIG_PATH),i={...await Re(),...n,...t,...e};if((!i.apiKey||!i.agentId)&&process.stdout.isTTY&&process.stdin.isTTY&&(i=await Le(i)),!i.apiKey||!i.agentId)return process.stderr.write(`${Ae}
|
|
2
|
-
`),null;let o={apiKey:i.apiKey,agentId:i.agentId};return i.baseUrl&&(o.baseUrl=i.baseUrl),o}var M=null,q={ready:!1,config:null};function v(){return M||(M=F().catch(e=>(process.stderr.write(`[VisIQ] Config resolution failed (treating as unconfigured): ${e instanceof Error?e.message:String(e)}
|
|
3
|
-
`),null)).then(e=>(q={ready:!0,config:e},e))),M}function L(){return q}function At(){v()}var x=class{entries=new Map;set(t,n){this.entries.set(t,n)}get(t){return this.entries.get(t)}delete(t){this.entries.delete(t)}clear(){this.entries.clear()}size(){return this.entries.size}},$=new Map;function _(e){let t=$.get(e);return t||(t=new x,$.set(e,t)),t}function B(e){$.delete(e)}var Q=new Set(["web_search","x_search","web_fetch","tool_search","tool_describe","get_account","get_transactions","get_devices","check_watchlist","search_knowledge"]);function Ce(e){if(typeof e!="string"||e.length===0)return e;let t=e.lastIndexOf("__");return t<0?e:e.slice(t+2)}function U(e){return Q.has(Ce(e))}function Rt(){return Q}import{z as g}from"zod";import{z as c}from"zod";import{createHash as Se}from"crypto";var G=new Map;function ke(e){let t=Se("sha256").update(e).digest("hex"),n=G.get(t);if(n)return n;let r=new Map,i=[],o=e.split(`
|
|
4
|
-
`).map(l=>Me(l)).filter(l=>l.trim().length>0),s=0;for(;s<o.length;){let l=o[s].trim();if(l.startsWith("package ")||l.startsWith("import ")){s++;continue}let p=l.match(/^default\s+(\w+)\s*=\s*(.+)$/);if(p){let f=p[1],h=p[2].trim();r.set(f,C(h)),s++;continue}let m=l.match(/^(\w+)\s*=\s*(.+?)\s*\{(.*)$/);if(m){let f=m[1],h=m[2].trim(),y=m[3].trim(),A=[];if(y&&y!=="}"){let j=y.endsWith("}")?y.slice(0,-1).trim():y;j&&A.push(j),y.endsWith("}")||(s++,s=E(o,s,A))}else y==="}"||(s++,s=E(o,s,A));let R=z(A);i.push({variable:f,value:C(h),conditions:R}),s++;continue}let w=l.match(/^(\w+)\s*\{(.*)$/);if(w){let f=w[1],h=w[2].trim(),y=[];if(h&&h!=="}"){let R=h.endsWith("}")?h.slice(0,-1).trim():h;R&&y.push(R),h.endsWith("}")||(s++,s=E(o,s,y))}else h==="}"||(s++,s=E(o,s,y));let A=z(y);i.push({variable:f,value:"true",conditions:A}),s++;continue}s++}let a={defaults:r,rules:i};return G.set(t,a),a}function Pe(e,t){let n={};for(let[r,i]of e.defaults)n[r]=i;for(let r=0;r<e.rules.length;r++){let i=e.rules[r];if(i.conditions.every(o=>$e(o,t)))return n[i.variable]=i.value,{bindings:n,matched:!0,matchedRuleIndex:r}}return{bindings:n,matched:!1,matchedRuleIndex:-1}}function Me(e){let t=!1,n="";for(let r=0;r<e.length;r++){let i=e[r];if(t)i===n&&e[r-1]!=="\\"&&(t=!1);else if(i==='"'||i==="'")t=!0,n=i;else if(i==="#")return e.slice(0,r)}return e}function E(e,t,n){let r=1,i=t;for(;i<e.length&&r>0;){let o=e[i].trim();for(let s of o)s==="{"&&r++,s==="}"&&r--;if(r>0)n.push(o),i++;else{let s=o.slice(0,o.lastIndexOf("}")).trim();return s&&n.push(s),i}}return i}function C(e){return e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'")?e.slice(1,-1):e}function z(e){let t=[];for(let n of e){let r=n.split(";").map(i=>i.trim()).filter(i=>i.length>0);for(let i of r){let o=xe(i);o&&t.push(o)}}return t}function xe(e){let t=!1,n=e.trim();n.startsWith("not ")&&(t=!0,n=n.slice(4).trim());let r=n.match(/^count\(([^)]+)\)\s*>\s*(\d+)$/);if(r)return{type:"count_gt",negated:t,field:r[1].trim(),value:parseInt(r[2],10)};let i=n.match(/^startswith\(([^,]+),\s*"([^"]*)"\)$/);if(i)return{type:"startswith",negated:t,field:i[1].trim(),value:i[2]};let o=n.match(/^endswith\(([^,]+),\s*"([^"]*)"\)$/);if(o)return{type:"endswith",negated:t,field:o[1].trim(),value:o[2]};let s=n.match(/^contains\(([^,]+),\s*"([^"]*)"\)$/);if(s)return{type:"contains",negated:t,field:s[1].trim(),value:s[2]};let a=n.match(/^([^\s=!]+)\s*==\s*(.+)$/);if(a)return{type:"equality",negated:t,field:a[1].trim(),value:C(a[2].trim())};let l=n.match(/^([^\s=!]+)\s*!=\s*(.+)$/);if(l)return{type:"inequality",negated:t,field:l[1].trim(),value:C(l[2].trim())};let p=n.match(/^(input\.[a-zA-Z0-9_.]+)$/);return p?{type:"truthy",negated:t,field:p[1].trim()}:{type:"truthy",negated:!1,field:"__unrecognized_condition_forces_deny__"}}function $e(e,t){let n;switch(e.type){case"equality":{let r=I(e.field,t);n=String(r)===String(e.value);break}case"inequality":{let r=I(e.field,t);n=String(r)!==String(e.value);break}case"startswith":{let r=I(e.field,t);typeof r!="string"?n=!1:n=r.startsWith(String(e.value));break}case"endswith":{let r=I(e.field,t);typeof r!="string"?n=!1:n=r.endsWith(String(e.value));break}case"contains":{let r=I(e.field,t);typeof r!="string"?n=!1:n=r.includes(String(e.value));break}case"truthy":{let r=I(e.field,t);n=Oe(r);break}case"count_gt":{let r=I(e.field,t),i=typeof e.value=="number"?e.value:0;Array.isArray(r)||typeof r=="string"?n=r.length>i:r&&typeof r=="object"?n=Object.keys(r).length>i:n=!1;break}default:n=!1}return e.negated?!n:n}function I(e,t){let n=(e.startsWith("input.")?e.slice(6):e).split("."),r=t;for(let i of n){if(r==null||typeof r!="object")return;r=r[i]}return r}function Oe(e){return!(e==null||e===!1||e===0||e==="")}function Ne(e,t){if(!e||e.trim().length===0)return{decision:"permit",matched:!0};try{let n=ke(e),r=Pe(n,{target_app:t.target_app,action:t.action,...t.context,normalized:t.normalized??{}});if(!r.matched)return{decision:"deny",matched:!1};let i=r.bindings.decision;return i!==void 0?{decision:je(i),matched:!0}:r.bindings.approval_required==="true"?{decision:"approval_required",matched:!0}:r.bindings.allow==="true"?{decision:"permit",matched:!0}:{decision:"deny",matched:!0}}catch{return{decision:"deny",matched:!1}}}function je(e){switch(e){case"permit":case"allow":return"permit";case"deny":return"deny";case"approval_required":return"approval_required";default:return"deny"}}function De(e,t){if(!e||e==="*")return!0;if(e.endsWith("*")){let n=e.slice(0,-1);return t.startsWith(n)}return e===t}function H(e,t){let n=[...e].sort((r,i)=>i.priority-r.priority);for(let r of n){if(r.target_app!==null&&r.target_app!==t.target_app||!De(r.action_pattern,t.action))continue;let i=Ne(r.rego_source,t);if(i.matched)return{decision:i.decision,reason:r.description??r.name,rule_id:r.id,rule_code:r.rule_code,description:r.description,matchedRule:!0}}return{decision:"deny",reason:"No matching rule",rule_id:null,rule_code:null,description:null,matchedRule:!1}}var Ve=g.object({agentId:g.string().min(1,"agentId is required"),toolName:g.string().min(1,"toolName is required"),toolArgs:g.record(g.unknown()),targetResource:g.string().optional(),context:g.record(g.unknown()).optional(),telemetry:g.record(g.unknown()).optional()}),kt=g.object({allowed:g.boolean(),reason:g.string(),ruleId:g.string().optional(),ruleCode:g.string().optional(),description:g.string().optional(),enforced:g.boolean().optional(),decision:g.enum(["permit","deny","approval_required"]).optional(),decisionId:g.string().optional()});var Ke=c.enum(["enforce","audit","off"]),We=c.enum(["closed","open"]),Z=c.enum(["enforce","monitor","off"]),Mt=c.object({apiKey:c.string().min(1,"apiKey is required"),agentId:c.string().min(1,"agentId is required"),endpoint:c.string().url().optional(),mode:Ke.optional(),timeoutMs:c.number().int().positive().optional(),hitlTimeoutMs:c.number().int().positive().optional(),failBehavior:We.optional()}),xt=c.object({agent_id:c.string().min(1),target_app:c.string().min(1),action:c.string().min(1),context:c.record(c.unknown()).optional(),telemetry:c.record(c.unknown()).optional()}),Fe=c.object({decision_id:c.string().min(1),decision:c.enum(["permit","deny","approval_required"]),reason:c.string().optional(),rule_code:c.string().nullable().optional(),enforced:c.boolean().optional(),agent_mode:Z.optional(),metadata:c.record(c.unknown()).optional()}),qe=c.object({field:c.string().min(1),operator:c.enum(["equals","in","not_equals","not_in","glob","gt","lt","gte","lte","contains","not_contains"]),value:c.union([c.string(),c.number(),c.array(c.string())])}),Be=c.object({id:c.string().min(1),rule_code:c.string().default(""),name:c.string().min(1),description:c.string().nullable().default(null),effect:c.enum(["allow","deny","hitl"]),resource_type:c.string().min(1),rego_source:c.string().default(""),target_app:c.string().nullable().default(null),action_pattern:c.string().nullable().default(null),conditions:c.array(qe).default([]),priority:c.number().int().default(0)}),Qe=c.object({version:c.string().min(1),agent_mode:Z.default("monitor"),rules:c.array(Be)}),Ue=2e3,Ge=class{config;originalFetch;constructor(e,t){this.config=e,this.originalFetch=t}async evaluate(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.config.timeoutMs),r;try{r=await this.originalFetch(`${this.config.endpoint}/allow/evaluate`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify(e),signal:t.signal})}finally{clearTimeout(n)}if(!r.ok)throw new Error(`ALLOW evaluate request failed: HTTP ${r.status} ${r.statusText}`);let i=await r.json();return Fe.parse(i)}async fetchBundle(){let e=this.config.agentId?`?agent_id=${encodeURIComponent(this.config.agentId)}`:"",t=`${this.config.endpoint}/allow/rules/bundle${e}`,n=new AbortController,r=setTimeout(()=>n.abort(),this.config.timeoutMs),i;try{i=await this.originalFetch(t,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`,Accept:"application/json"},signal:n.signal})}finally{clearTimeout(r)}if(!i.ok)throw new Error(`ALLOW rules/bundle fetch failed: HTTP ${i.status} ${i.statusText}`);let o=await i.json();return Qe.parse(o)}async sendTelemetry(e){if(e.length===0)return;let t=`${this.config.endpoint}/allow/telemetry`;try{let n=await this.originalFetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({decisions:e})});n.ok||console.warn(`[ALLOW] Telemetry delivery failed: HTTP ${n.status} ${n.statusText}`)}catch(n){console.warn("[ALLOW] Telemetry delivery failed:",n)}}async reportExecutionResult(e,t,n){let r=`${this.config.endpoint}/allow/execution-events`;try{let i=await this.originalFetch(r,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({decision_id:e,result:t,details:n})});i.ok||console.warn(`[ALLOW] Execution result report failed: HTTP ${i.status}`)}catch(i){console.warn("[ALLOW] Execution result report failed:",i)}}async waitForApproval(e){if(!e)throw new Error("waitForApproval: decisionId must be a non-empty string");let t=Date.now()+this.config.hitlTimeoutMs;for(;Date.now()<t;){let n=new AbortController,r=setTimeout(()=>n.abort(),this.config.timeoutMs),i;try{i=await this.originalFetch(`${this.config.endpoint}/v1/allow/decisions/${encodeURIComponent(e)}`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`},signal:n.signal})}finally{clearTimeout(r)}if(!i.ok)throw new Error(`ALLOW decisions poll failed: HTTP ${i.status} ${i.statusText}`);let o=await i.json();if(typeof o!="object"||o===null)throw new Error("ALLOW decisions poll returned unexpected non-object response");let s=o,a=s.hitl_result;if(a==="approved")return{decision_id:e,decision:"permit",reason:"Approved by human reviewer"};if(a==="rejected")return{decision_id:e,decision:"deny",reason:typeof s.reason=="string"?s.reason:"Rejected by human reviewer"};if(a==="timeout"||a==="expired")return{decision_id:e,decision:"deny",reason:"HITL approval timed out"};await ze(Ue)}return{decision_id:e,decision:"deny",reason:"HITL approval timed out"}}};function ze(e){return new Promise(t=>setTimeout(t,e))}var He=class{endpoint;apiKey;agentId;originalFetch;onModeChanged;abortController=null;reconnectTimer=null;backoffMs=1e3;stableTimer=null;stopped=!1;constructor(e){this.endpoint=e.endpoint,this.apiKey=e.apiKey,this.agentId=e.agentId,this.originalFetch=e.originalFetch,this.onModeChanged=e.onModeChanged}start(){if(this.stopped)throw new Error("AgentModeStream cannot be restarted after stop()");this.connect()}stop(){this.stopped=!0,this.reconnectTimer!==null&&(clearTimeout(this.reconnectTimer),this.reconnectTimer=null),this.stableTimer!==null&&(clearTimeout(this.stableTimer),this.stableTimer=null),this.abortController!==null&&(this.abortController.abort(),this.abortController=null)}async connect(){if(this.stopped)return;let e=new AbortController;this.abortController=e;let t=`${this.endpoint}/allow/agents/me/stream?agent_id=${encodeURIComponent(this.agentId)}`,n;try{n=await this.originalFetch(t,{method:"GET",headers:{Authorization:`Bearer ${this.apiKey}`,Accept:"text/event-stream","Cache-Control":"no-cache"},signal:e.signal})}catch(r){this.scheduleReconnect(`connection failed: ${Y(r)}`);return}if(!n.ok){this.scheduleReconnect(`HTTP ${n.status} ${n.statusText}`);return}if(!n.body){this.scheduleReconnect("no response body");return}this.stableTimer=setTimeout(()=>{this.backoffMs=1e3,this.stableTimer=null},3e4);try{await this.readLoop(n.body.getReader())}catch(r){if(this.stopped)return;this.scheduleReconnect(`read loop failed: ${Y(r)}`);return}this.stopped||this.scheduleReconnect("stream ended")}async readLoop(e){let t=new TextDecoder("utf-8"),n="";for(;;){let{value:r,done:i}=await e.read();if(i)break;if(this.stopped)return;n+=t.decode(r,{stream:!0});let o;for(;(o=n.indexOf(`
|
|
5
|
-
|
|
6
|
-
`))!==-1;){let s=n.slice(0,o);n=n.slice(o+2),this.handleEvent(s)}}}handleEvent(e){let t="message",n=[];for(let o of e.split(`
|
|
7
|
-
`)){if(o===""||o.startsWith(":"))continue;let s=o.indexOf(":");if(s===-1)continue;let a=o.slice(0,s),l=o.slice(s+1);l.startsWith(" ")&&(l=l.slice(1)),a==="event"?t=l:a==="data"&&n.push(l)}if(n.length===0||t!=="mode_changed"&&t!=="mode_snapshot")return;let r;try{r=JSON.parse(n.join(`
|
|
8
|
-
`))}catch{return}if(r===null||typeof r!="object"||!("agent_mode"in r))return;let i=r.agent_mode;if(!(i!=="enforce"&&i!=="monitor"&&i!=="off"))try{this.onModeChanged(i)}catch(o){console.error("[ALLOW] mode_changed listener threw:",o)}}scheduleReconnect(e){if(this.stopped)return;this.stableTimer!==null&&(clearTimeout(this.stableTimer),this.stableTimer=null),this.abortController!==null&&(this.abortController=null);let t=this.backoffMs;this.backoffMs=Math.min(this.backoffMs*2,3e4),console.warn(`[ALLOW] mode stream disconnected (${e}); reconnecting in ${t}ms`),this.reconnectTimer=setTimeout(()=>{this.reconnectTimer=null,this.connect()},t),this.reconnectTimer!==null&&typeof this.reconnectTimer.unref=="function"&&this.reconnectTimer.unref()}};function Y(e){return e instanceof Error?e.message:String(e)}var Ye=5e3,Je=1e4,Ze="monitor",X=class{client;resolvedApiKey;resolvedEndpoint;resolvedAgentId;deferHitl;rules=[];bundleVersion=null;bundleFetchInProgress=!1;refreshTimer=null;telemetryBuffer=[];telemetryTimer=null;agentMode=Ze;modeStream=null;constructor(e,t,n,r){let i=e??process.env.ALLOW_API_KEY,o=t??process.env.ALLOW_ENDPOINT,s=n??process.env.ALLOW_AGENT_ID??process.env.VISIQ_AGENT_ID??"";if(this.resolvedApiKey=i,this.resolvedEndpoint=o,this.resolvedAgentId=s,this.deferHitl=r?.deferHitl??!1,i&&o){let a={apiKey:i,agentId:s,endpoint:o,mode:"enforce",timeoutMs:5e3,hitlTimeoutMs:3e5,failBehavior:"closed"},l=globalThis.fetch.bind(globalThis);this.client=new Ge(a,l),this.fetchBundleBackground(),this.refreshTimer=setInterval(()=>this.fetchBundleBackground(),Ye),J(this.refreshTimer),this.telemetryTimer=setInterval(()=>this.flushTelemetry(),Je),J(this.telemetryTimer),s&&(this.modeStream=new He({endpoint:o,apiKey:i,agentId:s,originalFetch:l,onModeChanged:p=>{this.agentMode=p}}),this.modeStream.start())}else this.client=null}async evaluate(e){let t=Ve.parse(e),n=Date.now(),r=this.agentMode;if(r==="off")return{allowed:!0,reason:"agent_mode=off \u2014 evaluation bypassed",enforced:!1};if(this.rules.length>0){let i=H(this.toMatchable(),this.toMatchInput(t));if(i.matchedRule){if(i.decision==="approval_required"){if(this.client){let s=await this.evaluateRemote(t,n);return this.applyAgentMode(s,r,t,n,"remote")}return this.applyAgentMode({allowed:!1,reason:`${i.reason} (human approval required \u2014 no backend configured)`,...i.rule_id?{ruleId:i.rule_id}:{},...i.rule_code?{ruleCode:i.rule_code}:{},...i.description?{description:i.description}:{}},r,t,n,"local")}let o={allowed:i.decision==="permit",reason:i.reason,...i.rule_id?{ruleId:i.rule_id}:{},...i.rule_code?{ruleCode:i.rule_code}:{},...i.description?{description:i.description}:{}};return this.applyAgentMode(o,r,t,n,"local")}if(this.client){let o=await this.evaluateRemote(t,n);return this.applyAgentMode(o,r,t,n,"remote")}return this.applyAgentMode({allowed:!1,reason:"No matching ALLOW rule and no backend configured \u2014 fail-closed (G001)"},r,t,n,"local")}if(this.client){let i=await this.evaluateRemote(t,n);return this.applyAgentMode(i,r,t,n,"remote")}return this.applyAgentMode({allowed:!1,reason:"No ALLOW rules loaded and no backend configured \u2014 fail-closed (G001)"},r,t,n,"local")}hasRules(){return this.rules.length>0}hasClient(){return this.client!==null}getBundleVersion(){return this.bundleVersion}getAgentMode(){return this.agentMode}getEndpoint(){return this.resolvedEndpoint}getApiKey(){return this.resolvedApiKey}dispose(){this.refreshTimer&&(clearInterval(this.refreshTimer),this.refreshTimer=null),this.telemetryTimer&&(clearInterval(this.telemetryTimer),this.telemetryTimer=null),this.modeStream&&(this.modeStream.stop(),this.modeStream=null),this.flushTelemetry().catch(e=>{console.error("[AllowRuntime] final telemetry flush failed during destroy (non-fatal):",e)})}applyAgentMode(e,t,n,r,i){let o=Date.now()-r;return t==="enforce"?(this.bufferTelemetry(n,e,o,i,!0),{...e,enforced:!0}):(this.bufferTelemetry(n,e,o,i,!1),{allowed:!0,reason:e.reason,...e.ruleId!==void 0?{ruleId:e.ruleId}:{},...e.ruleCode!==void 0?{ruleCode:e.ruleCode}:{},...e.description!==void 0?{description:e.description}:{},enforced:!1})}toMatchable(){return this.rules.map(e=>({id:e.id,rule_code:e.rule_code||null,name:e.name,description:e.description,rego_source:e.rego_source??null,target_app:e.target_app??null,action_pattern:e.action_pattern??null,priority:e.priority}))}toMatchInput(e){return{target_app:e.targetResource??e.toolName,action:e.toolName,context:{[e.toolName]:e.toolArgs,...e.context??{}},normalized:{}}}async evaluateRemote(e,t){if(!this.client)return{allowed:!1,reason:"No backend configured \u2014 fail-closed (G001)"};try{let n={agent_id:e.agentId,target_app:e.targetResource??e.toolName,action:e.toolName,context:{[e.toolName]:e.toolArgs,...e.context},telemetry:e.telemetry},r=await this.client.evaluate(n);if(r.decision==="approval_required"&&r.decision_id){if(this.deferHitl)return{allowed:!1,reason:r.reason??"Human approval required",decision:"approval_required",decisionId:r.decision_id,...r.rule_code?{ruleCode:r.rule_code}:{}};let i=await this.client.waitForApproval(r.decision_id);return{allowed:i.decision==="permit",reason:i.reason??"HITL decision",...r.rule_code?{ruleCode:r.rule_code}:{}}}return{allowed:r.decision==="permit",reason:r.reason??`Backend: ${r.decision}`,...r.rule_code?{ruleCode:r.rule_code}:{}}}catch(n){return console.warn("[ALLOW] Network evaluation failed \u2014 denying (G001):",n),{allowed:!1,reason:`Network evaluation failed \u2014 fail-closed (G001) [${Date.now()-t}ms]`}}}async fetchBundleBackground(){if(!(this.bundleFetchInProgress||!this.client)){this.bundleFetchInProgress=!0;try{let e=await this.client.fetchBundle();e.version!==this.bundleVersion&&(this.rules=e.rules,this.bundleVersion=e.version),this.agentMode=e.agent_mode}catch(e){this.bundleVersion?console.warn("[ALLOW] Bundle refresh failed (using cached rules):",e):console.warn("[ALLOW] Initial bundle fetch failed (will use network evaluation):",e)}finally{this.bundleFetchInProgress=!1}}}bufferTelemetry(e,t,n,r,i){if(r==="remote")return;let o={agent_id:e.agentId,tool_name:e.toolName,target_resource:e.targetResource,...O(e.toolArgs,e.toolName),...O(e.context??{})};this.telemetryBuffer.push({decision_id:crypto.randomUUID(),agent_id:e.agentId,target_app:e.targetResource??e.toolName,action:e.toolName,decision:t.allowed?"permit":"deny",reason:t.reason,evaluated_at:new Date().toISOString(),rule_id:t.ruleId??null,rule_code:t.ruleCode??null,enforced:i,agent_mode:this.agentMode,latency_ms:n,evaluation_mode:r,raw_event:o})}async flushTelemetry(){if(this.telemetryBuffer.length===0||!this.client)return;let e=this.telemetryBuffer.splice(0);try{await this.client.sendTelemetry(e)}catch(t){console.error("[AllowRuntime] telemetry flush failed (non-fatal):",t)}}};function O(e,t=""){let n={};for(let[r,i]of Object.entries(e)){let o=t?`${t}/${r}`:r;i!==null&&typeof i=="object"&&!Array.isArray(i)?Object.assign(n,O(i,o)):n[o]=i}return n}function J(e){e&&typeof e=="object"&&"unref"in e&&e.unref()}import{z as u}from"zod";import{z as d}from"zod";var Xe=u.enum(["enforce","audit","off"]),et=u.enum(["allow","redact","deny","escalate"]),ee=u.object({agentId:u.string().min(1,"agentId is required"),agentRole:u.string().optional(),trustTier:u.number().int().min(1).max(3).optional(),operation:u.enum(["retrieve","tool_call","prompt_render"]),resourceType:u.enum(["document","tool_result","prompt"]),resourceMetadata:u.record(u.unknown()),query:u.string().optional(),contentPreview:u.string().optional(),telemetry:u.record(u.unknown()).optional()}),Kt=u.object({action:et,reason:u.string(),ruleId:u.string().optional(),redactionRules:u.array(u.object({field:u.string(),pattern:u.string(),replacement:u.string()})).optional(),metadata:u.record(u.unknown()).optional()}),tt=u.object({apiKey:u.string().optional(),endpoint:u.string().url().optional(),mode:Xe.optional(),wasmPath:u.string().optional(),bundleUrl:u.string().url().optional(),syncIntervalMs:u.number().int().positive().optional(),telemetryEnabled:u.boolean().optional(),timeoutMs:u.number().int().positive().optional()}),te="https://project-y-backend-mnxz.onrender.com",ne="enforce",re=6e4,ie=!0,oe=5e3;function ce(e){let t={apiKey:e.apiKey||process.env.RECALL_API_KEY||"",endpoint:e.endpoint||process.env.RECALL_ENDPOINT||te,mode:e.mode||nt(process.env.RECALL_MODE)||ne,wasmPath:e.wasmPath||process.env.RECALL_WASM_PATH,bundleUrl:e.bundleUrl||process.env.RECALL_BUNDLE_URL,syncIntervalMs:e.syncIntervalMs!==void 0?e.syncIntervalMs:se(process.env.RECALL_SYNC_INTERVAL_MS)??re,telemetryEnabled:e.telemetryEnabled!==void 0?e.telemetryEnabled:rt(process.env.RECALL_TELEMETRY_ENABLED)??ie,timeoutMs:e.timeoutMs!==void 0?e.timeoutMs:se(process.env.RECALL_TIMEOUT_MS)??oe},n=tt.parse(t);return{apiKey:n.apiKey??"",endpoint:n.endpoint??te,mode:n.mode??ne,wasmPath:n.wasmPath,bundleUrl:n.bundleUrl,syncIntervalMs:n.syncIntervalMs??re,telemetryEnabled:n.telemetryEnabled??ie,timeoutMs:n.timeoutMs??oe}}function nt(e){if(e==="enforce"||e==="audit"||e==="off")return e;if(e!==void 0)throw new Error(`Invalid RECALL_MODE env var: "${e}". Must be one of: enforce, audit, off`)}function se(e){if(e===void 0)return;let t=parseInt(e,10);if(isNaN(t)||t<=0)throw new Error(`Invalid numeric env var value: "${e}". Must be a positive integer.`);return t}function rt(e){if(e===void 0)return;let t=e.toLowerCase().trim();return t==="true"||t==="1"||t==="yes"}function it(e,t){let n=e;for(let r of t)try{let i=ot(r.pattern);n=n.replace(i,r.replacement)}catch(i){console.warn("[RECALL] redactText: skipping malformed redaction rule:",i)}return n}function ot(e){if(e instanceof RegExp){let n=e.flags.includes("g")?e.flags:`${e.flags}g`;return new RegExp(e.source,n)}let t=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(t,"g")}var N={action:"deny",reason:"No RECALL policy loaded \u2014 fail-closed (G001)"},b={action:"deny",reason:"RECALL policy evaluation error \u2014 fail-closed (G001)"},ue=class{config;client;telemetry;policy=null;policyVersion=null;policyData={};constructor(e,t=null,n=null){this.config=e,this.client=t,this.telemetry=n}async loadBundle(e,t,n){let{loadPolicy:r}=await import("@open-policy-agent/opa-wasm"),i=await r(e);i.setData(t),this.policy=i,this.policyData=t,this.policyVersion=n??null}evaluate(e){let t=ee.parse(e);if(this.policy===null)return N;let n=Date.now();try{let r=ae(t),i=this.policy.evaluate(r),o=le(i);return this.recordTelemetry(t,o,Date.now()-n,"wasm"),o}catch(r){return console.warn("[RECALL] WASM policy evaluation error \u2014 denying (G001):",r),this.recordTelemetry(t,b,Date.now()-n,"wasm"),b}}async evaluateAsync(e){if(this.config.mode==="off")return{action:"allow",reason:"RECALL mode is off"};let t=ee.parse(e),n=Date.now();if(this.policy!==null)try{let r=ae(t),i=this.policy.evaluate(r),o=le(i);return this.recordTelemetry(t,o,Date.now()-n,"wasm"),this.config.mode==="audit"?{action:"allow",reason:`audit: would have ${o.action}`}:o}catch(r){console.warn("[RECALL] WASM evaluation error, falling back to HTTP:",r)}if(this.client!==null)try{let r=await this.client.evaluate(t);return this.recordTelemetry(t,r,Date.now()-n,"remote"),this.config.mode==="audit"?{action:"allow",reason:`audit: would have ${r.action}`}:r}catch(r){return console.warn("[RECALL] Server-side evaluation failed \u2014 denying (G001):",r),this.recordTelemetry(t,b,Date.now()-n,"remote"),b}return this.recordTelemetry(t,N,Date.now()-n,"wasm"),N}async filterDocuments(e,t,n){if(this.config.mode==="off")return t;if(!e||e.trim()==="")return console.warn("[RECALL] filterDocuments called with empty agentId \u2014 denying all (G001)"),[];let r=[];for(let i of t){let o;try{o=n(i)}catch(l){console.warn("[RECALL] extractMeta threw \u2014 excluding document (G001):",l);continue}let s={agentId:e,operation:"retrieve",resourceType:"document",resourceMetadata:o},a;try{a=await this.evaluateAsync(s)}catch(l){console.warn("[RECALL] Unexpected error in evaluateAsync \u2014 excluding document (G001):",l);continue}switch(a.action){case"allow":case"escalate":r.push(i);break;case"redact":{if(a.redactionRules&&a.redactionRules.length>0){let l=st(i,a.redactionRules);r.push(l)}else r.push(i);break}case"deny":break;default:{let l=a.action;break}}}return r}getPolicyVersion(){return this.policyVersion}hasPolicy(){return this.policy!==null}recordTelemetry(e,t,n,r){if(this.telemetry!==null)try{this.telemetry.record({agentId:e.agentId,evaluatedAt:new Date().toISOString(),input:e,decision:t,latencyMs:n,evaluationMode:r})}catch{}}};function ae(e){return{agent_id:e.agentId,agent_role:e.agentRole,trust_tier:e.trustTier,operation:e.operation,resource_type:e.resourceType,resource_metadata:e.resourceMetadata,query:e.query,content_preview:e.contentPreview}}function le(e){if(!Array.isArray(e)||e.length===0)return b;let t=e[0]?.result;if(t===null||typeof t!="object")return b;let n=t,{action:r}=n;if(r!=="allow"&&r!=="redact"&&r!=="deny"&&r!=="escalate")return b;let i=typeof n.reason=="string"?n.reason:"Policy decision",o=typeof n.rule_id=="string"?n.rule_id:void 0,s;if(Array.isArray(n.redaction_rules)){s=[];for(let a of n.redaction_rules)if(a!==null&&typeof a=="object"&&typeof a.field=="string"&&typeof a.pattern=="string"&&typeof a.replacement=="string"){let l=a;s.push({field:l.field,pattern:l.pattern,replacement:l.replacement})}}return{action:r,reason:i,ruleId:o,redactionRules:s}}function st(e,t){if(e===null||typeof e!="object")return e;let n={...e};for(let r of t){let i=n[r.field];typeof i=="string"&&(n[r.field]=it(i,[{pattern:r.pattern,replacement:r.replacement}]))}return n}var at=d.object({decision_id:d.string().min(1),decision:d.enum(["allow","redact","deny","escalate"]),reason_code:d.string().optional(),reason:d.string().optional(),receipt_id:d.string().optional(),rule_id:d.string().optional(),redaction_rules:d.array(d.object({field:d.string().optional(),pattern:d.string().optional(),replacement:d.string().optional()})).optional()}),lt=d.object({id:d.string().min(1),name:d.string().min(1),rego_source:d.string().min(1),trust_tier:d.string().nullable(),surface:d.string().nullable(),principal_exclusions:d.array(d.string()),priority:d.number()}),ct=d.object({version:d.string().min(1),rules:d.array(lt)}),de=class{config;constructor(e){this.config=e}async evaluate(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.config.timeoutMs),r=e.trustTier!==void 0?`tier${e.trustTier}`:void 0,i={agent_id:e.agentId,operation:e.operation,resource_type:e.resourceType,resource_metadata:e.resourceMetadata,trust_tier:r,surface:e.resourceMetadata?.surface,query:e.query,telemetry:e.telemetry},o;try{o=await fetch(`${this.config.endpoint}/recall/evaluate`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify(i),signal:t.signal})}finally{clearTimeout(n)}if(!o.ok)throw new Error(`RECALL evaluate request failed: HTTP ${o.status} ${o.statusText}`);let s=await o.json(),a=at.parse(s),l=a.redaction_rules?.map(p=>({field:p.field??"",pattern:p.pattern??"",replacement:p.replacement??"[REDACTED]"}));return{action:a.decision,reason:a.reason??a.reason_code??"",ruleId:a.rule_id,...l?{redactionRules:l}:{}}}async fetchBundle(){let e=new AbortController,t=setTimeout(()=>e.abort(),this.config.timeoutMs),n;try{n=await fetch(`${this.config.endpoint}/recall/rules/bundle`,{method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`,Accept:"application/json"},signal:e.signal})}finally{clearTimeout(t)}if(!n.ok)throw new Error(`RECALL bundle fetch failed: HTTP ${n.status} ${n.statusText}`);let r=await n.json(),i=ct.parse(r);return{rules:i.rules,version:i.version}}async sendTelemetry(e){if(e.length===0)return;let t=`${this.config.endpoint}/recall/telemetry`;try{let n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({events:e})});n.ok||console.warn(`[RECALL] Telemetry delivery failed: HTTP ${n.status} ${n.statusText}`)}catch(n){console.warn("[RECALL] Telemetry delivery failed:",n)}}};var T=null;function pe(e){let t=`${e.apiKey}::${e.agentId}::${e.baseUrl??""}`;if(T&&T.key===t)return T.runtimes;let n=new X(e.apiKey,e.baseUrl,e.agentId),r=ce({apiKey:e.apiKey,endpoint:e.baseUrl}),i=new de(r),o=new ue(r,i,null);return T={key:t,runtimes:{allow:n,recall:o}},T.runtimes}var fe="@visiq/openclaw-plugin";function ut(e){return typeof e=="string"&&e.includes("human approval required")}function dt(e){let t=[],n=[],r;for(let o of e){let{field:s,pattern:a,replacement:l}=o;s&&t.push(s),a&&n.push(a),l&&r===void 0&&(r=l)}let i={};return t.length>0&&(i.fields=t),n.length>0&&(i.patterns=n),r!==void 0&&(i.replacement=r),i}async function Zt(e,t){let n=await v();if(!n)return;let r=U(e.toolName),i=pe(n),o=n.agentId??t.agentId,s=t.sessionId??t.sessionKey??"default",a=t.toolCallId??e.toolCallId,l,p,m;try{({allowed:l,reason:p,ruleCode:m}=await i.allow.evaluate({agentId:o,toolName:e.toolName,toolArgs:e.params??{}}))}catch(f){return{block:!0,blockReason:`[VisIQ ALLOW] Evaluation error (fail-closed): ${f instanceof Error?f.message:String(f)}`}}if(!l)return ut(p)?{requireApproval:{title:`VisIQ approval required: ${e.toolName}`,description:p,severity:"critical",allowedDecisions:["allow-once","allow-always","deny"],pluginId:fe}}:{block:!0,blockReason:`[VisIQ ${m??"DENY"}] ${p}`};if(!r)return;let w;try{w=await i.recall.evaluateAsync({agentId:o,operation:"tool_call",resourceType:"tool_result",resourceMetadata:{toolName:e.toolName,runId:e.runId??t.runId},query:pt(e.params)})}catch(f){return{block:!0,blockReason:`[VisIQ RECALL] Evaluation error (fail-closed): ${f instanceof Error?f.message:String(f)}`}}switch(w.action){case"allow":return;case"deny":return{block:!0,blockReason:`[VisIQ RECALL] ${w.reason}`};case"redact":{if(!a)return{block:!0,blockReason:"[VisIQ RECALL] Redact decision but no toolCallId \u2014 fail-closed"};let f=w.redactionRules??[];if(f.length===0)return;let h=dt(f);_(s).set(a,h);return}case"escalate":return{requireApproval:{title:`VisIQ approval required: ${e.toolName}`,description:w.reason,severity:"warning",allowedDecisions:["allow-once","allow-always","deny"],pluginId:fe}};default:{let{action:f}=w;return{block:!0,blockReason:`[VisIQ RECALL] Unknown action "${String(f)}" \u2014 fail-closed`}}}}function pt(e){if(e)for(let t of["query","q","url","prompt"]){let n=e[t];if(typeof n=="string"&&n.length>0)return n}}var ge="[REDACTED]";function he(e,t){return e==null?e:typeof e=="string"?me(e,t):typeof e=="object"?ft(e,t):e}function me(e,t){if(typeof e!="string")return e;let{patterns:n}=t;if(!n||n.length===0)return e;let r=t.replacement??ge,i=e;for(let o of n){if(typeof o!="string"||o.length===0)continue;let s;try{s=new RegExp(o,"g")}catch(a){let l=a instanceof Error?a.message:String(a);throw new Error(`[visiq-redact] Invalid redaction pattern "${o}": ${l}`)}i=i.replace(s,r)}return i}function ft(e,t){let n=new Set(t.fields??[]),r=t.replacement??ge,i=n.size>0,o=(t.patterns??[]).length>0,s=a=>{if(a==null)return a;if(Array.isArray(a))return a.map(l=>s(l));if(typeof a=="object"){let l=a,p={};for(let m of Object.keys(l)){if(i&&n.has(m)){p[m]=r;continue}p[m]=s(l[m])}return p}return typeof a=="string"&&o?me(a,t):a};return s(e)}function on(e,t){let{ready:n,config:r}=L();if(!n||!r)return;let i=e.toolCallId??t.toolCallId;if(!i)return;let o=t.sessionKey??"default",s=_(o),a=s.get(i);if(!a)return;let l={...e.message};return l.content!==void 0&&(l.content=he(l.content,a)),s.delete(i),{message:l}}function cn(e,t){let{ready:n,config:r}=L();if(n&&!r)return;let i=e.sessionKey??t.sessionKey??"default",o=_(i);if(o.size()>0)return o.clear(),{block:!0}}async function S(e,t){let r=`${(e.baseUrl??"https://api.visiqlabs.com").replace(/\/$/,"")}/v1/events`;try{let i=new AbortController,o=setTimeout(()=>i.abort(),5e3);try{let s=await fetch(r,{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.apiKey}`},body:JSON.stringify(t),signal:i.signal});s.ok||process.stderr.write(`[VisIQ] /v1/events POST failed: ${s.status} ${s.statusText}
|
|
9
|
-
`);try{await s.text()}catch{}}finally{clearTimeout(o)}}catch(i){if(i instanceof Error&&i.name==="AbortError"){process.stderr.write(`[VisIQ] /v1/events POST timed out (5s)
|
|
10
|
-
`);return}process.stderr.write(`[VisIQ] /v1/events POST error: ${i instanceof Error?i.message:String(i)}
|
|
11
|
-
`)}}async function gn(e,t){let n=await v();if(!n)return;let r=n.agentId??t.agentId;S(n,{type:"llm_input",agentId:r,sessionId:e.sessionId??t.sessionId??t.sessionKey,runId:e.runId??t.runId,timestamp:new Date().toISOString(),payload:{provider:e.provider,model:e.model,hasSystemPrompt:typeof e.systemPrompt=="string"&&e.systemPrompt.length>0,promptLength:typeof e.prompt=="string"?e.prompt.length:0,historyMessageCount:Array.isArray(e.historyMessages)?e.historyMessages.length:0,imagesCount:e.imagesCount??0,toolCount:Array.isArray(e.tools)?e.tools.length:0}})}function gt(e){if(!Array.isArray(e))return 0;let t=0;for(let n of e)typeof n=="string"&&(t+=n.length);return t}async function wn(e,t){let n=await v();if(!n)return;let r=n.agentId??t.agentId;S(n,{type:"llm_output",agentId:r,sessionId:e.sessionId??t.sessionId??t.sessionKey,runId:e.runId??t.runId,timestamp:new Date().toISOString(),payload:{provider:e.provider,model:e.model,resolvedRef:e.resolvedRef,harnessId:e.harnessId,assistantSegmentCount:Array.isArray(e.assistantTexts)?e.assistantTexts.length:0,assistantTotalChars:gt(e.assistantTexts),usage:e.usage??null}})}function bn(e,t){B(e.sessionId??e.sessionKey??"default")}export{F as a,At as b,x as c,_ as d,B as e,Ce as f,U as g,Rt as h,Zt as i,on as j,cn as k,gn as l,wn as m,bn as n};
|