跳转到正文

cli.ts ​

源文件: examples/patterns/rag-qa/cli.ts · 下载原文件 · 示例使用说明

ts
import { mkdir, mkdtemp, readFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { pathToFileURL } from "node:url";
import { parseArgs } from "node:util";
import {
  createDitto,
  loadRuntimeConfigFile,
  type RuntimeConfig,
} from "@codesoul-co/ditto/runtime";
import { createInferWorker } from "@codesoul-co/ditto/worker/infer";
import { createInteractionWorker } from "@codesoul-co/ditto/worker/interaction";
import { createRetrievalWorker } from "@codesoul-co/ditto-retrieval";
import { openAgentStorage } from "../../_shared/tools/storage/workers.ts";
import { RagAdapters } from "../../_shared/tools/rag/adapters.ts";
import { request, type Request } from "../../_shared/tools/rag/domain.ts";
import { runRag, type Options } from "./index.ts";
import { createFixture, seedInternalKnowledge } from "./fixtures.ts";
export async function openRag(
  directory: string,
  r: Request,
  config: RuntimeConfig,
) {
  const adapters = new RagAdapters(directory, r);
  try {
    const storage = await openAgentStorage(directory, config);
    try {
      const runtime = createDitto({
        config,
        sandbox: {
          ...config.sandbox,
          tools: adapters.tools.map((t) => t.name),
        },
        workers: [
          ...storage.workers,
          createInferWorker(),
          createRetrievalWorker({ providers: adapters.providers }),
          createInteractionWorker({ tools: adapters.tools }),
        ],
      });
      return {
        runtime,
        storage,
        adapters,
        async close() {
          try {
            await runtime.close();
          } finally {
            try {
              await storage.close();
            } finally {
              adapters.close();
            }
          }
        },
      };
    } catch (error) {
      await storage.close();
      throw error;
    }
  } catch (error) {
    adapters.close();
    throw error;
  }
}
export async function runCli() {
  const { values } = parseArgs({
    options: {
      directory: { type: "string" },
      question: { type: "string" },
      sources: { type: "string" },
      provider: { type: "string" },
      "stop-after": { type: "string" },
    },
  });
  if (values.directory && (values.question || values.sources))
    throw new Error(
      "Resume uses request.json; create a new task for a new question",
    );
  if (
    values["stop-after"] &&
    !["indexed", "retrieved", "selected", "report"].includes(
      values["stop-after"],
    )
  )
    throw new Error("Invalid stop stage");
  const config = loadRuntimeConfigFile("ditto.yaml", process.env),
    provider = values.provider ?? config.model?.provider;
  if (!provider || !config.providers[provider])
    throw new Error("Configure model provider");
  const model = config.providers[provider].model ?? config.model?.model;
  if (!model) throw new Error("Configure model");
  await mkdir(".examples-rag-tasks", { recursive: true });
  const directory = values.directory
    ? resolve(values.directory)
    : await mkdtemp(resolve(".examples-rag-tasks/cli-"));
  if (!values.directory)
    await createFixture(directory, {
      ...(values.question ? { question: values.question } : {}),
      ...(values.sources ? { sourceIds: values.sources.split(",") } : {}),
    });
  const r = request(
      JSON.parse(await readFile(join(directory, "request.json"), "utf8")),
    ),
    app = await openRag(directory, r, config),
    controller = new AbortController(),
    cancel = () => controller.abort();
  process.once("SIGINT", cancel);
  process.once("SIGTERM", cancel);
  try {
    if (!values.directory) await seedInternalKnowledge(app.runtime);
    const result = await runRag(
      app.runtime,
      { request: r, model: { provider, model } },
      {
        signal: controller.signal,
        ...(values["stop-after"]
          ? {
              stopAfter: values["stop-after"] as NonNullable<
                Options["stopAfter"]
              >,
            }
          : {}),
      },
    );
    console.log(JSON.stringify({ directory, result }, null, 2));
  } finally {
    process.off("SIGINT", cancel);
    process.off("SIGTERM", cancel);
    await app.close();
  }
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
  await runCli();

Ditto · @codesoul-co/ditto · Node.js 24+