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)
Direct workers (
runGraphComposer) — You setintent.action. Each action uses a dedicated system prompt (shared worox-graph fragments + oneaction-*.mdfile) plus the same skill catalogs and skill-mode gate as before. All graph-scoped actions are registered insrc/graphComposerActions.ts; adding an action means extending that registry and adding prompt files (seefunctions/graph-composer/prompts/README.md).Orchestrator (
runGraphComposerAgent) — You pass a natural-languagegoal. The orchestrator usesrunJsonCompletion(structured JSON steps) to choose registered tools, then runs each selection via the samerunGraphWorkerpath 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
catalogCandidatesonGraphComposerAgentInputwhen the goal involves catalog or scoping tools (host loads rows from Catalox vialoadCatalogCandidatesFromCatalox, 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-composerRequires 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. OptionalmatchListspre-pass (skills / scoping / narrix) injectscatalogMatchHintsinto the worker prompt whencatalogMatchListsAssist !== false(default) and an OpenRouter client is available.suggestCatalogCreations—catalogRequestProposals(+ optionalnewSkillDescriptors). Host applies approved rows via Catalox (or your store); this package emits JSON only.
Scoping need match & scoping map creation
suggestScopingNeedMatch— Does not requireexistingGraph(optional context). Requires non-emptycatalogCandidates.scopingMaps. Put the data need inintent.description. Output:hasSuitableMatch,recommended(scopingMapId/questionIdwhen true,nullwhen false),gaps, optionalalternatives. OptionalmatchListsinjectsscopingNeedMatchHints(same client /catalogMatchListsAssistflag).suggestScopingMapCreation— Plan a new scoping map:scopingMapProposal+ non-emptycatalogRequestProposals. Host persists approved artifacts; seeWoroxScopingMapCatalogCreatePayloadexported from@x12i/graph-composer(authored assrc/scopingCatalogHostTypes.tsin this repo).
RunGraphComposerOptions (workers)
In addition to client, mode, model, temperature, maxTokens, askTimeoutMs, connectTimeoutMs:
catalogMatchListsAssist— When notfalse, enablesmatchListspre-passes forsuggestCatalogResolution,suggestCatalogCreations, andsuggestScopingNeedMatchwhen a client is resolved (skips if no client).traceReviewConceptIo— Whentrue, emitreviewConceptrequest/response trace logs atinfo(still redacted). Whenfalse(default), the same traces usedebugonly.
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— runssuggestConceptObjectiveon the same sample graph.
export OPENROUTER_API_KEY=sk-or-...
npx @x12i/graph-composer explain-basic
npx @x12i/graph-composer network-vulnOr use the binary name:
graph-composer explain-basicAPI 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 declarationsfunctions/graph-composer/—prompts/(per-action workers,shared/,orchestrator-system.md,judge-rules.md+ JSON block,default-utility-skills.json), plusmeta.json,test-cases.jsonexamples/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 .envOptional: nx-config2 for scripts that load .env:
npx nx-config2 run --env-file .env -- npm testMaintainer 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
- Handoff / forward notes: docs/integration-handoff.md
- Catalog shapes & inspection: docs/worox-graphs-catalogs.md
- MetaDB / host CRUD handoff: docs/catalog-metadb-end-state-contract.md
- Task node (
aiTaskProfile) + worox-graph alignment: docs/task-node-worox-graph-and-graph-composer.md · docs/task-node-execution-protocol.md - aifunctions-js agent toolbox FR: docs/aifunctions-agent-toolbox-feature-request.md
- Funcx example generation context: docs/funcx-example-generation-feature-request.md
- Verify suggestConceptObjective: docs/verify-suggest-concept-objective.md
- aifunctions-js transport report: docs/report-aifunctions-js-undici-http.md
- Historical spec: docs/specs.md — not published on npm
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 publishConfirm tarball: npm run pack:check (must not list docs/, .env, or test/).
License
MIT — see LICENSE.