JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 319
  • Score
    100M100P100Q103355F
  • License MIT

LLM-backed worox-graph DAG composer: create, modify, explain, suggestConceptObjective, reviewConcept, catalog resolution/creation, scoping need match and scoping map creation plans, plus optional orchestrator — OpenRouter via @x12i/funcx; catalog rows from @x12i/catalox (loadCatalogCandidatesFromCatalox)

Package Exports

  • @x12i/graph-composer

Readme

@x12i/graph-composer

Location
GitHub (source) woroces/graph-composer — clone: git@github.com:woroces/graph-composer.git
npm (package) @x12i/graph-composer

The Git repo lives under the woroces org with repo name graph-composer. That is separate from the npm scope @x12i.

LLM-backed graph composer for the worox-graph DAG format using @x12i/funcx and OpenRouter.

Graph structure: create, modify, explain. Product metadata: suggestConceptObjective (metadata.graphConcept). Concept QA: reviewConcept (verdict + findings, no graph rewrite). Managed catalogs (Catalox-backed rows → planning JSON only — host applies CRUD): suggestCatalogResolution, suggestCatalogCreations. Scoping-only: suggestScopingNeedMatch (natural-language need vs catalogCandidates.scopingMaps), suggestScopingMapCreation (scopingMapProposal + catalogRequestProposals).

Architecture (two ways to run)

  1. Direct workers (runGraphComposer) — You set intent.action. Each action uses a dedicated system prompt (shared worox-graph fragments + one action-*.md file) plus the same skill catalogs and skill-mode gate as before. All graph-scoped actions are registered in src/graphComposerActions.ts; adding an action means extending that registry and adding prompt files (see functions/graph-composer/prompts/README.md).

  2. Orchestrator (runGraphComposerAgent) — You pass a natural-language goal. The orchestrator uses runJsonCompletion (structured JSON steps) to choose registered tools, then runs each selection via the same runGraphWorker path as direct mode. This costs more tokens and latency (multiple LLM rounds) than a single direct call.

    Registered tool ids (mirror GRAPH_COMPOSER_ACTION_REGISTRY): graph_create, graph_modify, graph_explain, graph_suggest_concept_objective, graph_suggest_catalog_resolution, graph_suggest_catalog_creations, graph_suggest_scoping_need_match, graph_suggest_scoping_map_creation, graph_review_concept.

    Pass catalogCandidates on GraphComposerAgentInput when the goal involves catalog or scoping tools (host loads rows from Catalox via loadCatalogCandidatesFromCatalox, or supplies fixtures).

Upstream feature request for first-class tool loops / worker profiles in aifunctions-js: docs/aifunctions-agent-toolbox-feature-request.md.

Install

npm install @x12i/graph-composer

Requires Node.js 20+ (Catalox embedder and this package align on >=20).

Environment

Variable Required Description
OPENROUTER_API_KEY Yes (for API runs) OpenRouter API key.
LLM_MODEL_STRONG No Model slug when using mode: "strong" (default preset from @x12i/funcx).
LLM_MODEL_NORMAL No Model slug for normal mode.
GRAPH_COMPOSER_LOGS_LEVEL No Log level for @x12i/logxer (info, warn, …).

Copy .env.example to .env for local development. Do not commit secrets.

Quick start (direct worker)

import { runGraphComposer } from "@x12i/graph-composer";

const result = await runGraphComposer(
  {
    intent: {
      action: "create",
      description: "Read a record, classify it, persist the result.",
    },
    skillMode: "locked",
    aiSkills: [
      {
        skillKey: "professional-answer",
        description: "Structured analysis with LLM",
        isLocal: false,
      },
    ],
    utilitySkills: [
      {
        skillKey: "scoped-data-reader",
        description: "Read scoped data",
        isLocal: true,
      },
      {
        skillKey: "scoped-answer-writer",
        description: "Persist results",
        isLocal: true,
      },
    ],
    constraints: { requireFinalizer: true },
  },
  {
    askTimeoutMs: 120_000,
    connectTimeoutMs: 60_000,
    maxTokens: 8192,
  }
);

Orchestrator (toolbox)

import { runGraphComposerAgent } from "@x12i/graph-composer";

const out = await runGraphComposerAgent(
  {
    goal:
      "Explain the attached graph for operators: summary, execution order, data flow.",
    existingGraph: myGraphJson,
    skillMode: "locked",
    aiSkills: [...],
    utilitySkills: [...],
  },
  {
    askTimeoutMs: 120_000,
    connectTimeoutMs: 60_000,
    maxTokens: 8192,
    maxOrchestratorSteps: 8,
  }
);
// out.orchestration.summary — orchestrator narrative
// out.orchestration.steps — which tools ran
// out.result — last worker JSON (e.g. explain payload)

runGraphComposerAgent uses the same OpenRouter client resolution as workers; pass options.model if you need an explicit model for orchestrator JSON steps (see aifunctions-js runJsonCompletion).

Explain an existing graph

Pass existingGraph (worox-graph JSON) and intent.action: "explain".

Suggest primary intent (suggestConceptObjective)

Generic API (any graph): set intent.action: "suggestConceptObjective", existingGraph (required), optional analysisContext, and the usual skill / constraint fields. This is not tied to a specific domain or subnet.

Bundled sample graph (legacy fixture): inputSuggestConceptObjectiveNetworkVulnSubnet() and the JSON under examples/ are non-normative test/demo payloads — not catalog ids, not a product-specific API surface. Prefer your own graphs and Catalox-backed catalogCandidates in production.

Optional intent.onlyIfEmpty: array of patch field names (primaryIntentType, primaryIntentStatement, businessObjective, primaryOutcome). The runtime drops any listed key from the model’s graphConceptPatch when existingGraph.metadata.graphConcept.<key> is already a non-empty string, and appends a short note to rationale when something was skipped.

Stable result shape (top-level, in addition to action):

{
  "action": "suggestConceptObjective",
  "graphConceptPatch": {
    "primaryIntentType": "objective",
    "primaryIntentStatement": "One or two product-facing sentences describing what this graph achieves for the user.",
    "businessObjective": "",
    "primaryOutcome": ""
  },
  "rationale": "Optional short note for UI or logs."
}

primaryIntentType is one of: question, decision, action, objective (same vocabulary as playground INTENT_TYPE_OPTIONS). Apply the patch in the consumer with a shallow merge into metadata.graphConcept, e.g. { ...existing, ...graphConceptPatch }.

Types: GraphConceptPatch, GraphConceptPatchKey, PrimaryIntentType. Helper: applyGraphConceptPatchOnlyIfEmpty() (same merge rule the runtime uses after the LLM returns).

Example using the bundled fixture helper:

import { runGraphComposer, inputSuggestConceptObjectiveNetworkVulnSubnet } from "@x12i/graph-composer";

const result = await runGraphComposer(inputSuggestConceptObjectiveNetworkVulnSubnet(), {
  askTimeoutMs: 120_000,
  connectTimeoutMs: 60_000,
  maxTokens: 4096,
});

Review concept (reviewConcept)

Requires existingGraph. Returns verdict (coherent, summary) and findings (category, severity, summary, optional taskIndex, proposal, nodeIds, suggestedChange). When metadata.graphConcept.coreTasks is non-empty, the model should return graphConceptPatch or suggestedConceptPatch (same partial shape; prefer one) with coreTasks index-aligned to that array and partial requirements (skill, catalogBinding, narrix, memoryIO, optional webScoping, etc.) inferred from the graph and catalogs. When a single value cannot be chosen, the model may return requirementOptions (ranked candidates per taskIndex + dot-path field, plus needsNewArtifact). Optional extended string fields on the patch (e.g. expectedInput, outputDescription) and optional catalogProposals for catalog gaps. No graph, changelog, or explanation. Use for design review before heavy edits.

Tracing: For reviewConcept only, runGraphWorker logs a redacted JSON snapshot of the serialized worker request and the raw LLM worker response (@x12i/funcx function-pack invocation): at debug by default (set GRAPH_COMPOSER_LOGS_LEVEL=debug), or at info when traceReviewConceptIo: true is passed in RunGraphComposerOptions. Payloads are capped (~500k chars) and keys matching secrets (apiKey, password, token, etc.) are replaced with [redacted].

Generate example input

Use generateGraphJsonInputExample when a host has a graph-specific expected input JSON Schema and wants a realistic smoke-test payload. It wraps Funcx generateJsonExample, adding graph metadata such as metadata.graphConcept.expectedInput and core tasks to the guidance.

import { generateGraphJsonInputExample } from "@x12i/graph-composer";

const out = await generateGraphJsonInputExample({
  existingGraph: myGraphJson,
  jsonSchema: graphExpectedInputSchema,
  guidance: ["Use fake subnet and CVE values.", "Keep the payload minimal."],
  examples: previousGoodInputs,
  timeoutMs: 120_000,
});

The package also re-exports Funcx generateJsonExample, generateMdExample, and generateContentExample for non-graph-specific examples.

Catalog resolution & creation (suggestCatalogResolution, suggestCatalogCreations)

Both require existingGraph. Pass catalogCandidates (from Catalox via loadCatalogCandidatesFromCatalox, or fixtures): aiSkills, utilitySkills, scopingMaps, narrixTemplates — see docs/worox-graphs-catalogs.md and docs/catalog-metadb-end-state-contract.md (Catalox bridge + catalogCandidates as documented there: @x12i/graph-composer ≥ 1.6.0).

  • suggestCatalogResolution — Per-node style recommendations: skillResolution, scopingResolution, narrixResolution, gaps. Optional matchLists pre-pass (skills / scoping / narrix) injects catalogMatchHints into the worker prompt when catalogMatchListsAssist !== false (default) and an OpenRouter client is available.
  • suggestCatalogCreationscatalogRequestProposals (+ optional newSkillDescriptors). Host applies approved rows via Catalox (or your store); this package emits JSON only.

Scoping need match & scoping map creation

  • suggestScopingNeedMatchDoes not require existingGraph (optional context). Requires non-empty catalogCandidates.scopingMaps. Put the data need in intent.description. Output: hasSuitableMatch, recommended (scopingMapId / questionId when true, null when false), gaps, optional alternatives. Optional matchLists injects scopingNeedMatchHints (same client / catalogMatchListsAssist flag).
  • suggestScopingMapCreation — Plan a new scoping map: scopingMapProposal + non-empty catalogRequestProposals. Host persists approved artifacts; see WoroxScopingMapCatalogCreatePayload exported from @x12i/graph-composer (authored as src/scopingCatalogHostTypes.ts in this repo).

RunGraphComposerOptions (workers)

In addition to client, mode, model, temperature, maxTokens, askTimeoutMs, connectTimeoutMs:

  • catalogMatchListsAssist — When not false, enables matchLists pre-passes for suggestCatalogResolution, suggestCatalogCreations, and suggestScopingNeedMatch when a client is resolved (skips if no client).
  • traceReviewConceptIo — When true, emit reviewConcept request/response trace logs at info (still redacted). When false (default), the same traces use debug only.

Worker actions cheat sheet

intent.action existingGraph Notes
create No Full graph + changelog
modify Yes Patched graph + changelog
explain Yes explanation object only
suggestConceptObjective Yes graphConceptPatch
reviewConcept Yes verdict + findings; optional patch + requirementOptions / catalogProposals
suggestCatalogResolution Yes Pass catalogCandidates; optional catalogMatchHints injection
suggestCatalogCreations Yes catalogRequestProposals
suggestScopingNeedMatch No* *Optional; requires non-empty catalogCandidates.scopingMaps
suggestScopingMapCreation No* *Optional; scopingMapProposal + catalogRequestProposals

Authoritative JSON shapes: functions/graph-composer/meta.json.

CLI (after install)

Core usage: pass a test-cases.json id (e.g. explain-basic, create-simple-linear) — these map to the pack’s machine fixtures.

Demo / smoke only (not the core API surface):

  • network-vuln — runs explain on the bundled subnet triage sample graph.
  • network-vuln-intent — runs suggestConceptObjective on the same sample graph.
export OPENROUTER_API_KEY=sk-or-...
npx @x12i/graph-composer explain-basic
npx @x12i/graph-composer network-vuln

Or use the binary name:

graph-composer explain-basic

API highlights

Export Purpose
runGraphComposer(input, options?) Direct worker for intent.action.
runGraphComposerAgent(input, options?) Orchestrator + toolbox (multi-step JSON).
runGraphWorker Same LLM path as runGraphComposer (used internally and for advanced composition).
getGraphComposerLlmClient Always returns an OpenRouter Client (orchestrator / custom ask use).
resolveGraphComposerClient Optional client + timeout wiring (may return undefined so aifunctions-js uses its default OpenRouter client for worker LLM calls).
GRAPH_COMPOSER_ACTION_REGISTRY, getActionDefinition, getActionDefinitionByToolName, requiredPromptPathsFromRegistry, loadWorkerBaseMarkdown Action registry + prompts.
composeWorkerInstructions Build full system text for one action + catalogs + mode gate.
applyGraphConceptPatchOnlyIfEmpty Apply intent.onlyIfEmpty rules to a graphConceptPatch.
composeInstructions, formatSkillList Lower-level composition from a raw base string + skill lists.
getPackDir(), graphComposerPackRoot() Path to bundled functions/graph-composer pack.
readGraphComposerPromptFile(name) Read a file under functions/graph-composer/prompts/.
DEFAULT_UTILITY_SKILLS Default local skills when utilitySkills is omitted.
buildCatalogMatchHints, buildScopingNeedMatchHints Optional matchLists helpers (normally invoked inside runGraphWorker).
generateGraphJsonInputExample, buildGraphInputExampleGuidance Generate a realistic JSON input example for a specific graph and expected input schema.
generateJsonExample, generateMdExample, generateContentExample Re-exported Funcx example-generation helpers.
validateSuggestCatalogResolutionOutput, validateSuggestCatalogCreationsOutput, validateSuggestScopingNeedMatchOutput, validateSuggestScopingMapCreationOutput, validateReviewConceptOutput Offline output validators for tests / hosts.
Types: GraphComposerInput, GraphComposerAgentInput, GraphComposerIntent, CatalogCandidates, ScopingMapCandidate, NarrixTemplateCandidate, … See dist/index.d.ts.
loadCatalogCandidatesFromCatalox, createCatalox, unifiedCatalogItemToSkillDescriptor, … Build catalogCandidates from Catalox catalogs; see docs/catalog-metadb-end-state-contract.md.
reportTaskNodeProtocolGaps Offline list of AI task nodes violating metadata.aiTaskProfile (pre/post, webScoping.questions when enabled, inputSynthesis.catalogId + strategyKey when synthesis is on). See docs/task-node-execution-protocol.md.
WoroxScopingMapCatalogCreatePayload, WoroxScopedDataDocumentShape Host-side CRUD handoff (align field names with your persisted catalog / scoping schema).
parseGraphConceptStory, isGraphConceptStoryDescription, GRAPH_CONCEPT_STORY_MARKER, … Parse graph concept story text for create / modify / reviews.
redactSecretsForLog Deep-redact sensitive key names for logging (used by reviewConcept tracing).

RunGraphComposerOptions: client, mode, model, temperature, maxTokens, askTimeoutMs, connectTimeoutMs, catalogMatchListsAssist, traceReviewConceptIo — see integration handoff.

Bundled content

Published tarball includes:

  • dist/ — compiled ESM + TypeScript declarations
  • functions/graph-composer/prompts/ (per-action workers, shared/, orchestrator-system.md, judge-rules.md + JSON block, default-utility-skills.json), plus meta.json, test-cases.json
  • examples/network-vuln-subnet-triage.v2.json — sample worox graph

It does not include internal docs/, tests, or .env.

Development (this repo)

The repository may keep a duplicate of the sample graph under docs/examples/ for documentation. The published package only ships examples/; keep them in sync if you change the sample.

cp .env.example .env
npm install
npm run build
npm run verify:local
npm run typecheck
npm test          # live tests; needs OPENROUTER_API_KEY in .env

Optional: nx-config2 for scripts that load .env:

npx nx-config2 run --env-file .env -- npm test

Maintainer smoke (suggest only, truncated JSON): npm run suggest-smoke (repo only; uses scripts/run-suggest-concept-smoke.ts).

Catalox / Firestore live catalog probe: npm run verify:catalog-live — lists configured aiSkills merge catalogs (core skills + PRE/POST by default; synthesis catalog only if GC_VERIFY_CATALOG_INPUT_SYNTHESIS_MODES is set) and runs loadCatalogCandidatesFromCatalox. Defaults CataloxContext.superAdmin=true; with @x12i/catalox ≥ 3.4.6, CATALOX_APP_ID is optional (catalog-id-first). Needs FIREBASE_PROJECT_ID (or other project id env) and FIREBASE_SERVICE_ACCOUNT_PATH / base64 SA / ADC. See docs/catalox-multi-app-context.md and docs/catalog-metadb-end-state-contract.md § Live verification.

Documentation in this repo

Published npm tarball still does not ship docs/; clone the repo or read these on GitHub for integration details.

Publishing (maintainers)

Scoped package @x12i/graph-composer uses publishConfig.access: "public". Ensure your npm user is a member of the x12i org (or owns the scope) and has a valid token in ~/.npmrc or project .npmrc (never commit tokens).

npm run build
npm publish

Confirm tarball: npm run pack:check (must not list docs/, .env, or test/).

License

MIT — see LICENSE.