UNPKG

life

Version:

Life.js is the first fullstack framework to build agentic web applications. It is minimal, extensible, and typesafe. Well, everything you love.

351 lines (345 loc) 10.5 kB
import { createLifeClient, parseAgentClientParam } from "../chunk-T6NMMENO.mjs"; import "../chunk-5BLN2MK4.mjs"; import "../chunk-VF3CTIUM.mjs"; import "../chunk-HZQWVS5S.mjs"; import "../chunk-6CBODJTF.mjs"; import { toMethodName } from "../chunk-X455LF5V.mjs"; import { zodObjectWithTelemetry } from "../chunk-D2T23PCX.mjs"; import "../chunk-ZHBK6UTM.mjs"; import { __name } from "../chunk-2D3UJWOA.mjs"; // agent/client/builder.ts var AgentClientBuilder = class _AgentClientBuilder { static { __name(this, "AgentClientBuilder"); } def; constructor(definition) { this.def = definition; } /** * Register plugins to extend the agent client features. * Defaults to `[generation, memories, stores, actions, percepts]` plugins if not specified. * * In case you want to register custom plugins and still keep the defaults you can do: * ```ts * import { defaults } from "life/server"; * * defineAgent("my-agent").plugins([...defaults.plugins, myCustomPlugin]); * ``` * * Or if you want only some of the defaults, you can do: * ```ts * import { defaults } from "life/server"; * * defineAgent("my-agent").plugins([defaults.plugins.generation, defaults.plugins.memories]); * ``` */ plugins(plugins) { const builder = new _AgentClientBuilder({ ...this.def, plugins: plugins.map((p) => p.def) }); const builderWithPlugins = _AgentClientBuilder.withPluginsMethods(builder); return builderWithPlugins; } // biome-ignore lint/suspicious/noExplicitAny: reason static withPluginsMethods(builder) { for (const plugin of builder.def.plugins) { Object.assign(builder, { [toMethodName(plugin.name)]: (config) => { const newBuilder = new _AgentClientBuilder({ ...builder.def, pluginConfigs: { ...builder.def.pluginConfigs ?? {}, [plugin.name]: config } }); return _AgentClientBuilder.withPluginsMethods(newBuilder); } }); } return builder; } }; function defineAgentClient(name) { const defaultDefinition = { name, plugins: [...defaults.plugins].map((p) => p.def), pluginConfigs: {}, $serverDef: {} }; const builder = new AgentClientBuilder(defaultDefinition); const builderWithPlugins = AgentClientBuilder.withPluginsMethods(builder); return builderWithPlugins; } __name(defineAgentClient, "defineAgentClient"); // plugins/client/builder.ts import { z } from "zod"; var PluginClientBuilder = class _PluginClientBuilder { static { __name(this, "PluginClientBuilder"); } def; constructor(definition) { this.def = definition; } /** * ### `.dependencies()` * * Specify other plugins clients as required by this plugin client. * * Their config, atoms, and class can then be accessed from `dependencies.*` inside the plugin client's class and atoms. * * @see TODO: Add docs link * * @example * ```ts * const pluginClient = definePluginClient("my-plugin") * .dependencies([anotherPluginClient]) * .atoms(({ dependencies }) => { * // Obtain the atoms of the dependency plugin client * const anotherPluginAtoms = dependencies.anotherPlugin.atoms(); * // ... * }); * ``` * &nbsp; * * --- * @param plugins - The dependencies definitions. * @returns TypedPluginClientBuilder */ dependencies(plugins) { const dependencies = plugins.map((p) => p.def); const builder = new _PluginClientBuilder({ ...this.def, dependencies }); return builder; } /** * ### `.config()` * * Add a configuration that users can provide to tweak plugin client's behavior. * * @see TODO: Add docs link * * @example * ```ts * const myPluginClient = definePluginClient("my-plugin") * .config({ schema: z.object({ refreshRate: z.number() }) }); * * const myAgentClient = defineAgentClient("my-agent") * .plugins([myPluginClient]) * .myPlugin({ refreshRate: 1000 }); // <-- Here * ``` * &nbsp; * * --- * * The provided config can then be accessed from `plugin.config` inside atoms and class. * * @example * ```ts * const pluginClient = definePluginClient("my-plugin") * .config({ schema: z.object({ refreshRate: z.number() }) }); * .atoms(({ config }) => { * const refreshRate = config.refreshRate; // <-- Here * }); * ``` * &nbsp; * * --- * @param config - The config definition. * @returns TypedPluginClientBuilder */ config(config) { return this.$config(zodObjectWithTelemetry(config)); } /** * ### `.$config()` * * Define plugin client config from the output of `definePluginClientConfig()`. * * @see TODO: Add docs link for `definePluginClientConfig()` * * --- * @param config - The config definition. * @returns TypedPluginClientBuilder */ $config(config) { const builder = new _PluginClientBuilder({ ...this.def, config }); return builder; } /** * ### `.class()` * * TODO * * @see TODO: Add docs link * * --- * @param input - The class definition. * @returns TypedPluginClientBuilder */ class(extension) { const builder = new _PluginClientBuilder({ ...this.def, class: extension }); return builder; } /** * ### `.atoms()` * * Add reactive states (atoms) that can then be consumed from various UI frameworks * (React, Vue, Svelte, etc.) to render the plugin data in real-time on the user interface. * * Atoms are powered by [nanostores](https://github.com/nanostores/nanostores). * * @see TODO: Add docs link * * @example * ```ts * import { onMount } from "nanostores"; * * const pluginClient = definePluginClient("my-plugin") * .atoms(({ plugin }) => { * const value = atom(0); * onMount(() => { * setInterval(async () => { * const context = await plugin.context.get(); * value.set(context.value + 1); * }, 1000); * }); * return { value }; * }); * ``` * &nbsp; * * --- * * Then from a React component, you can render the `value` atom: * ```ts * import { useStore } from "nanostores/react"; * * export default function Page() { * const agent = useAgent("my-agent"); * const value = useStore(agent.myPlugin.atoms.value); * return <div>{value}</div>; * }; * ``` * &nbsp; * * --- * @param definition - The atoms definition. * @returns TypedPluginClientBuilder */ atoms(atoms) { const builder = new _PluginClientBuilder({ ...this.def, atoms }); return builder; } }; function definePluginClient(name) { const defaultDefinition = { name, config: zodObjectWithTelemetry({ schema: z.object() }), dependencies: [], class: /* @__PURE__ */ __name((..._args) => class { }, "class"), atoms: /* @__PURE__ */ __name((..._args) => [], "atoms"), $serverDef: null }; return new PluginClientBuilder(defaultDefinition); } __name(definePluginClient, "definePluginClient"); // plugins/defaults/generation/client.ts import { atom, onMount } from "nanostores"; import z2 from "zod"; var generationPluginClient = definePluginClient("generation").config({ schema: z2.object({ enableVoice: z2.boolean().prefault(false) }) }).class( ({ plugin }) => class { async continue(params) { return await plugin.server.events.emit({ name: "agent.continue", data: params }); } async decide(params) { return await plugin.server.events.emit({ name: "agent.decide", data: params }); } async say(params) { return await plugin.server.events.emit({ name: "agent.say", data: params }); } async interrupt(params) { return await plugin.server.events.emit({ name: "agent.interrupt", data: params }); } messages = { create: /* @__PURE__ */ __name(async (params) => await plugin.server.events.emit({ name: "messages.create", data: params }), "create"), update: /* @__PURE__ */ __name(async (params) => await plugin.server.events.emit({ name: "messages.update", data: params }), "update"), get: /* @__PURE__ */ __name(() => plugin.server.context.get().messages, "get") }; } ).atoms(({ plugin, telemetry }) => [ { name: "status", create: /* @__PURE__ */ __name(() => { const store = atom(null); onMount(store, () => { const [error, context] = plugin.server.context.safe.get(); if (error) telemetry.log.error({ message: "Failed to fetch initial status from context.", error }); if (context?.status) store.set(context.status); const unsubscribe = plugin.server.context.onChange( (ctx) => ctx.status, (ctx) => store.set(ctx.status) ); return () => unsubscribe?.(); }); return { store, refresh: /* @__PURE__ */ __name(async () => void 0, "refresh") }; }, "create") }, { name: "messages", create: /* @__PURE__ */ __name(() => { const store = atom([]); onMount(store, () => { const [error, context] = plugin.server.context.safe.get(); if (error) telemetry.log.error({ message: "Failed to fetch initial messages from context.", error }); if (context?.messages) store.set(context.messages); const unsubscribe = plugin.server.context.onChange( (ctx) => ctx.messages, (ctx) => store.set(ctx.messages) ); return () => unsubscribe?.(); }); return { store, refresh: /* @__PURE__ */ __name(async () => void 0, "refresh") }; }, "create") } ]); // plugins/defaults/memories/client.ts var memoriesPluginClient = definePluginClient("memories").dependencies([generationPluginClient]).class((_) => class { }); // plugins/defaults/stores/client.ts var storesPluginClient = definePluginClient("stores"); // exports/client.ts var defaults = { plugins: { generation: generationPluginClient, memories: memoriesPluginClient, stores: storesPluginClient, *[Symbol.iterator]() { for (const entry of Object.values(this)) yield entry; } } }; export { createLifeClient, defaults, defineAgentClient, definePluginClient, parseAgentClientParam }; //# sourceMappingURL=client.mjs.map