Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions packages/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -966,6 +966,25 @@ export interface BuiltInCompileAndRunState<T> {
}

// Function type definitions
export type PatternFunction = {
<T, R>(
fn: (input: OpaqueRef<Required<T>>) => Opaque<R>,
): RecipeFactory<T, R>;

<T>(
fn: (input: OpaqueRef<Required<T>>) => unknown,
): RecipeFactory<T, ReturnType<typeof fn>>;

<IS extends JSONSchema = JSONSchema, OS extends JSONSchema = JSONSchema>(
fn: (
input: OpaqueRef<Required<Schema<IS>>>,
) => Opaque<Schema<OS>>,
argumentSchema: IS,
resultSchema: OS,
): RecipeFactory<Schema<IS>, Schema<OS>>;
};

/** @deprecated Use pattern() instead */
export type RecipeFunction = {
// Function-only overload
<T, R>(
Expand Down Expand Up @@ -1209,13 +1228,9 @@ export type CompileAndRunFunction = <T = any, S = any>(
) => OpaqueRef<BuiltInCompileAndRunState<S>>;

export type NavigateToFunction = (cell: OpaqueRef<any>) => OpaqueRef<string>;
export type WishFunction = {
<T = unknown>(target: Opaque<string>): OpaqueRef<T | undefined>;
<T = unknown>(
target: Opaque<string>,
defaultValue: Opaque<T>,
): OpaqueRef<T>;
};
export type WishFunction = <T = unknown>(
target: Opaque<string>,
) => OpaqueRef<T>;

export type CreateNodeFactoryFunction = <T = any, R = any>(
moduleSpec: Module,
Expand Down Expand Up @@ -1253,6 +1268,8 @@ export type GetRecipeEnvironmentFunction = () => RecipeEnvironment;

// Re-export all function types as values for destructuring imports
// These will be implemented by the factory
export declare const pattern: PatternFunction;
/** @deprecated Use pattern() instead */
export declare const recipe: RecipeFunction;
export declare const patternTool: PatternToolFunction;
export declare const lift: LiftFunction;
Expand Down
6 changes: 5 additions & 1 deletion packages/patterns/chatbot-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import {
Cell,
Default,
derive,
handler,
ID,
ifElse,
Expand Down Expand Up @@ -236,7 +237,10 @@ const extractLocalMentionable = lift<
export default recipe<Input, Output>(
"Launcher",
({ selectedCharm, charmsList, theme }) => {
const allCharms = wish<MentionableCharm[]>("#allCharms", []);
const allCharms = derive<MentionableCharm[], MentionableCharm[]>(
wish<MentionableCharm[]>("#allCharms"),
(c) => c ?? [],
);
logCharmsList({ charmsList: charmsList as unknown as Cell<CharmEntry[]> });

populateChatList({
Expand Down
5 changes: 2 additions & 3 deletions packages/patterns/chatbot-note-composed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
handler,
NAME,
navigateTo,
Opaque,
OpaqueRef,
recipe,
wish,
Expand All @@ -27,8 +26,8 @@ import {

import { type MentionableCharm } from "./backlinks-index.tsx";

function schemaifyWish<T>(path: string, def: Opaque<T>) {
return derive<T, T>(wish<T>(path, def), (i) => i);
function schemaifyWish<T>(path: string, def: T) {
return derive(wish<T>(path) as T, (i) => i ?? def);
}

type ChatbotNoteInput = {
Expand Down
25 changes: 14 additions & 11 deletions packages/patterns/chatbot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,21 +328,23 @@ export default recipe<ChatInput, ChatOutput>(
return attachments;
});

// Derive tools from attachments (including auto-attached recent charm)
// Surface attached charms so the LLM can use read/run/schema helpers.
const dynamicTools = computed(() => {
const tools: Record<string, any> = {};
const attached: Record<string, any> = {};

for (const attachment of attachmentsWithRecent || []) {
if (attachment.type === "mention" && attachment.charm) {
const charmName = attachment.charm[NAME] || "Charm";
tools[charmName] = {
charm: attachment.charm,
description: `Handlers from ${charmName}`,
};
}
if (attachment.type !== "mention" || !attachment.charm) continue;
const charmName = attachment.charm[NAME] || "Charm";
attached[charmName] = {
charm: attachment.charm,
description:
`Attached charm ${charmName}. Use schema("${charmName}") to ` +
`inspect it, then read("${charmName}/path") or ` +
`run("${charmName}/handler").`,
};
}

return tools;
return attached;
});

const attachmentTools = {
Expand All @@ -354,7 +356,8 @@ export default recipe<ChatInput, ChatOutput>(
}),
},
listAttachments: {
description: "List all attachments in the attachments array.",
description:
"List attachment names to use with schema(), read(), and run().",
handler: listAttachments({ allAttachments: attachmentsWithRecent }),
},
listMentionable: {
Expand Down
5 changes: 2 additions & 3 deletions packages/patterns/note.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
handler,
NAME,
navigateTo,
type Opaque,
type OpaqueRef,
patternTool,
recipe,
Expand Down Expand Up @@ -100,8 +99,8 @@ const handleCharmLinkClicked = handler<void, { charm: Cell<MentionableCharm> }>(
},
);

function schemaifyWish<T>(path: string, def: T | Opaque<T>) {
return derive<T, T>(wish<T>(path, def as Opaque<T>), (i) => i);
function schemaifyWish<T>(path: string, def: T) {
return derive(wish<T>(path) as T, (i) => i ?? def);
}

const Note = recipe<Input, Output>(
Expand Down
3 changes: 2 additions & 1 deletion packages/runner/src/builder/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
UI,
} from "./types.ts";
import { h } from "@commontools/html";
import { recipe } from "./recipe.ts";
import { pattern, recipe } from "./recipe.ts";
import { byRef, computed, derive, handler, lift } from "./module.ts";
import {
compileAndRun,
Expand Down Expand Up @@ -98,6 +98,7 @@ export const createBuilder = (): {
compileAndRun,
navigateTo,
wish,
pattern,

// Cell creation
cell: cellConstructorFactory<AsCell>("cell").of,
Expand Down
26 changes: 26 additions & 0 deletions packages/runner/src/builder/recipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
type Opaque,
type OpaqueCell,
type OpaqueRef,
type PatternFunction,
type Recipe,
type RecipeFactory,
type SchemaWithoutCell,
Expand Down Expand Up @@ -41,6 +42,31 @@ import {
MemorySpace,
} from "../storage/interface.ts";

export const pattern: PatternFunction = (
fn: (input: any) => any,
argumentSchema?: JSONSchema,
resultSchema?: JSONSchema,
) => {
const frame = pushFrame();

const inputs = opaqueRef(undefined, argumentSchema);

const outputs = fn!(inputs);

applyInputIfcToOutput(inputs, outputs);

const result = factoryFromRecipe(
argumentSchema,
resultSchema,
inputs,
outputs,
);

popFrame(frame);

return result;
};

/** Declare a recipe
*
* @param fn A function that creates the recipe graph
Expand Down
3 changes: 3 additions & 0 deletions packages/runner/src/builder/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {
NavigateToFunction,
Opaque,
OpaqueRef,
PatternFunction,
PatternToolFunction,
Recipe,
RecipeFunction,
Expand Down Expand Up @@ -102,6 +103,7 @@ export type {
Opaque,
OpaqueCell,
OpaqueRef,
PatternFunction,
Props,
Recipe,
RecipeFactory,
Expand Down Expand Up @@ -238,6 +240,7 @@ export type Frame = {
// Builder functions interface
export interface BuilderFunctionsAndConstants {
// Recipe creation
pattern: PatternFunction;
recipe: RecipeFunction;
patternTool: PatternToolFunction;

Expand Down
Loading
Loading