@ai-gui/vue 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +56 -12
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +57 -13
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -73,19 +73,25 @@ function useActionState(runtime, key) {
|
|
|
73
73
|
/** Host element for imperative `mount` outputs, wired to Vue's lifecycle. */
|
|
74
74
|
const MountHost = (0, vue.defineComponent)({
|
|
75
75
|
name: "MountHost",
|
|
76
|
-
props: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
props: {
|
|
77
|
+
mount: {
|
|
78
|
+
type: Function,
|
|
79
|
+
required: true
|
|
80
|
+
},
|
|
81
|
+
context: {
|
|
82
|
+
type: Object,
|
|
83
|
+
required: true
|
|
84
|
+
}
|
|
85
|
+
},
|
|
80
86
|
setup(props) {
|
|
81
87
|
const elRef = (0, vue.ref)(null);
|
|
82
88
|
let cleanup;
|
|
83
89
|
(0, vue.onMounted)(() => {
|
|
84
|
-
if (elRef.value) cleanup = props.mount(elRef.value);
|
|
90
|
+
if (elRef.value) cleanup = props.mount(elRef.value, props.context);
|
|
85
91
|
});
|
|
86
92
|
(0, vue.watch)(() => props.mount, (mount) => {
|
|
87
93
|
if (typeof cleanup === "function") cleanup();
|
|
88
|
-
cleanup = elRef.value ? mount(elRef.value) : void 0;
|
|
94
|
+
cleanup = elRef.value ? mount(elRef.value, props.context) : void 0;
|
|
89
95
|
});
|
|
90
96
|
(0, vue.onBeforeUnmount)(() => {
|
|
91
97
|
if (typeof cleanup === "function") cleanup();
|
|
@@ -97,11 +103,14 @@ const MountHost = (0, vue.defineComponent)({
|
|
|
97
103
|
}
|
|
98
104
|
});
|
|
99
105
|
/** Translate a framework-neutral RenderOutput into a Vue VNode. */
|
|
100
|
-
function renderOutput(out, sanitize) {
|
|
106
|
+
function renderOutput(out, sanitize, context = {}) {
|
|
101
107
|
switch (out.kind) {
|
|
102
108
|
case "html": return (0, vue.h)("div", { innerHTML: sanitizeOutput(out.html, sanitize) });
|
|
103
|
-
case "element": return (0, vue.h)(out.tag, out.props, (out.children ?? []).map((child) => renderOutput(child, sanitize)));
|
|
104
|
-
case "mount": return (0, vue.h)(MountHost, {
|
|
109
|
+
case "element": return (0, vue.h)(out.tag, out.props, (out.children ?? []).map((child) => renderOutput(child, sanitize, context)));
|
|
110
|
+
case "mount": return (0, vue.h)(MountHost, {
|
|
111
|
+
mount: out.mount,
|
|
112
|
+
context
|
|
113
|
+
});
|
|
105
114
|
case "card": return (0, vue.h)("pre", { "data-aigui-card-fallback": "" }, [(0, vue.h)("code", JSON.stringify(out.data, null, 2))]);
|
|
106
115
|
}
|
|
107
116
|
}
|
|
@@ -116,6 +125,10 @@ const AsyncOutput = (0, vue.defineComponent)({
|
|
|
116
125
|
sanitize: {
|
|
117
126
|
type: [Boolean, Object],
|
|
118
127
|
default: void 0
|
|
128
|
+
},
|
|
129
|
+
context: {
|
|
130
|
+
type: Object,
|
|
131
|
+
default: () => ({})
|
|
119
132
|
}
|
|
120
133
|
},
|
|
121
134
|
setup(props) {
|
|
@@ -142,13 +155,42 @@ const AsyncOutput = (0, vue.defineComponent)({
|
|
|
142
155
|
if (failed.value) return (0, vue.h)("span", { "data-aigui-async-error": "" });
|
|
143
156
|
if (!resolved.value) return (0, vue.h)("span", { "data-aigui-async-pending": "" });
|
|
144
157
|
try {
|
|
145
|
-
return renderOutput(resolved.value, props.sanitize);
|
|
158
|
+
return renderOutput(resolved.value, props.sanitize, props.context);
|
|
146
159
|
} catch {
|
|
147
160
|
return (0, vue.h)("span", { "data-aigui-async-error": "" });
|
|
148
161
|
}
|
|
149
162
|
};
|
|
150
163
|
}
|
|
151
164
|
});
|
|
165
|
+
function createRenderMountContext(registry, onCardAction) {
|
|
166
|
+
return { mountCard(host, request) {
|
|
167
|
+
const component = registry?.getRender(request.type);
|
|
168
|
+
if (!component) return void 0;
|
|
169
|
+
const card = (0, vue.markRaw)((0, vue.toRaw)(component));
|
|
170
|
+
let data = request.data;
|
|
171
|
+
let destroyed = false;
|
|
172
|
+
const renderCard$1 = () => (0, vue.render)((0, vue.h)(card, {
|
|
173
|
+
data,
|
|
174
|
+
onAction: (action) => onCardAction?.({
|
|
175
|
+
...action,
|
|
176
|
+
cardType: request.type
|
|
177
|
+
})
|
|
178
|
+
}), host);
|
|
179
|
+
renderCard$1();
|
|
180
|
+
return {
|
|
181
|
+
update(nextData) {
|
|
182
|
+
if (destroyed) return;
|
|
183
|
+
data = nextData;
|
|
184
|
+
renderCard$1();
|
|
185
|
+
},
|
|
186
|
+
destroy() {
|
|
187
|
+
if (destroyed) return;
|
|
188
|
+
destroyed = true;
|
|
189
|
+
(0, vue.render)(null, host);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
} };
|
|
193
|
+
}
|
|
152
194
|
function sanitizeOutput(html, sanitize) {
|
|
153
195
|
if (sanitize === false) return html;
|
|
154
196
|
return (0, __ai_gui_core.sanitizeHtml)(html, typeof sanitize === "object" ? sanitize : void 0);
|
|
@@ -166,12 +208,14 @@ function renderNode(node, ctx) {
|
|
|
166
208
|
});
|
|
167
209
|
try {
|
|
168
210
|
const out = r(node);
|
|
211
|
+
const mountContext = createRenderMountContext(ctx.registry, ctx.onCardAction);
|
|
169
212
|
if (out && typeof out.then === "function") return (0, vue.h)(AsyncOutput, {
|
|
170
213
|
key: node.key,
|
|
171
214
|
promise: out,
|
|
172
|
-
sanitize: ctx.sanitize
|
|
215
|
+
sanitize: ctx.sanitize,
|
|
216
|
+
context: mountContext
|
|
173
217
|
});
|
|
174
|
-
const vnode = renderOutput(out, ctx.sanitize);
|
|
218
|
+
const vnode = renderOutput(out, ctx.sanitize, mountContext);
|
|
175
219
|
vnode.key = node.key;
|
|
176
220
|
return vnode;
|
|
177
221
|
} catch {
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ShallowRef, VNode } from "vue";
|
|
2
|
-
import { AIGuiPlugin, ASTNode, ActionRuntime, ActionState, CardRegistry, CardStore, FeedOptions, FeedSource, NodeRenderer, RenderOutput, Renderer, RendererOptions } from "@ai-gui/core";
|
|
2
|
+
import { AIGuiPlugin, ASTNode, ActionRuntime, ActionState, CardRegistry, CardStore, FeedOptions, FeedSource, NodeRenderer, RenderMountContext, RenderOutput, Renderer, RendererOptions } from "@ai-gui/core";
|
|
3
3
|
|
|
4
4
|
//#region src/use-ai-renderer.d.ts
|
|
5
5
|
interface UseAIRendererResult {
|
|
@@ -41,7 +41,7 @@ declare function renderNode(node: ASTNode, ctx: RenderContext): VNode;
|
|
|
41
41
|
//#endregion
|
|
42
42
|
//#region src/render-output.d.ts
|
|
43
43
|
/** Translate a framework-neutral RenderOutput into a Vue VNode. */
|
|
44
|
-
declare function renderOutput(out: RenderOutput, sanitize?: RendererOptions["sanitize"]): VNode;
|
|
44
|
+
declare function renderOutput(out: RenderOutput, sanitize?: RendererOptions["sanitize"], context?: RenderMountContext): VNode;
|
|
45
45
|
|
|
46
46
|
//#endregion
|
|
47
47
|
/** Await an async RenderOutput, rendering a placeholder until it resolves. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ShallowRef, VNode } from "vue";
|
|
2
|
-
import { AIGuiPlugin, ASTNode, ActionRuntime, ActionState, CardRegistry, CardStore, FeedOptions, FeedSource, NodeRenderer, RenderOutput, Renderer, RendererOptions } from "@ai-gui/core";
|
|
2
|
+
import { AIGuiPlugin, ASTNode, ActionRuntime, ActionState, CardRegistry, CardStore, FeedOptions, FeedSource, NodeRenderer, RenderMountContext, RenderOutput, Renderer, RendererOptions } from "@ai-gui/core";
|
|
3
3
|
|
|
4
4
|
//#region src/use-ai-renderer.d.ts
|
|
5
5
|
interface UseAIRendererResult {
|
|
@@ -41,7 +41,7 @@ declare function renderNode(node: ASTNode, ctx: RenderContext): VNode;
|
|
|
41
41
|
//#endregion
|
|
42
42
|
//#region src/render-output.d.ts
|
|
43
43
|
/** Translate a framework-neutral RenderOutput into a Vue VNode. */
|
|
44
|
-
declare function renderOutput(out: RenderOutput, sanitize?: RendererOptions["sanitize"]): VNode;
|
|
44
|
+
declare function renderOutput(out: RenderOutput, sanitize?: RendererOptions["sanitize"], context?: RenderMountContext): VNode;
|
|
45
45
|
|
|
46
46
|
//#endregion
|
|
47
47
|
/** Await an async RenderOutput, rendering a placeholder until it resolves. */
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineComponent, h, markRaw, onBeforeUnmount, onMounted, onScopeDispose, ref, shallowRef, toRaw, watch } from "vue";
|
|
1
|
+
import { defineComponent, h, markRaw, onBeforeUnmount, onMounted, onScopeDispose, ref, render, shallowRef, toRaw, watch } from "vue";
|
|
2
2
|
import { Renderer, collectNodeRenderers, sanitizeHtml } from "@ai-gui/core";
|
|
3
3
|
|
|
4
4
|
//#region src/use-ai-renderer.ts
|
|
@@ -49,19 +49,25 @@ function useActionState(runtime, key) {
|
|
|
49
49
|
/** Host element for imperative `mount` outputs, wired to Vue's lifecycle. */
|
|
50
50
|
const MountHost = defineComponent({
|
|
51
51
|
name: "MountHost",
|
|
52
|
-
props: {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
props: {
|
|
53
|
+
mount: {
|
|
54
|
+
type: Function,
|
|
55
|
+
required: true
|
|
56
|
+
},
|
|
57
|
+
context: {
|
|
58
|
+
type: Object,
|
|
59
|
+
required: true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
56
62
|
setup(props) {
|
|
57
63
|
const elRef = ref(null);
|
|
58
64
|
let cleanup;
|
|
59
65
|
onMounted(() => {
|
|
60
|
-
if (elRef.value) cleanup = props.mount(elRef.value);
|
|
66
|
+
if (elRef.value) cleanup = props.mount(elRef.value, props.context);
|
|
61
67
|
});
|
|
62
68
|
watch(() => props.mount, (mount) => {
|
|
63
69
|
if (typeof cleanup === "function") cleanup();
|
|
64
|
-
cleanup = elRef.value ? mount(elRef.value) : void 0;
|
|
70
|
+
cleanup = elRef.value ? mount(elRef.value, props.context) : void 0;
|
|
65
71
|
});
|
|
66
72
|
onBeforeUnmount(() => {
|
|
67
73
|
if (typeof cleanup === "function") cleanup();
|
|
@@ -73,11 +79,14 @@ const MountHost = defineComponent({
|
|
|
73
79
|
}
|
|
74
80
|
});
|
|
75
81
|
/** Translate a framework-neutral RenderOutput into a Vue VNode. */
|
|
76
|
-
function renderOutput(out, sanitize) {
|
|
82
|
+
function renderOutput(out, sanitize, context = {}) {
|
|
77
83
|
switch (out.kind) {
|
|
78
84
|
case "html": return h("div", { innerHTML: sanitizeOutput(out.html, sanitize) });
|
|
79
|
-
case "element": return h(out.tag, out.props, (out.children ?? []).map((child) => renderOutput(child, sanitize)));
|
|
80
|
-
case "mount": return h(MountHost, {
|
|
85
|
+
case "element": return h(out.tag, out.props, (out.children ?? []).map((child) => renderOutput(child, sanitize, context)));
|
|
86
|
+
case "mount": return h(MountHost, {
|
|
87
|
+
mount: out.mount,
|
|
88
|
+
context
|
|
89
|
+
});
|
|
81
90
|
case "card": return h("pre", { "data-aigui-card-fallback": "" }, [h("code", JSON.stringify(out.data, null, 2))]);
|
|
82
91
|
}
|
|
83
92
|
}
|
|
@@ -92,6 +101,10 @@ const AsyncOutput = defineComponent({
|
|
|
92
101
|
sanitize: {
|
|
93
102
|
type: [Boolean, Object],
|
|
94
103
|
default: void 0
|
|
104
|
+
},
|
|
105
|
+
context: {
|
|
106
|
+
type: Object,
|
|
107
|
+
default: () => ({})
|
|
95
108
|
}
|
|
96
109
|
},
|
|
97
110
|
setup(props) {
|
|
@@ -118,13 +131,42 @@ const AsyncOutput = defineComponent({
|
|
|
118
131
|
if (failed.value) return h("span", { "data-aigui-async-error": "" });
|
|
119
132
|
if (!resolved.value) return h("span", { "data-aigui-async-pending": "" });
|
|
120
133
|
try {
|
|
121
|
-
return renderOutput(resolved.value, props.sanitize);
|
|
134
|
+
return renderOutput(resolved.value, props.sanitize, props.context);
|
|
122
135
|
} catch {
|
|
123
136
|
return h("span", { "data-aigui-async-error": "" });
|
|
124
137
|
}
|
|
125
138
|
};
|
|
126
139
|
}
|
|
127
140
|
});
|
|
141
|
+
function createRenderMountContext(registry, onCardAction) {
|
|
142
|
+
return { mountCard(host, request) {
|
|
143
|
+
const component = registry?.getRender(request.type);
|
|
144
|
+
if (!component) return void 0;
|
|
145
|
+
const card = markRaw(toRaw(component));
|
|
146
|
+
let data = request.data;
|
|
147
|
+
let destroyed = false;
|
|
148
|
+
const renderCard$1 = () => render(h(card, {
|
|
149
|
+
data,
|
|
150
|
+
onAction: (action) => onCardAction?.({
|
|
151
|
+
...action,
|
|
152
|
+
cardType: request.type
|
|
153
|
+
})
|
|
154
|
+
}), host);
|
|
155
|
+
renderCard$1();
|
|
156
|
+
return {
|
|
157
|
+
update(nextData) {
|
|
158
|
+
if (destroyed) return;
|
|
159
|
+
data = nextData;
|
|
160
|
+
renderCard$1();
|
|
161
|
+
},
|
|
162
|
+
destroy() {
|
|
163
|
+
if (destroyed) return;
|
|
164
|
+
destroyed = true;
|
|
165
|
+
render(null, host);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
} };
|
|
169
|
+
}
|
|
128
170
|
function sanitizeOutput(html, sanitize) {
|
|
129
171
|
if (sanitize === false) return html;
|
|
130
172
|
return sanitizeHtml(html, typeof sanitize === "object" ? sanitize : void 0);
|
|
@@ -142,12 +184,14 @@ function renderNode(node, ctx) {
|
|
|
142
184
|
});
|
|
143
185
|
try {
|
|
144
186
|
const out = r(node);
|
|
187
|
+
const mountContext = createRenderMountContext(ctx.registry, ctx.onCardAction);
|
|
145
188
|
if (out && typeof out.then === "function") return h(AsyncOutput, {
|
|
146
189
|
key: node.key,
|
|
147
190
|
promise: out,
|
|
148
|
-
sanitize: ctx.sanitize
|
|
191
|
+
sanitize: ctx.sanitize,
|
|
192
|
+
context: mountContext
|
|
149
193
|
});
|
|
150
|
-
const vnode = renderOutput(out, ctx.sanitize);
|
|
194
|
+
const vnode = renderOutput(out, ctx.sanitize, mountContext);
|
|
151
195
|
vnode.key = node.key;
|
|
152
196
|
return vnode;
|
|
153
197
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-gui/vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Vue 3 adapter for AIGUI — stream LLM output into live Vue components with cards and plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"llm",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@ai-gui/core": "0.
|
|
54
|
+
"@ai-gui/core": "0.4.1"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"vue": ">=3.3"
|