Skip to content

Commit 9c633a0

Browse files
authored
charm-cleanup-again (#608)
* add some sleep for ci in github * try to output logs in integration * fix logging in integartions * break single bdd into steps * trying to shortcut integration tests * don't throw execption on non-iframe charms * remove node type that we have now via deno.json types * remove old code / update comments * types * more cleanup * stop the loading stuff as soon as we show one
1 parent f5b22a8 commit 9c633a0

File tree

16 files changed

+318
-453
lines changed

16 files changed

+318
-453
lines changed

charm/src/charm.ts

Lines changed: 8 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,17 @@ export class CharmManager {
161161
return this.pinnedCharms;
162162
}
163163

164+
// FIXME(ja): this says it returns a list of charm, but it isn't! you will
165+
// have to call .get() to get the actual charm (this is missing the schema)
166+
// how can we fix the type here?
164167
getCharms(): Cell<Cell<Charm>[]> {
165168
// Start syncing if not already syncing. Will trigger a change to the list
166169
// once loaded.
167170
storage.syncCell(this.charmsDoc);
168171
return this.charms;
169172
}
170173

171-
async add(newCharms: Cell<Charm>[]) {
174+
private async add(newCharms: Cell<Charm>[]) {
172175
await storage.syncCell(this.charmsDoc);
173176
await idle();
174177

@@ -181,6 +184,8 @@ export class CharmManager {
181184
await idle();
182185
}
183186

187+
// FIXME(ja): if we are already running the charm, can we just return it?
188+
// if a charm has sideeffects we might multiple versions...
184189
async get<T = Charm>(
185190
id: string | Cell<Charm>,
186191
runIt: boolean = true,
@@ -291,46 +296,6 @@ export class CharmManager {
291296
): Promise<Cell<Charm>> {
292297
await idle();
293298

294-
// Fill in missing parameters from other charms. It's a simple match on
295-
// hashtags: For each top-level argument prop that has a hashtag in the
296-
// description, look for a charm that has a top-level output prop with the
297-
// same hashtag in the description, or has the hashtag in its own description.
298-
// If there is a match, assign the first one to the input property.
299-
300-
// TODO(seefeld,ben): This should be in spellcaster.
301-
/*
302-
if (
303-
!isDoc(inputs) && // Adding to a cell input is not supported yet
304-
!isDocLink(inputs) && // Neither for cell reference
305-
recipe.argumentSchema &&
306-
(recipe.argumentSchema as any).type === "object"
307-
) {
308-
const properties = (recipe.argumentSchema as any).properties;
309-
const inputProperties =
310-
typeof inputs === "object" && inputs !== null ? Object.keys(inputs) : [];
311-
for (const key in properties) {
312-
if (!(key in inputProperties) && properties[key].description?.includes("#")) {
313-
const hashtag = properties[key].description.match(/#(\w+)/)?.[1];
314-
if (hashtag) {
315-
this.charms.get().forEach((charm) => {
316-
const type = charm.getAsDocLink().cell?.sourceCell?.get()?.[TYPE];
317-
const recipe = getRecipe(type);
318-
const charmProperties = (recipe?.resultSchema as any)?.properties as any;
319-
const matchingProperty = Object.keys(charmProperties ?? {}).find((property) =>
320-
charmProperties[property].description?.includes(`#${hashtag}`),
321-
);
322-
if (matchingProperty) {
323-
inputs = {
324-
...inputs,
325-
[key]: { $alias: { cell: charm.getAsDocLink().cell, path: [matchingProperty] } },
326-
};
327-
}
328-
});
329-
}
330-
}
331-
}
332-
}*/
333-
334299
const syncAllMentionedCells = (
335300
value: any,
336301
promises: any[] = [],
@@ -360,7 +325,7 @@ export class CharmManager {
360325
}
361326

362327
// FIXME(JA): this really really really needs to be revisited
363-
async syncRecipe(charm: Cell<Charm>): Promise<string | undefined> {
328+
async syncRecipe(charm: Cell<Charm>): Promise<string> {
364329
const recipeId = charm.getSourceCell()?.get()?.[TYPE];
365330
if (!recipeId) throw new Error("charm missing recipe ID");
366331

@@ -372,7 +337,7 @@ export class CharmManager {
372337
}
373338

374339
async syncRecipeCells(recipeId: string) {
375-
// NOTE(ja): I don't think this actually syncs the recipe
340+
// NOTE(ja): this doesn't sync recipe to storage
376341
if (recipeId) await storage.syncCellById(this.space, { "/": recipeId });
377342
}
378343

charm/src/iframe/index.ts

Whitespace-only changes.

charm/src/iframe/recipe.ts

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -41,54 +41,28 @@ export const buildFullRecipe = (iframe: IFrameRecipe) => {
4141
`;
4242
};
4343

44-
function parseIframeRecipe(source: string): IFrameRecipe | undefined {
44+
function parseIframeRecipe(source: string): IFrameRecipe {
4545
// Extract content between IFRAME-V0 comments
4646
const match = source.match(
4747
/\/\* IFRAME-V0 \*\/([\s\S]*?)\/\* IFRAME-V0 \*\//,
4848
);
49-
if (!match) {
50-
console.warn("no IFRAME-V0 section in source");
51-
return undefined;
49+
50+
if (!match || !match[1]) {
51+
throw new Error("Could not find IFRAME-V0 recipe content in source");
5252
}
5353

5454
return JSON.parse(match[1]) as IFrameRecipe;
5555
}
5656

5757
export const getIframeRecipe = (charm: Cell<Charm>) => {
58-
const recipeId = charm.getSourceCell(processSchema)?.get()?.[TYPE];
59-
if (!recipeId) {
60-
console.error("FIXME, no recipeId, what should we do?");
61-
return {};
62-
}
63-
64-
const recipe = getRecipe(recipeId);
65-
if (!recipe) {
66-
console.error("FIXME, no recipe, what should we do?");
67-
return {};
68-
}
69-
const src = getRecipeSrc(recipeId);
70-
if (!src) {
71-
console.error("FIXME, no src, what should we do?");
72-
return {};
73-
}
74-
58+
const { src, recipeId } = getRecipeFrom(charm);
7559
return { recipeId, iframe: parseIframeRecipe(src) };
7660
};
7761

7862
export const getRecipeFrom = (charm: Cell<Charm>) => {
7963
const recipeId = charm.getSourceCell(processSchema)?.get()?.[TYPE];
80-
if (!recipeId) {
81-
throw new Error("No recipeId found");
82-
}
83-
84-
const recipe = getRecipe(recipeId);
85-
if (!recipe) {
86-
throw new Error("No recipe found for recipeId");
87-
}
88-
const src = getRecipeSrc(recipeId);
89-
if (!src) {
90-
throw new Error("No source found for recipeId");
91-
}
64+
const recipe = getRecipe(recipeId)!;
65+
const src = getRecipeSrc(recipeId)!;
9266

9367
return { recipeId, recipe, src };
9468
};

charm/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ export {
44
castNewRecipe,
55
compileAndRunRecipe,
66
compileRecipe,
7-
extend,
7+
generateNewRecipeVersion,
88
iterate,
9-
saveNewRecipeVersion,
109
} from "./iterate.ts";
1110
export { getIframeRecipe, type IFrameRecipe } from "./iframe/recipe.ts";

charm/src/iterate.ts

Lines changed: 23 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Charm, CharmManager } from "./charm.ts";
77
import { buildFullRecipe, getIframeRecipe } from "./iframe/recipe.ts";
88
import { buildPrompt, RESPONSE_PREFILL } from "./iframe/prompt.ts";
99
import { injectUserCode } from "./iframe/static.ts";
10+
import { isCell } from "../../runner/src/cell.ts";
1011

1112
const llm = new LLMClient(LLMClient.DEFAULT_URL);
1213

@@ -32,31 +33,25 @@ const genSrc = async ({
3233
response = RESPONSE_PREFILL + response;
3334
}
3435

35-
const source = injectUserCode(response.split(RESPONSE_PREFILL)[1].split("\n```")[0]);
36+
const source = injectUserCode(
37+
response.split(RESPONSE_PREFILL)[1].split("\n```")[0],
38+
);
3639
return source;
3740
};
3841

3942
export async function iterate(
4043
charmManager: CharmManager,
41-
charm: Cell<Charm> | null,
42-
value: string,
44+
charm: Cell<Charm>,
45+
spec: string,
4346
shiftKey: boolean,
4447
model?: string,
45-
): Promise<EntityId | undefined> {
46-
if (!charm) {
47-
console.error("FIXME, no charm, what should we do?");
48-
return;
49-
}
50-
48+
): Promise<Cell<Charm>> {
5149
const { iframe } = getIframeRecipe(charm);
5250
if (!iframe) {
53-
console.error(
54-
"Cannot iterate on a non-iframe. Must extend instead.",
55-
);
56-
return;
51+
throw new Error("Cannot iterate on a non-iframe. Must extend instead.");
5752
}
5853

59-
const newSpec = shiftKey ? iframe.spec + "\n" + value : value;
54+
const newSpec = shiftKey ? iframe.spec + "\n" + spec : spec;
6055

6156
const newIFrameSrc = await genSrc({
6257
src: iframe.src,
@@ -66,21 +61,7 @@ export async function iterate(
6661
model: model,
6762
});
6863

69-
return saveNewRecipeVersion(charmManager, charm, newIFrameSrc, newSpec);
70-
}
71-
72-
export async function extend(
73-
charmManager: CharmManager,
74-
charm: Cell<Charm> | null,
75-
value: string,
76-
model?: string,
77-
): Promise<EntityId | undefined> {
78-
if (!charm) {
79-
console.error("FIXME, no charm, what should we do?");
80-
return;
81-
}
82-
83-
return await castRecipeOnCell(charmManager, charm, value);
64+
return generateNewRecipeVersion(charmManager, charm, newIFrameSrc, newSpec);
8465
}
8566

8667
export function extractTitle(src: string, defaultTitle: string): string {
@@ -89,7 +70,7 @@ export function extractTitle(src: string, defaultTitle: string): string {
8970
return htmlTitleMatch || jsTitleMatch || defaultTitle;
9071
}
9172

92-
export const saveNewRecipeVersion = async (
73+
export const generateNewRecipeVersion = (
9374
charmManager: CharmManager,
9475
charm: Cell<Charm>,
9576
newIFrameSrc: string,
@@ -98,19 +79,18 @@ export const saveNewRecipeVersion = async (
9879
const { recipeId, iframe } = getIframeRecipe(charm);
9980

10081
if (!recipeId || !iframe) {
101-
console.error("FIXME, no recipeId or iframe, what should we do?");
102-
return;
82+
throw new Error("FIXME, no recipeId or iframe, what should we do?");
10383
}
10484

105-
const name = extractTitle(newIFrameSrc, '<unknown>');
85+
const name = extractTitle(newIFrameSrc, "<unknown>");
10686
const newRecipeSrc = buildFullRecipe({
10787
...iframe,
10888
src: newIFrameSrc,
10989
spec: newSpec,
11090
name,
11191
});
11292

113-
return await compileAndRunRecipe(
93+
return compileAndRunRecipe(
11494
charmManager,
11595
newRecipeSrc,
11696
newSpec,
@@ -119,38 +99,17 @@ export const saveNewRecipeVersion = async (
11999
);
120100
};
121101

122-
export async function castRecipeOnCell(
123-
charmManager: CharmManager,
124-
cell: Cell<any>,
125-
newSpec: string,
126-
): Promise<EntityId | undefined> {
127-
const schema = { ...cell.schema, description: newSpec };
128-
console.log("schema", schema);
129-
130-
const newIFrameSrc = await genSrc({ newSpec, schema });
131-
const name = extractTitle(newIFrameSrc, '<unknown>');
132-
const newRecipeSrc = buildFullRecipe({
133-
src: newIFrameSrc,
134-
spec: newSpec,
135-
argumentSchema: schema,
136-
resultSchema: {},
137-
name,
138-
});
139-
140-
return await compileAndRunRecipe(charmManager, newRecipeSrc, newSpec, cell);
141-
}
142-
143102
export async function castNewRecipe(
144103
charmManager: CharmManager,
145104
data: any,
146105
newSpec: string,
147-
): Promise<EntityId | undefined> {
148-
const schema = createJsonSchema({}, data);
106+
): Promise<Cell<Charm>> {
107+
const schema = isCell(data) ? { ...data.schema } : createJsonSchema({}, data);
149108
schema.description = newSpec;
150109
console.log("schema", schema);
151110

152111
const newIFrameSrc = await genSrc({ newSpec, schema });
153-
const name = extractTitle(newIFrameSrc, '<unknown>');
112+
const name = extractTitle(newIFrameSrc, "<unknown>");
154113
const newRecipeSrc = buildFullRecipe({
155114
src: newIFrameSrc,
156115
spec: newSpec,
@@ -159,7 +118,7 @@ export async function castNewRecipe(
159118
name,
160119
});
161120

162-
return await compileAndRunRecipe(charmManager, newRecipeSrc, newSpec, data);
121+
return compileAndRunRecipe(charmManager, newRecipeSrc, newSpec, data);
163122
}
164123

165124
export async function compileRecipe(
@@ -169,13 +128,11 @@ export async function compileRecipe(
169128
) {
170129
const { exports, errors } = await tsToExports(recipeSrc);
171130
if (errors) {
172-
console.error("Compilation errors in recipe:", errors);
173-
return;
131+
throw new Error("Compilation errors in recipe");
174132
}
175133
const recipe = exports.default;
176134
if (!recipe) {
177-
console.error("No default recipe found in the compiled exports.");
178-
return;
135+
throw new Error("No default recipe found in the compiled exports.");
179136
}
180137
const parentsIds = parents?.map((id) => id.toString());
181138
registerNewRecipe(recipe, recipeSrc, spec, parentsIds);
@@ -188,15 +145,11 @@ export async function compileAndRunRecipe(
188145
spec: string,
189146
runOptions: any,
190147
parents?: string[],
191-
): Promise<EntityId | undefined> {
148+
): Promise<Cell<Charm>> {
192149
const recipe = await compileRecipe(recipeSrc, spec, parents);
193150
if (!recipe) {
194-
return;
151+
throw new Error("Failed to compile recipe");
195152
}
196153

197-
const newCharm = await charmManager.runPersistent(recipe, runOptions);
198-
await charmManager.add([newCharm]);
199-
await charmManager.syncRecipe(newCharm);
200-
201-
return newCharm.entityId;
154+
return charmManager.runPersistent(recipe, runOptions);
202155
}

cli/charm_demo.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ async function main() {
5858
);
5959

6060
// let's add the cell to the charmManager
61-
await charmManager.add([cell]);
62-
log(charmManager, "charmmanager after adding cell");
61+
// await charmManager.add([cell]);
62+
// log(charmManager, "charmmanager after adding cell");
6363
}
6464

6565
main();

cli/main.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ async function main() {
7272
const recipeSrc = await Deno.readTextFile(recipeFile);
7373
const recipe = await compileRecipe(recipeSrc, "recipe", []);
7474
const charm = await manager.runPersistent(recipe, undefined, cause);
75-
await manager.syncRecipe(charm);
76-
manager.add([charm]);
7775
const charmWithSchema = (await manager.get(charm))!;
7876
charmWithSchema.sink((value) => {
7977
console.log("running charm:", getEntityId(charm), value);

0 commit comments

Comments
 (0)