wu-framework 1.1.6 → 1.1.8
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 +511 -977
- package/dist/wu-framework.cjs.js +3 -1
- package/dist/wu-framework.cjs.js.map +1 -0
- package/dist/wu-framework.dev.js +7533 -2761
- package/dist/wu-framework.dev.js.map +1 -1
- package/dist/wu-framework.esm.js +3 -0
- package/dist/wu-framework.esm.js.map +1 -0
- package/dist/wu-framework.umd.js +3 -1
- package/dist/wu-framework.umd.js.map +1 -0
- package/integrations/astro/README.md +127 -0
- package/integrations/astro/WuApp.astro +63 -0
- package/integrations/astro/WuShell.astro +39 -0
- package/integrations/astro/index.js +68 -0
- package/integrations/astro/package.json +38 -0
- package/integrations/astro/types.d.ts +53 -0
- package/package.json +94 -74
- package/src/adapters/angular/ai.js +30 -0
- package/src/adapters/angular/index.d.ts +154 -0
- package/src/adapters/angular/index.js +932 -0
- package/src/adapters/angular.d.ts +3 -154
- package/src/adapters/angular.js +3 -813
- package/src/adapters/index.js +35 -24
- package/src/adapters/lit/ai.js +20 -0
- package/src/adapters/lit/index.d.ts +120 -0
- package/src/adapters/lit/index.js +721 -0
- package/src/adapters/lit.d.ts +3 -120
- package/src/adapters/lit.js +3 -726
- package/src/adapters/preact/ai.js +33 -0
- package/src/adapters/preact/index.d.ts +108 -0
- package/src/adapters/preact/index.js +661 -0
- package/src/adapters/preact.d.ts +3 -108
- package/src/adapters/preact.js +3 -665
- package/src/adapters/react/ai.js +135 -0
- package/src/adapters/react/index.d.ts +246 -0
- package/src/adapters/react/index.js +689 -0
- package/src/adapters/react.d.ts +3 -212
- package/src/adapters/react.js +3 -513
- package/src/adapters/shared.js +64 -0
- package/src/adapters/solid/ai.js +32 -0
- package/src/adapters/solid/index.d.ts +101 -0
- package/src/adapters/solid/index.js +586 -0
- package/src/adapters/solid.d.ts +3 -101
- package/src/adapters/solid.js +3 -591
- package/src/adapters/svelte/ai.js +31 -0
- package/src/adapters/svelte/index.d.ts +166 -0
- package/src/adapters/svelte/index.js +798 -0
- package/src/adapters/svelte.d.ts +3 -166
- package/src/adapters/svelte.js +3 -803
- package/src/adapters/vanilla/ai.js +30 -0
- package/src/adapters/vanilla/index.d.ts +179 -0
- package/src/adapters/vanilla/index.js +785 -0
- package/src/adapters/vanilla.d.ts +3 -179
- package/src/adapters/vanilla.js +3 -791
- package/src/adapters/vue/ai.js +52 -0
- package/src/adapters/vue/index.d.ts +299 -0
- package/src/adapters/vue/index.js +608 -0
- package/src/adapters/vue.d.ts +3 -299
- package/src/adapters/vue.js +3 -611
- package/src/ai/wu-ai-actions.js +261 -0
- package/src/ai/wu-ai-browser.js +663 -0
- package/src/ai/wu-ai-context.js +332 -0
- package/src/ai/wu-ai-conversation.js +554 -0
- package/src/ai/wu-ai-permissions.js +381 -0
- package/src/ai/wu-ai-provider.js +605 -0
- package/src/ai/wu-ai-schema.js +225 -0
- package/src/ai/wu-ai-triggers.js +396 -0
- package/src/ai/wu-ai.js +474 -0
- package/src/core/wu-app.js +50 -8
- package/src/core/wu-cache.js +1 -1
- package/src/core/wu-core.js +645 -677
- package/src/core/wu-html-parser.js +121 -211
- package/src/core/wu-iframe-sandbox.js +328 -0
- package/src/core/wu-mcp-bridge.js +647 -0
- package/src/core/wu-overrides.js +510 -0
- package/src/core/wu-prefetch.js +414 -0
- package/src/core/wu-proxy-sandbox.js +398 -75
- package/src/core/wu-sandbox.js +86 -268
- package/src/core/wu-script-executor.js +79 -182
- package/src/core/wu-snapshot-sandbox.js +149 -106
- package/src/core/wu-strategies.js +13 -0
- package/src/core/wu-style-bridge.js +0 -2
- package/src/index.js +139 -665
- package/dist/wu-framework.hex.js +0 -23
- package/dist/wu-framework.min.js +0 -1
- package/dist/wu-framework.obf.js +0 -1
- package/scripts/build-protected.js +0 -366
- package/scripts/build.js +0 -212
- package/scripts/rollup-plugin-hex.js +0 -143
- package/src/core/wu-registry.js +0 -60
- package/src/core/wu-sandbox-pool.js +0 -390
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WU-AI-CONTEXT: Automatic context collector for LLMs
|
|
3
|
+
*
|
|
4
|
+
* Collects state from wu.store, wu.eventBus, and registered apps.
|
|
5
|
+
* Builds a structured context object and system prompt for the LLM.
|
|
6
|
+
*
|
|
7
|
+
* Key design:
|
|
8
|
+
* - ON-DEMAND collection (no polling, zero CPU idle)
|
|
9
|
+
* - Token budget with priority (high > medium > low)
|
|
10
|
+
* - Sensitive data redaction
|
|
11
|
+
* - System prompt generation
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { logger } from '../core/wu-logger.js';
|
|
15
|
+
import { redactSensitive, estimateTokens, truncateToTokenBudget } from './wu-ai-schema.js';
|
|
16
|
+
|
|
17
|
+
// ─── Context Source Config ───────────────────────────────────────
|
|
18
|
+
//
|
|
19
|
+
// store: { include: ['user.*', 'cart.*'], priority: 'high' }
|
|
20
|
+
// events: { include: ['cart:*', 'user:*'], lastN: 10, priority: 'medium' }
|
|
21
|
+
// custom: [{ key: 'appVersion', value: () => '1.0', priority: 'low' }]
|
|
22
|
+
|
|
23
|
+
export class WuAIContext {
|
|
24
|
+
constructor({ store, eventBus, core }) {
|
|
25
|
+
this._store = store;
|
|
26
|
+
this._eventBus = eventBus;
|
|
27
|
+
this._core = core;
|
|
28
|
+
|
|
29
|
+
this._config = {
|
|
30
|
+
budget: 4000, // token budget
|
|
31
|
+
charRatio: 4, // chars per token estimate
|
|
32
|
+
sources: {
|
|
33
|
+
store: { include: [], priority: 'high' },
|
|
34
|
+
events: { include: [], lastN: 10, priority: 'medium' },
|
|
35
|
+
custom: [],
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
this._collectors = new Map(); // name → { collector, priority }
|
|
40
|
+
this._lastSnapshot = null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Configure context collection.
|
|
45
|
+
*/
|
|
46
|
+
configure(config) {
|
|
47
|
+
if (config.budget !== undefined) this._config.budget = config.budget;
|
|
48
|
+
if (config.charRatio !== undefined) this._config.charRatio = config.charRatio;
|
|
49
|
+
if (config.sources) {
|
|
50
|
+
if (config.sources.store) Object.assign(this._config.sources.store, config.sources.store);
|
|
51
|
+
if (config.sources.events) Object.assign(this._config.sources.events, config.sources.events);
|
|
52
|
+
if (config.sources.custom) this._config.sources.custom = config.sources.custom;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Register a named context collector.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} name - Collector name (e.g., 'dashboard', 'analytics')
|
|
60
|
+
* @param {{ collector: Function, priority?: string }} config
|
|
61
|
+
*/
|
|
62
|
+
register(name, config) {
|
|
63
|
+
this._collectors.set(name, {
|
|
64
|
+
collector: config.collector,
|
|
65
|
+
priority: config.priority || 'medium',
|
|
66
|
+
});
|
|
67
|
+
logger.wuDebug(`[wu-ai] Context collector registered: '${name}' (${config.priority || 'medium'})`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Collect all context ON-DEMAND.
|
|
72
|
+
* Called before sending a message to the LLM.
|
|
73
|
+
*
|
|
74
|
+
* @returns {object} Context snapshot
|
|
75
|
+
*/
|
|
76
|
+
async collect() {
|
|
77
|
+
const snapshot = {
|
|
78
|
+
_timestamp: Date.now(),
|
|
79
|
+
_mountedApps: this._getMountedApps(),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Collect store sources
|
|
83
|
+
const storeData = this._collectStore();
|
|
84
|
+
if (storeData && Object.keys(storeData).length > 0) {
|
|
85
|
+
snapshot._store = storeData;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Collect recent events
|
|
89
|
+
const events = this._collectEvents();
|
|
90
|
+
if (events.length > 0) {
|
|
91
|
+
snapshot._events = events;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Collect custom sources
|
|
95
|
+
for (const custom of this._config.sources.custom) {
|
|
96
|
+
try {
|
|
97
|
+
const value = typeof custom.value === 'function' ? await custom.value() : custom.value;
|
|
98
|
+
snapshot[custom.key] = value;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
logger.wuDebug(`[wu-ai] Custom collector '${custom.key}' failed: ${err.message}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Collect registered collectors
|
|
105
|
+
for (const [name, config] of this._collectors) {
|
|
106
|
+
try {
|
|
107
|
+
const data = await config.collector();
|
|
108
|
+
snapshot[name] = data;
|
|
109
|
+
} catch (err) {
|
|
110
|
+
logger.wuDebug(`[wu-ai] Collector '${name}' failed: ${err.message}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this._lastSnapshot = snapshot;
|
|
115
|
+
return snapshot;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Build a system prompt from the context for the LLM.
|
|
120
|
+
*
|
|
121
|
+
* @param {{ tools?: Array }} [options] - Available tools to include
|
|
122
|
+
* @returns {string} System prompt
|
|
123
|
+
*/
|
|
124
|
+
toSystemPrompt(options = {}) {
|
|
125
|
+
const snapshot = this._lastSnapshot;
|
|
126
|
+
if (!snapshot) return this._baseSystemPrompt(options);
|
|
127
|
+
|
|
128
|
+
const parts = [];
|
|
129
|
+
|
|
130
|
+
// Base instruction
|
|
131
|
+
parts.push(
|
|
132
|
+
'You are an AI assistant connected to a live web application via Wu Framework.',
|
|
133
|
+
'You can observe application state and execute actions when appropriate.',
|
|
134
|
+
''
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Mounted apps (always included)
|
|
138
|
+
if (snapshot._mountedApps?.length) {
|
|
139
|
+
parts.push(`MOUNTED APPS: ${snapshot._mountedApps.join(', ')}`, '');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Budget tracking
|
|
143
|
+
const budget = this._config.budget;
|
|
144
|
+
const charBudget = budget * this._config.charRatio;
|
|
145
|
+
let usedChars = parts.join('\n').length;
|
|
146
|
+
|
|
147
|
+
// Priority-based inclusion
|
|
148
|
+
const prioritized = this._prioritizeSections(snapshot);
|
|
149
|
+
|
|
150
|
+
for (const section of prioritized) {
|
|
151
|
+
const sectionText = section.text;
|
|
152
|
+
if (usedChars + sectionText.length > charBudget) {
|
|
153
|
+
// Try to truncate if high priority
|
|
154
|
+
if (section.priority === 'high') {
|
|
155
|
+
const remaining = charBudget - usedChars;
|
|
156
|
+
if (remaining > 100) {
|
|
157
|
+
parts.push(sectionText.slice(0, remaining) + '\n...[truncated]');
|
|
158
|
+
usedChars += remaining;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
continue; // skip if over budget
|
|
162
|
+
}
|
|
163
|
+
parts.push(sectionText);
|
|
164
|
+
usedChars += sectionText.length;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Tools (outside budget — LLM needs these)
|
|
168
|
+
if (options.tools?.length) {
|
|
169
|
+
parts.push('', 'AVAILABLE TOOLS:');
|
|
170
|
+
for (const tool of options.tools) {
|
|
171
|
+
parts.push(`- ${tool.name}: ${tool.description}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return parts.join('\n');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get the last collected snapshot.
|
|
180
|
+
*/
|
|
181
|
+
getSnapshot() {
|
|
182
|
+
return this._lastSnapshot;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get a simplified context object for template interpolation.
|
|
187
|
+
*/
|
|
188
|
+
getInterpolationContext() {
|
|
189
|
+
if (!this._lastSnapshot) return {};
|
|
190
|
+
const { _timestamp, _mountedApps, _store, _events, ...custom } = this._lastSnapshot;
|
|
191
|
+
return {
|
|
192
|
+
apps: _mountedApps,
|
|
193
|
+
store: _store,
|
|
194
|
+
events: _events,
|
|
195
|
+
...custom,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ── Private: Data Collection ──
|
|
200
|
+
|
|
201
|
+
_collectStore() {
|
|
202
|
+
if (!this._store) return {};
|
|
203
|
+
const { include } = this._config.sources.store;
|
|
204
|
+
if (!include || include.length === 0) return {};
|
|
205
|
+
|
|
206
|
+
const data = {};
|
|
207
|
+
for (const path of include) {
|
|
208
|
+
try {
|
|
209
|
+
const value = this._store.get(path);
|
|
210
|
+
if (value !== undefined) {
|
|
211
|
+
data[path] = redactSensitive(value);
|
|
212
|
+
}
|
|
213
|
+
} catch {
|
|
214
|
+
// Path doesn't exist, skip
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return data;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
_collectEvents() {
|
|
221
|
+
if (!this._eventBus) return [];
|
|
222
|
+
const { include, lastN } = this._config.sources.events;
|
|
223
|
+
if (!include || include.length === 0) return [];
|
|
224
|
+
|
|
225
|
+
const history = this._eventBus.history || [];
|
|
226
|
+
const matching = history.filter(event => {
|
|
227
|
+
return include.some(pattern => this._matchPattern(event.name || event.event, pattern));
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return matching.slice(-(lastN || 10)).map(e => ({
|
|
231
|
+
event: e.name || e.event,
|
|
232
|
+
data: redactSensitive(e.data),
|
|
233
|
+
timestamp: e.timestamp,
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
_getMountedApps() {
|
|
238
|
+
if (!this._core) return [];
|
|
239
|
+
try {
|
|
240
|
+
// WuCore exposes mounted as Map or getStats()
|
|
241
|
+
if (this._core.mounted instanceof Map) {
|
|
242
|
+
return [...this._core.mounted.keys()];
|
|
243
|
+
}
|
|
244
|
+
const stats = this._core.getStats?.();
|
|
245
|
+
return stats?.apps || stats?.mounted || [];
|
|
246
|
+
} catch {
|
|
247
|
+
return [];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// ── Private: Priority & Budget ──
|
|
252
|
+
|
|
253
|
+
_prioritizeSections(snapshot) {
|
|
254
|
+
const sections = [];
|
|
255
|
+
const storePriority = this._config.sources.store.priority || 'high';
|
|
256
|
+
const eventPriority = this._config.sources.events.priority || 'medium';
|
|
257
|
+
|
|
258
|
+
// Store snapshot
|
|
259
|
+
if (snapshot._store && Object.keys(snapshot._store).length > 0) {
|
|
260
|
+
sections.push({
|
|
261
|
+
priority: storePriority,
|
|
262
|
+
text: `APPLICATION STATE:\n${JSON.stringify(snapshot._store, null, 2)}`,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Recent events
|
|
267
|
+
if (snapshot._events?.length) {
|
|
268
|
+
const eventLines = snapshot._events.map(e =>
|
|
269
|
+
` [${e.event}] ${JSON.stringify(e.data)}`
|
|
270
|
+
).join('\n');
|
|
271
|
+
sections.push({
|
|
272
|
+
priority: eventPriority,
|
|
273
|
+
text: `RECENT EVENTS:\n${eventLines}`,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Custom collectors
|
|
278
|
+
for (const [name, config] of this._collectors) {
|
|
279
|
+
if (snapshot[name] !== undefined) {
|
|
280
|
+
sections.push({
|
|
281
|
+
priority: config.priority,
|
|
282
|
+
text: `${name.toUpperCase()}:\n${JSON.stringify(snapshot[name], null, 2)}`,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Custom sources
|
|
288
|
+
for (const custom of this._config.sources.custom) {
|
|
289
|
+
if (snapshot[custom.key] !== undefined) {
|
|
290
|
+
sections.push({
|
|
291
|
+
priority: custom.priority || 'low',
|
|
292
|
+
text: `${custom.key}: ${JSON.stringify(snapshot[custom.key])}`,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Sort: high → medium → low
|
|
298
|
+
const order = { high: 0, medium: 1, low: 2 };
|
|
299
|
+
sections.sort((a, b) => (order[a.priority] ?? 1) - (order[b.priority] ?? 1));
|
|
300
|
+
|
|
301
|
+
return sections;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
_baseSystemPrompt(options = {}) {
|
|
305
|
+
let prompt = 'You are an AI assistant connected to a web application via Wu Framework.';
|
|
306
|
+
if (options.tools?.length) {
|
|
307
|
+
prompt += '\n\nAVAILABLE TOOLS:\n' + options.tools.map(t => `- ${t.name}: ${t.description}`).join('\n');
|
|
308
|
+
}
|
|
309
|
+
return prompt;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ── Pattern Matching (reuse wu-framework convention) ──
|
|
313
|
+
|
|
314
|
+
_matchPattern(eventName, pattern) {
|
|
315
|
+
if (!eventName || !pattern) return false;
|
|
316
|
+
if (pattern === '*') return true;
|
|
317
|
+
if (!pattern.includes('*')) return eventName === pattern;
|
|
318
|
+
|
|
319
|
+
const regex = new RegExp('^' + pattern.replace(/\*/g, '[^:]*') + '$');
|
|
320
|
+
return regex.test(eventName);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
getStats() {
|
|
324
|
+
return {
|
|
325
|
+
budget: this._config.budget,
|
|
326
|
+
collectors: [...this._collectors.keys()],
|
|
327
|
+
storePaths: this._config.sources.store.include,
|
|
328
|
+
eventPatterns: this._config.sources.events.include,
|
|
329
|
+
lastCollected: this._lastSnapshot?._timestamp || null,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|