@vibevibes/sdk 0.1.0 → 0.3.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/dist/index.js CHANGED
@@ -12,709 +12,108 @@ function defineTool(config) {
12
12
  function defineTest(config) {
13
13
  return { name: config.name, run: config.run };
14
14
  }
15
- function defineEphemeralAction(config) {
15
+ function defineStream(config) {
16
16
  return {
17
17
  name: config.name,
18
18
  description: config.description,
19
- input_schema: config.input_schema
20
- };
21
- }
22
- function quickTool(name, description, input_schema, handler) {
23
- return {
24
- name,
25
- description,
26
- input_schema,
27
- risk: "low",
28
- capabilities_required: ["state.write"],
29
- handler
19
+ input_schema: config.input_schema,
20
+ merge: config.merge,
21
+ rateLimit: config.rateLimit
30
22
  };
31
23
  }
32
24
  function defineExperience(module) {
33
- const m = module.manifest;
25
+ const m = module.manifest ?? {};
26
+ let initialState = module.initialState;
27
+ if (module.stateSchema && !initialState) {
28
+ try {
29
+ initialState = module.stateSchema.parse(void 0);
30
+ } catch {
31
+ try {
32
+ initialState = module.stateSchema.parse({});
33
+ } catch {
34
+ }
35
+ }
36
+ }
37
+ if (module.stateSchema && initialState) {
38
+ try {
39
+ module.stateSchema.parse(initialState);
40
+ } catch (err) {
41
+ console.warn(
42
+ `[vibevibes] initialState does not match stateSchema: ${err instanceof Error ? err.message : err}`
43
+ );
44
+ }
45
+ }
46
+ const rawParticipantSlots = module.participants ?? m.participantSlots ?? (module.agents || m.agentSlots)?.map((a) => ({ ...a, type: "ai" }));
47
+ const hasOrchestrator = rawParticipantSlots?.some((s) => s.role === "orchestrator");
48
+ const participantSlots = rawParticipantSlots ? hasOrchestrator ? rawParticipantSlots : [...rawParticipantSlots, { role: "orchestrator", type: "ai", maxInstances: 1 }] : [{ role: "orchestrator", type: "ai", maxInstances: 1 }];
49
+ const agentSlots = participantSlots?.filter(
50
+ (s) => s.type === "ai" || s.type === void 0 || s.type === "any"
51
+ ) ?? m.agentSlots ?? module.agents;
34
52
  return {
35
53
  ...module,
54
+ initialState,
36
55
  manifest: {
37
56
  ...m,
57
+ title: m.title || module.name || m.id,
38
58
  version: m.version || "0.0.1",
39
- requested_capabilities: m.requested_capabilities || ["state.write"]
59
+ requested_capabilities: m.requested_capabilities || ["state.write"],
60
+ participantSlots: participantSlots ?? m.participantSlots,
61
+ agentSlots: agentSlots ?? m.agentSlots
40
62
  }
41
63
  };
42
64
  }
43
- function validateExperience(module) {
44
- const errors = [];
45
- if (!module.manifest?.id) {
46
- errors.push("manifest.id is required");
47
- }
48
- if (!module.manifest?.version) {
49
- errors.push("manifest.version is required");
50
- }
51
- if (!module.manifest?.title) {
52
- errors.push("manifest.title is required");
53
- }
54
- if (!module.Canvas) {
55
- errors.push("Canvas component is required");
56
- }
57
- if (!Array.isArray(module.tools)) {
58
- errors.push("tools must be an array");
59
- } else {
60
- module.tools.forEach((tool, idx) => {
61
- if (!tool.name) {
62
- errors.push(`tools[${idx}].name is required`);
63
- }
64
- if (!tool.input_schema) {
65
- errors.push(`tools[${idx}].input_schema is required`);
66
- }
67
- if (typeof tool.handler !== "function") {
68
- errors.push(`tools[${idx}].handler must be a function`);
69
- }
70
- });
71
- }
72
- return {
73
- valid: errors.length === 0,
74
- errors
75
- };
76
- }
77
65
 
78
- // src/hooks.ts
79
- function getReact() {
80
- const R = globalThis.React;
81
- if (!R) throw new Error("React is not available. Hooks must be used inside a Canvas component.");
82
- return R;
83
- }
84
- var React = new Proxy({}, {
85
- get(_target, prop) {
86
- return getReact()[prop];
87
- }
88
- });
89
- function useToolCall(callTool) {
90
- const [loading, setLoading] = React.useState(false);
91
- const [error, setError] = React.useState(null);
92
- const call = React.useCallback(
93
- async (name, input) => {
94
- setLoading(true);
95
- setError(null);
96
- try {
97
- const result = await callTool(name, input);
98
- return result;
99
- } catch (err) {
100
- const msg = err instanceof Error ? err.message : String(err);
101
- setError(msg);
102
- throw err;
103
- } finally {
104
- setLoading(false);
105
- }
106
- },
107
- [callTool]
108
- );
109
- return { call, loading, error };
110
- }
111
- function useSharedState(sharedState, key, defaultValue) {
112
- const value = sharedState[key];
113
- if (value === void 0) return defaultValue;
114
- return value;
115
- }
116
- function useOptimisticTool(callTool, sharedState) {
117
- const [optimistic, setOptimistic] = React.useState(null);
118
- const [pending, setPending] = React.useState(false);
119
- const call = React.useCallback(
120
- async (name, input, optimisticState) => {
121
- setOptimistic(optimisticState);
122
- setPending(true);
123
- try {
124
- const result = await callTool(name, input);
125
- setOptimistic(null);
126
- return result;
127
- } catch (err) {
128
- setOptimistic(null);
129
- throw err;
130
- } finally {
131
- setPending(false);
132
- }
133
- },
134
- [callTool]
135
- );
136
- const state = optimistic ? { ...sharedState, ...optimistic } : sharedState;
137
- return { call, state, pending };
138
- }
139
- function useAnimationFrame(sharedState, interpolate) {
140
- const prevStateRef = React.useRef(sharedState);
141
- const targetStateRef = React.useRef(sharedState);
142
- const displayStateRef = React.useRef(sharedState);
143
- const [displayState, setDisplayState] = React.useState(sharedState);
144
- const rafRef = React.useRef(null);
145
- const transitionStartRef = React.useRef(0);
146
- const TRANSITION_MS = 50;
147
- React.useEffect(() => {
148
- prevStateRef.current = displayStateRef.current;
149
- targetStateRef.current = sharedState;
150
- transitionStartRef.current = performance.now();
151
- if (!rafRef.current) {
152
- const tick = () => {
153
- const now = performance.now();
154
- const elapsed = now - transitionStartRef.current;
155
- const t = Math.min(elapsed / TRANSITION_MS, 1);
156
- let next;
157
- if (interpolate && t < 1) {
158
- next = interpolate(prevStateRef.current, targetStateRef.current, t);
159
- } else {
160
- next = targetStateRef.current;
161
- }
162
- displayStateRef.current = next;
163
- setDisplayState(next);
164
- if (t < 1 && interpolate) {
165
- rafRef.current = requestAnimationFrame(tick);
166
- } else {
167
- rafRef.current = null;
168
- }
169
- };
170
- rafRef.current = requestAnimationFrame(tick);
171
- }
172
- }, [sharedState, interpolate]);
173
- React.useEffect(() => {
174
- return () => {
175
- if (rafRef.current) {
176
- cancelAnimationFrame(rafRef.current);
177
- rafRef.current = null;
178
- }
179
- };
180
- }, []);
181
- return displayState;
182
- }
183
- function useParticipants(participants) {
184
- return React.useMemo(() => {
185
- return participants.map((id) => {
186
- const match = id.match(/^(.+)-(human|ai)-(\d+)$/);
187
- if (match) {
188
- return {
189
- id,
190
- username: match[1],
191
- type: match[2],
192
- index: parseInt(match[3], 10)
193
- };
194
- }
195
- return { id, username: id, type: "unknown", index: 0 };
196
- });
197
- }, [participants]);
198
- }
199
- function useFollow(actorId, participants, ephemeralState, setEphemeral, _onEphemeralAction, dispatchEphemeralAction) {
200
- const myEphemeral = ephemeralState[actorId];
201
- const following = myEphemeral?._follow ?? null;
202
- const followers = React.useMemo(() => {
203
- const result = [];
204
- for (const pid of participants) {
205
- if (pid === actorId) continue;
206
- const peerFollow = ephemeralState[pid]?._follow;
207
- if (peerFollow && peerFollow.targetActorId === actorId) {
208
- result.push({
209
- actorId: pid,
210
- mode: peerFollow.mode,
211
- since: peerFollow.since
212
- });
213
- }
214
- }
215
- return result;
216
- }, [participants, ephemeralState, actorId]);
217
- const follow = React.useCallback(
218
- (targetActorId, mode) => {
219
- if (targetActorId === actorId) return;
220
- const followData = {
221
- targetActorId,
222
- mode,
223
- since: Date.now()
224
- };
225
- setEphemeral({ _follow: followData });
226
- if (dispatchEphemeralAction) {
227
- dispatchEphemeralAction("follow.started", {
228
- follower: actorId,
229
- target: targetActorId,
230
- mode
231
- });
232
- }
233
- },
234
- [actorId, setEphemeral, dispatchEphemeralAction]
235
- );
236
- const unfollow = React.useCallback(() => {
237
- const currentTarget = following?.targetActorId;
238
- setEphemeral({ _follow: null });
239
- if (dispatchEphemeralAction && currentTarget) {
240
- dispatchEphemeralAction("follow.stopped", {
241
- follower: actorId,
242
- target: currentTarget
243
- });
244
- }
245
- }, [actorId, following, setEphemeral, dispatchEphemeralAction]);
246
- React.useEffect(() => {
247
- if (!following) return;
248
- if (!participants.includes(following.targetActorId)) {
249
- setEphemeral({ _follow: null });
250
- }
251
- }, [following, participants, setEphemeral]);
252
- return { follow, unfollow, following, followers };
253
- }
254
- function useTypingIndicator(actorId, ephemeralState, setEphemeral, timeoutMs = 3e3) {
255
- const timerRef = React.useRef(null);
256
- const setTyping = React.useCallback((isTyping) => {
257
- setEphemeral({ _typing: isTyping ? Date.now() : null });
258
- if (timerRef.current) clearTimeout(timerRef.current);
259
- if (isTyping) {
260
- timerRef.current = setTimeout(() => {
261
- setEphemeral({ _typing: null });
262
- }, timeoutMs);
263
- }
264
- }, [setEphemeral, timeoutMs]);
265
- React.useEffect(() => {
266
- return () => {
267
- if (timerRef.current) clearTimeout(timerRef.current);
268
- };
269
- }, []);
270
- const now = Date.now();
271
- const typingUsers = Object.entries(ephemeralState).filter(([id, data]) => id !== actorId && data._typing && now - data._typing < timeoutMs + 2e3).map(([id]) => id);
272
- return { setTyping, typingUsers };
273
- }
274
-
275
- // src/components.ts
276
- function getReact2() {
277
- const R = globalThis.React;
278
- if (!R) throw new Error("React is not available.");
279
- return R;
280
- }
281
- function h(type, props, ...children) {
282
- return getReact2().createElement(type, props, ...children);
283
- }
284
- var buttonColors = {
285
- primary: { bg: "#6366f1", text: "#fff", hover: "#4f46e5" },
286
- secondary: { bg: "#f3f4f6", text: "#374151", hover: "#e5e7eb" },
287
- danger: { bg: "#ef4444", text: "#fff", hover: "#dc2626" },
288
- ghost: { bg: "transparent", text: "#6b7280", hover: "#f3f4f6" }
289
- };
290
- var buttonSizes = {
291
- sm: { padding: "0.375rem 0.75rem", fontSize: "0.8125rem" },
292
- md: { padding: "0.5rem 1rem", fontSize: "0.875rem" },
293
- lg: { padding: "0.625rem 1.25rem", fontSize: "1rem" }
294
- };
295
- function Button({ children, onClick, disabled, variant = "primary", size = "md", style }) {
296
- const colors = buttonColors[variant];
297
- const sizeStyles = buttonSizes[size];
298
- return h("button", {
299
- onClick,
300
- disabled,
301
- style: {
302
- ...sizeStyles,
303
- backgroundColor: colors.bg,
304
- color: colors.text,
305
- border: "none",
306
- borderRadius: "0.5rem",
307
- fontWeight: 500,
308
- cursor: disabled ? "not-allowed" : "pointer",
309
- opacity: disabled ? 0.5 : 1,
310
- transition: "background-color 0.15s, opacity 0.15s",
311
- fontFamily: "system-ui, -apple-system, sans-serif",
312
- lineHeight: 1.5,
313
- ...style
314
- }
315
- }, children);
316
- }
317
- function Card({ children, title, style }) {
318
- return h(
319
- "div",
320
- {
321
- style: {
322
- backgroundColor: "#fff",
323
- border: "1px solid #e5e7eb",
324
- borderRadius: "0.75rem",
325
- padding: "1.25rem",
326
- boxShadow: "0 1px 3px rgba(0,0,0,0.08)",
327
- ...style
328
- }
329
- },
330
- title ? h("h3", {
331
- style: { margin: "0 0 0.75rem 0", fontSize: "1rem", fontWeight: 600, color: "#111827" }
332
- }, title) : null,
333
- children
334
- );
335
- }
336
- function Input({ value, onChange, placeholder, type = "text", disabled, style }) {
337
- return h("input", {
338
- type,
339
- value,
340
- placeholder,
341
- disabled,
342
- onChange: onChange ? (e) => onChange(e.target.value) : void 0,
343
- style: {
344
- width: "100%",
345
- padding: "0.5rem 0.75rem",
346
- fontSize: "0.875rem",
347
- border: "1px solid #d1d5db",
348
- borderRadius: "0.5rem",
349
- outline: "none",
350
- backgroundColor: disabled ? "#f9fafb" : "#fff",
351
- color: "#111827",
352
- fontFamily: "system-ui, -apple-system, sans-serif",
353
- lineHeight: 1.5,
354
- boxSizing: "border-box",
355
- ...style
356
- }
357
- });
358
- }
359
- var badgeColors = {
360
- gray: { bg: "#f3f4f6", text: "#374151" },
361
- blue: { bg: "#dbeafe", text: "#1d4ed8" },
362
- green: { bg: "#dcfce7", text: "#15803d" },
363
- red: { bg: "#fee2e2", text: "#b91c1c" },
364
- yellow: { bg: "#fef9c3", text: "#a16207" },
365
- purple: { bg: "#f3e8ff", text: "#7e22ce" }
366
- };
367
- function Badge({ children, color = "gray", style }) {
368
- const colors = badgeColors[color];
369
- return h("span", {
370
- style: {
371
- display: "inline-flex",
372
- alignItems: "center",
373
- padding: "0.125rem 0.625rem",
374
- fontSize: "0.75rem",
375
- fontWeight: 500,
376
- borderRadius: "9999px",
377
- backgroundColor: colors.bg,
378
- color: colors.text,
379
- fontFamily: "system-ui, -apple-system, sans-serif",
380
- lineHeight: 1.5,
381
- ...style
382
- }
383
- }, children);
384
- }
385
- function Stack({ children, direction = "column", gap = "0.5rem", align, justify, style }) {
386
- return h("div", {
387
- style: {
388
- display: "flex",
389
- flexDirection: direction,
390
- gap,
391
- alignItems: align,
392
- justifyContent: justify,
393
- ...style
394
- }
395
- }, children);
396
- }
397
- function Grid({ children, columns = 2, gap = "0.75rem", style }) {
398
- return h("div", {
399
- style: {
400
- display: "grid",
401
- gridTemplateColumns: typeof columns === "number" ? `repeat(${columns}, 1fr)` : columns,
402
- gap,
403
- ...style
404
- }
405
- }, children);
406
- }
407
-
408
- // src/agent-protocol.ts
66
+ // src/chat.ts
409
67
  function uid() {
410
68
  return Math.random().toString(36).slice(2, 10) + Date.now().toString(36);
411
69
  }
412
- function capMessages(msgs, max = 100) {
70
+ function capMessages(msgs, max = 200) {
413
71
  return msgs.length > max ? msgs.slice(-max) : msgs;
414
72
  }
415
- function createAgentProtocolTools(namespace, z) {
73
+ function createChatTools(z) {
416
74
  return [
417
75
  {
418
- name: `${namespace}.agent.propose`,
419
- description: "Propose an action for other agents to vote on",
76
+ name: "_chat.send",
77
+ description: "Send a chat message",
420
78
  input_schema: z.object({
421
- proposal: z.string(),
422
- data: z.any().optional(),
423
- requiresVotes: z.number().optional()
79
+ message: z.string().min(1).max(2e3),
80
+ replyTo: z.string().optional()
424
81
  }),
425
82
  risk: "low",
426
83
  capabilities_required: ["state.write"],
427
84
  handler: async (ctx, input) => {
428
- const id = uid();
429
- const proposals = { ...ctx.state._agentProposals || {} };
430
- proposals[id] = {
431
- id,
432
- from: ctx.actorId,
433
- proposal: input.proposal,
434
- data: input.data,
435
- requiresVotes: input.requiresVotes || 1,
436
- votes: [],
437
- status: "pending",
438
- ts: ctx.timestamp
439
- };
85
+ const cleanMessage = input.message.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
440
86
  const messages = capMessages([
441
- ...ctx.state._agentMessages || [],
442
- { id, from: ctx.actorId, to: "*", type: "proposal", content: input.proposal, data: input.data, ts: ctx.timestamp }
87
+ ...ctx.state._chat || [],
88
+ {
89
+ id: uid(),
90
+ actorId: ctx.actorId,
91
+ message: cleanMessage,
92
+ replyTo: input.replyTo,
93
+ ts: ctx.timestamp
94
+ }
443
95
  ]);
444
- ctx.setState({ ...ctx.state, _agentProposals: proposals, _agentMessages: messages });
445
- return { proposalId: id };
96
+ ctx.setState({ ...ctx.state, _chat: messages });
97
+ return { sent: true, messageCount: messages.length };
446
98
  }
447
99
  },
448
100
  {
449
- name: `${namespace}.agent.vote`,
450
- description: "Vote on a pending proposal (approve or reject)",
451
- input_schema: z.object({
452
- proposalId: z.string(),
453
- vote: z.enum(["approve", "reject"]),
454
- reason: z.string().optional()
455
- }),
456
- risk: "low",
101
+ name: "_chat.clear",
102
+ description: "Clear all chat messages",
103
+ input_schema: z.object({}),
104
+ risk: "medium",
457
105
  capabilities_required: ["state.write"],
458
- handler: async (ctx, input) => {
459
- const proposals = { ...ctx.state._agentProposals || {} };
460
- const proposal = proposals[input.proposalId];
461
- if (!proposal) throw new Error(`Proposal ${input.proposalId} not found`);
462
- if (proposal.status !== "pending") throw new Error(`Proposal already ${proposal.status}`);
463
- if (proposal.votes.some((v) => v.actorId === ctx.actorId)) throw new Error("Already voted");
464
- const votes = [...proposal.votes, { actorId: ctx.actorId, vote: input.vote, reason: input.reason }];
465
- const approves = votes.filter((v) => v.vote === "approve").length;
466
- const rejects = votes.filter((v) => v.vote === "reject").length;
467
- let status = "pending";
468
- if (approves >= proposal.requiresVotes) status = "approved";
469
- else if (rejects >= proposal.requiresVotes) status = "rejected";
470
- proposals[input.proposalId] = { ...proposal, votes, status };
471
- const messages = capMessages([
472
- ...ctx.state._agentMessages || [],
473
- { id: uid(), from: ctx.actorId, to: proposal.from, type: "vote", content: `${input.vote}: ${input.reason || ""}`, data: { proposalId: input.proposalId, vote: input.vote }, ts: ctx.timestamp }
474
- ]);
475
- ctx.setState({ ...ctx.state, _agentProposals: proposals, _agentMessages: messages });
476
- return { status, voteCount: votes.length };
477
- }
478
- },
479
- {
480
- name: `${namespace}.agent.delegate`,
481
- description: "Delegate a task to another agent",
482
- input_schema: z.object({
483
- targetActorId: z.string(),
484
- task: z.string(),
485
- data: z.any().optional()
486
- }),
487
- risk: "low",
488
- capabilities_required: ["state.write"],
489
- handler: async (ctx, input) => {
490
- const id = uid();
491
- const messages = capMessages([
492
- ...ctx.state._agentMessages || [],
493
- { id, from: ctx.actorId, to: input.targetActorId, type: "delegate", content: input.task, data: input.data, ts: ctx.timestamp }
494
- ]);
495
- ctx.setState({ ...ctx.state, _agentMessages: messages });
496
- return { messageId: id };
497
- }
498
- },
499
- {
500
- name: `${namespace}.agent.inform`,
501
- description: "Share information with other agents",
502
- input_schema: z.object({
503
- to: z.string(),
504
- message: z.string(),
505
- data: z.any().optional()
506
- }),
507
- risk: "low",
508
- capabilities_required: ["state.write"],
509
- handler: async (ctx, input) => {
510
- const id = uid();
511
- const messages = capMessages([
512
- ...ctx.state._agentMessages || [],
513
- { id, from: ctx.actorId, to: input.to, type: "inform", content: input.message, data: input.data, ts: ctx.timestamp }
514
- ]);
515
- ctx.setState({ ...ctx.state, _agentMessages: messages });
516
- return { messageId: id };
517
- }
518
- },
519
- {
520
- name: `${namespace}.agent.request`,
521
- description: "Request an action from another agent",
522
- input_schema: z.object({
523
- targetActorId: z.string(),
524
- request: z.string(),
525
- data: z.any().optional()
526
- }),
527
- risk: "low",
528
- capabilities_required: ["state.write"],
529
- handler: async (ctx, input) => {
530
- const id = uid();
531
- const messages = capMessages([
532
- ...ctx.state._agentMessages || [],
533
- { id, from: ctx.actorId, to: input.targetActorId, type: "request", content: input.request, data: input.data, ts: ctx.timestamp }
534
- ]);
535
- ctx.setState({ ...ctx.state, _agentMessages: messages });
536
- return { messageId: id };
537
- }
538
- },
539
- {
540
- name: `${namespace}.agent.respond`,
541
- description: "Respond to a message, request, or delegation from another agent",
542
- input_schema: z.object({
543
- messageId: z.string(),
544
- response: z.string(),
545
- data: z.any().optional()
546
- }),
547
- risk: "low",
548
- capabilities_required: ["state.write"],
549
- handler: async (ctx, input) => {
550
- const id = uid();
551
- const messages = capMessages([
552
- ...ctx.state._agentMessages || [],
553
- { id, from: ctx.actorId, to: "*", type: "inform", content: input.response, data: { ...input.data, inReplyTo: input.messageId }, ts: ctx.timestamp }
554
- ]);
555
- ctx.setState({ ...ctx.state, _agentMessages: messages });
556
- return { messageId: id };
106
+ handler: async (ctx) => {
107
+ ctx.setState({ ...ctx.state, _chat: [] });
108
+ return { cleared: true };
557
109
  }
558
110
  }
559
111
  ];
560
112
  }
561
-
562
- // src/agent-hints.ts
563
- function createAgentProtocolHints(namespace) {
564
- return [
565
- {
566
- trigger: "A proposal is pending and you have not voted on it yet",
567
- condition: `Object.values(state._agentProposals || {}).some(p => p.status === 'pending' && !p.votes.some(v => v.actorId === actorId))`,
568
- suggestedTools: [`${namespace}.agent.vote`],
569
- priority: "high",
570
- cooldownMs: 2e3
571
- },
572
- {
573
- trigger: "You received a delegation addressed to you",
574
- condition: `(state._agentMessages || []).some(m => m.type === 'delegate' && m.to === actorId)`,
575
- suggestedTools: [`${namespace}.agent.respond`],
576
- priority: "high",
577
- cooldownMs: 3e3
578
- },
579
- {
580
- trigger: "You received a request addressed to you",
581
- condition: `(state._agentMessages || []).some(m => m.type === 'request' && m.to === actorId)`,
582
- suggestedTools: [`${namespace}.agent.respond`],
583
- priority: "medium",
584
- cooldownMs: 2e3
585
- },
586
- {
587
- trigger: "You have useful information to share with other agents",
588
- suggestedTools: [`${namespace}.agent.inform`],
589
- priority: "low",
590
- cooldownMs: 5e3
591
- },
592
- {
593
- trigger: "You want to propose a collaborative action for the group",
594
- suggestedTools: [`${namespace}.agent.propose`],
595
- priority: "low",
596
- cooldownMs: 1e4
597
- }
598
- ];
599
- }
600
-
601
- // src/migrations.ts
602
- function getStateVersion(state) {
603
- return typeof state._version === "string" ? state._version : "0.0.0";
604
- }
605
- function compareSemver(a, b) {
606
- const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
607
- const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
608
- const len = Math.max(pa.length, pb.length);
609
- for (let i = 0; i < len; i++) {
610
- const va = pa[i] || 0;
611
- const vb = pb[i] || 0;
612
- if (va < vb) return -1;
613
- if (va > vb) return 1;
614
- }
615
- return 0;
616
- }
617
- function migrateState(state, migrations, currentVersion) {
618
- const fromVersion = getStateVersion(state);
619
- if (compareSemver(fromVersion, currentVersion) >= 0) {
620
- return {
621
- migrated: false,
622
- fromVersion,
623
- toVersion: fromVersion,
624
- state
625
- };
626
- }
627
- if (!migrations || migrations.length === 0) {
628
- return {
629
- migrated: false,
630
- fromVersion,
631
- toVersion: currentVersion,
632
- state: { ...state, _version: currentVersion }
633
- };
634
- }
635
- const sorted = [...migrations].sort((a, b) => compareSemver(a.to, b.to));
636
- const applicable = sorted.filter(
637
- (m) => compareSemver(m.to, fromVersion) > 0 && compareSemver(m.to, currentVersion) <= 0
638
- );
639
- if (applicable.length === 0) {
640
- return {
641
- migrated: false,
642
- fromVersion,
643
- toVersion: currentVersion,
644
- state: { ...state, _version: currentVersion }
645
- };
646
- }
647
- let migratedState = { ...state };
648
- for (const migration of applicable) {
649
- migratedState = migration.migrate(migratedState);
650
- }
651
- migratedState._version = currentVersion;
652
- return {
653
- migrated: true,
654
- fromVersion,
655
- toVersion: currentVersion,
656
- state: migratedState
657
- };
658
- }
659
-
660
- // src/storage.ts
661
- var InMemoryAdapter = class {
662
- roomStates = /* @__PURE__ */ new Map();
663
- events = /* @__PURE__ */ new Map();
664
- profiles = /* @__PURE__ */ new Map();
665
- async saveRoomState(roomId, state) {
666
- this.roomStates.set(roomId, state);
667
- }
668
- async loadRoomState(roomId) {
669
- return this.roomStates.get(roomId) || null;
670
- }
671
- async appendEvent(roomId, event) {
672
- if (!this.events.has(roomId)) {
673
- this.events.set(roomId, []);
674
- }
675
- this.events.get(roomId).push(event);
676
- }
677
- async loadEvents(roomId, limit) {
678
- const events = this.events.get(roomId) || [];
679
- if (limit) {
680
- return events.slice(-limit);
681
- }
682
- return events;
683
- }
684
- async listExperiences(_userId) {
685
- return [];
686
- }
687
- async saveUserProfile(userId, profile) {
688
- this.profiles.set(userId, profile);
689
- }
690
- async loadUserProfile(userId) {
691
- return this.profiles.get(userId) || null;
692
- }
693
- };
694
113
  export {
695
- Badge,
696
- Button,
697
- Card,
698
- Grid,
699
- InMemoryAdapter,
700
- Input,
701
- Stack,
702
- compareSemver,
703
- createAgentProtocolHints,
704
- createAgentProtocolTools,
705
- defineEphemeralAction,
114
+ createChatTools,
706
115
  defineExperience,
116
+ defineStream,
707
117
  defineTest,
708
- defineTool,
709
- getStateVersion,
710
- migrateState,
711
- quickTool,
712
- useAnimationFrame,
713
- useFollow,
714
- useOptimisticTool,
715
- useParticipants,
716
- useSharedState,
717
- useToolCall,
718
- useTypingIndicator,
719
- validateExperience
118
+ defineTool
720
119
  };