Skip to content

Commit 93aa984

Browse files
ellyxirEllyse
andauthored
store a selected charm in a cell (selectedCharm) and also maintain a … (commontoolsinc#1788)
* store a selected charm in a cell (selectedCharm) and also maintain a list of charms (charmsList). show the selectedCharm in the UI, show a list of charms and allow user to change the value for selectedCharm which will update which charm we render * use Defaults instead of using cell() to create the selectedCharm and charmsList * use [ID] in the charmsList, each item is now of type CharmEntry * updated comment * added a lift for debugging the charms list, copied the id to local_id because i couldnt display [ID], removed [ID] from the JSON schema * wrap charm so we dont have pointer of pointer issue --------- Co-authored-by: Ellyse <[email protected]>
1 parent 8f4a79c commit 93aa984

File tree

2 files changed

+176
-132
lines changed

2 files changed

+176
-132
lines changed

packages/patterns/chat-launcher.tsx

Lines changed: 0 additions & 132 deletions
This file was deleted.
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/// <cts-enable />
2+
import {
3+
Cell,
4+
cell,
5+
Default,
6+
derive,
7+
h,
8+
handler,
9+
ID,
10+
ifElse,
11+
lift,
12+
NAME,
13+
navigateTo,
14+
recipe,
15+
UI,
16+
} from "commontools";
17+
18+
import Chat from "./chatbot.tsx";
19+
20+
type CharmEntry = {
21+
[ID]: string; // randomId is a string
22+
local_id: string; // same as ID but easier to access
23+
charm: any;
24+
};
25+
26+
type Input = {
27+
selectedCharm: Default<{ charm: any }, { charm: undefined }>;
28+
charmsList: Default<CharmEntry[], []>;
29+
};
30+
31+
type Output = Input;
32+
33+
// this will be called whenever charm or selectedCharm changes
34+
// pass isInitialized to make sure we dont call this each time
35+
// we change selectedCharm, otherwise creates a loop
36+
const storeCharm = lift(
37+
{
38+
type: "object",
39+
properties: {
40+
charm: { type: "object" },
41+
selectedCharm: {
42+
type: "object",
43+
properties: {
44+
charm: { type: "object" },
45+
},
46+
asCell: true,
47+
},
48+
charmsList: {
49+
type: "array",
50+
items: {
51+
type: "object",
52+
properties: {
53+
local_id: { type: "string" }, // display ID for the charm
54+
charm: { type: "object" },
55+
},
56+
},
57+
asCell: true,
58+
},
59+
isInitialized: { type: "boolean", asCell: true },
60+
},
61+
},
62+
undefined,
63+
({ charm, selectedCharm, charmsList, isInitialized }) => {
64+
if (!isInitialized.get()) {
65+
console.log(
66+
"storeCharm storing charm:",
67+
JSON.stringify(charm),
68+
);
69+
selectedCharm.set({ charm });
70+
71+
// create the chat charm with a custom name including a random suffix
72+
const randomId = Math.random().toString(36).substring(2, 10); // Random 8-char string
73+
charmsList.push({ [ID]: randomId, local_id: randomId, charm });
74+
75+
isInitialized.set(true);
76+
return charm;
77+
} else {
78+
console.log("storeCharm: already initialized");
79+
}
80+
return undefined;
81+
},
82+
);
83+
84+
const createChatRecipe = handler<
85+
unknown,
86+
{ selectedCharm: Cell<{ charm: any }>; charmsList: Cell<CharmEntry[]> }
87+
>(
88+
(_, { selectedCharm, charmsList }) => {
89+
const isInitialized = cell(false);
90+
91+
const charm = Chat({
92+
messages: [],
93+
tools: undefined,
94+
});
95+
// store the charm ref in a cell (pass isInitialized to prevent recursive calls)
96+
return storeCharm({ charm, selectedCharm, charmsList, isInitialized });
97+
},
98+
);
99+
100+
const selectCharm = handler<
101+
unknown,
102+
{ selectedCharm: Cell<{ charm: any }>; charm: any }
103+
>(
104+
(_, { selectedCharm, charm }) => {
105+
console.log("selectCharm: updating selectedCharm to ", charm);
106+
selectedCharm.set({ charm });
107+
return selectedCharm;
108+
},
109+
);
110+
111+
const logCharmsList = lift(
112+
{
113+
type: "object",
114+
properties: {
115+
charmsList: {
116+
type: "array",
117+
items: {
118+
type: "object",
119+
properties: {
120+
local_id: { type: "string" }, // display ID for the charm
121+
charm: { type: "object" },
122+
},
123+
},
124+
asCell: true,
125+
},
126+
},
127+
},
128+
undefined,
129+
({ charmsList }) => {
130+
console.log("logCharmsList: ", charmsList.get());
131+
return charmsList;
132+
},
133+
);
134+
135+
// create the named cell inside the recipe body, so we do it just once
136+
export default recipe<Input, Output>(
137+
"Launcher",
138+
({ selectedCharm, charmsList }) => {
139+
logCharmsList({ charmsList });
140+
141+
return {
142+
[NAME]: "Launcher",
143+
[UI]: (
144+
<div>
145+
<ct-button onClick={createChatRecipe({ selectedCharm, charmsList })}>
146+
Create New Chat
147+
</ct-button>
148+
149+
<div>
150+
<h3>Chat List</h3>
151+
</div>
152+
<div>
153+
{charmsList.map((charmEntry, i) => (
154+
<div>
155+
index={i} chat ID: {charmEntry.local_id}
156+
<ct-button
157+
onClick={selectCharm({
158+
selectedCharm: selectedCharm,
159+
charm: charmEntry.charm,
160+
})}
161+
>
162+
LOAD
163+
</ct-button>
164+
</div>
165+
))}
166+
</div>
167+
168+
<div>--- end chat list ---</div>
169+
<div>{selectedCharm.charm}</div>
170+
</div>
171+
),
172+
selectedCharm,
173+
charmsList,
174+
};
175+
},
176+
);

0 commit comments

Comments
 (0)