Ctrl K
ComunidadGuías…

examples/workflow-dsl.mjs

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env node

import { GraphRuntime, InMemoryCheckpointStore, workflow } from '../dist/index.js';
import { z } from 'zod';

function formatEvent(event) {
  switch (event.type) {
    case 'run_start':
      return `run_start ${event.runId}`;
    case 'node_start':
      return `node_start ${event.nodeId}`;
    case 'node_end':
      return `node_end ${event.nodeId}`;
    case 'edge_transition':
      return `edge_transition ${event.sourceId} -> ${event.targetId} (${event.edgeType})`;
    case 'checkpoint_saved':
      return `checkpoint_saved ${event.nodeId}`;
    case 'run_end':
      return 'run_end';
    default:
      return event.type;
  }
}

const onboarding = workflow('user-onboarding')
  .input(
    z.object({
      email: z.string().email(),
      name: z.string(),
      desiredPlan: z.enum(['free', 'pro']),
    }),
  )
  .returns(
    z.object({
      userId: z.string().optional(),
      plan: z.enum(['free', 'pro']).optional(),
      summary: z.string().optional(),
    }),
  )
  .step('validate-email', { tool: 'email_validator' })
  .branch(
    (state) => state.input.desiredPlan,
    {
      pro: { tool: 'activate_pro_plan' },
      free: { tool: 'create_free_account' },
    },
  )
  .parallel(
    [
      { tool: 'send_welcome_email' },
      { tool: 'notify_crm' },
    ],
    {
      strategy: 'all',
      merge: { 'scratch.completedTasks': 'concat' },
    },
  )
  .then('summarize', {
    gmi: { instructions: 'Summarize the onboarding result for the caller.' },
  })
  .compile();

const runtime = new GraphRuntime({
  checkpointStore: new InMemoryCheckpointStore(),
  nodeExecutor: {
    async execute(node, state) {
      const config = node.executorConfig;

      switch (config.type) {
        case 'tool': {
          switch (config.toolName) {
            case 'email_validator':
              return {
                success: true,
                output: { valid: true },
                scratchUpdate: { completedTasks: ['validated email'] },
              };
            case 'activate_pro_plan':
              return {
                success: true,
                output: { activated: true },
                artifactsUpdate: { userId: 'usr_pro_001', plan: 'pro' },
              };
            case 'create_free_account':
              return {
                success: true,
                output: { created: true },
                artifactsUpdate: { userId: 'usr_free_001', plan: 'free' },
              };
            case 'send_welcome_email':
              return {
                success: true,
                output: 'queued welcome email',
                scratchUpdate: { completedTasks: ['queued welcome email'] },
              };
            case 'notify_crm':
              return {
                success: true,
                output: 'updated CRM',
                scratchUpdate: { completedTasks: ['updated CRM'] },
              };
            default:
              return { success: true, output: `handled tool ${config.toolName}` };
          }
        }

        case 'router':
          return {
            success: true,
            output: config.condition.type === 'function'
              ? config.condition.fn(state)
              : state.input.desiredPlan,
          };

        case 'gmi':
          return {
            success: true,
            output: 'summary ready',
            artifactsUpdate: {
              ...state.artifacts,
              summary: [
                `Created a ${state.artifacts.plan} account for ${state.input.name}.`,
                `Completed tasks: ${(state.scratch.completedTasks ?? []).join(', ')}.`,
              ].join(' '),
            },
          };

        default:
          return { success: true, output: `noop:${node.id}` };
      }
    },
  },
});

async function main() {
  console.log('=== workflow() DSL ===');
  console.log('Compiled nodes:', onboarding.toIR().nodes.map((node) => node.id).join(' -> '));

  let finalOutput;
  for await (const event of runtime.stream(onboarding.toIR(), {
    email: 'johnn@example.com',
    name: 'John',
    desiredPlan: 'pro',
  })) {
    console.log(formatEvent(event));
    if (event.type === 'run_end') {
      finalOutput = event.finalOutput;
    }
  }

  console.log('\nFinal artifacts:');
  console.dir(finalOutput, { depth: null });
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});