Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/extensions/qa-lab/src/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 9 kB image not shown  

Quelle  scenario-flow-runner.ts

  Sprache: JAVA
 

Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import type { QaTransportState } from "./qa-transport.js";
import type { QaScenarioFlow, QaSeedScenarioWithSource } from "./scenario-catalog.js";

type QaSuiteStep = {
  name: string;
  run: () => Promise<string | void>;
};

type QaSuiteScenarioResult = {
  name: string;
  status: "pass" | "fail";
  steps: Array<{
    name: string;
    status: "pass" | "fail" | "skip";
    details?: string;
  }>;
  details?: string;
};

type QaFlowApi = Record<string, unknown> & {
  state: QaTransportState;
  scenario: QaSeedScenarioWithSource;
  config: Record<string, unknown>;
  runScenario: (name: string, steps: QaSuiteStep[]) => Promise<QaSuiteScenarioResult>;
};

type QaFlowVars = Record<string, unknown>;

const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor as new (
  ...args: string[]
) => (...fnArgs: unknown[]) => Promise<unknown>;

function isPlainObject(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

function formatFlowDetails(details: unknown) {
  if (details === undefined) {
    return undefined;
  }
  if (typeof details === "string") {
    return details;
  }
  if (typeof details === "number" || typeof details === "boolean" || typeof details === "bigint") {
    return String(details);
  }
  return JSON.stringify(details, null, 2);
}

function getPathWithParent(
  root: Record<string, unknown>,
  ref: string,
): { parent: Record<string, unknown> | null; value: unknown } {
  const parts = ref.split(".").filter(Boolean);
  let current: unknown = root;
  let parent: Record<string, unknown> | null = null;
  for (const part of parts) {
    if (!isPlainObject(current)) {
      return { parent: null, value: undefined };
    }
    parent = current;
    current = current[part];
  }
  return { parent, value: current };
}

function createEvalContext(api: QaFlowApi, vars: QaFlowVars) {
  return {
    ...api,
    qaImport: (specifier: string) => import(specifier),
    vars,
    ...vars,
  };
}

async function evalExpr(expr: string, api: QaFlowApi, vars: QaFlowVars) {
  const context = createEvalContext(api, vars);
  const names = Object.keys(context);
  const values = Object.values(context);
  const fn = new AsyncFunction(...names, `return (${expr});`);
  return await fn(...values);
}

function buildLambda(
  spec: { params?: string[]; expr: string; async?: boolean },
  api: QaFlowApi,
  vars: QaFlowVars,
) {
  const context = createEvalContext(api, vars);
  const names = Object.keys(context);
  const values = Object.values(context);
  const params = spec.params ?? [];
  const Factory = spec.async ? AsyncFunction : Function;
  const fn = new Factory(...names, ...params, `return (${spec.expr});`) as (
    ...fnArgs: unknown[]
  ) => unknown;
  return (...lambdaArgs: unknown[]) => fn(...values, ...lambdaArgs);
}

async function resolveValue(node: unknown, api: QaFlowApi, vars: QaFlowVars): Promise<unknown> {
  if (Array.isArray(node)) {
    return await Promise.all(node.map((entry) => resolveValue(entry, api, vars)));
  }
  if (!isPlainObject(node)) {
    return node;
  }
  const keys = Object.keys(node);
  if (keys.length === 1 && typeof node.ref === "string") {
    return getPathWithParent(createEvalContext(api, vars), node.ref).value;
  }
  if (keys.length === 1 && typeof node.expr === "string") {
    return await evalExpr(node.expr, api, vars);
  }
  if (keys.length === 1 && isPlainObject(node.lambda) && typeof node.lambda.expr === "string") {
    return buildLambda(
      {
        expr: node.lambda.expr,
        params: Array.isArray(node.lambda.params)
          ? node.lambda.params.filter((entry): entry is string => typeof entry === "string")
          : [],
        async: node.lambda.async === true,
      },
      api,
      vars,
    );
  }
  const entries = await Promise.all(
    Object.entries(node).map(async ([key, value]) => [key, await resolveValue(value, api, vars)]),
  );
  return Object.fromEntries(entries);
}

function resolveCallable(path: string, api: QaFlowApi, vars: QaFlowVars) {
  const { parent, value } = getPathWithParent(createEvalContext(api, vars), path);
  if (typeof value !== "function") {
    throw new Error(`qa flow callable not found: ${path}`);
  }
  return parent ? value.bind(parent) : value;
}

async function runFlowAction(action: unknown, api: QaFlowApi, vars: QaFlowVars) {
  if (!isPlainObject(action)) {
    throw new Error(`invalid qa flow action: ${JSON.stringify(action)}`);
  }
  if (typeof action.call === "string") {
    const callable = resolveCallable(action.call, api, vars);
    const args = Array.isArray(action.args)
      ? await Promise.all(action.args.map((entry) => resolveValue(entry, api, vars)))
      : [];
    const result = await callable(...args);
    if (typeof action.saveAs === "string" && action.saveAs.trim()) {
      vars[action.saveAs.trim()] = result;
    }
    return;
  }
  if (typeof action.set === "string") {
    vars[action.set] = await resolveValue(action.value, api, vars);
    return;
  }
  if (typeof action.assert === "string" || isPlainObject(action.assert)) {
    const spec =
      typeof action.assert === "string"
        ? { expr: action.assert, message: undefined }
        : {
            expr: typeof action.assert.expr === "string" ? action.assert.expr : "",
            message: action.assert.message,
          };
    if (!spec.expr) {
      throw new Error(`invalid qa flow assertion: ${JSON.stringify(action.assert)}`);
    }
    const passed = Boolean(await evalExpr(spec.expr, api, vars));
    if (!passed) {
      const message =
        spec.message === undefined ? undefined : await resolveValue(spec.message, api, vars);
      throw new Error(
        typeof message === "string" && message.trim()
          ? message
          : `qa flow assertion failed: ${spec.expr}`,
      );
    }
    return;
  }
  if (typeof action.throw === "string" || isPlainObject(action.throw)) {
    const spec =
      typeof action.throw === "string"
        ? { expr: undefined, message: action.throw }
        : {
            expr: typeof action.throw.expr === "string" ? action.throw.expr : undefined,
            message: action.throw.message,
          };
    const evaluated = spec.expr ? await evalExpr(spec.expr, api, vars) : undefined;
    const message =
      spec.message === undefined ? undefined : await resolveValue(spec.message, api, vars);
    if (evaluated instanceof Error) {
      throw evaluated;
    }
    if (typeof evaluated === "string" && evaluated.trim()) {
      throw new Error(evaluated);
    }
    if (typeof message === "string" && message.trim()) {
      throw new Error(message);
    }
    throw new Error("qa flow throw");
  }
  if (isPlainObject(action.if)) {
    const ifAction = action.if as { expr: string; then: unknown[]; else?: unknown[] };
    const passed = Boolean(await evalExpr(ifAction.expr, api, vars));
    const branch = passed ? ifAction.then : (ifAction.else ?? []);
    for (const nested of branch) {
      await runFlowAction(nested, api, vars);
    }
    return;
  }
  if (isPlainObject(action.forEach)) {
    const forEachAction = action.forEach as {
      items: unknown;
      item: string;
      index?: string;
      actions: unknown[];
    };
    const items = await resolveValue(forEachAction.items, api, vars);
    if (!Array.isArray(items)) {
      throw new Error(`qa flow forEach items must resolve to array: ${JSON.stringify(items)}`);
    }
    for (const [index, item] of items.entries()) {
      vars[forEachAction.item] = item;
      if (forEachAction.index) {
        vars[forEachAction.index] = index;
      }
      for (const nested of forEachAction.actions) {
        await runFlowAction(nested, api, vars);
      }
    }
    return;
  }
  if (isPlainObject(action.try)) {
    const tryAction = action.try as {
      actions: unknown[];
      catchAs?: string;
      catch?: unknown[];
      finally?: unknown[];
    };
    try {
      for (const nested of tryAction.actions) {
        await runFlowAction(nested, api, vars);
      }
    } catch (error) {
      if (!tryAction.catch && !tryAction.finally) {
        throw error;
      }
      if (tryAction.catchAs) {
        vars[tryAction.catchAs] = error;
      }
      if (tryAction.catch) {
        for (const nested of tryAction.catch) {
          await runFlowAction(nested, api, vars);
        }
      } else {
        throw error;
      }
    } finally {
      if (tryAction.finally) {
        for (const nested of tryAction.finally) {
          await runFlowAction(nested, api, vars);
        }
      }
    }
    return;
  }
  throw new Error(`unknown qa flow action: ${JSON.stringify(action)}`);
}

export async function runScenarioFlow(params: {
  api: QaFlowApi;
  flow: QaScenarioFlow;
  scenarioTitle: string;
}) {
  const vars: QaFlowVars = {};
  const steps: QaSuiteStep[] = params.flow.steps.map((step) => ({
    name: step.name,
    run: async () => {
      for (const action of step.actions) {
        await runFlowAction(action, params.api, vars);
      }
      if (!step.detailsExpr) {
        return undefined;
      }
      const details = await evalExpr(step.detailsExpr, params.api, vars);
      return formatFlowDetails(details);
    },
  }));
  return await params.api.runScenario(params.scenarioTitle, steps);
}

export function describeScenarioFlowError(error: unknown) {
  return formatErrorMessage(error);
}

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.