/ actors-main.ts
actors-main.ts
  1  #!/usr/bin/env deno run --allow-read --allow-write --allow-env --unstable-kv
  2  
  3  import { Task } from "./lib.ts";
  4  import { ActorManager } from "./actors/manager.ts";
  5  import { getActorRegistry, getAvailableActorNames } from "./actors/registry.ts";
  6  import { createActorInstances } from "./actors/core/runtime.ts";
  7  import { initializeEnv } from "./actors/utils/env.ts";
  8  
  9  /**
 10   * Parse command line arguments to configure actors
 11   */
 12  function parseArgs(args: string[]) {
 13    const config = {
 14      subscriber: 1,
 15      writer: 1,
 16      hybrid: 0,
 17      preset: "",
 18    };
 19  
 20    for (let i = 0; i < args.length; i++) {
 21      const arg = args[i];
 22      switch (arg) {
 23        case "--subscriber":
 24        case "--subscribers":
 25          config.subscriber = parseInt(args[++i]) || 1;
 26          break;
 27        case "--writer":
 28        case "--writers":
 29          config.writer = parseInt(args[++i]) || 1;
 30          break;
 31        case "--hybrid":
 32        case "--hybrids":
 33          config.hybrid = parseInt(args[++i]) || 0;
 34          break;
 35        case "--preset":
 36          config.preset = args[++i] || "";
 37          break;
 38      }
 39    }
 40  
 41    return config;
 42  }
 43  
 44  /**
 45   * Apply preset configurations
 46   */
 47  function applyPreset(config: any, preset: string) {
 48    switch (preset) {
 49      case "demo":
 50        return { ...config, subscriber: 2, writer: 1, hybrid: 1 };
 51      case "heavy":
 52        return { ...config, subscriber: 3, writer: 3, hybrid: 2 };
 53      case "light":
 54        return { ...config, subscriber: 1, writer: 0, hybrid: 1 };
 55      case "writers-only":
 56        return { ...config, subscriber: 0, writer: 5, hybrid: 0 };
 57      case "discord-bot-only":
 58        return {
 59          ...config,
 60          subscriber: 0,
 61          writer: 0,
 62          hybrid: 0,
 63          "discord-indexer": 0,
 64          "discord-slash-commands": 1,
 65        };
 66      case "discord":
 67        return {
 68          ...config,
 69          subscriber: 0,
 70          writer: 0,
 71          hybrid: 0,
 72          "discord-indexer": 1,
 73          "discord-slash-commands": 1,
 74        };
 75      case "discord-only":
 76        return {
 77          ...config,
 78          subscriber: 0,
 79          writer: 0,
 80          hybrid: 0,
 81          "discord-indexer": 1,
 82          "discord-slash-commands": 1,
 83        };
 84      case "llm-agent":
 85        return {
 86          ...config,
 87          subscriber: 0,
 88          writer: 0,
 89          hybrid: 0,
 90          "llm-response-agent": 1,
 91        };
 92      case "discord-full":
 93        return {
 94          ...config,
 95          subscriber: 0,
 96          writer: 0,
 97          hybrid: 0,
 98          "discord-indexer": 1,
 99          "discord-slash-commands": 1,
100          "llm-response-agent": 1,
101        };
102      case "lm-studio-insight":
103        return {
104          ...config,
105          subscriber: 0,
106          writer: 0,
107          hybrid: 0,
108          "lm-studio-insight-agent": 1,
109        };
110      case "lm-studio-tarot":
111        return {
112          ...config,
113          subscriber: 0,
114          writer: 0,
115          hybrid: 0,
116          "lm-studio-tarot-agent": 1,
117        };
118      case "discord-all":
119        return {
120          ...config,
121          subscriber: 0,
122          writer: 0,
123          hybrid: 0,
124          "discord-indexer": 1,
125          "discord-slash-commands": 1,
126          "llm-response-agent": 1,
127          "lm-studio-insight-agent": 1,
128        };
129      case "content-fragment":
130        return {
131          ...config,
132          subscriber: 0,
133          writer: 0,
134          hybrid: 0,
135          "content-fragment-agent": 1,
136        };
137      case "question":
138        return {
139          ...config,
140          subscriber: 0,
141          writer: 0,
142          hybrid: 0,
143          "question-agent": 1,
144        };
145      case "qa-feedback":
146        return {
147          ...config,
148          subscriber: 0,
149          writer: 0,
150          hybrid: 0,
151          "qa-feedback-loop-agent": 1,
152        };
153      case "qa-full":
154        return {
155          ...config,
156          subscriber: 0,
157          writer: 0,
158          hybrid: 0,
159          "question-agent": 1,
160          "content-fragment-agent": 1,
161          "qa-feedback-loop-agent": 1,
162        };
163      case "latent-space-navigator":
164        return {
165          ...config,
166          subscriber: 0,
167          writer: 0,
168          hybrid: 0,
169          "latent-space-navigator": 1,
170        };
171      default:
172        return config;
173    }
174  }
175  
176  /**
177   * Main function with auto-discovery
178   */
179  function main() {
180    return Task.spawn(function* () {
181      console.log("🎭 Actor System Starting...");
182  
183      // Parse command line arguments
184      const baseConfig = parseArgs(Deno.args);
185      const config = baseConfig.preset
186        ? applyPreset(baseConfig, baseConfig.preset)
187        : baseConfig;
188  
189      console.log("⚙️ Configuration:", config);
190  
191      // Initialize environment loading
192      console.log("📁 Loading environment configuration...");
193      yield* Task.wait(initializeEnv());
194  
195      // Auto-discover all available actors
196      console.log("🔍 Auto-discovering actors...");
197      const actorRegistry = yield* getActorRegistry();
198  
199      const availableNames = yield* getAvailableActorNames();
200      console.log("📋 Available actor types:", availableNames);
201  
202      // Create actor manager
203      const manager = new ActorManager();
204  
205      // Create instances based on configuration
206      for (const definition of actorRegistry) {
207        const count = config[definition.name as keyof typeof config] || 0;
208  
209        if (count > 0) {
210          console.log(
211            `🏗️ Creating ${count} instance(s) of ${definition.name}...`,
212          );
213          const instances = createActorInstances(definition, count);
214          manager.addActors(instances);
215        }
216      }
217  
218      const totalActors = manager.getActorCount();
219      console.log(
220        `🚀 Created ${totalActors} total actors: ${
221          manager.getActorNames().join(", ")
222        }`,
223      );
224  
225      if (totalActors === 0) {
226        console.log(
227          "⚠️ No actors to start. Try --preset demo or specify --subscriber 1 --writer 1",
228        );
229        return;
230      }
231  
232      // Start all actors
233      yield* manager.startAll();
234    });
235  }
236  
237  // Show help if requested
238  if (Deno.args.includes("--help") || Deno.args.includes("-h")) {
239    console.log(`
240  🎭 Actor System - Lightweight reactive agents for dialog database
241  
242  Usage:
243    deno run actors-main.ts [options]
244  
245  Options:
246    --subscriber N      Number of subscriber actors (default: 1)
247    --writer N          Number of writer actors (default: 1)
248    --hybrid N          Number of hybrid actors (default: 0)
249    --preset NAME       Use a preset configuration
250  
251  Presets:
252    demo               2 subscribers, 1 writer, 1 hybrid
253    heavy              3 subscribers, 3 writers, 2 hybrids
254    light              1 subscriber, 1 hybrid
255    writers-only       5 writers
256    discord            Discord indexer and slash commands
257    discord-full       Discord + LLM response agent
258    lm-studio-insight  LM Studio insight extraction agent
259    lm-studio-tarot    LM Studio tarot reading agent
260    content-fragment   Content fragment processing agent
261    question           Question processing agent
262    qa-feedback        QA feedback loop agent (discovers & generates Q&A)
263    qa-full            Question + Fragment + QA Feedback agents
264    discord-all        All Discord features + both AI agents
265    latent-space-navigator  Embedding space navigator with physics-based movement
266  
267  Examples:
268    deno run actors-main.ts --preset demo
269    deno run actors-main.ts --subscriber 3 --writer 2
270    deno run actors-main.ts --hybrid 5
271  
272  Note: Actors are auto-discovered from the /actors/implementations/ directory.
273  Add new actor files there and they'll be automatically available!
274    `);
275    Deno.exit(0);
276  }
277  
278  if (import.meta.main) {
279    main().catch(console.error);
280  }