wu-framework 1.2.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -18
- package/dist/adapters/alpine/index.js +2 -0
- package/dist/adapters/alpine/index.js.map +1 -0
- package/dist/adapters/angular/index.js +2 -0
- package/dist/adapters/angular/index.js.map +1 -0
- package/dist/adapters/htmx/index.js +2 -0
- package/dist/adapters/htmx/index.js.map +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/lit/index.js +44 -0
- package/dist/adapters/lit/index.js.map +1 -0
- package/dist/adapters/preact/index.js +2 -0
- package/dist/adapters/preact/index.js.map +1 -0
- package/dist/adapters/qwik/index.js +2 -0
- package/dist/adapters/qwik/index.js.map +1 -0
- package/dist/adapters/react/index.js +2 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/shared.js +2 -0
- package/dist/adapters/shared.js.map +1 -0
- package/dist/adapters/solid/index.js +2 -0
- package/dist/adapters/solid/index.js.map +1 -0
- package/dist/adapters/stencil/index.js +2 -0
- package/dist/adapters/stencil/index.js.map +1 -0
- package/dist/adapters/stimulus/index.js +2 -0
- package/dist/adapters/stimulus/index.js.map +1 -0
- package/dist/adapters/svelte/index.js +2 -0
- package/dist/adapters/svelte/index.js.map +1 -0
- package/dist/adapters/vanilla/index.js +2 -0
- package/dist/adapters/vanilla/index.js.map +1 -0
- package/dist/adapters/vue/index.js +2 -0
- package/dist/adapters/vue/index.js.map +1 -0
- package/dist/ai/wu-ai.js +2 -0
- package/dist/ai/wu-ai.js.map +1 -0
- package/dist/core/wu-mcp-bridge.js +2 -0
- package/dist/core/wu-mcp-bridge.js.map +1 -0
- package/{src → dist}/index.d.ts +445 -317
- package/dist/wu-ai-browser-primitives-BDKXJlwc.js +2 -0
- package/dist/wu-ai-browser-primitives-BDKXJlwc.js.map +1 -0
- package/dist/wu-framework.cjs.js +2 -2
- package/dist/wu-framework.cjs.js.map +1 -1
- package/dist/wu-framework.dev.js +2640 -9197
- package/dist/wu-framework.dev.js.map +1 -1
- package/dist/wu-framework.esm.js +2 -2
- package/dist/wu-framework.esm.js.map +1 -1
- package/dist/wu-framework.umd.js +2 -2
- package/dist/wu-framework.umd.js.map +1 -1
- package/dist/wu-html-parser.js +2 -0
- package/dist/wu-html-parser.js.map +1 -0
- package/dist/wu-iframe-sandbox.js +2 -0
- package/dist/wu-iframe-sandbox.js.map +1 -0
- package/dist/wu-logger-fJfUHBGA.js +2 -0
- package/dist/wu-logger-fJfUHBGA.js.map +1 -0
- package/dist/wu-script-executor.js +2 -0
- package/dist/wu-script-executor.js.map +1 -0
- package/package.json +43 -34
- package/src/adapters/alpine/index.js +0 -231
- package/src/adapters/alpine.js +0 -3
- package/src/adapters/angular/ai.js +0 -30
- package/src/adapters/angular/index.js +0 -932
- package/src/adapters/angular.js +0 -3
- package/src/adapters/htmx/index.js +0 -242
- package/src/adapters/htmx.js +0 -3
- package/src/adapters/index.js +0 -225
- package/src/adapters/lit/ai.js +0 -20
- package/src/adapters/lit/index.js +0 -721
- package/src/adapters/lit.js +0 -3
- package/src/adapters/preact/ai.js +0 -33
- package/src/adapters/preact/index.js +0 -661
- package/src/adapters/preact.js +0 -3
- package/src/adapters/qwik/index.js +0 -108
- package/src/adapters/qwik.js +0 -3
- package/src/adapters/react/ai.js +0 -135
- package/src/adapters/react/index.js +0 -695
- package/src/adapters/react.js +0 -3
- package/src/adapters/shared.js +0 -64
- package/src/adapters/solid/ai.js +0 -32
- package/src/adapters/solid/index.js +0 -586
- package/src/adapters/solid.js +0 -3
- package/src/adapters/stencil/index.js +0 -228
- package/src/adapters/stencil.js +0 -3
- package/src/adapters/stimulus/index.js +0 -255
- package/src/adapters/stimulus.js +0 -3
- package/src/adapters/svelte/ai.js +0 -31
- package/src/adapters/svelte/index.js +0 -798
- package/src/adapters/svelte.js +0 -3
- package/src/adapters/vanilla/ai.js +0 -30
- package/src/adapters/vanilla/index.js +0 -785
- package/src/adapters/vanilla.js +0 -3
- package/src/adapters/vue/ai.js +0 -52
- package/src/adapters/vue/index.js +0 -618
- package/src/adapters/vue.js +0 -3
- package/src/ai/wu-ai-actions.js +0 -261
- package/src/ai/wu-ai-agent.js +0 -546
- package/src/ai/wu-ai-browser-primitives.js +0 -354
- package/src/ai/wu-ai-browser.js +0 -380
- package/src/ai/wu-ai-context.js +0 -332
- package/src/ai/wu-ai-conversation.js +0 -613
- package/src/ai/wu-ai-orchestrate.js +0 -1021
- package/src/ai/wu-ai-permissions.js +0 -381
- package/src/ai/wu-ai-provider.js +0 -700
- package/src/ai/wu-ai-schema.js +0 -225
- package/src/ai/wu-ai-triggers.js +0 -396
- package/src/ai/wu-ai.js +0 -804
- package/src/core/wu-app.js +0 -236
- package/src/core/wu-cache.js +0 -498
- package/src/core/wu-core.js +0 -1412
- package/src/core/wu-error-boundary.js +0 -396
- package/src/core/wu-event-bus.js +0 -390
- package/src/core/wu-hooks.js +0 -350
- package/src/core/wu-html-parser.js +0 -199
- package/src/core/wu-iframe-sandbox.js +0 -328
- package/src/core/wu-loader.js +0 -450
- package/src/core/wu-logger.js +0 -143
- package/src/core/wu-manifest.js +0 -533
- package/src/core/wu-mcp-bridge.js +0 -432
- package/src/core/wu-overrides.js +0 -510
- package/src/core/wu-performance.js +0 -228
- package/src/core/wu-plugin.js +0 -401
- package/src/core/wu-prefetch.js +0 -414
- package/src/core/wu-proxy-sandbox.js +0 -477
- package/src/core/wu-sandbox.js +0 -779
- package/src/core/wu-script-executor.js +0 -161
- package/src/core/wu-sentinel-client.js +0 -311
- package/src/core/wu-snapshot-sandbox.js +0 -227
- package/src/core/wu-store.js +0 -307
- package/src/core/wu-strategies.js +0 -256
- package/src/core/wu-style-bridge.js +0 -477
- package/src/index.js +0 -234
- package/src/utils/dependency-resolver.js +0 -328
- /package/{src → dist}/adapters/alpine/index.d.ts +0 -0
- /package/{src → dist}/adapters/alpine.d.ts +0 -0
- /package/{src → dist}/adapters/angular/index.d.ts +0 -0
- /package/{src → dist}/adapters/angular.d.ts +0 -0
- /package/{src → dist}/adapters/htmx/index.d.ts +0 -0
- /package/{src → dist}/adapters/htmx.d.ts +0 -0
- /package/{src → dist}/adapters/lit/index.d.ts +0 -0
- /package/{src → dist}/adapters/lit.d.ts +0 -0
- /package/{src → dist}/adapters/preact/index.d.ts +0 -0
- /package/{src → dist}/adapters/preact.d.ts +0 -0
- /package/{src → dist}/adapters/qwik/index.d.ts +0 -0
- /package/{src → dist}/adapters/qwik.d.ts +0 -0
- /package/{src → dist}/adapters/react/index.d.ts +0 -0
- /package/{src → dist}/adapters/react.d.ts +0 -0
- /package/{src → dist}/adapters/solid/index.d.ts +0 -0
- /package/{src → dist}/adapters/solid.d.ts +0 -0
- /package/{src → dist}/adapters/stencil/index.d.ts +0 -0
- /package/{src → dist}/adapters/stencil.d.ts +0 -0
- /package/{src → dist}/adapters/stimulus/index.d.ts +0 -0
- /package/{src → dist}/adapters/stimulus.d.ts +0 -0
- /package/{src → dist}/adapters/svelte/index.d.ts +0 -0
- /package/{src → dist}/adapters/svelte.d.ts +0 -0
- /package/{src → dist}/adapters/vanilla/index.d.ts +0 -0
- /package/{src → dist}/adapters/vanilla.d.ts +0 -0
- /package/{src → dist}/adapters/vue/index.d.ts +0 -0
- /package/{src → dist}/adapters/vue.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wu-ai.js","sources":["../../src/ai/wu-ai-provider.js","../../src/ai/wu-ai-permissions.js","../../src/ai/wu-ai-schema.js","../../src/ai/wu-ai-context.js","../../src/ai/wu-ai-actions.js","../../src/ai/wu-ai-conversation.js","../../src/ai/wu-ai-triggers.js","../../src/ai/wu-ai-agent.js","../../src/ai/wu-ai-orchestrate.js","../../src/ai/wu-ai.js","../../src/ai/wu-ai-browser.js"],"sourcesContent":["/**\r\n * WU-AI-PROVIDER: BYOL (Bring Your Own LLM) provider system\r\n *\r\n * Pure fetch(), zero dependencies. Adapters normalize request/response\r\n * across OpenAI, Anthropic, Ollama, and custom providers.\r\n *\r\n * Internal normalized format:\r\n * Request: { role, content, tool_calls?, tool_call_id? }\r\n * Response: { content, tool_calls?, usage? }\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\n\r\n// ─── Normalized types (internal) ─────────────────────────────────\r\n//\r\n// Message: { role: 'system'|'user'|'assistant'|'tool', content: string,\r\n// tool_calls?: ToolCall[], tool_call_id?: string }\r\n//\r\n// ToolCall: { id: string, name: string, arguments: object }\r\n//\r\n// Response: { content: string, tool_calls?: ToolCall[], usage?: { prompt_tokens, completion_tokens } }\r\n//\r\n// StreamChunk: { type: 'text'|'tool_call'|'done'|'error', content?: string,\r\n// tool_call?: ToolCall, usage?: object, error?: string }\r\n\r\n// ─── Base Adapter ────────────────────────────────────────────────\r\n\r\nclass BaseAdapter {\r\n constructor(config = {}) {\r\n this.model = config.model || '';\r\n }\r\n\r\n /** Format messages + options into provider-specific request body */\r\n formatRequest(/* messages, options */) {\r\n throw new Error('Adapter must implement formatRequest()');\r\n }\r\n\r\n /** Parse provider response into normalized Response */\r\n parseResponse(/* rawData */) {\r\n throw new Error('Adapter must implement parseResponse()');\r\n }\r\n\r\n /** Parse a streaming SSE line into a StreamChunk (or null to skip) */\r\n parseStreamChunk(/* line */) {\r\n throw new Error('Adapter must implement parseStreamChunk()');\r\n }\r\n\r\n /** Get required headers for the provider */\r\n getHeaders(/* config */) {\r\n return { 'Content-Type': 'application/json' };\r\n }\r\n}\r\n\r\n// ─── OpenAI Adapter ──────────────────────────────────────────────\r\n\r\nclass OpenAIAdapter extends BaseAdapter {\r\n constructor(config) {\r\n super(config);\r\n this.model = config.model || 'gpt-4o';\r\n }\r\n\r\n getHeaders(config) {\r\n const h = { 'Content-Type': 'application/json' };\r\n if (config.apiKey) h['Authorization'] = `Bearer ${config.apiKey}`;\r\n return h;\r\n }\r\n\r\n formatRequest(messages, options = {}) {\r\n const body = {\r\n model: options.model || this.model,\r\n messages: messages.map(m => {\r\n const msg = { role: m.role, content: m.content };\r\n if (m.tool_call_id) msg.tool_call_id = m.tool_call_id;\r\n if (m.tool_calls) msg.tool_calls = m.tool_calls.map(tc => ({\r\n id: tc.id,\r\n type: 'function',\r\n function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },\r\n }));\r\n return msg;\r\n }),\r\n };\r\n if (options.tools?.length) {\r\n body.tools = options.tools.map(t => ({\r\n type: 'function',\r\n function: { name: t.name, description: t.description, parameters: t.parameters },\r\n }));\r\n }\r\n if (options.temperature !== undefined) body.temperature = options.temperature;\r\n if (options.maxTokens) body.max_tokens = options.maxTokens;\r\n if (options.stream) body.stream = true;\r\n\r\n // Structured output / JSON mode\r\n if (options.responseFormat) {\r\n const rf = options.responseFormat;\r\n if (rf === 'json' || rf?.type === 'json_object') {\r\n body.response_format = { type: 'json_object' };\r\n } else if (rf?.type === 'json_schema') {\r\n body.response_format = {\r\n type: 'json_schema',\r\n json_schema: {\r\n name: rf.name || 'response',\r\n schema: rf.schema,\r\n strict: rf.strict !== false,\r\n },\r\n };\r\n }\r\n }\r\n\r\n return body;\r\n }\r\n\r\n parseResponse(data) {\r\n const choice = data.choices?.[0];\r\n if (!choice) return { content: '', tool_calls: [], usage: data.usage };\r\n\r\n const msg = choice.message || {};\r\n const toolCalls = (msg.tool_calls || []).map(tc => ({\r\n id: tc.id,\r\n name: tc.function?.name,\r\n arguments: this._safeParseArgs(tc.function?.arguments),\r\n }));\r\n\r\n return {\r\n content: msg.content || '',\r\n tool_calls: toolCalls.length > 0 ? toolCalls : undefined,\r\n usage: data.usage ? {\r\n prompt_tokens: data.usage.prompt_tokens,\r\n completion_tokens: data.usage.completion_tokens,\r\n } : undefined,\r\n };\r\n }\r\n\r\n parseStreamChunk(line) {\r\n if (!line.startsWith('data: ')) return null;\r\n const raw = line.slice(6).trim();\r\n if (raw === '[DONE]') return { type: 'done' };\r\n\r\n try {\r\n const data = JSON.parse(raw);\r\n const delta = data.choices?.[0]?.delta;\r\n if (!delta) return null;\r\n\r\n if (delta.tool_calls?.length) {\r\n const tc = delta.tool_calls[0];\r\n return {\r\n type: 'tool_call_delta',\r\n index: tc.index,\r\n id: tc.id,\r\n name: tc.function?.name,\r\n argumentsDelta: tc.function?.arguments || '',\r\n };\r\n }\r\n\r\n if (delta.content) {\r\n return { type: 'text', content: delta.content };\r\n }\r\n\r\n if (data.usage) {\r\n return { type: 'usage', usage: data.usage };\r\n }\r\n\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n _safeParseArgs(str) {\r\n if (!str) return {};\r\n try { return JSON.parse(str); } catch { return {}; }\r\n }\r\n}\r\n\r\n// ─── Anthropic Adapter ───────────────────────────────────────────\r\n\r\nclass AnthropicAdapter extends BaseAdapter {\r\n constructor(config) {\r\n super(config);\r\n this.model = config.model || 'claude-sonnet-4-5-20250929';\r\n }\r\n\r\n getHeaders(config) {\r\n const h = { 'Content-Type': 'application/json' };\r\n if (config.apiKey) {\r\n h['x-api-key'] = config.apiKey;\r\n h['anthropic-version'] = '2023-06-01';\r\n }\r\n return h;\r\n }\r\n\r\n formatRequest(messages, options = {}) {\r\n // Anthropic separates system from messages\r\n const systemMsgs = messages.filter(m => m.role === 'system');\r\n const otherMsgs = messages.filter(m => m.role !== 'system');\r\n\r\n const body = {\r\n model: options.model || this.model,\r\n max_tokens: options.maxTokens || 4096,\r\n messages: otherMsgs.map(m => {\r\n if (m.role === 'tool') {\r\n return {\r\n role: 'user',\r\n content: [{\r\n type: 'tool_result',\r\n tool_use_id: m.tool_call_id,\r\n content: m.content,\r\n }],\r\n };\r\n }\r\n if (m.tool_calls) {\r\n return {\r\n role: 'assistant',\r\n content: m.tool_calls.map(tc => ({\r\n type: 'tool_use',\r\n id: tc.id,\r\n name: tc.name,\r\n input: tc.arguments,\r\n })),\r\n };\r\n }\r\n return { role: m.role, content: m.content };\r\n }),\r\n };\r\n\r\n if (systemMsgs.length) {\r\n body.system = systemMsgs.map(m => m.content).join('\\n\\n');\r\n }\r\n\r\n // Structured output / JSON mode (Anthropic has no native support)\r\n // Strategy: augment system prompt + prefill assistant turn with '{'\r\n if (options.responseFormat) {\r\n const rf = options.responseFormat;\r\n const jsonInstruction = '\\n\\nYou MUST respond with valid JSON only. No markdown, no explanation.';\r\n\r\n if (rf === 'json' || rf?.type === 'json_object') {\r\n body.system = (body.system || '') + jsonInstruction;\r\n } else if (rf?.type === 'json_schema') {\r\n const schemaStr = JSON.stringify(rf.schema, null, 2);\r\n body.system = (body.system || '') +\r\n jsonInstruction +\r\n `\\n\\nYour response MUST conform to this JSON schema:\\n${schemaStr}`;\r\n }\r\n\r\n // Prefill assistant message with '{' to force JSON output\r\n body.messages.push({ role: 'assistant', content: '{' });\r\n }\r\n\r\n if (options.tools?.length) {\r\n body.tools = options.tools.map(t => ({\r\n name: t.name,\r\n description: t.description,\r\n input_schema: t.parameters,\r\n }));\r\n }\r\n if (options.temperature !== undefined) body.temperature = options.temperature;\r\n if (options.stream) body.stream = true;\r\n return body;\r\n }\r\n\r\n parseResponse(data) {\r\n const textBlocks = (data.content || []).filter(b => b.type === 'text');\r\n const toolBlocks = (data.content || []).filter(b => b.type === 'tool_use');\r\n\r\n const content = textBlocks.map(b => b.text).join('');\r\n const toolCalls = toolBlocks.map(b => ({\r\n id: b.id,\r\n name: b.name,\r\n arguments: b.input || {},\r\n }));\r\n\r\n return {\r\n content,\r\n tool_calls: toolCalls.length > 0 ? toolCalls : undefined,\r\n usage: data.usage ? {\r\n prompt_tokens: data.usage.input_tokens,\r\n completion_tokens: data.usage.output_tokens,\r\n } : undefined,\r\n };\r\n }\r\n\r\n parseStreamChunk(line) {\r\n if (!line.startsWith('data: ')) return null;\r\n const raw = line.slice(6).trim();\r\n\r\n try {\r\n const data = JSON.parse(raw);\r\n\r\n if (data.type === 'content_block_delta') {\r\n if (data.delta?.type === 'text_delta') {\r\n return { type: 'text', content: data.delta.text };\r\n }\r\n if (data.delta?.type === 'input_json_delta') {\r\n return { type: 'tool_call_delta', argumentsDelta: data.delta.partial_json || '' };\r\n }\r\n }\r\n\r\n if (data.type === 'content_block_start' && data.content_block?.type === 'tool_use') {\r\n return {\r\n type: 'tool_call_start',\r\n id: data.content_block.id,\r\n name: data.content_block.name,\r\n };\r\n }\r\n\r\n if (data.type === 'message_delta' && data.usage) {\r\n return {\r\n type: 'usage',\r\n usage: { prompt_tokens: data.usage.input_tokens, completion_tokens: data.usage.output_tokens },\r\n };\r\n }\r\n\r\n if (data.type === 'message_stop') {\r\n return { type: 'done' };\r\n }\r\n\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n// ─── Ollama Adapter ──────────────────────────────────────────────\r\n\r\nclass OllamaAdapter extends BaseAdapter {\r\n constructor(config) {\r\n super(config);\r\n this.model = config.model || 'llama3';\r\n }\r\n\r\n getHeaders() {\r\n return { 'Content-Type': 'application/json' };\r\n }\r\n\r\n formatRequest(messages, options = {}) {\r\n const body = {\r\n model: options.model || this.model,\r\n messages: messages.map(m => ({ role: m.role, content: m.content })),\r\n };\r\n if (options.tools?.length) {\r\n body.tools = options.tools.map(t => ({\r\n type: 'function',\r\n function: { name: t.name, description: t.description, parameters: t.parameters },\r\n }));\r\n }\r\n if (options.temperature !== undefined) body.options = { temperature: options.temperature };\r\n if (options.stream !== undefined) body.stream = options.stream;\r\n\r\n // Structured output / JSON mode\r\n if (options.responseFormat) {\r\n const rf = options.responseFormat;\r\n if (rf === 'json' || rf?.type === 'json_object') {\r\n body.format = 'json';\r\n } else if (rf?.type === 'json_schema') {\r\n body.format = rf.schema;\r\n }\r\n }\r\n\r\n return body;\r\n }\r\n\r\n parseResponse(data) {\r\n const msg = data.message || {};\r\n const toolCalls = (msg.tool_calls || []).map((tc, i) => ({\r\n id: `ollama_${i}_${Date.now()}`,\r\n name: tc.function?.name,\r\n arguments: tc.function?.arguments || {},\r\n }));\r\n\r\n return {\r\n content: msg.content || '',\r\n tool_calls: toolCalls.length > 0 ? toolCalls : undefined,\r\n usage: data.eval_count ? {\r\n prompt_tokens: data.prompt_eval_count || 0,\r\n completion_tokens: data.eval_count || 0,\r\n } : undefined,\r\n };\r\n }\r\n\r\n parseStreamChunk(line) {\r\n try {\r\n const data = JSON.parse(line);\r\n if (data.done) return { type: 'done' };\r\n if (data.message?.content) return { type: 'text', content: data.message.content };\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n// ─── Custom Adapter (user-provided send/stream) ──────────────────\r\n\r\nclass CustomAdapter extends BaseAdapter {\r\n constructor(config) {\r\n super(config);\r\n this._sendFn = config.send || null;\r\n this._streamFn = config.stream || null;\r\n }\r\n\r\n /** Custom adapters bypass formatRequest/parseResponse */\r\n get isCustom() { return true; }\r\n}\r\n\r\n// ─── Provider Registry ───────────────────────────────────────────\r\n\r\nconst BUILTIN_ADAPTERS = {\r\n openai: OpenAIAdapter,\r\n anthropic: AnthropicAdapter,\r\n ollama: OllamaAdapter,\r\n};\r\n\r\n// ─── Main Provider Class ─────────────────────────────────────────\r\n\r\nexport class WuAIProvider {\r\n constructor() {\r\n this._providers = new Map();\r\n this._active = null;\r\n this._activeName = null;\r\n this._activeConfig = {};\r\n this._retryConfig = { maxRetries: 3, baseDelayMs: 1000 };\r\n }\r\n\r\n /**\r\n * Register and activate a provider.\r\n *\r\n * @param {string} name - Provider name or built-in adapter ('openai', 'anthropic', 'ollama', 'custom')\r\n * @param {object} config - Provider configuration\r\n * @param {string} [config.endpoint] - API endpoint URL\r\n * @param {string} [config.adapter] - Built-in adapter name (if name is custom)\r\n * @param {string} [config.apiKey] - API key (WARNING: exposed in browser)\r\n * @param {string} [config.model] - Model name\r\n * @param {Function} [config.send] - Custom send function\r\n * @param {Function} [config.stream] - Custom stream generator function\r\n */\r\n register(name, config = {}) {\r\n const adapterName = config.adapter || name;\r\n const AdapterClass = BUILTIN_ADAPTERS[adapterName];\r\n\r\n let adapter;\r\n if (config.send || config.stream) {\r\n adapter = new CustomAdapter(config);\r\n } else if (AdapterClass) {\r\n adapter = new AdapterClass(config);\r\n } else {\r\n throw new Error(\r\n `[wu-ai] Unknown adapter '${adapterName}'. ` +\r\n `Available: ${Object.keys(BUILTIN_ADAPTERS).join(', ')}, or provide custom send/stream.`\r\n );\r\n }\r\n\r\n this._providers.set(name, { adapter, config });\r\n\r\n // Auto-activate if first provider or explicitly active\r\n if (!this._active || config.active !== false) {\r\n this._active = adapter;\r\n this._activeName = name;\r\n this._activeConfig = config;\r\n }\r\n\r\n logger.wuInfo(`[wu-ai] Provider registered: '${name}' (adapter: ${adapterName})`);\r\n }\r\n\r\n /**\r\n * Switch active provider.\r\n */\r\n use(name) {\r\n const entry = this._providers.get(name);\r\n if (!entry) throw new Error(`[wu-ai] Provider '${name}' not registered`);\r\n this._active = entry.adapter;\r\n this._activeName = name;\r\n this._activeConfig = entry.config;\r\n }\r\n\r\n /**\r\n * Send a non-streaming request.\r\n *\r\n * @param {Array} messages - Normalized messages\r\n * @param {object} [options] - { tools, temperature, maxTokens, signal }\r\n * @returns {Promise<{ content: string, tool_calls?: Array, usage?: object }>}\r\n */\r\n async send(messages, options = {}) {\r\n const { adapter, config } = this._resolveProvider(options.provider);\r\n\r\n // Custom adapter: call user function directly\r\n if (adapter.isCustom && adapter._sendFn) {\r\n return adapter._sendFn(messages, options);\r\n }\r\n\r\n const endpoint = config.endpoint || config.baseUrl;\r\n if (!endpoint) {\r\n throw new Error('[wu-ai] No endpoint configured. Set config.endpoint or config.baseUrl.');\r\n }\r\n\r\n const url = this._resolveUrl(endpoint);\r\n const body = adapter.formatRequest(messages, { ...options, stream: false });\r\n const headers = adapter.getHeaders(config);\r\n\r\n const response = await this._fetchWithRetry(url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(body),\r\n signal: options.signal,\r\n });\r\n\r\n const data = await response.json();\r\n const result = adapter.parseResponse(data);\r\n\r\n // Anthropic prefill compensation: we prepended '{' to force JSON,\r\n // so the response content is the continuation — restore the full JSON\r\n if (adapter instanceof AnthropicAdapter && options.responseFormat && result.content) {\r\n result.content = '{' + result.content;\r\n }\r\n\r\n // Validate JSON when responseFormat was requested\r\n if (options.responseFormat && result.content) {\r\n try {\r\n result.parsed = JSON.parse(result.content);\r\n } catch {\r\n result.parseError = 'Response is not valid JSON';\r\n logger.wuDebug('[wu-ai] responseFormat requested but LLM returned invalid JSON');\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Send a streaming request. Returns an async generator of chunks.\r\n *\r\n * @param {Array} messages - Normalized messages\r\n * @param {object} [options] - { tools, temperature, maxTokens, signal }\r\n * @yields {StreamChunk}\r\n */\r\n async *stream(messages, options = {}) {\r\n const { adapter, config } = this._resolveProvider(options.provider);\r\n\r\n // Custom adapter: call user generator directly\r\n if (adapter.isCustom && adapter._streamFn) {\r\n yield* adapter._streamFn(messages, options);\r\n return;\r\n }\r\n\r\n const endpoint = config.endpoint || config.baseUrl;\r\n if (!endpoint) {\r\n throw new Error('[wu-ai] No endpoint configured. Set config.endpoint or config.baseUrl.');\r\n }\r\n\r\n const url = this._resolveUrl(endpoint);\r\n const body = adapter.formatRequest(messages, { ...options, stream: true });\r\n const headers = adapter.getHeaders(config);\r\n\r\n const response = await fetch(url, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(body),\r\n signal: options.signal,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`[wu-ai] Stream request failed: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n // Anthropic prefill compensation for streaming:\r\n // emit the '{' we used as prefill before the first real chunk\r\n let needsPrefill = adapter instanceof AnthropicAdapter && !!options.responseFormat;\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() || ''; // keep incomplete last line\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (!trimmed) continue;\r\n\r\n const chunk = adapter.parseStreamChunk(trimmed);\r\n if (chunk) {\r\n if (needsPrefill && chunk.type === 'text') {\r\n chunk.content = '{' + chunk.content;\r\n needsPrefill = false;\r\n }\r\n yield chunk;\r\n }\r\n if (chunk?.type === 'done') return;\r\n }\r\n }\r\n\r\n // Process remaining buffer\r\n if (buffer.trim()) {\r\n const chunk = adapter.parseStreamChunk(buffer.trim());\r\n if (chunk) yield chunk;\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n }\r\n\r\n // ── Retry logic ──\r\n\r\n async _fetchWithRetry(url, options) {\r\n let lastError;\r\n for (let attempt = 0; attempt <= this._retryConfig.maxRetries; attempt++) {\r\n try {\r\n const response = await fetch(url, options);\r\n\r\n // Only retry on 429 (rate limit) and 5xx\r\n if (response.ok) return response;\r\n\r\n if (response.status === 429 || response.status >= 500) {\r\n lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);\r\n if (attempt < this._retryConfig.maxRetries) {\r\n const delay = this._retryConfig.baseDelayMs * Math.pow(2, attempt);\r\n logger.wuDebug(`[wu-ai] Retry ${attempt + 1}/${this._retryConfig.maxRetries} in ${delay}ms (${response.status})`);\r\n await new Promise(r => setTimeout(r, delay));\r\n continue;\r\n }\r\n }\r\n\r\n // 4xx (except 429) — don't retry, fail immediately\r\n const clientError = new Error(`[wu-ai] Request failed: ${response.status} ${response.statusText}`);\r\n clientError._noRetry = true;\r\n throw clientError;\r\n } catch (err) {\r\n if (err.name === 'AbortError') throw err;\r\n if (err._noRetry) throw err; // 4xx — don't retry\r\n lastError = err;\r\n if (attempt < this._retryConfig.maxRetries) {\r\n const delay = this._retryConfig.baseDelayMs * Math.pow(2, attempt);\r\n await new Promise(r => setTimeout(r, delay));\r\n continue;\r\n }\r\n }\r\n }\r\n throw lastError;\r\n }\r\n\r\n // ── Helpers ──\r\n\r\n _resolveUrl(endpoint) {\r\n // Relative URLs (e.g., '/api/ai/chat') resolve against current origin\r\n if (endpoint.startsWith('/')) {\r\n return typeof window !== 'undefined'\r\n ? `${window.location.origin}${endpoint}`\r\n : endpoint;\r\n }\r\n return endpoint;\r\n }\r\n\r\n /**\r\n * Resolve which provider/adapter to use for a request.\r\n * Supports per-call selection: options.provider = 'anthropic'\r\n *\r\n * @param {string} [providerName] - Optional provider name override\r\n * @returns {{ adapter: BaseAdapter, config: object }}\r\n */\r\n _resolveProvider(providerName) {\r\n if (providerName) {\r\n const entry = this._providers.get(providerName);\r\n if (!entry) {\r\n throw new Error(`[wu-ai] Provider '${providerName}' not registered. Available: ${[...this._providers.keys()].join(', ')}`);\r\n }\r\n return { adapter: entry.adapter, config: entry.config };\r\n }\r\n this._ensureActive();\r\n return { adapter: this._active, config: this._activeConfig };\r\n }\r\n\r\n _ensureActive() {\r\n if (!this._active) {\r\n throw new Error(\r\n '[wu-ai] No provider configured. Call wu.ai.provider(\"name\", { endpoint, adapter }) first.'\r\n );\r\n }\r\n }\r\n\r\n configureRetry(config) {\r\n if (config.maxRetries !== undefined) this._retryConfig.maxRetries = config.maxRetries;\r\n if (config.baseDelayMs !== undefined) this._retryConfig.baseDelayMs = config.baseDelayMs;\r\n }\r\n\r\n getActiveProvider() {\r\n return this._activeName;\r\n }\r\n\r\n getStats() {\r\n return {\r\n activeProvider: this._activeName,\r\n registeredProviders: [...this._providers.keys()],\r\n };\r\n }\r\n}\r\n","/**\r\n * WU-AI-PERMISSIONS: Security, rate limiting, circuit breaker, loop protection\r\n *\r\n * 4-layer defense:\r\n * 1. Permission flags (readStore, writeStore, emitEvents, etc.)\r\n * 2. Rate limiting (per-minute, per-namespace, concurrent)\r\n * 3. Circuit breaker (CLOSED → OPEN → HALF-OPEN)\r\n * 4. Loop protection (depth counter + causal chain tracking)\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\n\r\n// ─── Permission Defaults ─────────────────────────────────────────\r\n\r\nconst DEFAULT_PERMISSIONS = {\r\n readStore: true,\r\n writeStore: false,\r\n emitEvents: true,\r\n readDOM: false,\r\n modifyDOM: false,\r\n executeActions: true,\r\n allowDirectKey: false,\r\n};\r\n\r\n// ─── Circuit Breaker States ──────────────────────────────────────\r\n\r\nconst CB_CLOSED = 'closed';\r\nconst CB_OPEN = 'open';\r\nconst CB_HALF_OPEN = 'half-open';\r\n\r\n// ─── Rate Limiter ────────────────────────────────────────────────\r\n\r\nclass RateLimiter {\r\n constructor(config = {}) {\r\n this._maxPerMinute = config.requestsPerMinute ?? 20;\r\n this._maxPerMinutePerNs = config.requestsPerMinutePerNs ?? 10;\r\n this._maxConcurrent = config.maxConcurrent ?? 3;\r\n\r\n this._globalTimestamps = [];\r\n this._nsTimestamps = new Map();\r\n this._concurrent = 0;\r\n }\r\n\r\n configure(config) {\r\n if (config.requestsPerMinute !== undefined) this._maxPerMinute = config.requestsPerMinute;\r\n if (config.requestsPerMinutePerNs !== undefined) this._maxPerMinutePerNs = config.requestsPerMinutePerNs;\r\n if (config.maxConcurrent !== undefined) this._maxConcurrent = config.maxConcurrent;\r\n }\r\n\r\n canSend(namespace = 'default') {\r\n this._pruneOld();\r\n\r\n if (this._concurrent >= this._maxConcurrent) {\r\n return { allowed: false, reason: `Max concurrent (${this._maxConcurrent}) reached` };\r\n }\r\n if (this._globalTimestamps.length >= this._maxPerMinute) {\r\n return { allowed: false, reason: `Global rate limit (${this._maxPerMinute}/min) exceeded` };\r\n }\r\n\r\n const nsTs = this._nsTimestamps.get(namespace) || [];\r\n if (nsTs.length >= this._maxPerMinutePerNs) {\r\n return { allowed: false, reason: `Namespace '${namespace}' rate limit (${this._maxPerMinutePerNs}/min) exceeded` };\r\n }\r\n\r\n return { allowed: true };\r\n }\r\n\r\n recordStart(namespace = 'default') {\r\n const now = Date.now();\r\n this._globalTimestamps.push(now);\r\n if (!this._nsTimestamps.has(namespace)) this._nsTimestamps.set(namespace, []);\r\n this._nsTimestamps.get(namespace).push(now);\r\n this._concurrent++;\r\n }\r\n\r\n recordEnd() {\r\n this._concurrent = Math.max(0, this._concurrent - 1);\r\n }\r\n\r\n _pruneOld() {\r\n const cutoff = Date.now() - 60000;\r\n this._globalTimestamps = this._globalTimestamps.filter(t => t > cutoff);\r\n for (const [ns, timestamps] of this._nsTimestamps) {\r\n const pruned = timestamps.filter(t => t > cutoff);\r\n if (pruned.length === 0) this._nsTimestamps.delete(ns);\r\n else this._nsTimestamps.set(ns, pruned);\r\n }\r\n }\r\n\r\n getStats() {\r\n this._pruneOld();\r\n return {\r\n globalRequestsLastMinute: this._globalTimestamps.length,\r\n concurrent: this._concurrent,\r\n maxPerMinute: this._maxPerMinute,\r\n maxConcurrent: this._maxConcurrent,\r\n };\r\n }\r\n}\r\n\r\n// ─── Circuit Breaker ─────────────────────────────────────────────\r\n\r\nclass CircuitBreaker {\r\n constructor(config = {}) {\r\n this._state = CB_CLOSED;\r\n this._failureCount = 0;\r\n this._maxFailures = config.maxFailures ?? 3;\r\n this._cooldownMs = config.cooldownMs ?? 30000;\r\n this._openedAt = 0;\r\n this._rapidFireThreshold = config.rapidFireThreshold ?? 5;\r\n this._rapidFireWindowMs = config.rapidFireWindowMs ?? 2000;\r\n this._recentRequests = [];\r\n }\r\n\r\n configure(config) {\r\n if (config.maxFailures !== undefined) this._maxFailures = config.maxFailures;\r\n if (config.cooldownMs !== undefined) this._cooldownMs = config.cooldownMs;\r\n }\r\n\r\n canPass() {\r\n if (this._state === CB_CLOSED) return { allowed: true };\r\n\r\n if (this._state === CB_OPEN) {\r\n if (Date.now() - this._openedAt >= this._cooldownMs) {\r\n this._state = CB_HALF_OPEN;\r\n logger.wuDebug('[wu-ai] Circuit breaker → HALF-OPEN (testing)');\r\n return { allowed: true };\r\n }\r\n const remainingMs = this._cooldownMs - (Date.now() - this._openedAt);\r\n return { allowed: false, reason: `Circuit breaker OPEN (${Math.ceil(remainingMs / 1000)}s remaining)` };\r\n }\r\n\r\n // HALF-OPEN: allow one request through\r\n return { allowed: true };\r\n }\r\n\r\n recordSuccess() {\r\n if (this._state === CB_HALF_OPEN) {\r\n this._state = CB_CLOSED;\r\n this._failureCount = 0;\r\n logger.wuInfo('[wu-ai] Circuit breaker → CLOSED (recovered)');\r\n } else {\r\n this._failureCount = 0;\r\n }\r\n this._recordRequest();\r\n }\r\n\r\n recordFailure() {\r\n this._failureCount++;\r\n this._recordRequest();\r\n\r\n if (this._state === CB_HALF_OPEN) {\r\n this._tripOpen('Failed during half-open test');\r\n return;\r\n }\r\n\r\n if (this._failureCount >= this._maxFailures) {\r\n this._tripOpen(`${this._failureCount} consecutive failures`);\r\n }\r\n }\r\n\r\n _recordRequest() {\r\n const now = Date.now();\r\n this._recentRequests.push(now);\r\n this._recentRequests = this._recentRequests.filter(t => now - t < this._rapidFireWindowMs);\r\n\r\n if (this._state === CB_CLOSED && this._recentRequests.length >= this._rapidFireThreshold) {\r\n this._tripOpen(`${this._recentRequests.length} requests in ${this._rapidFireWindowMs}ms (rapid fire)`);\r\n }\r\n }\r\n\r\n _tripOpen(reason) {\r\n this._state = CB_OPEN;\r\n this._openedAt = Date.now();\r\n logger.wuWarn(`[wu-ai] Circuit breaker → OPEN: ${reason}. Cooldown: ${this._cooldownMs / 1000}s`);\r\n }\r\n\r\n getState() {\r\n return this._state;\r\n }\r\n\r\n getStats() {\r\n return {\r\n state: this._state,\r\n failureCount: this._failureCount,\r\n maxFailures: this._maxFailures,\r\n cooldownMs: this._cooldownMs,\r\n openedAt: this._openedAt,\r\n };\r\n }\r\n\r\n reset() {\r\n this._state = CB_CLOSED;\r\n this._failureCount = 0;\r\n this._openedAt = 0;\r\n this._recentRequests = [];\r\n }\r\n}\r\n\r\n// ─── Loop Protection ─────────────────────────────────────────────\r\n\r\nclass LoopProtection {\r\n constructor(config = {}) {\r\n this._maxDepth = config.maxDepth ?? 3;\r\n this._activeTraces = new Map(); // traceId → count\r\n this._traceLog = []; // last N traces for debugging\r\n this._maxTraceLog = 50;\r\n }\r\n\r\n configure(config) {\r\n if (config.maxDepth !== undefined) this._maxDepth = config.maxDepth;\r\n }\r\n\r\n /**\r\n * Check if a request at the given depth/trace is allowed.\r\n * @param {number} depth - Current AI depth\r\n * @param {string} traceId - Causal chain trace ID\r\n * @returns {{ allowed: boolean, reason?: string }}\r\n */\r\n canProceed(depth, traceId) {\r\n if (depth > this._maxDepth) {\r\n return { allowed: false, reason: `Max AI depth (${this._maxDepth}) exceeded at depth ${depth}` };\r\n }\r\n\r\n if (traceId) {\r\n const count = (this._activeTraces.get(traceId) || 0) + 1;\r\n if (count > this._maxDepth) {\r\n return { allowed: false, reason: `Causal chain '${traceId}' looped ${count} times (max ${this._maxDepth})` };\r\n }\r\n }\r\n\r\n return { allowed: true };\r\n }\r\n\r\n /**\r\n * Record that a trace is being processed.\r\n */\r\n enter(traceId) {\r\n if (!traceId) return;\r\n const count = (this._activeTraces.get(traceId) || 0) + 1;\r\n this._activeTraces.set(traceId, count);\r\n\r\n this._traceLog.push({ traceId, count, timestamp: Date.now() });\r\n if (this._traceLog.length > this._maxTraceLog) {\r\n this._traceLog.shift();\r\n }\r\n }\r\n\r\n /**\r\n * Record that a trace finished processing.\r\n */\r\n exit(traceId) {\r\n if (!traceId) return;\r\n const count = (this._activeTraces.get(traceId) || 0) - 1;\r\n if (count <= 0) this._activeTraces.delete(traceId);\r\n else this._activeTraces.set(traceId, count);\r\n }\r\n\r\n /**\r\n * Generate a new trace ID.\r\n */\r\n createTraceId() {\r\n return `t_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\r\n }\r\n\r\n getTraces() {\r\n return [...this._traceLog];\r\n }\r\n\r\n getStats() {\r\n return {\r\n maxDepth: this._maxDepth,\r\n activeTraces: this._activeTraces.size,\r\n traceLogSize: this._traceLog.length,\r\n };\r\n }\r\n}\r\n\r\n// ─── Main Permissions Class ──────────────────────────────────────\r\n\r\nexport class WuAIPermissions {\r\n constructor(config = {}) {\r\n this._permissions = { ...DEFAULT_PERMISSIONS };\r\n this.rateLimiter = new RateLimiter(config.rateLimit);\r\n this.circuitBreaker = new CircuitBreaker(config.circuitBreaker);\r\n this.loopProtection = new LoopProtection(config.loopProtection);\r\n this._allowedDomains = config.allowedDomains || [];\r\n\r\n if (config.permissions) {\r\n this.configure(config.permissions);\r\n }\r\n }\r\n\r\n // ── Permission checks ──\r\n\r\n configure(permissions) {\r\n Object.assign(this._permissions, permissions);\r\n\r\n // HARD BLOCK: never allow direct API key in production\r\n if (this._isProduction() && this._permissions.allowDirectKey) {\r\n logger.wuWarn('[wu-ai] allowDirectKey FORCED to false in production');\r\n this._permissions.allowDirectKey = false;\r\n }\r\n }\r\n\r\n check(permission) {\r\n return this._permissions[permission] === true;\r\n }\r\n\r\n getPermissions() {\r\n return { ...this._permissions };\r\n }\r\n\r\n // ── Domain whitelist for action fetch ──\r\n\r\n setAllowedDomains(domains) {\r\n this._allowedDomains = domains;\r\n }\r\n\r\n isDomainAllowed(url) {\r\n if (this._allowedDomains.length === 0) return true;\r\n try {\r\n const hostname = new URL(url).hostname;\r\n return this._allowedDomains.some(pattern => {\r\n if (pattern.startsWith('*.')) {\r\n const suffix = pattern.slice(2);\r\n return hostname === suffix || hostname.endsWith('.' + suffix);\r\n }\r\n return hostname === pattern;\r\n });\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n // ── Full pre-flight check ──\r\n\r\n /**\r\n * Run all checks before sending an AI request.\r\n * @param {{ namespace?: string, depth?: number, traceId?: string }} meta\r\n * @returns {{ allowed: boolean, reason?: string }}\r\n */\r\n preflight(meta = {}) {\r\n // 1. Circuit breaker\r\n const cb = this.circuitBreaker.canPass();\r\n if (!cb.allowed) return cb;\r\n\r\n // 2. Rate limiter\r\n const rl = this.rateLimiter.canSend(meta.namespace);\r\n if (!rl.allowed) return rl;\r\n\r\n // 3. Loop protection\r\n const lp = this.loopProtection.canProceed(meta.depth || 0, meta.traceId);\r\n if (!lp.allowed) return lp;\r\n\r\n return { allowed: true };\r\n }\r\n\r\n // ── Stats ──\r\n\r\n getStats() {\r\n return {\r\n permissions: { ...this._permissions },\r\n rateLimiter: this.rateLimiter.getStats(),\r\n circuitBreaker: this.circuitBreaker.getStats(),\r\n loopProtection: this.loopProtection.getStats(),\r\n allowedDomains: [...this._allowedDomains],\r\n };\r\n }\r\n\r\n // ── Private ──\r\n\r\n _isProduction() {\r\n if (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production') return true;\r\n if (typeof window !== 'undefined') {\r\n const h = window.location?.hostname || '';\r\n return h !== 'localhost' && h !== '127.0.0.1' && h !== '0.0.0.0' && !h.endsWith('.local');\r\n }\r\n return false;\r\n }\r\n}\r\n","/**\r\n * WU-AI-SCHEMA: Tool schema generation for function calling\r\n *\r\n * Converts wu.ai.action() definitions into the canonical tool format\r\n * that providers consume. Also handles input sanitization for prompts.\r\n *\r\n * Canonical tool format:\r\n * { name: string, description: string, parameters: JSONSchema }\r\n */\r\n\r\n// ─── Sanitization ────────────────────────────────────────────────\r\n\r\nconst SENSITIVE_KEYS = ['password', 'token', 'apiKey', 'secret', 'credential', 'authorization', 'cookie', 'session'];\r\n\r\n/**\r\n * Sanitize data before injecting into prompts.\r\n * Prevents prompt injection and redacts sensitive fields.\r\n *\r\n * @param {*} data - Any value to sanitize\r\n * @param {number} [maxChars=2000] - Max chars per value\r\n * @returns {string} Safe string representation\r\n */\r\nexport function sanitizeForPrompt(data, maxChars = 2000) {\r\n if (data === null || data === undefined) return 'null';\r\n if (typeof data === 'function') return '[Function]';\r\n if (typeof data === 'symbol') return '[Symbol]';\r\n\r\n if (typeof data === 'string') {\r\n const truncated = data.length > maxChars ? data.slice(0, maxChars) + '...[truncated]' : data;\r\n return `<user_data>${truncated}</user_data>`;\r\n }\r\n\r\n if (typeof data === 'number' || typeof data === 'boolean') {\r\n return String(data);\r\n }\r\n\r\n if (typeof data === 'object') {\r\n const redacted = redactSensitive(data);\r\n const json = JSON.stringify(redacted);\r\n if (json.length > maxChars) {\r\n return `<user_data>${json.slice(0, maxChars)}...[truncated]</user_data>`;\r\n }\r\n return `<user_data>${json}</user_data>`;\r\n }\r\n\r\n return String(data).slice(0, maxChars);\r\n}\r\n\r\n/**\r\n * Deep-clone an object, replacing sensitive keys with [REDACTED].\r\n *\r\n * @param {*} obj\r\n * @param {number} [depth=0]\r\n * @returns {*}\r\n */\r\nexport function redactSensitive(obj, depth = 0) {\r\n if (depth > 10) return '[MAX_DEPTH]';\r\n if (obj === null || obj === undefined) return obj;\r\n if (typeof obj !== 'object') return obj;\r\n\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => redactSensitive(item, depth + 1));\r\n }\r\n\r\n const result = {};\r\n for (const [key, value] of Object.entries(obj)) {\r\n const lowerKey = key.toLowerCase();\r\n if (SENSITIVE_KEYS.some(sk => lowerKey.includes(sk.toLowerCase()))) {\r\n result[key] = '[REDACTED]';\r\n } else {\r\n result[key] = redactSensitive(value, depth + 1);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n// ─── Template Interpolation ──────────────────────────────────────\r\n\r\n/**\r\n * Interpolate {{var}} placeholders in a template string.\r\n * Supports dot-notation: {{data.user.name}}\r\n *\r\n * @param {string} template\r\n * @param {object} vars - Variable map { data: ..., context: ... }\r\n * @returns {string}\r\n */\r\nexport function interpolate(template, vars) {\r\n return template.replace(/\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g, (_match, path) => {\r\n const value = path.split('.').reduce((obj, key) => obj?.[key], vars);\r\n if (value === undefined || value === null) return '';\r\n if (typeof value === 'object') return sanitizeForPrompt(value);\r\n return String(value);\r\n });\r\n}\r\n\r\n// ─── Tool Schema Builder ─────────────────────────────────────────\r\n\r\n/**\r\n * Build canonical tool definitions from registered actions.\r\n *\r\n * @param {Map<string, object>} actions - Map of action name → config\r\n * @returns {Array<{ name: string, description: string, parameters: object }>}\r\n */\r\nexport function buildToolSchemas(actions) {\r\n const tools = [];\r\n\r\n for (const [name, config] of actions) {\r\n tools.push({\r\n name,\r\n description: config.description || `Execute action: ${name}`,\r\n parameters: normalizeParameters(config.parameters),\r\n });\r\n }\r\n\r\n return tools;\r\n}\r\n\r\n/**\r\n * Normalize user-provided parameter definitions into JSON Schema.\r\n *\r\n * Accepts two formats:\r\n * 1. Full JSON Schema: { type: 'object', properties: {...}, required: [...] }\r\n * 2. Shorthand: { message: { type: 'string', required: true }, count: { type: 'number' } }\r\n *\r\n * @param {object} params\r\n * @returns {object} Valid JSON Schema\r\n */\r\nexport function normalizeParameters(params) {\r\n if (!params || typeof params !== 'object') {\r\n return { type: 'object', properties: {}, required: [] };\r\n }\r\n\r\n // Already a JSON Schema\r\n if (params.type === 'object' && params.properties) {\r\n return params;\r\n }\r\n\r\n // Shorthand format — convert\r\n const properties = {};\r\n const required = [];\r\n\r\n for (const [key, def] of Object.entries(params)) {\r\n if (typeof def === 'string') {\r\n // Simplest: { message: 'string' }\r\n properties[key] = { type: def };\r\n } else if (typeof def === 'object') {\r\n const { required: isRequired, ...rest } = def;\r\n properties[key] = rest.type ? rest : { type: 'string', ...rest };\r\n if (isRequired) required.push(key);\r\n }\r\n }\r\n\r\n return { type: 'object', properties, required };\r\n}\r\n\r\n/**\r\n * Validate params against a JSON Schema (lightweight, no external deps).\r\n * Only checks type, required, and enum — not full JSON Schema validation.\r\n *\r\n * @param {object} params - Actual params from LLM\r\n * @param {object} schema - JSON Schema from normalizeParameters()\r\n * @returns {{ valid: boolean, errors: string[] }}\r\n */\r\nexport function validateParams(params, schema) {\r\n const errors = [];\r\n if (!schema || !schema.properties) return { valid: true, errors };\r\n\r\n // Check required\r\n for (const key of (schema.required || [])) {\r\n if (params[key] === undefined || params[key] === null) {\r\n errors.push(`'${key}' is required`);\r\n }\r\n }\r\n\r\n // Check types and enums\r\n for (const [key, def] of Object.entries(schema.properties)) {\r\n const value = params[key];\r\n if (value === undefined || value === null) continue;\r\n\r\n if (def.type && def.type !== 'any') {\r\n const actualType = Array.isArray(value) ? 'array' : typeof value;\r\n if (def.type === 'integer') {\r\n if (typeof value !== 'number' || !Number.isInteger(value)) {\r\n errors.push(`'${key}' must be integer, got ${actualType}`);\r\n }\r\n } else if (def.type !== actualType) {\r\n errors.push(`'${key}' must be ${def.type}, got ${actualType}`);\r\n }\r\n }\r\n\r\n if (def.enum && !def.enum.includes(value)) {\r\n errors.push(`'${key}' must be one of [${def.enum.join(', ')}], got '${value}'`);\r\n }\r\n }\r\n\r\n return { valid: errors.length === 0, errors };\r\n}\r\n\r\n// ─── Context Budget ──────────────────────────────────────────────\r\n\r\n/**\r\n * Estimate token count from character count.\r\n * Rough heuristic: 1 token ≈ 4 chars for English, ≈ 2 chars for CJK.\r\n *\r\n * @param {string} text\r\n * @param {number} [charRatio=4]\r\n * @returns {number}\r\n */\r\nexport function estimateTokens(text, charRatio = 4) {\r\n return Math.ceil(text.length / charRatio);\r\n}\r\n\r\n/**\r\n * Truncate text to fit within a token budget.\r\n *\r\n * @param {string} text\r\n * @param {number} maxTokens\r\n * @param {number} [charRatio=4]\r\n * @returns {string}\r\n */\r\nexport function truncateToTokenBudget(text, maxTokens, charRatio = 4) {\r\n const maxChars = maxTokens * charRatio;\r\n if (text.length <= maxChars) return text;\r\n return text.slice(0, maxChars) + '\\n...[truncated to fit token budget]';\r\n}\r\n","/**\r\n * WU-AI-CONTEXT: Automatic context collector for LLMs\r\n *\r\n * Collects state from wu.store, wu.eventBus, and registered apps.\r\n * Builds a structured context object and system prompt for the LLM.\r\n *\r\n * Key design:\r\n * - ON-DEMAND collection (no polling, zero CPU idle)\r\n * - Token budget with priority (high > medium > low)\r\n * - Sensitive data redaction\r\n * - System prompt generation\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\nimport { redactSensitive, estimateTokens, truncateToTokenBudget } from './wu-ai-schema.js';\r\n\r\n// ─── Context Source Config ───────────────────────────────────────\r\n//\r\n// store: { include: ['user.*', 'cart.*'], priority: 'high' }\r\n// events: { include: ['cart:*', 'user:*'], lastN: 10, priority: 'medium' }\r\n// custom: [{ key: 'appVersion', value: () => '1.0', priority: 'low' }]\r\n\r\nexport class WuAIContext {\r\n constructor({ store, eventBus, core }) {\r\n this._store = store;\r\n this._eventBus = eventBus;\r\n this._core = core;\r\n\r\n this._config = {\r\n budget: 4000, // token budget\r\n charRatio: 4, // chars per token estimate\r\n sources: {\r\n store: { include: [], priority: 'high' },\r\n events: { include: [], lastN: 10, priority: 'medium' },\r\n custom: [],\r\n },\r\n };\r\n\r\n this._collectors = new Map(); // name → { collector, priority }\r\n this._lastSnapshot = null;\r\n }\r\n\r\n /**\r\n * Configure context collection.\r\n */\r\n configure(config) {\r\n if (config.budget !== undefined) this._config.budget = config.budget;\r\n if (config.charRatio !== undefined) this._config.charRatio = config.charRatio;\r\n if (config.sources) {\r\n if (config.sources.store) Object.assign(this._config.sources.store, config.sources.store);\r\n if (config.sources.events) Object.assign(this._config.sources.events, config.sources.events);\r\n if (config.sources.custom) this._config.sources.custom = config.sources.custom;\r\n }\r\n }\r\n\r\n /**\r\n * Register a named context collector.\r\n *\r\n * @param {string} name - Collector name (e.g., 'dashboard', 'analytics')\r\n * @param {{ collector: Function, priority?: string }} config\r\n */\r\n register(name, config) {\r\n this._collectors.set(name, {\r\n collector: config.collector,\r\n priority: config.priority || 'medium',\r\n });\r\n logger.wuDebug(`[wu-ai] Context collector registered: '${name}' (${config.priority || 'medium'})`);\r\n }\r\n\r\n /**\r\n * Collect all context ON-DEMAND.\r\n * Called before sending a message to the LLM.\r\n *\r\n * @returns {object} Context snapshot\r\n */\r\n async collect() {\r\n const snapshot = {\r\n _timestamp: Date.now(),\r\n _mountedApps: this._getMountedApps(),\r\n };\r\n\r\n // Collect store sources\r\n const storeData = this._collectStore();\r\n if (storeData && Object.keys(storeData).length > 0) {\r\n snapshot._store = storeData;\r\n }\r\n\r\n // Collect recent events\r\n const events = this._collectEvents();\r\n if (events.length > 0) {\r\n snapshot._events = events;\r\n }\r\n\r\n // Collect custom sources\r\n for (const custom of this._config.sources.custom) {\r\n try {\r\n const value = typeof custom.value === 'function' ? await custom.value() : custom.value;\r\n snapshot[custom.key] = value;\r\n } catch (err) {\r\n logger.wuDebug(`[wu-ai] Custom collector '${custom.key}' failed: ${err.message}`);\r\n }\r\n }\r\n\r\n // Collect registered collectors\r\n for (const [name, config] of this._collectors) {\r\n try {\r\n const data = await config.collector();\r\n snapshot[name] = data;\r\n } catch (err) {\r\n logger.wuDebug(`[wu-ai] Collector '${name}' failed: ${err.message}`);\r\n }\r\n }\r\n\r\n this._lastSnapshot = snapshot;\r\n return snapshot;\r\n }\r\n\r\n /**\r\n * Build a system prompt from the context for the LLM.\r\n *\r\n * @param {{ tools?: Array }} [options] - Available tools to include\r\n * @returns {string} System prompt\r\n */\r\n toSystemPrompt(options = {}) {\r\n const snapshot = this._lastSnapshot;\r\n if (!snapshot) return this._baseSystemPrompt(options);\r\n\r\n const parts = [];\r\n\r\n // Base instruction\r\n parts.push(\r\n 'You are an AI assistant connected to a live web application via Wu Framework.',\r\n 'You can observe application state and execute actions when appropriate.',\r\n ''\r\n );\r\n\r\n // Mounted apps (always included)\r\n if (snapshot._mountedApps?.length) {\r\n parts.push(`MOUNTED APPS: ${snapshot._mountedApps.join(', ')}`, '');\r\n }\r\n\r\n // Budget tracking\r\n const budget = this._config.budget;\r\n const charBudget = budget * this._config.charRatio;\r\n let usedChars = parts.join('\\n').length;\r\n\r\n // Priority-based inclusion\r\n const prioritized = this._prioritizeSections(snapshot);\r\n\r\n for (const section of prioritized) {\r\n const sectionText = section.text;\r\n if (usedChars + sectionText.length > charBudget) {\r\n // Try to truncate if high priority\r\n if (section.priority === 'high') {\r\n const remaining = charBudget - usedChars;\r\n if (remaining > 100) {\r\n parts.push(sectionText.slice(0, remaining) + '\\n...[truncated]');\r\n usedChars += remaining;\r\n }\r\n }\r\n continue; // skip if over budget\r\n }\r\n parts.push(sectionText);\r\n usedChars += sectionText.length;\r\n }\r\n\r\n // Tools (outside budget — LLM needs these)\r\n if (options.tools?.length) {\r\n parts.push('', 'AVAILABLE TOOLS:');\r\n for (const tool of options.tools) {\r\n parts.push(`- ${tool.name}: ${tool.description}`);\r\n }\r\n }\r\n\r\n return parts.join('\\n');\r\n }\r\n\r\n /**\r\n * Get the last collected snapshot.\r\n */\r\n getSnapshot() {\r\n return this._lastSnapshot;\r\n }\r\n\r\n /**\r\n * Get a simplified context object for template interpolation.\r\n */\r\n getInterpolationContext() {\r\n if (!this._lastSnapshot) return {};\r\n const { _timestamp, _mountedApps, _store, _events, ...custom } = this._lastSnapshot;\r\n return {\r\n apps: _mountedApps,\r\n store: _store,\r\n events: _events,\r\n ...custom,\r\n };\r\n }\r\n\r\n // ── Private: Data Collection ──\r\n\r\n _collectStore() {\r\n if (!this._store) return {};\r\n const { include } = this._config.sources.store;\r\n if (!include || include.length === 0) return {};\r\n\r\n const data = {};\r\n for (const path of include) {\r\n try {\r\n const value = this._store.get(path);\r\n if (value !== undefined) {\r\n data[path] = redactSensitive(value);\r\n }\r\n } catch {\r\n // Path doesn't exist, skip\r\n }\r\n }\r\n return data;\r\n }\r\n\r\n _collectEvents() {\r\n if (!this._eventBus) return [];\r\n const { include, lastN } = this._config.sources.events;\r\n if (!include || include.length === 0) return [];\r\n\r\n const history = this._eventBus.history || [];\r\n const matching = history.filter(event => {\r\n return include.some(pattern => this._matchPattern(event.name || event.event, pattern));\r\n });\r\n\r\n return matching.slice(-(lastN || 10)).map(e => ({\r\n event: e.name || e.event,\r\n data: redactSensitive(e.data),\r\n timestamp: e.timestamp,\r\n }));\r\n }\r\n\r\n _getMountedApps() {\r\n if (!this._core) return [];\r\n try {\r\n // WuCore exposes mounted as Map or getStats()\r\n if (this._core.mounted instanceof Map) {\r\n return [...this._core.mounted.keys()];\r\n }\r\n const stats = this._core.getStats?.();\r\n return stats?.apps || stats?.mounted || [];\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n // ── Private: Priority & Budget ──\r\n\r\n _prioritizeSections(snapshot) {\r\n const sections = [];\r\n const storePriority = this._config.sources.store.priority || 'high';\r\n const eventPriority = this._config.sources.events.priority || 'medium';\r\n\r\n // Store snapshot\r\n if (snapshot._store && Object.keys(snapshot._store).length > 0) {\r\n sections.push({\r\n priority: storePriority,\r\n text: `APPLICATION STATE:\\n${JSON.stringify(snapshot._store, null, 2)}`,\r\n });\r\n }\r\n\r\n // Recent events\r\n if (snapshot._events?.length) {\r\n const eventLines = snapshot._events.map(e =>\r\n ` [${e.event}] ${JSON.stringify(e.data)}`\r\n ).join('\\n');\r\n sections.push({\r\n priority: eventPriority,\r\n text: `RECENT EVENTS:\\n${eventLines}`,\r\n });\r\n }\r\n\r\n // Custom collectors\r\n for (const [name, config] of this._collectors) {\r\n if (snapshot[name] !== undefined) {\r\n sections.push({\r\n priority: config.priority,\r\n text: `${name.toUpperCase()}:\\n${JSON.stringify(snapshot[name], null, 2)}`,\r\n });\r\n }\r\n }\r\n\r\n // Custom sources\r\n for (const custom of this._config.sources.custom) {\r\n if (snapshot[custom.key] !== undefined) {\r\n sections.push({\r\n priority: custom.priority || 'low',\r\n text: `${custom.key}: ${JSON.stringify(snapshot[custom.key])}`,\r\n });\r\n }\r\n }\r\n\r\n // Sort: high → medium → low\r\n const order = { high: 0, medium: 1, low: 2 };\r\n sections.sort((a, b) => (order[a.priority] ?? 1) - (order[b.priority] ?? 1));\r\n\r\n return sections;\r\n }\r\n\r\n _baseSystemPrompt(options = {}) {\r\n let prompt = 'You are an AI assistant connected to a web application via Wu Framework.';\r\n if (options.tools?.length) {\r\n prompt += '\\n\\nAVAILABLE TOOLS:\\n' + options.tools.map(t => `- ${t.name}: ${t.description}`).join('\\n');\r\n }\r\n return prompt;\r\n }\r\n\r\n // ── Pattern Matching (reuse wu-framework convention) ──\r\n\r\n _matchPattern(eventName, pattern) {\r\n if (!eventName || !pattern) return false;\r\n if (pattern === '*') return true;\r\n if (!pattern.includes('*')) return eventName === pattern;\r\n\r\n const regex = new RegExp('^' + pattern.replace(/\\*/g, '[^:]*') + '$');\r\n return regex.test(eventName);\r\n }\r\n\r\n getStats() {\r\n return {\r\n budget: this._config.budget,\r\n collectors: [...this._collectors.keys()],\r\n storePaths: this._config.sources.store.include,\r\n eventPatterns: this._config.sources.events.include,\r\n lastCollected: this._lastSnapshot?._timestamp || null,\r\n };\r\n }\r\n}\r\n","/**\r\n * WU-AI-ACTIONS: Action registry and executor\r\n *\r\n * Actions are capabilities that the LLM can invoke via tool_use / function_call.\r\n * Each action has:\r\n * - A handler function (sandboxed API, not raw wu access)\r\n * - JSON Schema parameters\r\n * - Permission requirements\r\n * - Optional confirmation flow\r\n *\r\n * Security: Actions receive a sandboxed API, not the full wu object.\r\n * The LLM cannot do anything the developer didn't explicitly expose.\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\nimport { validateParams, normalizeParameters, buildToolSchemas } from './wu-ai-schema.js';\r\n\r\nexport class WuAIActions {\r\n constructor({ eventBus, store, permissions }) {\r\n this._eventBus = eventBus;\r\n this._store = store;\r\n this._permissions = permissions;\r\n this._actions = new Map();\r\n this._executionLog = [];\r\n this._maxLogSize = 100;\r\n this._pendingConfirms = new Map(); // callId → { resolve, reject, timeout }\r\n }\r\n\r\n /**\r\n * Register an action that the LLM can invoke.\r\n *\r\n * @param {string} name - Action name (used in tool_call)\r\n * @param {object} config\r\n * @param {string} config.description - Human-readable description (sent to LLM)\r\n * @param {object} [config.parameters] - JSON Schema or shorthand for params\r\n * @param {Function} config.handler - async (params, sandboxedApi) => result\r\n * @param {boolean} [config.confirm=false] - Require user confirmation before executing\r\n * @param {string[]} [config.permissions=[]] - Required permission flags\r\n * @param {boolean} [config.dangerous=false] - Mark as dangerous in logs\r\n */\r\n register(name, config) {\r\n if (!config.handler || typeof config.handler !== 'function') {\r\n throw new Error(`[wu-ai] Action '${name}' must have a handler function`);\r\n }\r\n\r\n this._actions.set(name, {\r\n description: config.description || `Execute: ${name}`,\r\n parameters: normalizeParameters(config.parameters),\r\n handler: config.handler,\r\n confirm: config.confirm || false,\r\n permissions: config.permissions || [],\r\n dangerous: config.dangerous || false,\r\n });\r\n\r\n logger.wuDebug(`[wu-ai] Action registered: '${name}'${config.dangerous ? ' [DANGEROUS]' : ''}`);\r\n }\r\n\r\n /**\r\n * Unregister an action.\r\n */\r\n unregister(name) {\r\n this._actions.delete(name);\r\n }\r\n\r\n /**\r\n * Execute an action (called when LLM returns tool_call).\r\n *\r\n * @param {string} name - Action name\r\n * @param {object} params - Parameters from LLM\r\n * @param {object} [meta] - { traceId, depth, callId }\r\n * @returns {Promise<{ success: boolean, result?: any, reason?: string }>}\r\n */\r\n async execute(name, params, meta = {}) {\r\n const action = this._actions.get(name);\r\n if (!action) {\r\n return { success: false, reason: `Action '${name}' not registered` };\r\n }\r\n\r\n // 1. Check permissions\r\n for (const perm of action.permissions) {\r\n if (!this._permissions.check(perm)) {\r\n this._emitDenied(name, params, `Missing permission: ${perm}`);\r\n return { success: false, reason: `Permission denied: ${perm}` };\r\n }\r\n }\r\n\r\n // 2. Validate params\r\n const validation = validateParams(params || {}, action.parameters);\r\n if (!validation.valid) {\r\n return { success: false, reason: `Invalid params: ${validation.errors.join(', ')}` };\r\n }\r\n\r\n // 3. Confirmation (if required)\r\n if (action.confirm) {\r\n const confirmed = await this._requestConfirmation(name, params, meta.callId);\r\n if (!confirmed) {\r\n return { success: false, reason: 'User denied action' };\r\n }\r\n }\r\n\r\n // 4. Execute with sandboxed API\r\n try {\r\n if (action.dangerous) {\r\n logger.wuWarn(`[wu-ai] Executing DANGEROUS action: '${name}' with params: ${JSON.stringify(params)}`);\r\n }\r\n\r\n const api = this._createSandboxedApi(action.permissions);\r\n const result = await action.handler(params, api);\r\n\r\n // Audit log\r\n this._log(name, params, result, meta);\r\n\r\n // Emit success event\r\n this._eventBus.emit('ai:action:executed', {\r\n action: name,\r\n params,\r\n result,\r\n traceId: meta.traceId,\r\n }, { appName: 'wu-ai' });\r\n\r\n return { success: true, result };\r\n } catch (err) {\r\n this._eventBus.emit('ai:action:error', {\r\n action: name,\r\n params,\r\n error: err.message,\r\n traceId: meta.traceId,\r\n }, { appName: 'wu-ai' });\r\n\r\n return { success: false, reason: err.message };\r\n }\r\n }\r\n\r\n /**\r\n * Get tool schemas for the LLM (function calling format).\r\n */\r\n getToolSchemas() {\r\n return buildToolSchemas(this._actions);\r\n }\r\n\r\n /**\r\n * Check if an action is registered.\r\n */\r\n has(name) {\r\n return this._actions.has(name);\r\n }\r\n\r\n /**\r\n * Get registered action names.\r\n */\r\n getNames() {\r\n return [...this._actions.keys()];\r\n }\r\n\r\n /**\r\n * Get execution log.\r\n */\r\n getLog() {\r\n return [...this._executionLog];\r\n }\r\n\r\n /**\r\n * Confirm a pending tool call (called by developer/UI).\r\n */\r\n confirmTool(callId) {\r\n const pending = this._pendingConfirms.get(callId);\r\n if (pending) {\r\n clearTimeout(pending.timeout);\r\n this._pendingConfirms.delete(callId);\r\n pending.resolve(true);\r\n }\r\n }\r\n\r\n /**\r\n * Reject a pending tool call.\r\n */\r\n rejectTool(callId) {\r\n const pending = this._pendingConfirms.get(callId);\r\n if (pending) {\r\n clearTimeout(pending.timeout);\r\n this._pendingConfirms.delete(callId);\r\n pending.resolve(false);\r\n }\r\n }\r\n\r\n // ── Private: Sandboxed API ──\r\n\r\n _createSandboxedApi(requiredPermissions) {\r\n const api = {};\r\n const perms = new Set(requiredPermissions);\r\n\r\n // Store access (read)\r\n if (this._permissions.check('readStore')) {\r\n api.getState = (path) => this._store.get(path);\r\n }\r\n\r\n // Store access (write) — only if explicitly permitted\r\n if (this._permissions.check('writeStore') && perms.has('writeStore')) {\r\n api.setState = (path, value) => this._store.set(path, value);\r\n }\r\n\r\n // Event emission\r\n if (this._permissions.check('emitEvents')) {\r\n api.emit = (event, data) => this._eventBus.emit(event, data, { appName: 'wu-ai' });\r\n }\r\n\r\n return api;\r\n }\r\n\r\n // ── Private: Confirmation Flow ──\r\n\r\n _requestConfirmation(actionName, params, callId) {\r\n const id = callId || `confirm_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;\r\n\r\n return new Promise((resolve) => {\r\n const timeoutHandle = setTimeout(() => {\r\n this._pendingConfirms.delete(id);\r\n resolve(false); // Timeout = deny\r\n logger.wuDebug(`[wu-ai] Confirmation timeout for action '${actionName}'`);\r\n }, 30000);\r\n\r\n this._pendingConfirms.set(id, { resolve, timeout: timeoutHandle });\r\n\r\n this._eventBus.emit('ai:tool:confirm', {\r\n callId: id,\r\n action: actionName,\r\n params,\r\n message: `AI wants to execute: ${actionName}`,\r\n }, { appName: 'wu-ai' });\r\n });\r\n }\r\n\r\n // ── Private: Logging ──\r\n\r\n _log(action, params, result, meta) {\r\n this._executionLog.push({\r\n action,\r\n params,\r\n result: typeof result === 'object' ? { ...result } : result,\r\n timestamp: Date.now(),\r\n traceId: meta.traceId,\r\n });\r\n\r\n if (this._executionLog.length > this._maxLogSize) {\r\n this._executionLog.shift();\r\n }\r\n }\r\n\r\n _emitDenied(action, params, reason) {\r\n this._eventBus.emit('ai:action:denied', { action, params, reason }, { appName: 'wu-ai' });\r\n logger.wuWarn(`[wu-ai] Action denied: '${action}' — ${reason}`);\r\n }\r\n\r\n getStats() {\r\n return {\r\n registeredActions: [...this._actions.keys()],\r\n executionLogSize: this._executionLog.length,\r\n pendingConfirmations: this._pendingConfirms.size,\r\n };\r\n }\r\n}\r\n","/**\r\n * WU-AI-CONVERSATION: Multi-turn conversation manager\r\n *\r\n * Manages conversation state per namespace. Each namespace maintains\r\n * its own message history, enabling multiple independent AI conversations\r\n * (e.g., chat widget, background triggers, admin panel).\r\n *\r\n * Key features:\r\n * - Multi-turn per namespace (isolated histories)\r\n * - Streaming with async generator passthrough\r\n * - Tool call loop (max rounds configurable, default 5)\r\n * - Abort support via AbortController\r\n * - Automatic context injection before each send\r\n * - Token-aware history truncation\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\nimport { sanitizeForPrompt, interpolate } from './wu-ai-schema.js';\r\n\r\n// ─── Default Config ──────────────────────────────────────────────\r\n\r\nconst DEFAULT_CONFIG = {\r\n maxHistoryMessages: 50, // per namespace\r\n maxToolRounds: 5, // tool call loop limit\r\n defaultNamespace: 'default',\r\n systemPrompt: null, // string or function returning string\r\n temperature: undefined,\r\n maxTokens: undefined,\r\n namespaceTTL: 30 * 60_000, // 30 min — auto-expire inactive namespaces (0 = disabled)\r\n gcInterval: 5 * 60_000, // 5 min — how often to sweep for expired namespaces\r\n};\r\n\r\n// ─── Conversation Namespace ──────────────────────────────────────\r\n\r\nclass ConversationNamespace {\r\n constructor(name) {\r\n this.name = name;\r\n this.messages = [];\r\n this.createdAt = Date.now();\r\n this.lastActivity = Date.now();\r\n this._abortController = null;\r\n }\r\n\r\n addMessage(msg) {\r\n this.messages.push({ ...msg, _ts: Date.now() });\r\n this.lastActivity = Date.now();\r\n }\r\n\r\n getMessages() {\r\n return this.messages.map(({ _ts, ...rest }) => rest);\r\n }\r\n\r\n truncate(maxMessages) {\r\n if (this.messages.length <= maxMessages) return;\r\n\r\n // Keep system messages + last N messages\r\n const system = this.messages.filter(m => m.role === 'system');\r\n const nonSystem = this.messages.filter(m => m.role !== 'system');\r\n const kept = nonSystem.slice(-maxMessages);\r\n this.messages = [...system, ...kept];\r\n }\r\n\r\n clear() {\r\n this.messages = [];\r\n this.lastActivity = Date.now();\r\n }\r\n\r\n abort() {\r\n if (this._abortController) {\r\n this._abortController.abort();\r\n this._abortController = null;\r\n }\r\n }\r\n\r\n createAbortController() {\r\n this.abort(); // cancel previous if any\r\n this._abortController = new AbortController();\r\n return this._abortController;\r\n }\r\n}\r\n\r\n// ─── Main Conversation Manager ───────────────────────────────────\r\n\r\nexport class WuAIConversation {\r\n constructor({ provider, actions, context, permissions, eventBus }) {\r\n this._provider = provider;\r\n this._actions = actions;\r\n this._context = context;\r\n this._permissions = permissions;\r\n this._eventBus = eventBus;\r\n\r\n this._config = { ...DEFAULT_CONFIG };\r\n this._namespaces = new Map();\r\n this._activeRequests = new Map(); // namespace → promise\r\n this._lastGcRun = Date.now();\r\n }\r\n\r\n /**\r\n * Configure conversation defaults.\r\n */\r\n configure(config) {\r\n Object.assign(this._config, config);\r\n }\r\n\r\n /**\r\n * Send a message and get a complete response.\r\n * Handles multi-turn tool call loops automatically.\r\n *\r\n * @param {string} message - User message\r\n * @param {object} [options]\r\n * @param {string} [options.namespace='default'] - Conversation namespace\r\n * @param {string} [options.systemPrompt] - Override system prompt\r\n * @param {object} [options.templateVars] - Variables for template interpolation\r\n * @param {number} [options.temperature] - Override temperature\r\n * @param {number} [options.maxTokens] - Override max tokens\r\n * @param {string|object} [options.responseFormat] - Request JSON output ('json' or { type: 'json_schema', schema, name? })\r\n * @param {AbortSignal} [options.signal] - External abort signal\r\n * @returns {Promise<{ content: string, tool_results?: Array, usage?: object, namespace: string }>}\r\n */\r\n async send(message, options = {}) {\r\n const ns = this._getOrCreateNamespace(options.namespace);\r\n const traceId = this._permissions.loopProtection.createTraceId();\r\n const meta = { namespace: ns.name, depth: 0, traceId };\r\n\r\n // Preflight checks\r\n const preflight = this._permissions.preflight(meta);\r\n if (!preflight.allowed) {\r\n return { content: `[blocked] ${preflight.reason}`, namespace: ns.name };\r\n }\r\n\r\n // Build system prompt\r\n const systemPrompt = await this._buildSystemPrompt(options);\r\n\r\n // Ensure system message is set/updated\r\n this._setSystemMessage(ns, systemPrompt);\r\n\r\n // Add user message\r\n const processedMessage = this._processMessage(message, options.templateVars);\r\n ns.addMessage({ role: 'user', content: processedMessage });\r\n\r\n // Truncate history if needed\r\n ns.truncate(this._config.maxHistoryMessages);\r\n\r\n // Create abort controller (merges with external signal)\r\n const controller = ns.createAbortController();\r\n const signal = this._mergeSignals(controller.signal, options.signal);\r\n\r\n // Rate limit tracking\r\n this._permissions.rateLimiter.recordStart(ns.name);\r\n\r\n try {\r\n // Tool call loop\r\n const toolResults = [];\r\n let rounds = 0;\r\n const maxRounds = this._config.maxToolRounds;\r\n\r\n while (rounds <= maxRounds) {\r\n // Get tools if actions are registered\r\n const tools = this._actions.getToolSchemas();\r\n\r\n const response = await this._provider.send(ns.getMessages(), {\r\n tools: tools.length > 0 ? tools : undefined,\r\n temperature: options.temperature ?? this._config.temperature,\r\n maxTokens: options.maxTokens ?? this._config.maxTokens,\r\n responseFormat: options.responseFormat,\r\n provider: options.provider,\r\n signal,\r\n });\r\n\r\n // Add assistant response to history\r\n const assistantMsg = { role: 'assistant', content: response.content || '' };\r\n if (response.tool_calls) assistantMsg.tool_calls = response.tool_calls;\r\n ns.addMessage(assistantMsg);\r\n\r\n // No tool calls → we're done\r\n if (!response.tool_calls || response.tool_calls.length === 0) {\r\n this._permissions.circuitBreaker.recordSuccess();\r\n\r\n this._eventBus.emit('ai:response', {\r\n namespace: ns.name,\r\n content: response.content,\r\n toolResults: toolResults.length > 0 ? toolResults : undefined,\r\n usage: response.usage,\r\n traceId,\r\n }, { appName: 'wu-ai' });\r\n\r\n return {\r\n content: response.content || '',\r\n tool_results: toolResults.length > 0 ? toolResults : undefined,\r\n usage: response.usage,\r\n namespace: ns.name,\r\n };\r\n }\r\n\r\n // Execute tool calls\r\n rounds++;\r\n if (rounds > maxRounds) {\r\n const msg = `[wu-ai] Tool call loop limit (${maxRounds}) reached in namespace '${ns.name}'`;\r\n logger.wuWarn(msg);\r\n ns.addMessage({ role: 'assistant', content: msg });\r\n return { content: msg, tool_results: toolResults, namespace: ns.name };\r\n }\r\n\r\n // Loop protection\r\n this._permissions.loopProtection.enter(traceId);\r\n\r\n for (const toolCall of response.tool_calls) {\r\n const result = await this._actions.execute(toolCall.name, toolCall.arguments, {\r\n traceId,\r\n depth: rounds,\r\n callId: toolCall.id,\r\n });\r\n\r\n toolResults.push({\r\n tool: toolCall.name,\r\n params: toolCall.arguments,\r\n result: result.result,\r\n success: result.success,\r\n });\r\n\r\n // Add tool result to conversation\r\n ns.addMessage({\r\n role: 'tool',\r\n content: JSON.stringify(result.success ? result.result : { error: result.reason }),\r\n tool_call_id: toolCall.id,\r\n });\r\n }\r\n\r\n this._permissions.loopProtection.exit(traceId);\r\n }\r\n\r\n // Should not reach here, but safety net\r\n return { content: '', tool_results: toolResults, namespace: ns.name };\r\n\r\n } catch (err) {\r\n this._permissions.circuitBreaker.recordFailure();\r\n\r\n if (err.name === 'AbortError') {\r\n return { content: '[aborted]', namespace: ns.name };\r\n }\r\n\r\n this._eventBus.emit('ai:error', {\r\n namespace: ns.name,\r\n error: err.message,\r\n traceId,\r\n }, { appName: 'wu-ai' });\r\n\r\n throw err;\r\n } finally {\r\n this._permissions.rateLimiter.recordEnd();\r\n ns._abortController = null;\r\n }\r\n }\r\n\r\n /**\r\n * Send a message with streaming response.\r\n * Returns an async generator that yields chunks.\r\n *\r\n * @param {string} message - User message\r\n * @param {object} [options] - Same as send()\r\n * @yields {{ type: 'text'|'tool_call'|'done'|'error', content?: string, tool_call?: object }}\r\n */\r\n async *stream(message, options = {}) {\r\n const ns = this._getOrCreateNamespace(options.namespace);\r\n const traceId = this._permissions.loopProtection.createTraceId();\r\n const meta = { namespace: ns.name, depth: 0, traceId };\r\n\r\n // Preflight checks\r\n const preflight = this._permissions.preflight(meta);\r\n if (!preflight.allowed) {\r\n yield { type: 'error', error: preflight.reason };\r\n return;\r\n }\r\n\r\n // Build system prompt and set it\r\n const systemPrompt = await this._buildSystemPrompt(options);\r\n this._setSystemMessage(ns, systemPrompt);\r\n\r\n // Add user message\r\n const processedMessage = this._processMessage(message, options.templateVars);\r\n ns.addMessage({ role: 'user', content: processedMessage });\r\n ns.truncate(this._config.maxHistoryMessages);\r\n\r\n // Abort controller\r\n const controller = ns.createAbortController();\r\n const signal = this._mergeSignals(controller.signal, options.signal);\r\n\r\n this._permissions.rateLimiter.recordStart(ns.name);\r\n\r\n try {\r\n // Tool call loop — mirrors send() behavior (up to maxToolRounds)\r\n let rounds = 0;\r\n const maxRounds = this._config.maxToolRounds;\r\n\r\n while (rounds <= maxRounds) {\r\n const tools = this._actions.getToolSchemas();\r\n let fullContent = '';\r\n const toolCallAccumulator = new Map(); // index → { id, name, args }\r\n let streamEnded = false;\r\n\r\n for await (const chunk of this._provider.stream(ns.getMessages(), {\r\n tools: tools.length > 0 ? tools : undefined,\r\n temperature: options.temperature ?? this._config.temperature,\r\n maxTokens: options.maxTokens ?? this._config.maxTokens,\r\n responseFormat: options.responseFormat,\r\n provider: options.provider,\r\n signal,\r\n })) {\r\n if (chunk.type === 'text') {\r\n fullContent += chunk.content;\r\n yield chunk;\r\n } else if (chunk.type === 'tool_call_start') {\r\n toolCallAccumulator.set(toolCallAccumulator.size, {\r\n id: chunk.id,\r\n name: chunk.name,\r\n args: '',\r\n });\r\n } else if (chunk.type === 'tool_call_delta') {\r\n const idx = chunk.index ?? (toolCallAccumulator.size - 1);\r\n const acc = toolCallAccumulator.get(idx);\r\n if (acc) {\r\n if (chunk.id) acc.id = chunk.id;\r\n if (chunk.name) acc.name = chunk.name;\r\n acc.args += chunk.argumentsDelta || '';\r\n } else {\r\n toolCallAccumulator.set(idx, {\r\n id: chunk.id || `tc_${idx}`,\r\n name: chunk.name || '',\r\n args: chunk.argumentsDelta || '',\r\n });\r\n }\r\n } else if (chunk.type === 'done') {\r\n streamEnded = true;\r\n break; // exit inner loop, handle tool calls below\r\n } else if (chunk.type === 'usage') {\r\n yield chunk;\r\n } else if (chunk.type === 'error') {\r\n yield chunk;\r\n }\r\n }\r\n\r\n // No tool calls → final response, we're done\r\n if (toolCallAccumulator.size === 0) {\r\n if (fullContent) {\r\n ns.addMessage({ role: 'assistant', content: fullContent });\r\n }\r\n this._permissions.circuitBreaker.recordSuccess();\r\n yield { type: 'done' };\r\n return;\r\n }\r\n\r\n // Tool calls detected — execute them\r\n rounds++;\r\n if (rounds > maxRounds) {\r\n const msg = `[wu-ai] Tool call loop limit (${maxRounds}) reached in streaming namespace '${ns.name}'`;\r\n logger.wuWarn(msg);\r\n yield { type: 'error', error: msg };\r\n yield { type: 'done' };\r\n return;\r\n }\r\n\r\n // Parse accumulated tool calls\r\n const toolCalls = [];\r\n for (const [, acc] of toolCallAccumulator) {\r\n let parsedArgs = {};\r\n try { parsedArgs = JSON.parse(acc.args); } catch { /* empty args */ }\r\n toolCalls.push({ id: acc.id, name: acc.name, arguments: parsedArgs });\r\n }\r\n\r\n // Add assistant message with tool calls to history\r\n ns.addMessage({ role: 'assistant', content: fullContent, tool_calls: toolCalls });\r\n\r\n // Execute each tool call\r\n this._permissions.loopProtection.enter(traceId);\r\n for (const tc of toolCalls) {\r\n const result = await this._actions.execute(tc.name, tc.arguments, {\r\n traceId, depth: rounds, callId: tc.id,\r\n });\r\n\r\n yield {\r\n type: 'tool_result',\r\n tool: tc.name,\r\n result: result.success ? result.result : { error: result.reason },\r\n success: result.success,\r\n };\r\n\r\n ns.addMessage({\r\n role: 'tool',\r\n content: JSON.stringify(result.success ? result.result : { error: result.reason }),\r\n tool_call_id: tc.id,\r\n });\r\n }\r\n this._permissions.loopProtection.exit(traceId);\r\n\r\n yield { type: 'tool_calls_done', count: toolCalls.length };\r\n // Loop continues → re-stream with tool results in history\r\n }\r\n\r\n } catch (err) {\r\n this._permissions.circuitBreaker.recordFailure();\r\n\r\n if (err.name === 'AbortError') {\r\n yield { type: 'error', error: 'aborted' };\r\n return;\r\n }\r\n\r\n yield { type: 'error', error: err.message };\r\n\r\n this._eventBus.emit('ai:error', {\r\n namespace: ns.name,\r\n error: err.message,\r\n traceId,\r\n }, { appName: 'wu-ai' });\r\n } finally {\r\n this._permissions.rateLimiter.recordEnd();\r\n ns._abortController = null;\r\n }\r\n }\r\n\r\n /**\r\n * Add a message to a namespace without sending to LLM.\r\n * Useful for injecting context or tool results manually.\r\n */\r\n inject(role, content, options = {}) {\r\n const ns = this._getOrCreateNamespace(options.namespace);\r\n ns.addMessage({ role, content });\r\n }\r\n\r\n /**\r\n * Get conversation history for a namespace.\r\n */\r\n getHistory(namespace) {\r\n const ns = this._namespaces.get(namespace || this._config.defaultNamespace);\r\n return ns ? ns.getMessages() : [];\r\n }\r\n\r\n /**\r\n * Clear conversation history for a namespace.\r\n */\r\n clear(namespace) {\r\n const ns = this._namespaces.get(namespace || this._config.defaultNamespace);\r\n if (ns) ns.clear();\r\n }\r\n\r\n /**\r\n * Clear all namespaces.\r\n */\r\n clearAll() {\r\n for (const ns of this._namespaces.values()) {\r\n ns.clear();\r\n }\r\n }\r\n\r\n /**\r\n * Abort an active request in a namespace.\r\n */\r\n abort(namespace) {\r\n const ns = this._namespaces.get(namespace || this._config.defaultNamespace);\r\n if (ns) ns.abort();\r\n }\r\n\r\n /**\r\n * Abort all active requests.\r\n */\r\n abortAll() {\r\n for (const ns of this._namespaces.values()) {\r\n ns.abort();\r\n }\r\n }\r\n\r\n /**\r\n * List active namespaces.\r\n */\r\n getNamespaces() {\r\n return [...this._namespaces.keys()];\r\n }\r\n\r\n /**\r\n * Delete a namespace entirely.\r\n */\r\n deleteNamespace(namespace) {\r\n const ns = this._namespaces.get(namespace);\r\n if (ns) {\r\n ns.abort();\r\n this._namespaces.delete(namespace);\r\n }\r\n }\r\n\r\n // ── Private ──\r\n\r\n _getOrCreateNamespace(name) {\r\n const nsName = name || this._config.defaultNamespace;\r\n\r\n // Lazy GC sweep — only runs periodically, not on every access\r\n this._maybeGcSweep();\r\n\r\n if (!this._namespaces.has(nsName)) {\r\n this._namespaces.set(nsName, new ConversationNamespace(nsName));\r\n }\r\n const ns = this._namespaces.get(nsName);\r\n ns.lastActivity = Date.now();\r\n return ns;\r\n }\r\n\r\n /**\r\n * Sweep expired namespaces. Called lazily on access, throttled by gcInterval.\r\n * Never deletes the default namespace or namespaces with active requests.\r\n */\r\n _maybeGcSweep() {\r\n const ttl = this._config.namespaceTTL;\r\n const interval = this._config.gcInterval;\r\n if (!ttl || ttl <= 0) return; // GC disabled\r\n\r\n const now = Date.now();\r\n if (now - this._lastGcRun < interval) return; // Not time yet\r\n this._lastGcRun = now;\r\n\r\n const cutoff = now - ttl;\r\n const toDelete = [];\r\n\r\n for (const [name, ns] of this._namespaces) {\r\n // Never GC the default namespace\r\n if (name === this._config.defaultNamespace) continue;\r\n // Don't GC namespaces with active abort controllers (in-flight request)\r\n if (ns._abortController) continue;\r\n // Expired?\r\n if (ns.lastActivity < cutoff) {\r\n toDelete.push(name);\r\n }\r\n }\r\n\r\n for (const name of toDelete) {\r\n this._namespaces.delete(name);\r\n }\r\n\r\n if (toDelete.length > 0) {\r\n logger.wuDebug(`[wu-ai] GC sweep: removed ${toDelete.length} expired namespace(s): ${toDelete.join(', ')}`);\r\n }\r\n }\r\n\r\n async _buildSystemPrompt(options) {\r\n // 1. Explicit override\r\n if (options.systemPrompt) {\r\n return typeof options.systemPrompt === 'function'\r\n ? await options.systemPrompt()\r\n : options.systemPrompt;\r\n }\r\n\r\n // 2. Config-level system prompt\r\n if (this._config.systemPrompt) {\r\n return typeof this._config.systemPrompt === 'function'\r\n ? await this._config.systemPrompt()\r\n : this._config.systemPrompt;\r\n }\r\n\r\n // 3. Auto-generate from context\r\n if (this._context) {\r\n await this._context.collect();\r\n const tools = this._actions.getToolSchemas();\r\n return this._context.toSystemPrompt({ tools });\r\n }\r\n\r\n return 'You are an AI assistant connected to a web application via Wu Framework.';\r\n }\r\n\r\n _setSystemMessage(ns, systemPrompt) {\r\n // Replace or insert system message at the beginning\r\n if (ns.messages.length > 0 && ns.messages[0].role === 'system') {\r\n ns.messages[0].content = systemPrompt;\r\n ns.messages[0]._ts = Date.now();\r\n } else {\r\n ns.messages.unshift({ role: 'system', content: systemPrompt, _ts: Date.now() });\r\n }\r\n }\r\n\r\n _processMessage(message, templateVars) {\r\n if (!templateVars) return message;\r\n try {\r\n const contextVars = this._context?.getInterpolationContext() || {};\r\n return interpolate(message, { ...contextVars, ...templateVars });\r\n } catch {\r\n return message;\r\n }\r\n }\r\n\r\n _mergeSignals(internalSignal, externalSignal) {\r\n if (!externalSignal) return internalSignal;\r\n\r\n // If AbortSignal.any is available (modern browsers), use it\r\n if (typeof AbortSignal !== 'undefined' && AbortSignal.any) {\r\n return AbortSignal.any([internalSignal, externalSignal]);\r\n }\r\n\r\n // Fallback: create a new controller that listens to both\r\n const merged = new AbortController();\r\n const onAbort = () => merged.abort();\r\n internalSignal.addEventListener('abort', onAbort, { once: true });\r\n externalSignal.addEventListener('abort', onAbort, { once: true });\r\n return merged.signal;\r\n }\r\n\r\n getStats() {\r\n const namespaces = {};\r\n for (const [name, ns] of this._namespaces) {\r\n namespaces[name] = {\r\n messageCount: ns.messages.length,\r\n lastActivity: ns.lastActivity,\r\n hasActiveRequest: !!ns._abortController,\r\n };\r\n }\r\n return { namespaces, config: { ...this._config } };\r\n }\r\n}\r\n","/**\r\n * WU-AI-TRIGGERS: Event-to-AI bridge\r\n *\r\n * Listens to wu.eventBus events and automatically triggers LLM interactions.\r\n * This is the \"reactive AI\" — the app becomes intelligent by responding\r\n * to events with AI-generated actions.\r\n *\r\n * Features:\r\n * - Pattern-based event matching (wu convention: 'cart:*', 'user:login')\r\n * - Debounce per trigger (avoid flooding LLM)\r\n * - Conditional execution (only trigger if condition returns true)\r\n * - Priority batching (high triggers fire immediately, low ones batch)\r\n * - Template interpolation ({{event.data.user}} in prompts)\r\n * - Namespace isolation (each trigger uses its own conversation namespace)\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\nimport { interpolate, sanitizeForPrompt } from './wu-ai-schema.js';\r\n\r\n// ─── Trigger Config ──────────────────────────────────────────────\r\n\r\nconst DEFAULT_TRIGGER_CONFIG = {\r\n enabled: true,\r\n maxActiveTriggers: 20,\r\n defaultDebounceMs: 1000,\r\n batchIntervalMs: 2000,\r\n};\r\n\r\n// ─── Single Trigger ──────────────────────────────────────────────\r\n\r\nclass Trigger {\r\n constructor(name, config) {\r\n this.name = name;\r\n this.pattern = config.pattern; // event pattern: 'cart:updated', 'user:*'\r\n this.prompt = config.prompt; // string or function(eventData) → string\r\n this.condition = config.condition || null; // function(eventData) → boolean\r\n this.debounceMs = config.debounce ?? DEFAULT_TRIGGER_CONFIG.defaultDebounceMs;\r\n this.priority = config.priority || 'medium'; // 'high' | 'medium' | 'low'\r\n this.namespace = config.namespace || `trigger:${name}`;\r\n this.systemPrompt = config.systemPrompt || null;\r\n this.onResult = config.onResult || null; // callback(result, eventData) → void\r\n this.enabled = config.enabled !== false;\r\n this.maxTokens = config.maxTokens || undefined;\r\n this.temperature = config.temperature || undefined;\r\n\r\n // Internal state\r\n this._debounceTimer = null;\r\n this._lastFired = 0;\r\n this._fireCount = 0;\r\n this._pendingEvent = null;\r\n }\r\n\r\n /**\r\n * Check if this trigger matches an event name.\r\n */\r\n matches(eventName) {\r\n if (!this.pattern) return false;\r\n if (this.pattern === '*') return true;\r\n if (!this.pattern.includes('*')) return eventName === this.pattern;\r\n\r\n const regex = new RegExp('^' + this.pattern.replace(/\\*/g, '[^:]*') + '$');\r\n return regex.test(eventName);\r\n }\r\n\r\n /**\r\n * Build the prompt for this trigger given event data.\r\n */\r\n buildPrompt(eventData) {\r\n if (typeof this.prompt === 'function') {\r\n return this.prompt(eventData);\r\n }\r\n\r\n // Template interpolation\r\n return interpolate(this.prompt, {\r\n event: eventData,\r\n data: eventData?.data,\r\n timestamp: Date.now(),\r\n });\r\n }\r\n\r\n /**\r\n * Check condition (if any).\r\n */\r\n async checkCondition(eventData) {\r\n if (!this.condition) return true;\r\n try {\r\n const result = this.condition(eventData);\r\n return result instanceof Promise ? await result : result;\r\n } catch (err) {\r\n logger.wuDebug(`[wu-ai] Trigger '${this.name}' condition error: ${err.message}`);\r\n return false;\r\n }\r\n }\r\n}\r\n\r\n// ─── Main Triggers Manager ───────────────────────────────────────\r\n\r\nexport class WuAITriggers {\r\n constructor({ eventBus, conversation, permissions }) {\r\n this._eventBus = eventBus;\r\n this._conversation = conversation;\r\n this._permissions = permissions;\r\n\r\n this._config = { ...DEFAULT_TRIGGER_CONFIG };\r\n this._triggers = new Map(); // name → Trigger\r\n this._listeners = new Map(); // name → unsubscribe function\r\n this._batchQueue = []; // low-priority triggers pending batch\r\n this._batchTimer = null;\r\n this._stats = {\r\n totalFired: 0,\r\n totalSkipped: 0,\r\n totalErrors: 0,\r\n };\r\n }\r\n\r\n /**\r\n * Configure trigger system.\r\n */\r\n configure(config) {\r\n Object.assign(this._config, config);\r\n }\r\n\r\n /**\r\n * Register a trigger.\r\n *\r\n * @param {string} name - Trigger name (unique identifier)\r\n * @param {object} config\r\n * @param {string} config.pattern - Event pattern to match (e.g., 'cart:*')\r\n * @param {string|Function} config.prompt - Prompt template or function\r\n * @param {Function} [config.condition] - Optional condition function\r\n * @param {number} [config.debounce=1000] - Debounce in ms\r\n * @param {string} [config.priority='medium'] - 'high' | 'medium' | 'low'\r\n * @param {string} [config.namespace] - Conversation namespace\r\n * @param {string} [config.systemPrompt] - Override system prompt\r\n * @param {Function} [config.onResult] - Callback for results\r\n * @param {boolean} [config.enabled=true] - Whether trigger is active\r\n */\r\n register(name, config) {\r\n if (this._triggers.size >= this._config.maxActiveTriggers) {\r\n logger.wuWarn(`[wu-ai] Max triggers (${this._config.maxActiveTriggers}) reached. Cannot register '${name}'.`);\r\n return;\r\n }\r\n\r\n // Unregister existing trigger with same name\r\n if (this._triggers.has(name)) {\r\n this.unregister(name);\r\n }\r\n\r\n const trigger = new Trigger(name, config);\r\n this._triggers.set(name, trigger);\r\n\r\n // Subscribe to matching events\r\n const handler = (eventData) => this._handleEvent(name, eventData);\r\n const unsub = this._eventBus.on(trigger.pattern, handler);\r\n this._listeners.set(name, unsub);\r\n\r\n logger.wuDebug(`[wu-ai] Trigger registered: '${name}' → pattern '${trigger.pattern}' (${trigger.priority})`);\r\n }\r\n\r\n /**\r\n * Unregister a trigger.\r\n */\r\n unregister(name) {\r\n const trigger = this._triggers.get(name);\r\n if (trigger) {\r\n // Clear any pending debounce\r\n if (trigger._debounceTimer) {\r\n clearTimeout(trigger._debounceTimer);\r\n }\r\n }\r\n\r\n // Remove event listener\r\n const unsub = this._listeners.get(name);\r\n if (typeof unsub === 'function') {\r\n unsub();\r\n }\r\n\r\n this._triggers.delete(name);\r\n this._listeners.delete(name);\r\n }\r\n\r\n /**\r\n * Enable/disable a trigger.\r\n */\r\n setEnabled(name, enabled) {\r\n const trigger = this._triggers.get(name);\r\n if (trigger) trigger.enabled = enabled;\r\n }\r\n\r\n /**\r\n * Enable/disable all triggers.\r\n */\r\n setAllEnabled(enabled) {\r\n this._config.enabled = enabled;\r\n for (const trigger of this._triggers.values()) {\r\n trigger.enabled = enabled;\r\n }\r\n }\r\n\r\n /**\r\n * Fire a trigger manually (bypasses event matching).\r\n */\r\n async fire(name, eventData = {}) {\r\n const trigger = this._triggers.get(name);\r\n if (!trigger) {\r\n logger.wuWarn(`[wu-ai] Trigger '${name}' not found`);\r\n return null;\r\n }\r\n return this._executeTrigger(trigger, eventData);\r\n }\r\n\r\n /**\r\n * Get registered trigger names.\r\n */\r\n getNames() {\r\n return [...this._triggers.keys()];\r\n }\r\n\r\n /**\r\n * Get trigger info.\r\n */\r\n getTrigger(name) {\r\n const t = this._triggers.get(name);\r\n if (!t) return null;\r\n return {\r\n name: t.name,\r\n pattern: t.pattern,\r\n priority: t.priority,\r\n namespace: t.namespace,\r\n enabled: t.enabled,\r\n fireCount: t._fireCount,\r\n lastFired: t._lastFired,\r\n };\r\n }\r\n\r\n /**\r\n * Destroy all triggers and clean up.\r\n */\r\n destroy() {\r\n for (const name of [...this._triggers.keys()]) {\r\n this.unregister(name);\r\n }\r\n if (this._batchTimer) {\r\n clearTimeout(this._batchTimer);\r\n this._batchTimer = null;\r\n }\r\n this._batchQueue = [];\r\n }\r\n\r\n // ── Private: Event Handling ──\r\n\r\n async _handleEvent(triggerName, eventData) {\r\n if (!this._config.enabled) return;\r\n\r\n const trigger = this._triggers.get(triggerName);\r\n if (!trigger || !trigger.enabled) return;\r\n\r\n // Check condition\r\n const conditionMet = await trigger.checkCondition(eventData);\r\n if (!conditionMet) {\r\n this._stats.totalSkipped++;\r\n return;\r\n }\r\n\r\n // Priority routing\r\n if (trigger.priority === 'high') {\r\n // High priority: fire immediately (with debounce)\r\n this._debouncedFire(trigger, eventData);\r\n } else if (trigger.priority === 'low') {\r\n // Low priority: batch\r\n this._batchQueue.push({ trigger, eventData });\r\n this._scheduleBatch();\r\n } else {\r\n // Medium: debounce\r\n this._debouncedFire(trigger, eventData);\r\n }\r\n }\r\n\r\n _debouncedFire(trigger, eventData) {\r\n // Store pending event (latest wins for debounce)\r\n trigger._pendingEvent = eventData;\r\n\r\n if (trigger._debounceTimer) {\r\n clearTimeout(trigger._debounceTimer);\r\n }\r\n\r\n if (trigger.debounceMs <= 0) {\r\n // No debounce\r\n this._executeTrigger(trigger, eventData);\r\n return;\r\n }\r\n\r\n trigger._debounceTimer = setTimeout(() => {\r\n trigger._debounceTimer = null;\r\n const pending = trigger._pendingEvent;\r\n trigger._pendingEvent = null;\r\n if (pending) {\r\n this._executeTrigger(trigger, pending);\r\n }\r\n }, trigger.debounceMs);\r\n }\r\n\r\n _scheduleBatch() {\r\n if (this._batchTimer) return;\r\n\r\n this._batchTimer = setTimeout(() => {\r\n this._batchTimer = null;\r\n this._processBatch();\r\n }, this._config.batchIntervalMs);\r\n }\r\n\r\n async _processBatch() {\r\n const batch = [...this._batchQueue];\r\n this._batchQueue = [];\r\n\r\n // Deduplicate: keep last event per trigger\r\n const byTrigger = new Map();\r\n for (const { trigger, eventData } of batch) {\r\n byTrigger.set(trigger.name, { trigger, eventData });\r\n }\r\n\r\n for (const { trigger, eventData } of byTrigger.values()) {\r\n await this._executeTrigger(trigger, eventData);\r\n }\r\n }\r\n\r\n async _executeTrigger(trigger, eventData) {\r\n try {\r\n const prompt = trigger.buildPrompt(eventData);\r\n if (!prompt) {\r\n this._stats.totalSkipped++;\r\n return null;\r\n }\r\n\r\n logger.wuDebug(`[wu-ai] Trigger '${trigger.name}' firing with prompt: ${prompt.slice(0, 100)}...`);\r\n\r\n const result = await this._conversation.send(prompt, {\r\n namespace: trigger.namespace,\r\n systemPrompt: trigger.systemPrompt,\r\n temperature: trigger.temperature,\r\n maxTokens: trigger.maxTokens,\r\n });\r\n\r\n trigger._fireCount++;\r\n trigger._lastFired = Date.now();\r\n this._stats.totalFired++;\r\n\r\n // Emit trigger result event\r\n this._eventBus.emit('ai:trigger:result', {\r\n trigger: trigger.name,\r\n pattern: trigger.pattern,\r\n result,\r\n }, { appName: 'wu-ai' });\r\n\r\n // Call onResult callback if provided\r\n if (trigger.onResult) {\r\n try {\r\n await trigger.onResult(result, eventData);\r\n } catch (err) {\r\n logger.wuDebug(`[wu-ai] Trigger '${trigger.name}' onResult error: ${err.message}`);\r\n }\r\n }\r\n\r\n return result;\r\n } catch (err) {\r\n this._stats.totalErrors++;\r\n logger.wuWarn(`[wu-ai] Trigger '${trigger.name}' error: ${err.message}`);\r\n\r\n this._eventBus.emit('ai:trigger:error', {\r\n trigger: trigger.name,\r\n error: err.message,\r\n }, { appName: 'wu-ai' });\r\n\r\n return null;\r\n }\r\n }\r\n\r\n getStats() {\r\n const triggers = {};\r\n for (const [name, t] of this._triggers) {\r\n triggers[name] = {\r\n pattern: t.pattern,\r\n priority: t.priority,\r\n enabled: t.enabled,\r\n fireCount: t._fireCount,\r\n lastFired: t._lastFired,\r\n };\r\n }\r\n return {\r\n ...this._stats,\r\n triggerCount: this._triggers.size,\r\n batchQueueSize: this._batchQueue.length,\r\n triggers,\r\n };\r\n }\r\n}\r\n","/**\r\n * WU-AI-AGENT: Autonomous agent loop (Paradigm 3)\r\n *\r\n * The agent is the third paradigm of wu.ai:\r\n * Paradigm 1 — App sends messages to LLM (conversation)\r\n * Paradigm 2 — External LLM calls into app (tools/WebMCP)\r\n * Paradigm 3 — AI as autonomous director (this file)\r\n *\r\n * The agent receives a goal and iterates: send to LLM, execute tool calls,\r\n * observe results, repeat — until the goal is achieved or limits are hit.\r\n * It is an async generator, yielding each step so the caller can observe,\r\n * log, render, or intervene at any point.\r\n *\r\n * This is a foundation, not a planner. It does not decompose goals into\r\n * sub-tasks or maintain a world model. It trusts the LLM to drive the\r\n * loop and uses the [DONE] marker or tool-call cessation as termination\r\n * signals. More sophisticated planning belongs in userland, composed\r\n * on top of this primitive.\r\n *\r\n * Key features:\r\n * - Async generator yielding step results (observable, composable)\r\n * - Human-in-the-loop via shouldContinue callback\r\n * - Abort support via AbortController\r\n * - Permission preflight before every step\r\n * - Event emission on start, step, done, error\r\n * - Auto-generated system prompt describing agent role and tools\r\n * - Configurable step limit (default 10)\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\n\r\n// ─── Constants ──────────────────────────────────────────────────\r\n\r\nconst DONE_MARKER = '[DONE]';\r\n\r\nconst DEFAULT_MAX_STEPS = 10;\r\n\r\nconst AGENT_NAMESPACE_PREFIX = 'agent:';\r\n\r\n// ─── Step Result Types ──────────────────────────────────────────\r\n\r\n/**\r\n * @typedef {object} AgentStepResult\r\n * @property {number} step - Step number (1-indexed)\r\n * @property {'thinking'|'tool_call'|'done'|'blocked'|'aborted'|'interrupted'} type\r\n * @property {string} [content] - LLM text response for this step\r\n * @property {Array} [toolResults] - Tool execution results (if tools were called)\r\n * @property {object} [usage] - Token usage for this step\r\n * @property {string} [reason] - Reason for termination (done/blocked/aborted)\r\n * @property {number} elapsed - Time in ms for this step\r\n */\r\n\r\n// ─── Agent Class ────────────────────────────────────────────────\r\n\r\nexport class WuAIAgent {\r\n /**\r\n * @param {object} deps - Injected dependencies (same pattern as other wu-ai modules)\r\n * @param {import('./wu-ai-conversation.js').WuAIConversation} deps.conversation - Conversation manager\r\n * @param {import('./wu-ai-actions.js').WuAIActions} deps.actions - Action registry\r\n * @param {import('./wu-ai-context.js').WuAIContext} deps.context - Context collector\r\n * @param {import('./wu-ai-permissions.js').WuAIPermissions} deps.permissions - Permission system\r\n * @param {object} deps.eventBus - WuEventBus instance\r\n */\r\n constructor({ conversation, actions, context, permissions, eventBus }) {\r\n this._conversation = conversation;\r\n this._actions = actions;\r\n this._context = context;\r\n this._permissions = permissions;\r\n this._eventBus = eventBus;\r\n\r\n this._config = {\r\n maxSteps: DEFAULT_MAX_STEPS,\r\n systemPrompt: null,\r\n };\r\n\r\n this._activeRuns = new Map(); // runId -> AbortController\r\n this._stats = {\r\n totalRuns: 0,\r\n totalSteps: 0,\r\n completedRuns: 0,\r\n abortedRuns: 0,\r\n errorRuns: 0,\r\n };\r\n }\r\n\r\n /**\r\n * Post-init configuration.\r\n *\r\n * @param {object} config\r\n * @param {number} [config.maxSteps] - Default max steps for all runs\r\n * @param {string|Function} [config.systemPrompt] - Default agent system prompt\r\n */\r\n configure(config) {\r\n if (config.maxSteps !== undefined) this._config.maxSteps = config.maxSteps;\r\n if (config.systemPrompt !== undefined) this._config.systemPrompt = config.systemPrompt;\r\n }\r\n\r\n /**\r\n * Run the agent loop toward a goal.\r\n *\r\n * The generator yields after each LLM round. The caller can inspect\r\n * the result, update UI, or break out of the loop to abort early.\r\n *\r\n * Termination conditions (checked in order):\r\n * 1. AbortController signal fired\r\n * 2. shouldContinue() returns false (human-in-the-loop gate)\r\n * 3. Permission preflight denied\r\n * 4. LLM response contains [DONE] marker\r\n * 5. LLM stops requesting tool calls (after previously requesting them)\r\n * 6. maxSteps reached\r\n *\r\n * @param {string} goal - Natural language description of what to achieve\r\n * @param {object} [options]\r\n * @param {number} [options.maxSteps] - Override max steps for this run\r\n * @param {string} [options.provider] - Use a specific registered provider\r\n * @param {string} [options.namespace] - Conversation namespace (auto-generated if omitted)\r\n * @param {string|Function} [options.systemPrompt] - Override system prompt\r\n * @param {Function} [options.onStep] - Callback invoked after each step: (stepResult) => void\r\n * @param {Function} [options.shouldContinue] - Async gate: (stepResult) => boolean. Return false to stop.\r\n * @param {AbortSignal} [options.signal] - External abort signal\r\n * @param {number} [options.temperature] - LLM temperature\r\n * @param {number} [options.maxTokens] - LLM max tokens per step\r\n * @yields {AgentStepResult}\r\n */\r\n async *run(goal, options = {}) {\r\n const maxSteps = options.maxSteps ?? this._config.maxSteps;\r\n const namespace = options.namespace || this._generateNamespace();\r\n const runId = this._generateRunId();\r\n\r\n // Abort controller: merge external signal with our own\r\n const controller = new AbortController();\r\n this._activeRuns.set(runId, controller);\r\n\r\n if (options.signal) {\r\n if (options.signal.aborted) {\r\n controller.abort();\r\n } else {\r\n options.signal.addEventListener('abort', () => controller.abort(), { once: true });\r\n }\r\n }\r\n\r\n this._stats.totalRuns++;\r\n\r\n // Build the agent system prompt\r\n const systemPrompt = await this._buildAgentSystemPrompt(goal, options);\r\n\r\n // Emit start event\r\n this._eventBus.emit('ai:agent:start', {\r\n runId,\r\n goal,\r\n namespace,\r\n maxSteps,\r\n }, { appName: 'wu-ai' });\r\n\r\n logger.wuInfo(`[wu-ai] Agent run started: \"${goal.slice(0, 80)}${goal.length > 80 ? '...' : ''}\" (max ${maxSteps} steps)`);\r\n\r\n let step = 0;\r\n let previousHadToolCalls = false;\r\n let finalReason = 'max_steps';\r\n\r\n try {\r\n // Inject the goal as the first user message via conversation.send\r\n // The loop sends the goal on step 1, then follow-up prompts on subsequent steps.\r\n\r\n while (step < maxSteps) {\r\n step++;\r\n const stepStart = Date.now();\r\n\r\n // ── 1. Check abort ──\r\n if (controller.signal.aborted) {\r\n const result = this._buildStepResult(step, 'aborted', {\r\n reason: 'Aborted by caller',\r\n elapsed: Date.now() - stepStart,\r\n });\r\n this._stats.abortedRuns++;\r\n finalReason = 'aborted';\r\n this._emitStep(runId, result);\r\n yield result;\r\n return;\r\n }\r\n\r\n // ── 2. Permission preflight ──\r\n const traceId = this._permissions.loopProtection.createTraceId();\r\n const preflight = this._permissions.preflight({\r\n namespace,\r\n depth: step,\r\n traceId,\r\n });\r\n\r\n if (!preflight.allowed) {\r\n const result = this._buildStepResult(step, 'blocked', {\r\n reason: preflight.reason,\r\n elapsed: Date.now() - stepStart,\r\n });\r\n finalReason = 'blocked';\r\n this._emitStep(runId, result);\r\n yield result;\r\n return;\r\n }\r\n\r\n // ── 3. Compose the message for this step ──\r\n const message = step === 1\r\n ? goal\r\n : 'Continue working toward the goal. If you are done, include [DONE] in your response.';\r\n\r\n // ── 4. Send to conversation (handles tool call loops internally) ──\r\n let response;\r\n try {\r\n response = await this._conversation.send(message, {\r\n namespace,\r\n systemPrompt,\r\n provider: options.provider,\r\n temperature: options.temperature,\r\n maxTokens: options.maxTokens,\r\n signal: controller.signal,\r\n });\r\n } catch (err) {\r\n if (err.name === 'AbortError' || controller.signal.aborted) {\r\n const result = this._buildStepResult(step, 'aborted', {\r\n reason: 'Aborted during LLM call',\r\n elapsed: Date.now() - stepStart,\r\n });\r\n this._stats.abortedRuns++;\r\n finalReason = 'aborted';\r\n this._emitStep(runId, result);\r\n yield result;\r\n return;\r\n }\r\n throw err;\r\n }\r\n\r\n const elapsed = Date.now() - stepStart;\r\n this._stats.totalSteps++;\r\n\r\n const hasToolResults = response.tool_results && response.tool_results.length > 0;\r\n const content = response.content || '';\r\n\r\n // ── 5. Check for DONE marker ──\r\n if (content.includes(DONE_MARKER)) {\r\n const result = this._buildStepResult(step, 'done', {\r\n content: content.replace(DONE_MARKER, '').trim(),\r\n toolResults: response.tool_results,\r\n usage: response.usage,\r\n reason: 'Goal completed (DONE marker)',\r\n elapsed,\r\n });\r\n finalReason = 'done';\r\n this._stats.completedRuns++;\r\n this._emitStep(runId, result);\r\n if (options.onStep) await this._safeCallback(options.onStep, result);\r\n yield result;\r\n return;\r\n }\r\n\r\n // ── 6. Check for tool-call cessation ──\r\n // If the LLM was previously calling tools but stopped, it has\r\n // settled on a final answer. This is the implicit completion signal.\r\n const currentHasToolCalls = hasToolResults;\r\n if (previousHadToolCalls && !currentHasToolCalls) {\r\n const result = this._buildStepResult(step, 'done', {\r\n content,\r\n toolResults: response.tool_results,\r\n usage: response.usage,\r\n reason: 'Goal completed (no further tool calls)',\r\n elapsed,\r\n });\r\n finalReason = 'done';\r\n this._stats.completedRuns++;\r\n this._emitStep(runId, result);\r\n if (options.onStep) await this._safeCallback(options.onStep, result);\r\n yield result;\r\n return;\r\n }\r\n\r\n previousHadToolCalls = currentHasToolCalls;\r\n\r\n // ── 7. Yield the step result ──\r\n const stepType = hasToolResults ? 'tool_call' : 'thinking';\r\n const result = this._buildStepResult(step, stepType, {\r\n content,\r\n toolResults: response.tool_results,\r\n usage: response.usage,\r\n elapsed,\r\n });\r\n\r\n this._emitStep(runId, result);\r\n if (options.onStep) await this._safeCallback(options.onStep, result);\r\n yield result;\r\n\r\n // ── 8. Human-in-the-loop gate ──\r\n if (options.shouldContinue) {\r\n let shouldGo;\r\n try {\r\n shouldGo = await options.shouldContinue(result);\r\n } catch {\r\n shouldGo = false;\r\n }\r\n\r\n if (!shouldGo) {\r\n const interrupted = this._buildStepResult(step, 'interrupted', {\r\n content,\r\n reason: 'Stopped by shouldContinue callback',\r\n elapsed: 0,\r\n });\r\n finalReason = 'interrupted';\r\n this._emitStep(runId, interrupted);\r\n yield interrupted;\r\n return;\r\n }\r\n }\r\n }\r\n\r\n // ── Max steps reached ──\r\n const maxStepResult = this._buildStepResult(step, 'done', {\r\n reason: `Max steps (${maxSteps}) reached`,\r\n elapsed: 0,\r\n });\r\n finalReason = 'max_steps';\r\n yield maxStepResult;\r\n\r\n } catch (err) {\r\n this._stats.errorRuns++;\r\n finalReason = 'error';\r\n\r\n logger.wuWarn(`[wu-ai] Agent run error: ${err.message}`);\r\n\r\n this._eventBus.emit('ai:agent:error', {\r\n runId,\r\n goal,\r\n namespace,\r\n step,\r\n error: err.message,\r\n }, { appName: 'wu-ai' });\r\n\r\n throw err;\r\n } finally {\r\n // Clean up\r\n this._activeRuns.delete(runId);\r\n\r\n // Delete auto-generated agent namespaces to prevent memory leaks\r\n // User-provided namespaces are preserved (the user owns their lifecycle)\r\n if (!options.namespace && namespace.startsWith(AGENT_NAMESPACE_PREFIX)) {\r\n this._conversation.deleteNamespace(namespace);\r\n }\r\n\r\n this._eventBus.emit('ai:agent:done', {\r\n runId,\r\n goal,\r\n namespace,\r\n totalSteps: step,\r\n reason: finalReason,\r\n }, { appName: 'wu-ai' });\r\n\r\n logger.wuDebug(`[wu-ai] Agent run finished: ${finalReason} after ${step} step(s)`);\r\n }\r\n }\r\n\r\n /**\r\n * Abort an active agent run by runId.\r\n *\r\n * @param {string} runId - The run ID to abort\r\n */\r\n abort(runId) {\r\n const controller = this._activeRuns.get(runId);\r\n if (controller) {\r\n controller.abort();\r\n logger.wuDebug(`[wu-ai] Agent run aborted: ${runId}`);\r\n }\r\n }\r\n\r\n /**\r\n * Abort all active agent runs.\r\n */\r\n abortAll() {\r\n for (const [runId, controller] of this._activeRuns) {\r\n controller.abort();\r\n }\r\n this._activeRuns.clear();\r\n }\r\n\r\n /**\r\n * Get IDs of currently active runs.\r\n *\r\n * @returns {string[]}\r\n */\r\n getActiveRuns() {\r\n return [...this._activeRuns.keys()];\r\n }\r\n\r\n /**\r\n * Get agent statistics.\r\n *\r\n * @returns {object}\r\n */\r\n getStats() {\r\n return {\r\n ...this._stats,\r\n activeRuns: this._activeRuns.size,\r\n config: { ...this._config },\r\n };\r\n }\r\n\r\n /**\r\n * Destroy the agent, aborting all active runs.\r\n */\r\n destroy() {\r\n this.abortAll();\r\n this._stats = {\r\n totalRuns: 0,\r\n totalSteps: 0,\r\n completedRuns: 0,\r\n abortedRuns: 0,\r\n errorRuns: 0,\r\n };\r\n }\r\n\r\n // ─── Private ──────────────────────────────────────────────────\r\n\r\n /**\r\n * Build the agent-specific system prompt. This tells the LLM it is\r\n * operating as an autonomous agent with a goal, available tools, and\r\n * the [DONE] completion protocol.\r\n */\r\n async _buildAgentSystemPrompt(goal, options) {\r\n // Explicit override takes precedence\r\n const basePrompt = options.systemPrompt\r\n ?? this._config.systemPrompt\r\n ?? null;\r\n\r\n if (basePrompt) {\r\n const resolved = typeof basePrompt === 'function'\r\n ? await basePrompt(goal)\r\n : basePrompt;\r\n return resolved;\r\n }\r\n\r\n // Auto-generate from context and tools\r\n const parts = [];\r\n\r\n parts.push(\r\n 'You are an autonomous AI agent connected to a live web application via Wu Framework.',\r\n 'You have been given a goal and must work step-by-step to achieve it.',\r\n '',\r\n 'PROTOCOL:',\r\n '- Each message you send is one \"step\" in your execution.',\r\n '- You may call tools to read or modify application state.',\r\n '- After each step, you will be prompted to continue.',\r\n '- When the goal is fully achieved, include the marker [DONE] in your response.',\r\n '- If you determine the goal cannot be achieved, include [DONE] and explain why.',\r\n '- Be concise. Each step should make meaningful progress.',\r\n '',\r\n );\r\n\r\n // Collect context if available\r\n if (this._context) {\r\n try {\r\n await this._context.collect();\r\n const snapshot = this._context.getSnapshot();\r\n if (snapshot?._mountedApps?.length) {\r\n parts.push(`MOUNTED APPS: ${snapshot._mountedApps.join(', ')}`, '');\r\n }\r\n if (snapshot?._store && Object.keys(snapshot._store).length > 0) {\r\n parts.push(`APPLICATION STATE:\\n${JSON.stringify(snapshot._store, null, 2)}`, '');\r\n }\r\n } catch {\r\n // Context collection is best-effort\r\n }\r\n }\r\n\r\n // List available tools\r\n const tools = this._actions.getToolSchemas();\r\n if (tools.length > 0) {\r\n parts.push('AVAILABLE TOOLS:');\r\n for (const tool of tools) {\r\n const paramKeys = tool.parameters?.properties\r\n ? Object.keys(tool.parameters.properties).join(', ')\r\n : 'none';\r\n parts.push(`- ${tool.name}(${paramKeys}): ${tool.description}`);\r\n }\r\n parts.push('');\r\n }\r\n\r\n parts.push(`GOAL: ${goal}`);\r\n\r\n return parts.join('\\n');\r\n }\r\n\r\n /**\r\n * Build a normalized step result object.\r\n *\r\n * @param {number} step\r\n * @param {string} type\r\n * @param {object} data\r\n * @returns {AgentStepResult}\r\n */\r\n _buildStepResult(step, type, data = {}) {\r\n return {\r\n step,\r\n type,\r\n content: data.content ?? null,\r\n toolResults: data.toolResults ?? null,\r\n usage: data.usage ?? null,\r\n reason: data.reason ?? null,\r\n elapsed: data.elapsed ?? 0,\r\n };\r\n }\r\n\r\n /**\r\n * Emit an ai:agent:step event.\r\n */\r\n _emitStep(runId, result) {\r\n this._eventBus.emit('ai:agent:step', {\r\n runId,\r\n ...result,\r\n }, { appName: 'wu-ai' });\r\n }\r\n\r\n /**\r\n * Safely invoke a callback, swallowing errors so the agent loop\r\n * is never broken by a faulty onStep handler.\r\n */\r\n async _safeCallback(fn, ...args) {\r\n try {\r\n const result = fn(...args);\r\n if (result && typeof result.then === 'function') {\r\n await result;\r\n }\r\n } catch (err) {\r\n logger.wuDebug(`[wu-ai] Agent callback error: ${err.message}`);\r\n }\r\n }\r\n\r\n /**\r\n * Generate a unique namespace for an agent run.\r\n */\r\n _generateNamespace() {\r\n return AGENT_NAMESPACE_PREFIX + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 6);\r\n }\r\n\r\n /**\r\n * Generate a unique run ID.\r\n */\r\n _generateRunId() {\r\n return 'run_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8);\r\n }\r\n}\r\n","/**\r\n * WU-AI-ORCHESTRATE: Cross-Micro-App AI Coordination (Paradigm 4)\r\n *\r\n * The fourth paradigm of wu.ai:\r\n * Paradigm 1 — App sends messages to LLM (conversation)\r\n * Paradigm 2 — External LLM calls into app (tools/WebMCP)\r\n * Paradigm 3 — AI as autonomous director (agent loop)\r\n * Paradigm 4 — AI as microfrontend glue (this file)\r\n *\r\n * The Problem:\r\n * In microfrontend architectures, apps are isolated by design.\r\n * Cross-app coordination requires manual wiring through events\r\n * and shared state. As apps grow, wiring becomes n² complexity.\r\n *\r\n * The Solution:\r\n * Each micro-app declares its capabilities to the AI layer.\r\n * The AI understands the semantic meaning of each capability\r\n * and can resolve natural-language intents by calling the right\r\n * actions across the right apps — without tight coupling.\r\n *\r\n * Key Concepts:\r\n * - Capability: An action scoped to a specific micro-app\r\n * Registered as 'appName:actionName', cleaned up on unmount.\r\n * - Intent: A natural-language cross-app request resolved in\r\n * a single conversation turn with an orchestrator system prompt.\r\n * - Capability Map: The AI's understanding of system topology —\r\n * which apps exist and what each can do.\r\n *\r\n * This module does NOT replace actions, triggers, or agents.\r\n * It enriches them with cross-app topology awareness.\r\n *\r\n * API (accessible via wu.ai):\r\n * wu.ai.capability(app, name, config) → Register app-scoped capability\r\n * wu.ai.intent(description, options) → Resolve cross-app intent\r\n * wu.ai.removeApp(appName) → Cleanup on unmount\r\n * wu.ai.workflow(name, config) → Register reusable AI workflow\r\n * wu.ai.runWorkflow(name, params, opts) → Execute a registered workflow\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\nimport { clickElement, typeIntoElement } from './wu-ai-browser-primitives.js';\r\n\r\n// ─── Constants ──────────────────────────────────────────────────\r\n\r\nconst INTENT_NAMESPACE_PREFIX = 'intent:';\r\n\r\n// ─── Deterministic Step Actions ─────────────────────────────────\r\n\r\n/**\r\n * Execute a single deterministic workflow step.\r\n * No AI needed — directly calls browser primitives.\r\n *\r\n * @param {object} step - Step definition\r\n * @param {string} step.action - 'click' | 'type' | 'navigate' | 'wait' | 'emit' | 'setState'\r\n * @param {object} params - Interpolated params\r\n * @returns {{ success: boolean, detail?: string, error?: string }}\r\n */\r\nfunction executeDeterministicStep(step, eventBus, store) {\r\n switch (step.action) {\r\n case 'click': {\r\n const result = clickElement(step.selector, step.text);\r\n if (result.error) return { success: false, error: result.error };\r\n return { success: true, detail: `Clicked: ${step.selector || step.text}` };\r\n }\r\n\r\n case 'type': {\r\n const result = typeIntoElement(step.selector, step.value, {\r\n clear: step.clear ?? true,\r\n submit: step.submit ?? false,\r\n });\r\n if (result.error) return { success: false, error: result.error };\r\n return { success: true, detail: `Typed \"${step.value}\" into ${step.selector}` };\r\n }\r\n\r\n case 'navigate': {\r\n if (eventBus && step.section) {\r\n eventBus.emit('nav:section', { section: step.section }, { appName: 'wu-ai' });\r\n return { success: true, detail: `Navigated to section: ${step.section}` };\r\n }\r\n if (step.selector) {\r\n const result = clickElement(step.selector, step.text);\r\n if (result.error) return { success: false, error: result.error };\r\n return { success: true, detail: `Navigated via click: ${step.selector}` };\r\n }\r\n return { success: false, error: 'navigate requires \"section\" or \"selector\"' };\r\n }\r\n\r\n case 'wait': {\r\n // Wait is handled by the runner (delay + optional selector poll)\r\n return { success: true, detail: `Wait: ${step.ms || 0}ms` };\r\n }\r\n\r\n case 'emit': {\r\n if (!eventBus) return { success: false, error: 'eventBus not available' };\r\n eventBus.emit(step.event, step.data || {}, { appName: 'wu-ai' });\r\n return { success: true, detail: `Emitted: ${step.event}` };\r\n }\r\n\r\n case 'setState': {\r\n if (!store) return { success: false, error: 'store not available' };\r\n store.set(step.path, step.value);\r\n return { success: true, detail: `Set state: ${step.path}` };\r\n }\r\n\r\n default:\r\n return { success: false, error: `Unknown action: ${step.action}` };\r\n }\r\n}\r\n\r\n/**\r\n * Wait for a selector to appear in the DOM (with timeout).\r\n *\r\n * @param {string} selector\r\n * @param {number} timeout - ms\r\n * @returns {Promise<boolean>}\r\n */\r\nfunction waitForSelector(selector, timeout = 5000) {\r\n return new Promise((resolve) => {\r\n if (document.querySelector(selector)) {\r\n resolve(true);\r\n return;\r\n }\r\n\r\n const interval = 100;\r\n let elapsed = 0;\r\n const timer = setInterval(() => {\r\n elapsed += interval;\r\n if (document.querySelector(selector)) {\r\n clearInterval(timer);\r\n resolve(true);\r\n } else if (elapsed >= timeout) {\r\n clearInterval(timer);\r\n resolve(false);\r\n }\r\n }, interval);\r\n });\r\n}\r\n\r\n/**\r\n * Simple delay.\r\n */\r\nfunction delay(ms) {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n// ─── WuAIOrchestrate ────────────────────────────────────────────\r\n\r\nexport class WuAIOrchestrate {\r\n /**\r\n * @param {object} deps\r\n * @param {import('./wu-ai-actions.js').WuAIActions} deps.actions\r\n * @param {import('./wu-ai-conversation.js').WuAIConversation} deps.conversation\r\n * @param {import('./wu-ai-context.js').WuAIContext} deps.context\r\n * @param {import('./wu-ai-permissions.js').WuAIPermissions} deps.permissions\r\n * @param {object} deps.eventBus\r\n */\r\n constructor({ actions, conversation, context, permissions, eventBus, agent, store }) {\r\n this._actions = actions;\r\n this._conversation = conversation;\r\n this._context = context;\r\n this._permissions = permissions;\r\n this._eventBus = eventBus;\r\n this._agent = agent; // WuAIAgent — for workflow execution\r\n this._store = store; // WuStore — for deterministic setState steps\r\n\r\n // appName → Map<actionName, { description, qualifiedName }>\r\n this._capabilities = new Map();\r\n\r\n // name → { goal, steps, parameters, provider, ... }\r\n this._workflows = new Map();\r\n\r\n this._config = {\r\n defaultProvider: null,\r\n defaultTemperature: 0.3, // lower temp for orchestration\r\n };\r\n\r\n this._stats = {\r\n totalIntents: 0,\r\n resolvedIntents: 0,\r\n failedIntents: 0,\r\n workflowsRegistered: 0,\r\n workflowsExecuted: 0,\r\n };\r\n }\r\n\r\n /**\r\n * Post-init configuration.\r\n *\r\n * @param {object} config\r\n * @param {string} [config.defaultProvider] - Default provider for intents\r\n * @param {number} [config.defaultTemperature] - Default temperature for intents\r\n */\r\n configure(config) {\r\n if (config.defaultProvider !== undefined) this._config.defaultProvider = config.defaultProvider;\r\n if (config.defaultTemperature !== undefined) this._config.defaultTemperature = config.defaultTemperature;\r\n }\r\n\r\n // ─── Capability Registration ────────────────────────────────────\r\n\r\n /**\r\n * Register a capability scoped to a micro-app.\r\n *\r\n * Under the hood this registers a normal action with the qualified\r\n * name 'appName:actionName' so the LLM can call it directly.\r\n * The capability map is tracked separately for lifecycle management\r\n * (removeApp) and system prompt enrichment.\r\n *\r\n * @param {string} appName - The micro-app name (e.g., 'orders', 'dashboard')\r\n * @param {string} actionName - The capability name (e.g., 'getRecent', 'updateKPIs')\r\n * @param {object} config - Same as wu.ai.action() config:\r\n * { description, parameters, handler, confirm?, permissions?, dangerous? }\r\n */\r\n register(appName, actionName, config) {\r\n if (!appName || !actionName) {\r\n throw new Error('[wu-ai] capability() requires both appName and actionName');\r\n }\r\n if (!config || typeof config.handler !== 'function') {\r\n throw new Error(`[wu-ai] capability '${appName}:${actionName}' must have a handler function`);\r\n }\r\n\r\n const qualifiedName = `${appName}:${actionName}`;\r\n\r\n // Track in capability map\r\n if (!this._capabilities.has(appName)) {\r\n this._capabilities.set(appName, new Map());\r\n }\r\n this._capabilities.get(appName).set(actionName, {\r\n description: config.description || actionName,\r\n qualifiedName,\r\n });\r\n\r\n // Register as a normal action with enriched description\r\n this._actions.register(qualifiedName, {\r\n ...config,\r\n description: `[${appName}] ${config.description || actionName}`,\r\n });\r\n\r\n logger.wuDebug(`[wu-ai] Capability registered: ${qualifiedName}`);\r\n }\r\n\r\n /**\r\n * Remove a single capability.\r\n *\r\n * @param {string} appName\r\n * @param {string} actionName\r\n */\r\n unregister(appName, actionName) {\r\n const appCaps = this._capabilities.get(appName);\r\n if (!appCaps) return;\r\n\r\n const qualifiedName = `${appName}:${actionName}`;\r\n appCaps.delete(actionName);\r\n this._actions.unregister(qualifiedName);\r\n\r\n // Clean up empty app entry\r\n if (appCaps.size === 0) {\r\n this._capabilities.delete(appName);\r\n }\r\n }\r\n\r\n /**\r\n * Remove all capabilities for a micro-app (unmount cleanup).\r\n *\r\n * Call this when a micro-app is unmounted to prevent stale\r\n * capabilities from appearing in the AI's capability map.\r\n *\r\n * @param {string} appName\r\n * @returns {number} Number of capabilities removed\r\n */\r\n removeApp(appName) {\r\n const appCaps = this._capabilities.get(appName);\r\n if (!appCaps) return 0;\r\n\r\n let removed = 0;\r\n for (const [actionName] of appCaps) {\r\n const qualifiedName = `${appName}:${actionName}`;\r\n this._actions.unregister(qualifiedName);\r\n removed++;\r\n }\r\n\r\n this._capabilities.delete(appName);\r\n\r\n logger.wuDebug(`[wu-ai] All capabilities removed for app '${appName}' (${removed})`);\r\n\r\n this._eventBus.emit('ai:app:removed', {\r\n appName,\r\n capabilitiesRemoved: removed,\r\n }, { appName: 'wu-ai' });\r\n\r\n return removed;\r\n }\r\n\r\n // ─── Capability Map ─────────────────────────────────────────────\r\n\r\n /**\r\n * Get the full capability map grouped by app.\r\n *\r\n * Used for system prompt enrichment and debugging.\r\n *\r\n * @returns {object} { appName: [{ action, description }], ... }\r\n */\r\n getCapabilityMap() {\r\n const map = {};\r\n for (const [appName, actions] of this._capabilities) {\r\n map[appName] = [];\r\n for (const [, meta] of actions) {\r\n map[appName].push({\r\n action: meta.qualifiedName,\r\n description: meta.description,\r\n });\r\n }\r\n }\r\n return map;\r\n }\r\n\r\n /**\r\n * Get app names that have registered capabilities.\r\n *\r\n * @returns {string[]}\r\n */\r\n getRegisteredApps() {\r\n return [...this._capabilities.keys()];\r\n }\r\n\r\n /**\r\n * Check if an app has registered capabilities.\r\n *\r\n * @param {string} appName\r\n * @returns {boolean}\r\n */\r\n hasApp(appName) {\r\n return this._capabilities.has(appName);\r\n }\r\n\r\n /**\r\n * Get the total number of registered capabilities across all apps.\r\n *\r\n * @returns {number}\r\n */\r\n getTotalCapabilities() {\r\n let count = 0;\r\n for (const actions of this._capabilities.values()) {\r\n count += actions.size;\r\n }\r\n return count;\r\n }\r\n\r\n // ─── Intent Resolution ──────────────────────────────────────────\r\n\r\n /**\r\n * Resolve a cross-app intent in a single conversation turn.\r\n *\r\n * The AI receives:\r\n * - The full capability map (what each app can do)\r\n * - Current application state (via context)\r\n * - Mounted apps list\r\n * - All registered tools (capabilities are tools)\r\n *\r\n * Unlike agent(), this is NOT a multi-step autonomous loop.\r\n * The LLM resolves the intent in one logical request (which may\r\n * include multiple tool calls within the conversation's tool-call\r\n * loop, but conceptually is a single turn).\r\n *\r\n * Unlike send(), the namespace is ephemeral and auto-cleaned,\r\n * and the system prompt is auto-built with the capability map.\r\n *\r\n * @param {string} description - Natural language intent\r\n * e.g., \"Show me the top customer by order count\"\r\n * e.g., \"Update dashboard stats and notify the topbar\"\r\n * @param {object} [options]\r\n * @param {string[]} [options.plan] - Optional action sequence hint.\r\n * The AI uses this as guidance but can deviate if needed.\r\n * e.g., ['orders:getRecent', 'customers:lookup']\r\n * @param {string} [options.provider] - LLM provider override\r\n * @param {number} [options.temperature] - Temperature override\r\n * @param {number} [options.maxTokens] - Max tokens override\r\n * @param {AbortSignal} [options.signal] - Abort signal\r\n * @param {string|object} [options.responseFormat] - Response format\r\n * @returns {Promise<{\r\n * content: string,\r\n * tool_results: Array,\r\n * usage: object|null,\r\n * resolved: boolean,\r\n * appsInvolved: string[]\r\n * }>}\r\n */\r\n async resolve(description, options = {}) {\r\n if (!description || typeof description !== 'string') {\r\n throw new Error('[wu-ai] intent() requires a description string');\r\n }\r\n\r\n this._stats.totalIntents++;\r\n const namespace = this._generateNamespace();\r\n\r\n // Collect fresh context before building the prompt\r\n if (this._context) {\r\n try {\r\n await this._context.collect();\r\n } catch {\r\n // Context collection is best-effort\r\n }\r\n }\r\n\r\n const systemPrompt = this._buildOrchestratorPrompt(options);\r\n\r\n this._eventBus.emit('ai:intent:start', {\r\n description: description.slice(0, 200),\r\n namespace,\r\n capabilities: this.getTotalCapabilities(),\r\n }, { appName: 'wu-ai' });\r\n\r\n try {\r\n const response = await this._conversation.send(description, {\r\n namespace,\r\n systemPrompt,\r\n provider: options.provider || this._config.defaultProvider,\r\n temperature: options.temperature ?? this._config.defaultTemperature,\r\n maxTokens: options.maxTokens,\r\n signal: options.signal,\r\n responseFormat: options.responseFormat,\r\n });\r\n\r\n const toolResults = response.tool_results || [];\r\n const appsInvolved = this._extractInvolvedApps(toolResults);\r\n const resolved = !!(response.content);\r\n\r\n if (resolved) {\r\n this._stats.resolvedIntents++;\r\n } else {\r\n this._stats.failedIntents++;\r\n }\r\n\r\n const result = {\r\n content: response.content || '',\r\n tool_results: toolResults,\r\n usage: response.usage || null,\r\n resolved,\r\n appsInvolved,\r\n };\r\n\r\n this._eventBus.emit('ai:intent:resolved', {\r\n description: description.slice(0, 200),\r\n resolved,\r\n appsInvolved,\r\n }, { appName: 'wu-ai' });\r\n\r\n return result;\r\n } catch (err) {\r\n this._stats.failedIntents++;\r\n\r\n this._eventBus.emit('ai:intent:error', {\r\n description: description.slice(0, 200),\r\n error: err.message,\r\n }, { appName: 'wu-ai' });\r\n\r\n throw err;\r\n } finally {\r\n // Always clean up the ephemeral namespace\r\n this._conversation.deleteNamespace(namespace);\r\n }\r\n }\r\n\r\n // ─── System Prompt Builder ──────────────────────────────────────\r\n\r\n /**\r\n * Build the orchestrator system prompt with full capability map.\r\n *\r\n * This method is also available to other modules (triggers, agents)\r\n * that want capability-aware system prompts.\r\n *\r\n * @param {object} [options]\r\n * @param {string[]} [options.plan] - Optional action sequence hint\r\n * @returns {string}\r\n */\r\n buildOrchestratorPrompt(options = {}) {\r\n return this._buildOrchestratorPrompt(options);\r\n }\r\n\r\n /** @private */\r\n _buildOrchestratorPrompt(options = {}) {\r\n const parts = [];\r\n\r\n parts.push(\r\n 'You are an AI orchestrator for a microfrontend application.',\r\n 'Multiple independent apps are mounted, each with specific capabilities.',\r\n 'Resolve cross-app requests by calling the right capabilities in the right order.',\r\n '',\r\n 'RULES:',\r\n '- Call capabilities (tools) to gather data or trigger actions.',\r\n '- You may call multiple capabilities from different apps if needed.',\r\n '- Synthesize results into a clear, actionable response.',\r\n '- If a required app is not available or lacks a capability, explain what is missing.',\r\n '',\r\n );\r\n\r\n // Capability map\r\n const capMap = this.getCapabilityMap();\r\n const appNames = Object.keys(capMap);\r\n\r\n if (appNames.length > 0) {\r\n parts.push('CAPABILITY MAP:');\r\n for (const appName of appNames) {\r\n parts.push(` ${appName}:`);\r\n for (const cap of capMap[appName]) {\r\n parts.push(` - ${cap.action}: ${cap.description}`);\r\n }\r\n }\r\n parts.push('');\r\n } else {\r\n parts.push(\r\n 'NOTE: No app capabilities are registered. Answer based on available context only.',\r\n '',\r\n );\r\n }\r\n\r\n // Optional plan hint\r\n if (options.plan && options.plan.length > 0) {\r\n parts.push(\r\n 'SUGGESTED PLAN (follow this unless a better approach is evident):',\r\n );\r\n for (let i = 0; i < options.plan.length; i++) {\r\n parts.push(` ${i + 1}. ${options.plan[i]}`);\r\n }\r\n parts.push('');\r\n }\r\n\r\n // Context snapshot (state, mounted apps)\r\n const snapshot = this._context?.getSnapshot();\r\n if (snapshot?._mountedApps?.length) {\r\n parts.push(`MOUNTED APPS: ${snapshot._mountedApps.join(', ')}`, '');\r\n }\r\n if (snapshot?._store && Object.keys(snapshot._store).length > 0) {\r\n parts.push(\r\n 'CURRENT STATE:',\r\n JSON.stringify(snapshot._store, null, 2),\r\n '',\r\n );\r\n }\r\n\r\n return parts.join('\\n');\r\n }\r\n\r\n // ─── Workflows ─────────────────────────────────────────────────\r\n\r\n /**\r\n * Register a reusable AI workflow.\r\n *\r\n * A workflow is a named, parameterized recipe that the AI agent\r\n * follows step by step. Think of it as a macro: you define it once,\r\n * then run it whenever you need with different parameters.\r\n *\r\n * The AI receives the steps as instructions and uses browser actions\r\n * (screenshot, click, type) plus any registered capabilities/actions\r\n * to execute them. You can watch every step in real time.\r\n *\r\n * @param {string} name - Workflow name (e.g., 'register-user')\r\n * @param {object} config\r\n * @param {string} config.description - What this workflow does\r\n * @param {string[]} config.steps - Step-by-step instructions for the AI\r\n * @param {object} [config.parameters] - Parameter definitions for interpolation\r\n * e.g., { name: { type: 'string', required: true }, email: { type: 'string' } }\r\n * @param {number} [config.maxSteps=15] - Max agent steps allowed\r\n * @param {string} [config.provider] - LLM provider to use\r\n * @param {number} [config.temperature] - Temperature (default: 0.2 for precision)\r\n *\r\n * @example\r\n * // ── AI Mode (default): steps are natural language ──\r\n * wu.ai.workflow('register-user', {\r\n * description: 'Register a new user in the system',\r\n * steps: [\r\n * 'Navigate to the Customers section',\r\n * 'Click the \"Add Customer\" button',\r\n * 'Fill in the name field with {{name}}',\r\n * 'Click Submit',\r\n * ],\r\n * parameters: { name: { type: 'string', required: true } },\r\n * });\r\n *\r\n * // ── Deterministic Mode: steps are exact actions, NO AI NEEDED ──\r\n * wu.ai.workflow('register-user', {\r\n * mode: 'deterministic',\r\n * description: 'Register a new user',\r\n * steps: [\r\n * { action: 'navigate', section: 'customers' },\r\n * { action: 'click', selector: '#add-customer-btn' },\r\n * { action: 'type', selector: '#name', value: '{{name}}' },\r\n * { action: 'type', selector: '#email', value: '{{email}}' },\r\n * { action: 'click', selector: '#submit-btn' },\r\n * { action: 'wait', selector: '.success-message', timeout: 5000 },\r\n * ],\r\n * parameters: {\r\n * name: { type: 'string', required: true },\r\n * email: { type: 'string', required: true },\r\n * },\r\n * });\r\n */\r\n registerWorkflow(name, config) {\r\n if (!name) {\r\n throw new Error('[wu-ai] workflow() requires a name');\r\n }\r\n if (!config || !config.steps || !Array.isArray(config.steps) || config.steps.length === 0) {\r\n throw new Error(`[wu-ai] workflow '${name}' must have a non-empty steps array`);\r\n }\r\n\r\n // Detect mode: if steps are objects with 'action', it's deterministic\r\n const mode = config.mode || (\r\n config.steps.length > 0 && typeof config.steps[0] === 'object' && config.steps[0].action\r\n ? 'deterministic'\r\n : 'ai'\r\n );\r\n\r\n this._workflows.set(name, {\r\n description: config.description || name,\r\n steps: config.steps,\r\n mode,\r\n parameters: config.parameters || {},\r\n maxSteps: config.maxSteps ?? 15,\r\n provider: config.provider || null,\r\n temperature: config.temperature ?? 0.2,\r\n });\r\n\r\n this._stats.workflowsRegistered++;\r\n\r\n logger.wuDebug(`[wu-ai] Workflow registered: '${name}' (${config.steps.length} steps)`);\r\n }\r\n\r\n /**\r\n * Execute a registered workflow with parameters.\r\n *\r\n * Returns an async generator (like agent) — you iterate over it\r\n * to observe each step in real time.\r\n *\r\n * @param {string} name - Workflow name\r\n * @param {object} [params={}] - Parameters to interpolate into steps\r\n * e.g., { name: 'Juan Pérez', email: 'juan@test.com' }\r\n * @param {object} [options={}]\r\n * @param {Function} [options.onStep] - Callback per step\r\n * @param {Function} [options.shouldContinue] - Human-in-the-loop gate\r\n * @param {AbortSignal} [options.signal] - Abort signal\r\n * @returns {AsyncGenerator<AgentStepResult>}\r\n *\r\n * @example\r\n * for await (const step of wu.ai.runWorkflow('register-user', {\r\n * name: 'Juan Pérez',\r\n * email: 'juan@test.com',\r\n * })) {\r\n * console.log(`Paso ${step.step}: ${step.content}`);\r\n * if (step.type === 'done') console.log('Workflow completado!');\r\n * }\r\n *\r\n * // With human approval per step:\r\n * for await (const step of wu.ai.runWorkflow('register-user', params, {\r\n * shouldContinue: (step) => confirm(`¿Continuar? ${step.content?.slice(0, 60)}`),\r\n * })) {\r\n * renderStep(step);\r\n * }\r\n */\r\n async *executeWorkflow(name, params = {}, options = {}) {\r\n const workflow = this._workflows.get(name);\r\n if (!workflow) {\r\n throw new Error(`[wu-ai] Workflow '${name}' is not registered`);\r\n }\r\n\r\n // Validate required parameters\r\n for (const [paramName, paramConfig] of Object.entries(workflow.parameters)) {\r\n if (paramConfig.required && (params[paramName] === undefined || params[paramName] === null)) {\r\n throw new Error(`[wu-ai] Workflow '${name}' requires parameter '${paramName}'`);\r\n }\r\n }\r\n\r\n this._stats.workflowsExecuted++;\r\n\r\n // Branch on mode\r\n if (workflow.mode === 'deterministic') {\r\n yield* this._executeDeterministic(name, workflow, params, options);\r\n } else {\r\n yield* this._executeWithAgent(name, workflow, params, options);\r\n }\r\n }\r\n\r\n /**\r\n * Execute workflow using the AI agent (natural language steps).\r\n * @private\r\n */\r\n async *_executeWithAgent(name, workflow, params, options) {\r\n if (!this._agent) {\r\n throw new Error('[wu-ai] Agent module not available for workflow execution');\r\n }\r\n\r\n // Interpolate parameters into string steps\r\n const interpolatedSteps = workflow.steps.map(step => {\r\n let result = step;\r\n for (const [key, value] of Object.entries(params)) {\r\n result = result.replace(new RegExp(`\\\\{\\\\{${key}\\\\}\\\\}`, 'g'), String(value));\r\n }\r\n return result;\r\n });\r\n\r\n const goal = this._buildWorkflowGoal(workflow, interpolatedSteps, params);\r\n\r\n this._eventBus.emit('ai:workflow:start', {\r\n workflow: name,\r\n mode: 'ai',\r\n params,\r\n steps: interpolatedSteps.length,\r\n }, { appName: 'wu-ai' });\r\n\r\n let finalStep = null;\r\n\r\n try {\r\n yield* this._agent.run(goal, {\r\n maxSteps: workflow.maxSteps,\r\n provider: options.provider || workflow.provider || this._config.defaultProvider,\r\n temperature: workflow.temperature ?? 0.2,\r\n onStep: (step) => {\r\n finalStep = step;\r\n if (options.onStep) options.onStep(step);\r\n },\r\n shouldContinue: options.shouldContinue,\r\n signal: options.signal,\r\n });\r\n } finally {\r\n this._eventBus.emit('ai:workflow:done', {\r\n workflow: name,\r\n params,\r\n totalSteps: finalStep?.step || 0,\r\n result: finalStep?.type || 'unknown',\r\n }, { appName: 'wu-ai' });\r\n }\r\n }\r\n\r\n /**\r\n * Execute workflow deterministically — NO AI NEEDED.\r\n * Steps are exact actions: { action: 'click', selector: '#btn' }\r\n * @private\r\n */\r\n async *_executeDeterministic(name, workflow, params, options) {\r\n // Interpolate parameters into step values\r\n const steps = workflow.steps.map(step => {\r\n const interpolated = { ...step };\r\n for (const [key, value] of Object.entries(params)) {\r\n const pattern = new RegExp(`\\\\{\\\\{${key}\\\\}\\\\}`, 'g');\r\n for (const field of ['value', 'selector', 'text', 'section', 'event', 'path']) {\r\n if (typeof interpolated[field] === 'string') {\r\n interpolated[field] = interpolated[field].replace(pattern, String(value));\r\n }\r\n }\r\n }\r\n return interpolated;\r\n });\r\n\r\n this._eventBus?.emit('ai:workflow:start', {\r\n workflow: name,\r\n mode: 'deterministic',\r\n params,\r\n steps: steps.length,\r\n }, { appName: 'wu-ai' });\r\n\r\n let lastStep = null;\r\n\r\n try {\r\n for (let i = 0; i < steps.length; i++) {\r\n const step = steps[i];\r\n const stepNum = i + 1;\r\n const startTime = Date.now();\r\n\r\n // Check abort\r\n if (options.signal?.aborted) {\r\n const result = {\r\n step: stepNum,\r\n type: 'aborted',\r\n content: 'Workflow aborted',\r\n reason: 'Aborted by caller',\r\n elapsed: 0,\r\n };\r\n lastStep = result;\r\n yield result;\r\n return;\r\n }\r\n\r\n // Handle 'wait' specially — it's async\r\n if (step.action === 'wait') {\r\n if (step.selector) {\r\n const found = await waitForSelector(step.selector, step.timeout || 5000);\r\n const elapsed = Date.now() - startTime;\r\n const result = {\r\n step: stepNum,\r\n type: found ? 'action' : 'error',\r\n content: found\r\n ? `Waited for \"${step.selector}\" — found`\r\n : `Timeout waiting for \"${step.selector}\"`,\r\n elapsed,\r\n };\r\n lastStep = result;\r\n if (options.onStep) options.onStep(result);\r\n yield result;\r\n if (!found) return; // stop on timeout\r\n } else if (step.ms) {\r\n await delay(step.ms);\r\n const result = {\r\n step: stepNum,\r\n type: 'action',\r\n content: `Waited ${step.ms}ms`,\r\n elapsed: step.ms,\r\n };\r\n lastStep = result;\r\n if (options.onStep) options.onStep(result);\r\n yield result;\r\n }\r\n continue;\r\n }\r\n\r\n // Execute the step\r\n const execResult = executeDeterministicStep(step, this._eventBus, this._store);\r\n const elapsed = Date.now() - startTime;\r\n\r\n const stepResult = {\r\n step: stepNum,\r\n type: execResult.success ? 'action' : 'error',\r\n content: execResult.success ? execResult.detail : execResult.error,\r\n elapsed,\r\n };\r\n\r\n lastStep = stepResult;\r\n if (options.onStep) options.onStep(stepResult);\r\n yield stepResult;\r\n\r\n // Human-in-the-loop gate\r\n if (options.shouldContinue) {\r\n let shouldGo;\r\n try {\r\n shouldGo = await options.shouldContinue(stepResult);\r\n } catch {\r\n shouldGo = false;\r\n }\r\n if (!shouldGo) {\r\n const interrupted = {\r\n step: stepNum,\r\n type: 'interrupted',\r\n content: 'Stopped by user',\r\n reason: 'shouldContinue returned false',\r\n elapsed: 0,\r\n };\r\n lastStep = interrupted;\r\n yield interrupted;\r\n return;\r\n }\r\n }\r\n\r\n // Stop on error\r\n if (!execResult.success) return;\r\n\r\n // Small delay between steps for UI to update\r\n if (i < steps.length - 1) {\r\n await delay(step.delay ?? 200);\r\n }\r\n }\r\n\r\n // All steps completed\r\n const done = {\r\n step: steps.length,\r\n type: 'done',\r\n content: `Workflow \"${name}\" completed (${steps.length} steps)`,\r\n reason: 'All steps executed',\r\n elapsed: 0,\r\n };\r\n lastStep = done;\r\n if (options.onStep) options.onStep(done);\r\n yield done;\r\n\r\n } finally {\r\n this._eventBus?.emit('ai:workflow:done', {\r\n workflow: name,\r\n mode: 'deterministic',\r\n params,\r\n totalSteps: lastStep?.step || 0,\r\n result: lastStep?.type || 'unknown',\r\n }, { appName: 'wu-ai' });\r\n }\r\n }\r\n\r\n /**\r\n * Check if a workflow is registered.\r\n *\r\n * @param {string} name\r\n * @returns {boolean}\r\n */\r\n hasWorkflow(name) {\r\n return this._workflows.has(name);\r\n }\r\n\r\n /**\r\n * Get a workflow definition.\r\n *\r\n * @param {string} name\r\n * @returns {object|null}\r\n */\r\n getWorkflow(name) {\r\n const w = this._workflows.get(name);\r\n if (!w) return null;\r\n return {\r\n description: w.description,\r\n steps: [...w.steps],\r\n mode: w.mode,\r\n parameters: { ...w.parameters },\r\n maxSteps: w.maxSteps,\r\n };\r\n }\r\n\r\n /**\r\n * Remove a registered workflow.\r\n *\r\n * @param {string} name\r\n */\r\n removeWorkflow(name) {\r\n this._workflows.delete(name);\r\n }\r\n\r\n /**\r\n * Get all workflow names.\r\n *\r\n * @returns {string[]}\r\n */\r\n getWorkflowNames() {\r\n return [...this._workflows.keys()];\r\n }\r\n\r\n /** @private */\r\n _buildWorkflowGoal(workflow, steps, params) {\r\n const parts = [];\r\n\r\n parts.push(\r\n `WORKFLOW: ${workflow.description}`,\r\n '',\r\n 'You must follow these steps IN ORDER. Use browser tools (screenshot, click, type)',\r\n 'to interact with the application. After each step, take a screenshot to verify.',\r\n '',\r\n 'STEPS:',\r\n );\r\n\r\n for (let i = 0; i < steps.length; i++) {\r\n parts.push(` ${i + 1}. ${steps[i]}`);\r\n }\r\n\r\n parts.push(\r\n '',\r\n 'After completing all steps successfully, respond with [DONE].',\r\n 'If a step fails, explain what went wrong.',\r\n );\r\n\r\n // Add capability context if available\r\n const capMap = this.getCapabilityMap();\r\n const appNames = Object.keys(capMap);\r\n if (appNames.length > 0) {\r\n parts.push('', 'AVAILABLE APP CAPABILITIES:');\r\n for (const appName of appNames) {\r\n for (const cap of capMap[appName]) {\r\n parts.push(` - ${cap.action}: ${cap.description}`);\r\n }\r\n }\r\n }\r\n\r\n return parts.join('\\n');\r\n }\r\n\r\n // ─── Stats & Lifecycle ──────────────────────────────────────────\r\n\r\n getStats() {\r\n return {\r\n ...this._stats,\r\n registeredApps: this.getRegisteredApps(),\r\n totalCapabilities: this.getTotalCapabilities(),\r\n capabilityMap: this.getCapabilityMap(),\r\n workflows: this.getWorkflowNames(),\r\n config: { ...this._config },\r\n };\r\n }\r\n\r\n destroy() {\r\n // Remove all capabilities from the action registry\r\n for (const [appName, actions] of this._capabilities) {\r\n for (const [actionName] of actions) {\r\n this._actions.unregister(`${appName}:${actionName}`);\r\n }\r\n }\r\n this._capabilities.clear();\r\n this._workflows.clear();\r\n\r\n this._stats = {\r\n totalIntents: 0,\r\n resolvedIntents: 0,\r\n failedIntents: 0,\r\n workflowsRegistered: 0,\r\n workflowsExecuted: 0,\r\n };\r\n }\r\n\r\n // ─── Private Helpers ────────────────────────────────────────────\r\n\r\n /**\r\n * Extract app names from tool results based on qualified action names.\r\n * e.g., tool name 'orders:getRecent' → app 'orders'\r\n */\r\n _extractInvolvedApps(toolResults) {\r\n if (!toolResults || !Array.isArray(toolResults)) return [];\r\n const apps = new Set();\r\n for (const result of toolResults) {\r\n const name = result.name || result.tool || '';\r\n const colonIdx = name.indexOf(':');\r\n if (colonIdx > 0) {\r\n apps.add(name.slice(0, colonIdx));\r\n }\r\n }\r\n return [...apps];\r\n }\r\n\r\n _generateNamespace() {\r\n return INTENT_NAMESPACE_PREFIX + Date.now().toString(36) +\r\n '_' + Math.random().toString(36).slice(2, 6);\r\n }\r\n}\r\n","/**\r\n * WU-AI: Central orchestrator for AI integration\r\n *\r\n * This is the main entry point for wu.ai — it wires together all sub-modules\r\n * and exposes the public API. Lazy-initialized on first use.\r\n *\r\n * Architecture:\r\n * WuAI (this file)\r\n * ├── WuAIProvider → BYOL provider management (OpenAI, Anthropic, Ollama, Custom)\r\n * ├── WuAIPermissions → 4-layer security (perms, rate limit, circuit breaker, loop guard)\r\n * ├── WuAIContext → Auto context collection with token budget\r\n * ├── WuAIActions → Tool/action registry and sandboxed execution\r\n * ├── WuAIConversation → Multi-turn conversation manager with namespaces\r\n * ├── WuAITriggers → Event-to-AI reactive bridge\r\n * ├── WuAIAgent → Autonomous agent loop (goal → steps → done)\r\n * ├── WuAIOrchestrate → Cross-micro-app AI coordination (capabilities + intents)\r\n * └── BrowserPrimitives → Shared screenshot, click, type, a11y tree, interceptors\r\n *\r\n * Four Paradigms:\r\n * 1. App → LLM send/stream/json → conversation with tool loops\r\n * 2. LLM → App tools/execute/expose → external agents call into the app\r\n * 3. AI Director agent(goal) → autonomous multi-step loop\r\n * 4. MF Glue capability/intent → cross-app coordination via AI\r\n *\r\n * Public API (accessible via wu.ai):\r\n * wu.ai.provider(name, config) → Register LLM provider\r\n * wu.ai.send(message, opts) → Send message (non-streaming)\r\n * wu.ai.stream(message, opts) → Send message (streaming)\r\n * wu.ai.json(message, schema?) → Send and get parsed JSON back\r\n * wu.ai.agent(goal, opts) → Run autonomous agent loop\r\n * wu.ai.action(name, config) → Register an action/tool\r\n * wu.ai.trigger(name, config) → Register an event trigger\r\n * wu.ai.capability(app, name, c) → Register app-scoped capability\r\n * wu.ai.intent(desc, opts) → Resolve cross-app intent\r\n * wu.ai.removeApp(appName) → Remove app capabilities (unmount)\r\n * wu.ai.workflow(name, config) → Register reusable AI workflow\r\n * wu.ai.runWorkflow(name, params)→ Execute workflow (async generator)\r\n * wu.ai.context.configure(...) → Configure context collection\r\n * wu.ai.abort(namespace?) → Abort active request\r\n *\r\n * Paradigm 2 (External agent access):\r\n * wu.ai.tools() → Get all registered tools (for CDP/WebMCP)\r\n * wu.ai.execute(name, params) → Execute action directly (for external agents)\r\n * wu.ai.expose() → Register tools via WebMCP (navigator.modelContext)\r\n */\r\n\r\nimport { logger } from '../core/wu-logger.js';\r\nimport { WuAIProvider } from './wu-ai-provider.js';\r\nimport { WuAIPermissions } from './wu-ai-permissions.js';\r\nimport { WuAIContext } from './wu-ai-context.js';\r\nimport { WuAIActions } from './wu-ai-actions.js';\r\nimport { WuAIConversation } from './wu-ai-conversation.js';\r\nimport { WuAITriggers } from './wu-ai-triggers.js';\r\nimport { WuAIAgent } from './wu-ai-agent.js';\r\nimport { WuAIOrchestrate } from './wu-ai-orchestrate.js';\r\nimport { registerBrowserActions } from './wu-ai-browser.js';\r\n\r\nexport class WuAI {\r\n /**\r\n * @param {object} deps - Injected from WuCore\r\n * @param {object} deps.eventBus - WuEventBus instance\r\n * @param {object} deps.store - WuStore instance\r\n * @param {object} deps.core - WuCore instance (for mounted apps)\r\n */\r\n constructor({ eventBus, store, core, token }) {\r\n this._store = store;\r\n this._core = core;\r\n this._initialized = false;\r\n this._modules = {};\r\n\r\n // Secret token minted by WuEventBus.getInternalToken('wu-ai') and passed\r\n // in by setupLazyAi(). EventBus rejects appName='wu-ai' emits without a\r\n // matching token in strictMode — this prevents micro-apps from spoofing\r\n // wu-ai as their source. We wrap eventBus once here so every submodule\r\n // that receives this._eventBus gets the token injected automatically.\r\n this._token = token || null;\r\n this._eventBus = this._wrapEventBus(eventBus);\r\n }\r\n\r\n /**\r\n * Wrap the raw event bus so emits from this WuAI instance (and any\r\n * submodule that receives this wrapper) carry our internal token.\r\n * Other methods (on/off/once/replay/...) pass through untouched.\r\n * @private\r\n */\r\n _wrapEventBus(rawBus) {\r\n if (!this._token) return rawBus; // No token → fall back to legacy behavior\r\n const token = this._token;\r\n return new Proxy(rawBus, {\r\n get(target, prop) {\r\n if (prop === 'emit') {\r\n return function autoTokenEmit(eventName, data, options = {}) {\r\n return target.emit(eventName, data, {\r\n ...options,\r\n appName: options.appName || 'wu-ai',\r\n token: options.token || token,\r\n });\r\n };\r\n }\r\n const value = Reflect.get(target, prop);\r\n return typeof value === 'function' ? value.bind(target) : value;\r\n },\r\n });\r\n }\r\n\r\n // ─── Lazy Initialization ───────────────────────────────────────\r\n\r\n /**\r\n * Initialize all sub-modules. Called automatically on first use,\r\n * or can be called explicitly with configuration.\r\n *\r\n * @param {object} [config]\r\n * @param {object} [config.permissions] - Permission overrides\r\n * @param {object} [config.rateLimit] - Rate limit config\r\n * @param {object} [config.circuitBreaker] - Circuit breaker config\r\n * @param {object} [config.loopProtection] - Loop protection config\r\n * @param {object} [config.context] - Context collection config\r\n * @param {object} [config.conversation] - Conversation defaults\r\n * @param {object} [config.triggers] - Trigger system config\r\n */\r\n init(config = {}) {\r\n if (this._initialized) {\r\n // Reconfigure if already initialized\r\n this._reconfigure(config);\r\n return this;\r\n }\r\n\r\n // 1. Permissions (independent — no deps)\r\n this._modules.permissions = new WuAIPermissions({\r\n permissions: config.permissions,\r\n rateLimit: config.rateLimit,\r\n circuitBreaker: config.circuitBreaker,\r\n loopProtection: config.loopProtection,\r\n allowedDomains: config.allowedDomains,\r\n });\r\n\r\n // 2. Provider (independent — no deps)\r\n this._modules.provider = new WuAIProvider();\r\n\r\n // 3. Context (depends on store, eventBus, core)\r\n this._modules.context = new WuAIContext({\r\n store: this._store,\r\n eventBus: this._eventBus,\r\n core: this._core,\r\n });\r\n if (config.context) {\r\n this._modules.context.configure(config.context);\r\n }\r\n\r\n // 4. Actions (depends on eventBus, store, permissions)\r\n this._modules.actions = new WuAIActions({\r\n eventBus: this._eventBus,\r\n store: this._store,\r\n permissions: this._modules.permissions,\r\n });\r\n\r\n // 5. Conversation (depends on provider, actions, context, permissions, eventBus)\r\n this._modules.conversation = new WuAIConversation({\r\n provider: this._modules.provider,\r\n actions: this._modules.actions,\r\n context: this._modules.context,\r\n permissions: this._modules.permissions,\r\n eventBus: this._eventBus,\r\n });\r\n if (config.conversation) {\r\n this._modules.conversation.configure(config.conversation);\r\n }\r\n\r\n // 6. Triggers (depends on eventBus, conversation, permissions)\r\n this._modules.triggers = new WuAITriggers({\r\n eventBus: this._eventBus,\r\n conversation: this._modules.conversation,\r\n permissions: this._modules.permissions,\r\n });\r\n if (config.triggers) {\r\n this._modules.triggers.configure(config.triggers);\r\n }\r\n\r\n // 7. Agent (depends on conversation, actions, context, permissions, eventBus)\r\n this._modules.agent = new WuAIAgent({\r\n conversation: this._modules.conversation,\r\n actions: this._modules.actions,\r\n context: this._modules.context,\r\n permissions: this._modules.permissions,\r\n eventBus: this._eventBus,\r\n });\r\n if (config.agent) {\r\n this._modules.agent.configure(config.agent);\r\n }\r\n\r\n // 8. Orchestrate — Paradigm 4: AI as microfrontend glue\r\n // Agent ref is passed so workflows can delegate to the agent loop\r\n // Store ref is passed for deterministic setState steps\r\n this._modules.orchestrate = new WuAIOrchestrate({\r\n actions: this._modules.actions,\r\n conversation: this._modules.conversation,\r\n context: this._modules.context,\r\n permissions: this._modules.permissions,\r\n eventBus: this._eventBus,\r\n agent: this._modules.agent,\r\n store: this._store,\r\n });\r\n if (config.orchestrate) {\r\n this._modules.orchestrate.configure(config.orchestrate);\r\n }\r\n\r\n this._initialized = true;\r\n logger.wuInfo('[wu-ai] Initialized');\r\n\r\n // 9. Browser automation actions (screenshot, click, type, network, etc.)\r\n // Must be AFTER _initialized = true to prevent recursive init loop\r\n if (typeof window !== 'undefined') {\r\n registerBrowserActions(this, this._core);\r\n logger.wuInfo('[wu-ai] Browser actions registered (10 tools)');\r\n }\r\n\r\n this._eventBus.emit('ai:initialized', {}, { appName: 'wu-ai' });\r\n\r\n return this;\r\n }\r\n\r\n // ─── Provider Management ───────────────────────────────────────\r\n\r\n /**\r\n * Register an LLM provider.\r\n *\r\n * @param {string} name - Provider name ('openai', 'anthropic', 'ollama', or custom)\r\n * @param {object} config - { endpoint, apiKey?, model?, adapter?, send?, stream? }\r\n *\r\n * @example\r\n * // OpenAI via proxy (recommended)\r\n * wu.ai.provider('openai', { endpoint: '/api/ai/chat', model: 'gpt-4o' });\r\n *\r\n * // Anthropic direct (development only)\r\n * wu.ai.provider('anthropic', {\r\n * endpoint: 'https://api.anthropic.com/v1/messages',\r\n * apiKey: 'sk-...',\r\n * model: 'claude-sonnet-4-5-20250929',\r\n * });\r\n *\r\n * // Local Ollama\r\n * wu.ai.provider('ollama', { endpoint: 'http://localhost:11434/api/chat', model: 'llama3' });\r\n *\r\n * // Custom provider\r\n * wu.ai.provider('my-llm', { send: async (messages, opts) => ({ content: '...' }) });\r\n */\r\n provider(name, config) {\r\n this._ensureInit();\r\n this._modules.provider.register(name, config);\r\n return this;\r\n }\r\n\r\n // ─── Paradigm 1: App → LLM (Conversation) ─────────────────────\r\n\r\n /**\r\n * Send a message to the LLM and get a complete response.\r\n *\r\n * @param {string} message - User message\r\n * @param {object} [options] - { namespace, systemPrompt, templateVars, temperature, maxTokens, provider, responseFormat, signal }\r\n * @param {string} [options.provider] - Use a specific registered provider (e.g., 'anthropic', 'openai')\r\n * @param {string|object} [options.responseFormat] - Request JSON output.\r\n * - `'json'` — simple JSON mode (OpenAI: json_object, Ollama: format:\"json\", Anthropic: prompt injection)\r\n * - `{ type: 'json_schema', schema: {...}, name?: string }` — structured output with JSON Schema\r\n * (OpenAI: native json_schema mode, Ollama: schema in format, Anthropic: schema in system prompt)\r\n * @returns {Promise<{ content: string, tool_results?: Array, usage?: object, namespace: string }>}\r\n *\r\n * @example\r\n * const response = await wu.ai.send('What items are in the cart?');\r\n * console.log(response.content);\r\n *\r\n * // With namespace for separate conversation\r\n * const response = await wu.ai.send('Analyze this chart', { namespace: 'analytics' });\r\n *\r\n * // Use a specific provider for this message\r\n * const response = await wu.ai.send('Translate this', { provider: 'anthropic' });\r\n *\r\n * // Simple JSON mode\r\n * const response = await wu.ai.send('List 5 colors', { responseFormat: 'json' });\r\n *\r\n * // Structured output with JSON Schema\r\n * const response = await wu.ai.send('List 5 colors', {\r\n * responseFormat: {\r\n * type: 'json_schema',\r\n * schema: { type: 'object', properties: { colors: { type: 'array', items: { type: 'string' } } } },\r\n * name: 'color_list',\r\n * },\r\n * });\r\n */\r\n async send(message, options = {}) {\r\n this._ensureInit();\r\n return this._modules.conversation.send(message, options);\r\n }\r\n\r\n /**\r\n * Send a message and stream the response.\r\n *\r\n * @param {string} message - User message\r\n * @param {object} [options] - Same as send()\r\n * @yields {{ type: 'text'|'tool_result'|'done'|'error', content?: string }}\r\n *\r\n * @example\r\n * for await (const chunk of wu.ai.stream('Tell me about this page')) {\r\n * if (chunk.type === 'text') outputEl.textContent += chunk.content;\r\n * if (chunk.type === 'done') console.log('Done!');\r\n * }\r\n */\r\n async *stream(message, options = {}) {\r\n this._ensureInit();\r\n yield* this._modules.conversation.stream(message, options);\r\n }\r\n\r\n /**\r\n * Send a message and get a parsed JSON response.\r\n * Shortcut for send() with responseFormat + automatic JSON.parse().\r\n *\r\n * @param {string} message - User message\r\n * @param {object} [options] - All send() options plus:\r\n * @param {object} [options.schema] - JSON Schema for structured output\r\n * @param {string} [options.schemaName='response'] - Schema name (required by OpenAI)\r\n * @returns {Promise<{ data: object|null, raw: string, error?: string, usage?: object, namespace: string }>}\r\n *\r\n * @example\r\n * // Simple JSON (no schema)\r\n * const { data } = await wu.ai.json('List 5 colors as a JSON array');\r\n * // data = [\"red\", \"blue\", ...]\r\n *\r\n * // With schema\r\n * const { data } = await wu.ai.json('List 5 colors', {\r\n * schema: { type: 'object', properties: { colors: { type: 'array', items: { type: 'string' } } } },\r\n * });\r\n * // data = { colors: [\"red\", \"blue\", ...] }\r\n *\r\n * // With schema + provider\r\n * const { data } = await wu.ai.json('List 5 colors', {\r\n * schema: mySchema,\r\n * provider: 'openai',\r\n * temperature: 0,\r\n * });\r\n */\r\n async json(message, options = {}) {\r\n this._ensureInit();\r\n\r\n const { schema, schemaName, ...rest } = options;\r\n\r\n let responseFormat;\r\n if (schema) {\r\n responseFormat = { type: 'json_schema', schema, name: schemaName || 'response' };\r\n } else {\r\n responseFormat = options.responseFormat || 'json';\r\n }\r\n\r\n const response = await this._modules.conversation.send(message, { ...rest, responseFormat });\r\n\r\n // The provider already attempts parse and sets response.parsed / response.parseError\r\n let data = null;\r\n let error;\r\n\r\n if (response.parsed !== undefined) {\r\n data = response.parsed;\r\n } else if (response.content) {\r\n try {\r\n data = JSON.parse(response.content);\r\n } catch {\r\n error = 'LLM response is not valid JSON';\r\n }\r\n }\r\n\r\n return {\r\n data,\r\n raw: response.content || '',\r\n error: error || response.parseError,\r\n usage: response.usage,\r\n namespace: response.namespace,\r\n };\r\n }\r\n\r\n /**\r\n * Abort active request(s).\r\n *\r\n * @param {string} [namespace] - Specific namespace, or all if omitted\r\n */\r\n abort(namespace) {\r\n if (!this._initialized) return;\r\n if (namespace) {\r\n this._modules.conversation.abort(namespace);\r\n } else {\r\n this._modules.conversation.abortAll();\r\n }\r\n }\r\n\r\n // ─── Actions / Tools ───────────────────────────────────────────\r\n\r\n /**\r\n * Register an action that the LLM can call.\r\n *\r\n * @param {string} name - Action name (used in tool_call)\r\n * @param {object} config - { description, parameters, handler, confirm?, permissions?, dangerous? }\r\n *\r\n * @example\r\n * wu.ai.action('addToCart', {\r\n * description: 'Add an item to the shopping cart',\r\n * parameters: {\r\n * productId: { type: 'string', required: true },\r\n * quantity: { type: 'number' },\r\n * },\r\n * handler: async (params, api) => {\r\n * api.setState('cart.items', [...api.getState('cart.items'), params]);\r\n * api.emit('cart:updated', params);\r\n * return { added: params.productId };\r\n * },\r\n * confirm: true, // require user confirmation\r\n * });\r\n */\r\n action(name, config) {\r\n this._ensureInit();\r\n this._modules.actions.register(name, config);\r\n return this;\r\n }\r\n\r\n /**\r\n * Execute an action directly (used by external agents via CDP/WebMCP).\r\n *\r\n * @param {string} name - Action name\r\n * @param {object} params - Parameters\r\n * @returns {Promise<{ success: boolean, result?: any, reason?: string }>}\r\n */\r\n async execute(name, params) {\r\n this._ensureInit();\r\n const traceId = this._modules.permissions.loopProtection.createTraceId();\r\n return this._modules.actions.execute(name, params, { traceId, depth: 0 });\r\n }\r\n\r\n // ─── Triggers (Reactive AI) ────────────────────────────────────\r\n\r\n /**\r\n * Register a trigger that automatically sends messages to the LLM\r\n * when specific events occur.\r\n *\r\n * @param {string} name - Trigger name\r\n * @param {object} config - { pattern, prompt, condition?, debounce?, priority?, onResult? }\r\n *\r\n * @example\r\n * wu.ai.trigger('cartAnalysis', {\r\n * pattern: 'cart:updated',\r\n * prompt: 'The cart was updated: {{data}}. Suggest complementary products.',\r\n * debounce: 3000,\r\n * priority: 'low',\r\n * onResult: (result) => {\r\n * wu.emit('ai:suggestions', { suggestions: result.content });\r\n * },\r\n * });\r\n */\r\n trigger(name, config) {\r\n this._ensureInit();\r\n this._modules.triggers.register(name, config);\r\n return this;\r\n }\r\n\r\n /**\r\n * Fire a trigger manually.\r\n */\r\n async fireTrigger(name, eventData) {\r\n this._ensureInit();\r\n return this._modules.triggers.fire(name, eventData);\r\n }\r\n\r\n // ─── Agent (Paradigm 3: Autonomous AI) ─────────────────────────\r\n\r\n /**\r\n * Run an autonomous agent that pursues a goal using available tools.\r\n * Returns an async generator that yields step-by-step results.\r\n *\r\n * @param {string} goal - What the agent should accomplish\r\n * @param {object} [options]\r\n * @param {number} [options.maxSteps=10] - Maximum autonomous steps\r\n * @param {string} [options.provider] - Which LLM provider to use\r\n * @param {string} [options.namespace] - Conversation namespace\r\n * @param {string} [options.systemPrompt] - Override system prompt\r\n * @param {Function} [options.onStep] - Callback per step: (stepResult) => void\r\n * @param {Function} [options.shouldContinue] - Human-in-the-loop: (stepResult) => boolean|Promise<boolean>\r\n * @param {AbortSignal} [options.signal] - Abort signal\r\n * @returns {AsyncGenerator<AgentStepResult>}\r\n *\r\n * @example\r\n * // Basic usage\r\n * for await (const step of wu.ai.agent('Find all orders above $100 and summarize them')) {\r\n * console.log(`Step ${step.step}: ${step.content?.slice(0, 100)}`);\r\n * if (step.done) console.log('Agent finished!');\r\n * }\r\n *\r\n * // With human-in-the-loop\r\n * for await (const step of wu.ai.agent('Reorganize the product catalog', {\r\n * shouldContinue: (step) => confirm(`Continue? Step ${step.step}: ${step.content?.slice(0, 50)}`),\r\n * })) {\r\n * updateUI(step);\r\n * }\r\n */\r\n async *agent(goal, options = {}) {\r\n this._ensureInit();\r\n yield* this._modules.agent.run(goal, options);\r\n }\r\n\r\n // ─── Paradigm 4: AI as Microfrontend Glue ─────────────────────\r\n\r\n /**\r\n * Register a capability scoped to a specific micro-app.\r\n *\r\n * Each micro-app calls this to declare what it can do. The AI uses\r\n * the capability map to resolve cross-app intents.\r\n *\r\n * @param {string} appName - The micro-app name (e.g., 'orders', 'dashboard')\r\n * @param {string} actionName - The capability name (e.g., 'getRecent', 'updateKPIs')\r\n * @param {object} config - Same as wu.ai.action() config:\r\n * { description, parameters, handler, confirm?, permissions?, dangerous? }\r\n *\r\n * @example\r\n * // In orders micro-app (React):\r\n * wu.ai.capability('orders', 'getRecent', {\r\n * description: 'Get the N most recent orders',\r\n * parameters: { limit: { type: 'number' } },\r\n * handler: async (params) => fetchOrders({ limit: params.limit || 10 }),\r\n * });\r\n *\r\n * // In dashboard micro-app (Svelte):\r\n * wu.ai.capability('dashboard', 'updateKPIs', {\r\n * description: 'Refresh the KPI cards with latest data',\r\n * handler: async () => { refreshKPIs(); return { updated: true }; },\r\n * });\r\n */\r\n capability(appName, actionName, config) {\r\n this._ensureInit();\r\n this._modules.orchestrate.register(appName, actionName, config);\r\n return this;\r\n }\r\n\r\n /**\r\n * Resolve a cross-app intent in a single conversation turn.\r\n *\r\n * The AI receives the full capability map (what each app can do),\r\n * current application state, and mounted apps. It resolves the\r\n * intent by calling the right capabilities across app boundaries.\r\n *\r\n * @param {string} description - Natural language intent\r\n * @param {object} [options]\r\n * @param {string[]} [options.plan] - Optional action sequence hint\r\n * @param {string} [options.provider] - LLM provider override\r\n * @param {number} [options.temperature] - Temperature override\r\n * @param {number} [options.maxTokens] - Max tokens override\r\n * @param {AbortSignal} [options.signal] - Abort signal\r\n * @param {string|object} [options.responseFormat] - Response format\r\n * @returns {Promise<{ content: string, tool_results: Array, usage: object|null, resolved: boolean, appsInvolved: string[] }>}\r\n *\r\n * @example\r\n * // Simple cross-app query\r\n * const result = await wu.ai.intent('Show me the top customer by order count');\r\n * // AI calls orders:getRecent → aggregates → returns answer\r\n *\r\n * // With plan hint\r\n * const result = await wu.ai.intent('Update all views after a new order', {\r\n * plan: ['orders:getRecent', 'dashboard:updateKPIs', 'analytics:refresh'],\r\n * });\r\n *\r\n * // With JSON response\r\n * const result = await wu.ai.intent('Get order stats by status', {\r\n * responseFormat: 'json',\r\n * });\r\n */\r\n async intent(description, options = {}) {\r\n this._ensureInit();\r\n return this._modules.orchestrate.resolve(description, options);\r\n }\r\n\r\n /**\r\n * Remove all capabilities for a micro-app.\r\n * Call this when a micro-app is unmounted to prevent stale\r\n * capabilities from appearing in the AI's capability map.\r\n *\r\n * @param {string} appName - The micro-app name\r\n *\r\n * @example\r\n * // In unmount lifecycle:\r\n * wu.ai.removeApp('orders');\r\n */\r\n removeApp(appName) {\r\n this._ensureInit();\r\n this._modules.orchestrate.removeApp(appName);\r\n return this;\r\n }\r\n\r\n /**\r\n * Register a reusable AI workflow — a named, step-by-step recipe\r\n * that the AI agent follows using browser automation.\r\n *\r\n * @param {string} name - Workflow name (e.g., 'register-user')\r\n * @param {object} config\r\n * @param {string} config.description - What this workflow does\r\n * @param {string[]} config.steps - Step-by-step instructions\r\n * Use {{paramName}} for parameter interpolation.\r\n * @param {object} [config.parameters] - Parameter definitions\r\n * @param {number} [config.maxSteps=15] - Max agent steps\r\n * @param {string} [config.provider] - LLM provider\r\n *\r\n * @example\r\n * wu.ai.workflow('register-user', {\r\n * description: 'Register a new user in the system',\r\n * steps: [\r\n * 'Navigate to the Customers section',\r\n * 'Click the \"Add Customer\" button',\r\n * 'Type \"{{name}}\" into the name field',\r\n * 'Type \"{{email}}\" into the email field',\r\n * 'Click Submit',\r\n * 'Verify the success message appears',\r\n * ],\r\n * parameters: {\r\n * name: { type: 'string', required: true },\r\n * email: { type: 'string', required: true },\r\n * },\r\n * });\r\n */\r\n workflow(name, config) {\r\n this._ensureInit();\r\n this._modules.orchestrate.registerWorkflow(name, config);\r\n return this;\r\n }\r\n\r\n /**\r\n * Execute a registered workflow. Returns an async generator\r\n * so you can observe each step in real time.\r\n *\r\n * @param {string} name - Workflow name\r\n * @param {object} [params={}] - Parameters to fill into the steps\r\n * @param {object} [options={}]\r\n * @param {Function} [options.onStep] - Callback per step\r\n * @param {Function} [options.shouldContinue] - Human-in-the-loop gate\r\n * @param {AbortSignal} [options.signal] - Abort signal\r\n * @returns {AsyncGenerator<AgentStepResult>}\r\n *\r\n * @example\r\n * // Run and watch every step\r\n * for await (const step of wu.ai.runWorkflow('register-user', {\r\n * name: 'Juan Pérez',\r\n * email: 'juan@test.com',\r\n * })) {\r\n * console.log(`Step ${step.step}: ${step.content}`);\r\n * if (step.type === 'done') console.log('Workflow complete!');\r\n * }\r\n *\r\n * // With human approval per step\r\n * for await (const step of wu.ai.runWorkflow('register-user', params, {\r\n * shouldContinue: (s) => confirm(`Continue? ${s.content?.slice(0, 60)}`),\r\n * })) {\r\n * renderStep(step);\r\n * }\r\n */\r\n async *runWorkflow(name, params = {}, options = {}) {\r\n this._ensureInit();\r\n yield* this._modules.orchestrate.executeWorkflow(name, params, options);\r\n }\r\n\r\n // ─── Context ───────────────────────────────────────────────────\r\n\r\n /**\r\n * Context configuration sub-API.\r\n * Access via wu.ai.context\r\n */\r\n get context() {\r\n this._ensureInit();\r\n return {\r\n configure: (config) => this._modules.context.configure(config),\r\n register: (name, config) => this._modules.context.register(name, config),\r\n collect: () => this._modules.context.collect(),\r\n getSnapshot: () => this._modules.context.getSnapshot(),\r\n };\r\n }\r\n\r\n // ─── Conversation Management ───────────────────────────────────\r\n\r\n /**\r\n * Conversation sub-API for direct history management.\r\n */\r\n get conversation() {\r\n this._ensureInit();\r\n return {\r\n getHistory: (ns) => this._modules.conversation.getHistory(ns),\r\n clear: (ns) => this._modules.conversation.clear(ns),\r\n clearAll: () => this._modules.conversation.clearAll(),\r\n inject: (role, content, opts) => this._modules.conversation.inject(role, content, opts),\r\n getNamespaces: () => this._modules.conversation.getNamespaces(),\r\n deleteNamespace: (ns) => this._modules.conversation.deleteNamespace(ns),\r\n };\r\n }\r\n\r\n // ─── Permissions ───────────────────────────────────────────────\r\n\r\n /**\r\n * Permissions sub-API.\r\n */\r\n get permissions() {\r\n this._ensureInit();\r\n return {\r\n configure: (config) => this._modules.permissions.configure(config),\r\n check: (perm) => this._modules.permissions.check(perm),\r\n getPermissions: () => this._modules.permissions.getPermissions(),\r\n setAllowedDomains: (domains) => this._modules.permissions.setAllowedDomains(domains),\r\n };\r\n }\r\n\r\n // ─── Paradigm 2: LLM → App (External Agent Access) ────────────\r\n\r\n /**\r\n * Get all registered tools (for external agents).\r\n * An agent connected via CDP can call: window.wu.ai.tools()\r\n *\r\n * @returns {Array<{ name, description, parameters }>}\r\n */\r\n tools() {\r\n this._ensureInit();\r\n return this._modules.actions.getToolSchemas();\r\n }\r\n\r\n /**\r\n * Expose tools via WebMCP (Chrome 146+ / W3C proposal).\r\n * Registers all actions with navigator.modelContext.registerTool()\r\n *\r\n * @returns {boolean} Whether WebMCP is available\r\n */\r\n expose() {\r\n this._ensureInit();\r\n\r\n if (typeof navigator === 'undefined' || !navigator.modelContext) {\r\n logger.wuDebug('[wu-ai] WebMCP not available (navigator.modelContext missing)');\r\n return false;\r\n }\r\n\r\n const tools = this._modules.actions.getToolSchemas();\r\n const actionNames = this._modules.actions.getNames();\r\n\r\n for (let i = 0; i < tools.length; i++) {\r\n const tool = tools[i];\r\n const actionName = actionNames[i];\r\n\r\n try {\r\n navigator.modelContext.registerTool({\r\n name: tool.name,\r\n description: tool.description,\r\n inputSchema: tool.parameters,\r\n handler: async (params) => {\r\n const result = await this.execute(actionName, params);\r\n return result.success ? result.result : { error: result.reason };\r\n },\r\n });\r\n } catch (err) {\r\n logger.wuDebug(`[wu-ai] WebMCP register failed for '${tool.name}': ${err.message}`);\r\n }\r\n }\r\n\r\n logger.wuInfo(`[wu-ai] Exposed ${tools.length} tools via WebMCP`);\r\n\r\n this._eventBus.emit('ai:webmcp:exposed', {\r\n toolCount: tools.length,\r\n tools: tools.map(t => t.name),\r\n }, { appName: 'wu-ai' });\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Confirm a pending tool call (for UI integration).\r\n */\r\n confirmTool(callId) {\r\n if (!this._initialized) return;\r\n this._modules.actions.confirmTool(callId);\r\n }\r\n\r\n /**\r\n * Reject a pending tool call.\r\n */\r\n rejectTool(callId) {\r\n if (!this._initialized) return;\r\n this._modules.actions.rejectTool(callId);\r\n }\r\n\r\n // ─── Stats & Debug ─────────────────────────────────────────────\r\n\r\n getStats() {\r\n if (!this._initialized) return { initialized: false };\r\n\r\n return {\r\n initialized: true,\r\n provider: this._modules.provider.getStats(),\r\n permissions: this._modules.permissions.getStats(),\r\n context: this._modules.context.getStats(),\r\n actions: this._modules.actions.getStats(),\r\n conversation: this._modules.conversation.getStats(),\r\n triggers: this._modules.triggers.getStats(),\r\n agent: this._modules.agent.getStats(),\r\n orchestrate: this._modules.orchestrate.getStats(),\r\n };\r\n }\r\n\r\n /**\r\n * Destroy the AI system and clean up all resources.\r\n */\r\n destroy() {\r\n if (!this._initialized) return;\r\n\r\n this._modules.orchestrate.destroy();\r\n this._modules.agent.destroy();\r\n this._modules.conversation.abortAll();\r\n this._modules.triggers.destroy();\r\n this._modules = {};\r\n this._initialized = false;\r\n\r\n logger.wuInfo('[wu-ai] Destroyed');\r\n this._eventBus.emit('ai:destroyed', {}, { appName: 'wu-ai' });\r\n }\r\n\r\n // ─── Private ───────────────────────────────────────────────────\r\n\r\n _ensureInit() {\r\n if (!this._initialized) {\r\n this.init();\r\n }\r\n }\r\n\r\n _reconfigure(config) {\r\n if (config.permissions) this._modules.permissions.configure(config.permissions);\r\n if (config.rateLimit) this._modules.permissions.rateLimiter.configure(config.rateLimit);\r\n if (config.circuitBreaker) this._modules.permissions.circuitBreaker.configure(config.circuitBreaker);\r\n if (config.loopProtection) this._modules.permissions.loopProtection.configure(config.loopProtection);\r\n if (config.context) this._modules.context.configure(config.context);\r\n if (config.conversation) this._modules.conversation.configure(config.conversation);\r\n if (config.triggers) this._modules.triggers.configure(config.triggers);\r\n if (config.agent) this._modules.agent.configure(config.agent);\r\n if (config.orchestrate) this._modules.orchestrate.configure(config.orchestrate);\r\n }\r\n}\r\n","/**\r\n * WU-AI Browser Actions\r\n *\r\n * Registers browser automation tools into wu.ai so any LLM provider\r\n * (OpenAI, Claude, Gemini, Ollama, etc.) can autonomously see and\r\n * control the page — no human intervention required.\r\n *\r\n * Tools registered:\r\n * browser_screenshot — Capture page/element as PNG (Canvas API)\r\n * browser_click — Click element by selector or visible text\r\n * browser_type — Type into inputs (React/Vue/framework compatible)\r\n * browser_snapshot — Get accessibility tree of the DOM\r\n * browser_navigate — Navigate SPA routes\r\n * browser_network — View captured HTTP requests (fetch + XHR)\r\n * browser_console — View captured console messages\r\n * browser_info — Get page state: apps, store, URL, viewport\r\n * browser_select — Select option in dropdowns\r\n * browser_scroll — Scroll page or element\r\n *\r\n * @example\r\n * // Auto-registered when wu.ai initializes\r\n * // Any LLM connected via wu.ai.provider can now use these tools:\r\n * const tools = wu.ai.tools();\r\n * // → includes browser_screenshot, browser_click, etc.\r\n */\r\n\r\nimport {\r\n ensureInterceptors,\r\n networkLog,\r\n consoleLog,\r\n captureScreenshot,\r\n buildA11yTree,\r\n clickElement,\r\n typeIntoElement,\r\n getFilteredNetwork,\r\n getFilteredConsole,\r\n} from './wu-ai-browser-primitives.js';\r\n\r\n/**\r\n * Register all browser automation actions into a WuAI instance.\r\n *\r\n * @param {object} ai - The WuAI instance (wu.ai)\r\n * @param {object} wu - The Wu Framework instance (window.wu)\r\n */\r\nexport function registerBrowserActions(ai, wu) {\r\n ensureInterceptors();\r\n\r\n // ════════════════════════════════════════════\r\n // SCREENSHOT — Canvas API (SVG foreignObject)\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_screenshot', {\r\n description: 'Take a screenshot of the current page or a specific element. Returns a base64 PNG image. Use this to SEE what the user sees.',\r\n parameters: {\r\n selector: {\r\n type: 'string',\r\n description: 'CSS selector of the element to capture. Empty = full visible page.',\r\n required: false,\r\n },\r\n },\r\n handler: async (params) => captureScreenshot(params.selector),\r\n permissions: [],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // CLICK\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_click', {\r\n description: 'Click an element on the page. Find by CSS selector or by visible text content. Use this to interact with buttons, links, tabs, etc.',\r\n parameters: {\r\n selector: {\r\n type: 'string',\r\n description: 'CSS selector (e.g. \"#submit-btn\", \".nav-link\", \"button[type=submit]\")',\r\n required: false,\r\n },\r\n text: {\r\n type: 'string',\r\n description: 'Visible text to find and click (e.g. \"Submit\", \"Next\", \"Guardar\"). Searches buttons, links, and clickable elements.',\r\n required: false,\r\n },\r\n },\r\n handler: async (params, api) => {\r\n const result = clickElement(params.selector, params.text);\r\n if (!result.error) {\r\n api.emit?.('browser:clicked', { selector: params.selector, text: params.text });\r\n }\r\n return result;\r\n },\r\n permissions: ['emitEvents'],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // TYPE\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_type', {\r\n description: 'Type text into an input, textarea, or contenteditable element. Works with React, Vue, Angular, and other frameworks. Can optionally clear existing text first and submit the form.',\r\n parameters: {\r\n selector: {\r\n type: 'string',\r\n description: 'CSS selector of the input (e.g. \"#email\", \"input[name=search]\", \"textarea.comment\")',\r\n required: true,\r\n },\r\n text: {\r\n type: 'string',\r\n description: 'Text to type into the element',\r\n required: true,\r\n },\r\n clear: {\r\n type: 'boolean',\r\n description: 'Clear existing value before typing (default: false)',\r\n required: false,\r\n },\r\n submit: {\r\n type: 'boolean',\r\n description: 'Submit the form or press Enter after typing (default: false)',\r\n required: false,\r\n },\r\n },\r\n handler: async (params, api) => {\r\n const result = typeIntoElement(params.selector, params.text, {\r\n clear: params.clear,\r\n submit: params.submit,\r\n });\r\n if (!result.error) {\r\n api.emit?.('browser:typed', { selector: params.selector, length: params.text.length });\r\n }\r\n return result;\r\n },\r\n permissions: ['emitEvents'],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // SELECT (dropdowns)\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_select', {\r\n description: 'Select an option in a <select> dropdown or a custom dropdown component.',\r\n parameters: {\r\n selector: {\r\n type: 'string',\r\n description: 'CSS selector of the <select> element',\r\n required: true,\r\n },\r\n value: {\r\n type: 'string',\r\n description: 'The value attribute of the option to select. Use \"text:\" prefix to match by visible text (e.g. \"text:Mexico\")',\r\n required: true,\r\n },\r\n },\r\n handler: async (params, api) => {\r\n const el = document.querySelector(params.selector);\r\n if (!el) return { error: `Element not found: ${params.selector}` };\r\n\r\n if (el.tagName?.toLowerCase() === 'select') {\r\n const options = Array.from(el.options);\r\n let option;\r\n\r\n if (params.value.startsWith('text:')) {\r\n const searchText = params.value.slice(5).toLowerCase();\r\n option = options.find((o) => o.textContent.trim().toLowerCase().includes(searchText));\r\n } else {\r\n option = options.find((o) => o.value === params.value);\r\n }\r\n\r\n if (!option) return { error: `Option not found: ${params.value}` };\r\n\r\n el.value = option.value;\r\n el.dispatchEvent(new Event('change', { bubbles: true }));\r\n el.dispatchEvent(new Event('input', { bubbles: true }));\r\n\r\n api.emit?.('browser:selected', { selector: params.selector, value: option.value });\r\n return { selected: option.value, text: option.textContent.trim() };\r\n }\r\n\r\n // Custom dropdown: try clicking the trigger, then the option\r\n el.click();\r\n return { clicked: params.selector, note: 'Custom dropdown — clicked trigger. Use browser_click to select an option from the opened menu.' };\r\n },\r\n permissions: ['emitEvents'],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // SCROLL\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_scroll', {\r\n description: 'Scroll the page or a specific element. Use to reveal content that is not visible.',\r\n parameters: {\r\n direction: {\r\n type: 'string',\r\n description: 'Direction: \"up\", \"down\", \"top\", \"bottom\"',\r\n required: true,\r\n },\r\n selector: {\r\n type: 'string',\r\n description: 'CSS selector of scrollable container (empty = page)',\r\n required: false,\r\n },\r\n amount: {\r\n type: 'number',\r\n description: 'Pixels to scroll (default: 500). Ignored for \"top\"/\"bottom\".',\r\n required: false,\r\n },\r\n },\r\n handler: async (params) => {\r\n const target = params.selector\r\n ? document.querySelector(params.selector)\r\n : window;\r\n const amount = params.amount || 500;\r\n\r\n if (params.selector && !target) return { error: `Element not found: ${params.selector}` };\r\n\r\n const scrollEl = target === window ? document.documentElement : target;\r\n\r\n switch (params.direction) {\r\n case 'up': scrollEl.scrollBy({ top: -amount, behavior: 'smooth' }); break;\r\n case 'down': scrollEl.scrollBy({ top: amount, behavior: 'smooth' }); break;\r\n case 'top': scrollEl.scrollTo({ top: 0, behavior: 'smooth' }); break;\r\n case 'bottom': scrollEl.scrollTo({ top: scrollEl.scrollHeight, behavior: 'smooth' }); break;\r\n default: return { error: `Invalid direction: ${params.direction}` };\r\n }\r\n\r\n return {\r\n scrolled: params.direction,\r\n amount: params.direction === 'top' || params.direction === 'bottom' ? 'max' : amount,\r\n currentScroll: scrollEl.scrollTop,\r\n };\r\n },\r\n permissions: [],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // SNAPSHOT — Accessibility tree\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_snapshot', {\r\n description: 'Get a text representation of the visible DOM structure (accessibility tree). Use this to understand what elements are on the page, their roles, IDs, and text content. Cheaper and faster than a screenshot.',\r\n parameters: {\r\n selector: {\r\n type: 'string',\r\n description: 'CSS selector to snapshot (empty = full page). Use \"[data-wu-app=appName]\" for a specific micro-app.',\r\n required: false,\r\n },\r\n depth: {\r\n type: 'number',\r\n description: 'Max depth to traverse (default: 5)',\r\n required: false,\r\n },\r\n },\r\n handler: async (params) => {\r\n const target = params.selector\r\n ? document.querySelector(params.selector)\r\n : document.body;\r\n\r\n if (!target) return { error: `Element not found: ${params.selector}` };\r\n\r\n const tree = buildA11yTree(target, 0, params.depth || 5);\r\n return { snapshot: tree };\r\n },\r\n permissions: [],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // NAVIGATE\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_navigate', {\r\n description: 'Navigate to a route within the SPA application. Emits a shell:navigate event and updates the store.',\r\n parameters: {\r\n route: {\r\n type: 'string',\r\n description: 'Route path (e.g. \"/dashboard\", \"/users\", \"/pos/cotizador\")',\r\n required: true,\r\n },\r\n },\r\n handler: async (params, api) => {\r\n api.emit?.('shell:navigate', { route: params.route });\r\n api.setState?.('currentPath', params.route);\r\n return { navigated: params.route };\r\n },\r\n permissions: ['emitEvents', 'writeStore'],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // NETWORK — Captured HTTP requests\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_network', {\r\n description: 'View captured HTTP network requests (fetch and XHR). Shows URL, method, status code, duration, and size. Use to debug API calls, check for errors, or monitor performance.',\r\n parameters: {\r\n method: {\r\n type: 'string',\r\n description: 'Filter by HTTP method: GET, POST, PUT, DELETE (empty = all)',\r\n required: false,\r\n },\r\n status: {\r\n type: 'string',\r\n description: 'Filter: \"2\" (2xx success), \"4\" (4xx errors), \"5\" (5xx errors), \"error\" (all failures)',\r\n required: false,\r\n },\r\n limit: {\r\n type: 'number',\r\n description: 'Max requests to return (default: 30)',\r\n required: false,\r\n },\r\n },\r\n handler: async (params) => getFilteredNetwork(params.method, params.status, params.limit),\r\n permissions: [],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // CONSOLE — Captured logs\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_console', {\r\n description: 'View captured browser console messages (log, warn, error). Use to check for errors, warnings, or debug output.',\r\n parameters: {\r\n level: {\r\n type: 'string',\r\n description: 'Filter by level: \"log\", \"warn\", \"error\" (empty = all)',\r\n required: false,\r\n },\r\n limit: {\r\n type: 'number',\r\n description: 'Max messages to return (default: 30)',\r\n required: false,\r\n },\r\n },\r\n handler: async (params) => getFilteredConsole(params.level, params.limit),\r\n permissions: [],\r\n });\r\n\r\n // ════════════════════════════════════════════\r\n // INFO — Page state overview\r\n // ════════════════════════════════════════════\r\n\r\n ai.action('browser_info', {\r\n description: 'Get an overview of the current page state: URL, viewport size, mounted micro-apps, store keys, visible elements summary. Use this FIRST to understand the page before taking actions.',\r\n parameters: {},\r\n handler: async (params, api) => {\r\n const apps = [];\r\n\r\n // Discover mounted apps\r\n if (wu._apps) {\r\n for (const [name, app] of Object.entries(wu._apps)) {\r\n apps.push({\r\n name,\r\n mounted: app.mounted || app.isMounted || false,\r\n status: app.status || 'unknown',\r\n });\r\n }\r\n }\r\n if (apps.length === 0) {\r\n document.querySelectorAll('[data-wu-app]').forEach((el) => {\r\n apps.push({ name: el.getAttribute('data-wu-app'), mounted: true });\r\n });\r\n }\r\n\r\n const storeData = api.getState?.('') || {};\r\n const storeKeys = typeof storeData === 'object' ? Object.keys(storeData) : [];\r\n\r\n return {\r\n url: window.location.href,\r\n title: document.title,\r\n viewport: { width: window.innerWidth, height: window.innerHeight },\r\n apps,\r\n storeKeys,\r\n networkRequests: networkLog.length,\r\n consoleMessages: consoleLog.length,\r\n consoleErrors: consoleLog.filter((m) => m.level === 'error').length,\r\n };\r\n },\r\n permissions: ['readStore'],\r\n });\r\n}\r\n\r\n// All private helpers (buildA11yTree, inlineComputedStyles, interceptors)\r\n// are now in wu-ai-browser-primitives.js — single source of truth.\r\n"],"names":["BaseAdapter","constructor","config","this","model","formatRequest","Error","parseResponse","parseStreamChunk","getHeaders","AnthropicAdapter","super","h","apiKey","messages","options","systemMsgs","filter","m","role","otherMsgs","body","max_tokens","maxTokens","map","content","type","tool_use_id","tool_call_id","tool_calls","tc","id","name","input","arguments","length","system","join","responseFormat","rf","jsonInstruction","schemaStr","JSON","stringify","schema","push","tools","t","description","input_schema","parameters","undefined","temperature","stream","data","textBlocks","b","toolBlocks","text","toolCalls","usage","prompt_tokens","input_tokens","completion_tokens","output_tokens","line","startsWith","raw","slice","trim","parse","delta","argumentsDelta","partial_json","content_block","CustomAdapter","_sendFn","send","_streamFn","isCustom","BUILTIN_ADAPTERS","openai","msg","function","response_format","json_schema","strict","choice","choices","message","_safeParseArgs","index","str","anthropic","ollama","format","i","Date","now","eval_count","prompt_eval_count","done","WuAIProvider","_providers","Map","_active","_activeName","_activeConfig","_retryConfig","maxRetries","baseDelayMs","register","adapterName","adapter","AdapterClass","Object","keys","set","active","logger","wuInfo","use","entry","get","_resolveProvider","provider","endpoint","baseUrl","url","_resolveUrl","headers","response","_fetchWithRetry","method","signal","json","result","parsed","parseError","wuDebug","fetch","ok","status","statusText","reader","getReader","decoder","TextDecoder","buffer","needsPrefill","value","read","decode","lines","split","pop","trimmed","chunk","releaseLock","lastError","attempt","delay","Math","pow","Promise","r","setTimeout","clientError","_noRetry","err","window","location","origin","providerName","_ensureActive","configureRetry","getActiveProvider","getStats","activeProvider","registeredProviders","DEFAULT_PERMISSIONS","readStore","writeStore","emitEvents","readDOM","modifyDOM","executeActions","allowDirectKey","CB_CLOSED","CB_OPEN","CB_HALF_OPEN","RateLimiter","_maxPerMinute","requestsPerMinute","_maxPerMinutePerNs","requestsPerMinutePerNs","_maxConcurrent","maxConcurrent","_globalTimestamps","_nsTimestamps","_concurrent","configure","canSend","namespace","_pruneOld","allowed","reason","recordStart","has","recordEnd","max","cutoff","ns","timestamps","pruned","delete","globalRequestsLastMinute","concurrent","maxPerMinute","CircuitBreaker","_state","_failureCount","_maxFailures","maxFailures","_cooldownMs","cooldownMs","_openedAt","_rapidFireThreshold","rapidFireThreshold","_rapidFireWindowMs","rapidFireWindowMs","_recentRequests","canPass","remainingMs","ceil","recordSuccess","_recordRequest","recordFailure","_tripOpen","wuWarn","getState","state","failureCount","openedAt","reset","LoopProtection","_maxDepth","maxDepth","_activeTraces","_traceLog","_maxTraceLog","canProceed","depth","traceId","count","enter","timestamp","shift","exit","createTraceId","toString","random","getTraces","activeTraces","size","traceLogSize","WuAIPermissions","_permissions","rateLimiter","rateLimit","circuitBreaker","loopProtection","_allowedDomains","allowedDomains","permissions","assign","_isProduction","check","permission","getPermissions","setAllowedDomains","domains","isDomainAllowed","hostname","URL","some","pattern","suffix","endsWith","preflight","meta","cb","rl","lp","process","env","NODE_ENV","SENSITIVE_KEYS","redactSensitive","obj","Array","isArray","item","key","entries","lowerKey","toLowerCase","sk","includes","interpolate","template","vars","replace","_match","path","reduce","maxChars","String","redacted","sanitizeForPrompt","normalizeParameters","params","properties","required","def","isRequired","rest","WuAIContext","store","eventBus","core","_store","_eventBus","_core","_config","budget","charRatio","sources","include","priority","events","lastN","custom","_collectors","_lastSnapshot","collector","collect","snapshot","_timestamp","_mountedApps","_getMountedApps","storeData","_collectStore","_collectEvents","_events","toSystemPrompt","_baseSystemPrompt","parts","charBudget","usedChars","prioritized","_prioritizeSections","section","sectionText","remaining","tool","getSnapshot","getInterpolationContext","apps","history","event","_matchPattern","e","mounted","stats","sections","storePriority","eventPriority","eventLines","toUpperCase","order","high","medium","low","sort","a","prompt","eventName","RegExp","test","collectors","storePaths","eventPatterns","lastCollected","WuAIActions","_actions","_executionLog","_maxLogSize","_pendingConfirms","handler","confirm","dangerous","unregister","execute","action","success","perm","_emitDenied","validation","errors","valid","actualType","Number","isInteger","enum","validateParams","_requestConfirmation","callId","api","_createSandboxedApi","_log","emit","appName","error","getToolSchemas","actions","buildToolSchemas","getNames","getLog","confirmTool","pending","clearTimeout","timeout","resolve","rejectTool","requiredPermissions","perms","Set","setState","actionName","timeoutHandle","registeredActions","executionLogSize","pendingConfirmations","DEFAULT_CONFIG","maxHistoryMessages","maxToolRounds","defaultNamespace","systemPrompt","namespaceTTL","gcInterval","ConversationNamespace","createdAt","lastActivity","_abortController","addMessage","_ts","getMessages","truncate","maxMessages","kept","clear","abort","createAbortController","AbortController","WuAIConversation","context","_provider","_context","_namespaces","_activeRequests","_lastGcRun","_getOrCreateNamespace","_buildSystemPrompt","_setSystemMessage","processedMessage","_processMessage","templateVars","controller","_mergeSignals","toolResults","rounds","maxRounds","assistantMsg","tool_results","toolCall","fullContent","toolCallAccumulator","streamEnded","args","idx","acc","parsedArgs","inject","getHistory","clearAll","values","abortAll","getNamespaces","deleteNamespace","nsName","_maybeGcSweep","ttl","interval","toDelete","unshift","internalSignal","externalSignal","AbortSignal","any","merged","onAbort","addEventListener","once","namespaces","messageCount","hasActiveRequest","DEFAULT_TRIGGER_CONFIG","enabled","maxActiveTriggers","defaultDebounceMs","batchIntervalMs","Trigger","condition","debounceMs","debounce","onResult","_debounceTimer","_lastFired","_fireCount","_pendingEvent","matches","buildPrompt","eventData","checkCondition","WuAITriggers","conversation","_conversation","_triggers","_listeners","_batchQueue","_batchTimer","_stats","totalFired","totalSkipped","totalErrors","trigger","unsub","on","_handleEvent","setEnabled","setAllEnabled","fire","_executeTrigger","getTrigger","fireCount","lastFired","destroy","triggerName","_debouncedFire","_scheduleBatch","_processBatch","batch","byTrigger","triggers","triggerCount","batchQueueSize","DONE_MARKER","AGENT_NAMESPACE_PREFIX","WuAIAgent","maxSteps","_activeRuns","totalRuns","totalSteps","completedRuns","abortedRuns","errorRuns","run","goal","_generateNamespace","runId","_generateRunId","aborted","_buildAgentSystemPrompt","step","previousHadToolCalls","finalReason","stepStart","_buildStepResult","elapsed","_emitStep","hasToolResults","onStep","_safeCallback","currentHasToolCalls","stepType","shouldContinue","shouldGo","interrupted","maxStepResult","getActiveRuns","activeRuns","basePrompt","paramKeys","fn","then","executeDeterministicStep","clickElement","selector","detail","typeIntoElement","submit","ms","waitForSelector","document","querySelector","timer","setInterval","clearInterval","WuAIOrchestrate","agent","_agent","_capabilities","_workflows","defaultProvider","defaultTemperature","totalIntents","resolvedIntents","failedIntents","workflowsRegistered","workflowsExecuted","qualifiedName","appCaps","removeApp","removed","capabilitiesRemoved","getCapabilityMap","getRegisteredApps","hasApp","getTotalCapabilities","_buildOrchestratorPrompt","capabilities","appsInvolved","_extractInvolvedApps","resolved","buildOrchestratorPrompt","capMap","appNames","cap","plan","registerWorkflow","steps","mode","executeWorkflow","workflow","paramName","paramConfig","_executeDeterministic","_executeWithAgent","interpolatedSteps","_buildWorkflowGoal","finalStep","interpolated","field","lastStep","stepNum","startTime","found","execResult","stepResult","hasWorkflow","getWorkflow","w","removeWorkflow","getWorkflowNames","registeredApps","totalCapabilities","capabilityMap","workflows","colonIdx","indexOf","add","WuAI","token","_initialized","_modules","_token","_wrapEventBus","rawBus","Proxy","target","prop","Reflect","bind","init","_reconfigure","orchestrate","ai","wu","ensureInterceptors","async","captureScreenshot","el","tagName","from","option","searchText","find","o","textContent","dispatchEvent","Event","bubbles","selected","click","clicked","note","direction","amount","scrollEl","documentElement","scrollBy","top","behavior","scrollTo","scrollHeight","scrolled","currentScroll","scrollTop","buildA11yTree","route","navigated","limit","getFilteredNetwork","level","getFilteredConsole","_apps","app","isMounted","querySelectorAll","forEach","getAttribute","storeKeys","href","title","viewport","width","innerWidth","height","innerHeight","networkRequests","networkLog","consoleMessages","consoleLog","consoleErrors","_ensureInit","schemaName","fireTrigger","capability","intent","runWorkflow","opts","expose","navigator","modelContext","actionNames","registerTool","inputSchema","toolCount","initialized"],"mappings":"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"}
|