{"_rev":"8-927b7128ccd37216f022e10f7e10c039","time":{"created":"2026-03-28T14:37:11.493Z","modified":"2026-03-28T14:37:12.006Z","1.0.1":"2025-05-02T16:31:35.349Z","1.0.0":"2025-05-02T21:03:42.326Z","1.0.2":"2025-05-02T21:12:40.868Z","1.0.3":"2026-02-08T16:37:26.749Z","1.0.4":"2026-03-28T14:37:11.766Z"},"_id":"@graph-compose/core","name":"@graph-compose/core","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.4":{"name":"@graph-compose/core","version":"1.0.4","description":"Core functionality for Graph Compose","license":"AGPL-3.0-only","main":"dist/index.js","types":"dist/index.d.ts","publishConfig":{"access":"public"},"keywords":["graph","compose","core"],"repository":{"type":"git","url":"git+https://github.com/graph-compose/core.git"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"dependencies":{"jsonata":"^2.0.5","ms":"^2.1.3","uuid":"^11.0.5","zod":"^3.24.3","zod-openapi":"^4.2.4","zod-to-json-schema":"^3.24.1"},"devDependencies":{"@tsconfig/node18":"^1.0.3","@types/jest":"^29.5.14","@types/ms":"^0.7.34","@types/node":"^18.0.0","@typescript-eslint/eslint-plugin":"^6.7.3","@typescript-eslint/parser":"^6.7.3","eslint":"^7.32.0","jest":"^29.7.0","ts-jest":"^29.1.1","typescript":"^5.0.4"},"jest":{"preset":"ts-jest","testEnvironment":"node","testRegex":"src/__tests__/.*\\.test\\.ts$","moduleFileExtensions":["ts","js","json"],"transform":{"^.+\\.ts$":["ts-jest",{"tsconfig":"tsconfig.json"}]}},"scripts":{"build":"tsc --build","watch":"tsc --build --watch","dev":"tsc --build --watch","format":"prettier --write .","lint":"eslint src","test":"jest --verbose --runInBand","check:circulars":"madge --circular --extensions ts src"},"_id":"@graph-compose/core@1.0.4","bugs":{"url":"https://github.com/graph-compose/core/issues"},"homepage":"https://github.com/graph-compose/core#readme","_integrity":"sha512-b9yv8P78Vp0uObQc0lTHVVz7ikTPwFnISemSxysAeTI/HNRtIbvurUhaGv/v+6/ELQz4fA9EWYqOLljTNPsm2w==","_resolved":"/private/var/folders/hn/z8grpd2x2fjb0gk_70mvwjxh0000gn/T/174c773b38b6d5953ea5ee34e0232cc7/graph-compose-core-1.0.4.tgz","_from":"file:graph-compose-core-1.0.4.tgz","_nodeVersion":"22.22.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-b9yv8P78Vp0uObQc0lTHVVz7ikTPwFnISemSxysAeTI/HNRtIbvurUhaGv/v+6/ELQz4fA9EWYqOLljTNPsm2w==","shasum":"dceaf751291cde9e9370269d9103136522a045e5","tarball":"https://registry.npmjs.org/@graph-compose/core/-/core-1.0.4.tgz","fileCount":216,"unpackedSize":751926,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFPsrcuMpo30LBOvTLoXVdUcX6JnZfk2wxK4MvJ2Bn/DAiEAjc6yGsahjScgy9kA16X/nR+m7t/el7nZ7VpMF7noBLM="}]},"_npmUser":{"name":"graph-compose","email":"jason@dontpanictechnologies.com"},"directories":{},"maintainers":[{"name":"graph-compose","email":"jason@dontpanictechnologies.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/core_1.0.4_1774708631591_0.6370413760348064"},"_hasShrinkwrap":false}},"maintainers":[{"name":"graph-compose","email":"jason@dontpanictechnologies.com"}],"description":"Core functionality for Graph Compose","homepage":"https://github.com/graph-compose/core#readme","keywords":["graph","compose","core"],"repository":{"type":"git","url":"git+https://github.com/graph-compose/core.git"},"bugs":{"url":"https://github.com/graph-compose/core/issues"},"license":"AGPL-3.0-only","readme":"# @graph-compose/core\n\nCore TypeScript types, Zod schemas, and validation logic for Graph Compose workflow graphs.\n\n> **Note:** This package provides the foundational type definitions and schemas. If you want a fluent builder API to programmatically construct and execute workflows, use [`@graph-compose/client`](../client/README.md) instead. This package is for developers who need to interact directly with the underlying workflow structures or build custom tooling.\n\n## Installation\n\n```bash\nnpm install @graph-compose/core\n# or\npnpm add @graph-compose/core\n# or\nyarn add @graph-compose/core\n```\n\n> **Tip:** If you're using `@graph-compose/client`, all commonly-used core types are re-exported from it, so you don't need to install this package separately.\n\n## The Workflow Graph\n\nEverything revolves around the `WorkflowGraph`. This object describes the complete structure of your workflow.\n\n```typescript\nimport { WorkflowGraphSchema } from '@graph-compose/core';\nimport { z } from 'zod';\n\nconst myWorkflow = {\n  nodes: [\n    {\n      id: 'fetch_user',\n      type: 'http',\n      dependencies: [],\n      http: {\n        method: 'GET',\n        url: 'https://api.example.com/users/{{context.userId}}'\n      }\n    },\n    {\n      id: 'process_user',\n      type: 'http',\n      dependencies: ['fetch_user'],\n      http: {\n        method: 'POST',\n        url: 'https://api.example.com/process',\n        headers: { 'Content-Type': 'application/json' },\n        body: { data: '{{results.fetch_user.data}}' }\n      }\n    }\n  ],\n  context: { userId: 'user_123' },\n  webhookUrl: 'https://my-service.com/webhook'\n};\n\n// Validate\ntry {\n  const validated = WorkflowGraphSchema.parse(myWorkflow);\n  console.log('Valid workflow!');\n} catch (error) {\n  if (error instanceof z.ZodError) {\n    console.error('Validation failed:', error.errors);\n  }\n}\n\n// Infer types\ntype MyWorkflow = z.infer<typeof WorkflowGraphSchema>;\n```\n\n### WorkflowGraph Fields\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `nodes` | `Node[]` | Yes | Array of workflow nodes |\n| `context` | `Record<string, any>` | No | Initial data available to all nodes via `{{context.*}}` |\n| `webhookUrl` | `string` | No | URL to notify on workflow events |\n| `workflowConfig` | `WorkflowConfig` | No | Workflow-level settings (e.g., execution timeout) |\n| `meta` | `Record<string, any>` | No | Additional metadata |\n\n### WorkflowConfig\n\n```typescript\n{\n  workflowExecutionTimeout?: Duration  // e.g., \"5 minutes\", \"1h\"\n}\n```\n\n## Node Types\n\nAll nodes share a base structure:\n\n```typescript\n{\n  id: string;          // Alphanumeric + underscores only (no dashes)\n  type: string;        // Node type discriminator\n  activityConfig?: ActivityConfig;  // Optional retry/timeout config\n}\n```\n\n### HTTP Node\n\nThe primary building block. Makes HTTP requests to external services.\n\n```typescript\n{\n  id: 'fetch_data',\n  type: 'http',\n  dependencies: ['auth_node'],\n  http: {\n    method: 'GET',                                    // GET | POST | PUT | DELETE | PATCH | HEAD | OPTIONS\n    url: 'https://api.example.com/data',\n    headers: {\n      'Authorization': 'Bearer {{$secret(\"api_token\")}}',\n      'X-Request-ID': '{{context.requestId}}'\n    },\n    body: {                                           // Not allowed for GET requests\n      userId: '{{results.auth_node.data.userId}}'\n    }\n  },\n  validation: {                                       // Optional JSON Schema validation\n    input: { /* JSON Schema */ },\n    output: { /* JSON Schema */ }\n  },\n  conditions: {                                       // Optional control flow\n    terminateWhen: ['{{results.fetch_data.data.status = \"done\"}}'],\n    continueTo: [\n      { to: 'process_node', when: '{{results.fetch_data.data.ready = true}}' }\n    ],\n    pollUntil: ['{{results.fetch_data.data.complete = true}}']\n  }\n}\n```\n\n### Error Boundary Node\n\nCatches and handles errors from protected nodes.\n\n```typescript\n{\n  id: 'error_handler',\n  type: 'error_boundary',\n  protectedNodes: ['fetch_data', 'process_data'],    // Nodes to protect (cannot protect other error boundaries)\n  http: {\n    method: 'POST',\n    url: 'https://api.example.com/error-handler',\n    body: { error: '{{results.error}}', nodeId: '{{results.nodeId}}' }\n  }\n}\n```\n\n### Confirmation Node\n\nPauses workflow execution until a user signal is received.\n\n```typescript\n{\n  id: 'approve_payment',\n  type: 'confirmation',\n  dependencies: ['process_payment']\n}\n```\n\nConfirmation nodes are signaled via Temporal workflow signals (`confirmNode`).\n\n### ForEach Node\n\nIterates over an array and spawns a child workflow for each element. Nodes between the `forEach` and its matching `endForEach` run inside each child workflow. Nodes downstream of the `endForEach` run in the parent workflow after all children complete.\n\n```typescript\n{\n  id: 'process_users',\n  type: 'forEach',\n  dependencies: ['get_users'],\n  forEach: {\n    items: '{{ results.get_users.data.users }}'      // JSONata expression resolving to an array\n  },\n  config: {                                           // Optional\n    concurrency: 5,                                   // Max parallel child workflows\n    continueOnError: true,                            // Complete even if some children fail\n    maxFailures: 10,                                  // Abort after this many child failures\n    childWorkflowConfig: {                            // Per-child timeout/retry\n      workflowExecutionTimeout: '5 minutes',\n      retry: { maximumAttempts: 3 }\n    }\n  }\n}\n```\n\nChild workflows get access to:\n- `{{row.index}}` - zero-based iteration index\n- `{{row.data}}` - the current array element\n- `{{row.data.property}}` - nested properties on the element\n\n### EndForEach Node\n\nMarks the end of a forEach loop body. Nodes downstream of this node run in the parent workflow with access to aggregated results via `{{ results.<forEachId>.data.items }}`.\n\n```typescript\n{\n  id: 'process_users_end',\n  type: 'endForEach',\n  forEachId: 'process_users',                        // ID of the forEach node this closes\n  dependencies: ['enrich_user']                       // Last node(s) inside the loop\n}\n```\n\n### ADK Node\n\nEmbeds an entire Agent Development Kit workflow as a single node, enabling multi-agent AI orchestration.\n\n```typescript\n{\n  id: 'ai_workflow',\n  type: 'adk',\n  dependencies: ['fetch_context'],\n  config: {\n    rootAgentId: 'coordinator',\n    agents: [\n      {\n        type: 'LlmAgent',\n        id: 'coordinator',\n        httpConfig: { url: 'https://llm.example.com', method: 'POST' },\n        tools: ['search_tool'],\n        outputKey: 'coordinator_response'\n      }\n    ],\n    globalTools: [\n      {\n        type: 'HttpTool',\n        id: 'search_tool',\n        httpConfig: { url: 'https://api.example.com/search', method: 'POST' },\n        outputKey: 'search_results'\n      }\n    ],\n    maxOrchestrationCycles: 10,\n    initialUserInput: 'Help me with this task',\n    state: { user_id: '123' }\n  }\n}\n```\n\n#### Agent Types\n\n| Type | Description |\n|---|---|\n| `LlmAgent` | Language model agent with HTTP config, tools, and optional sub-agents |\n| `SequentialAgent` | Executes sub-agents one after another (runs natively, not as HTTP activity) |\n| `ParallelAgent` | Executes sub-agents concurrently (runs natively) |\n| `LoopAgent` | Repeats sub-agents until exit condition or max iterations |\n\n#### Global Tool Types\n\n| Type | Description |\n|---|---|\n| `HttpTool` | Makes HTTP calls when invoked by agents |\n| `AgentTool` | Delegates to another agent (specialist pattern) |\n\n### Iterator Node\n\nProcesses collections by creating virtual copies of downstream nodes for each item. Used internally by the UI.\n\n```typescript\n{\n  id: 'iterate_items',\n  type: 'source_iterator',\n  dependencies: [],                   // Must be empty\n  http: {\n    method: 'GET',\n    url: 'https://api.example.com/items'\n  }\n}\n```\n\nChild workflows get access to `{{row.index}}` and `{{row.data.columnName}}`.\n\n### Destination Node\n\nOutputs data to specific destinations (e.g., spreadsheets). Used internally by the UI.\n\n```typescript\n{\n  id: 'save_to_sheet',\n  type: 'destination',\n  dependencies: ['process_data'],\n  http: {\n    method: 'POST',\n    url: 'https://api.example.com/destination',\n    body: {\n      sheetId: 'your_sheet_id',\n      cellValues: [\n        { columnName: 'Name', value: '{{results.process_data.data.name}}' },\n        { columnName: 'Email', value: '{{results.process_data.data.email}}' }\n      ]\n    }\n  }\n}\n```\n\n## Activity Configuration\n\nControls Temporal activity behavior (retries and timeouts) for any node.\n\n```typescript\n{\n  activityConfig: {\n    startToCloseTimeout: '30s',         // Max time for activity to complete once started\n    scheduleToCloseTimeout: '5m',       // Max time from scheduling to completion\n    retryPolicy: {\n      maximumAttempts: 5,\n      initialInterval: '1s',\n      backoffCoefficient: 2.0,\n      maximumInterval: '30s'\n    }\n  }\n}\n```\n\nDuration strings use the [ms](https://github.com/vercel/ms) library format: `'30s'`, `'5m'`, `'1h'`, `'2d'`, etc.\n\n## JSONata Expressions\n\nAll string fields support dynamic expressions using `{{ }}` delimiters with full [JSONata](https://jsonata.org/) support.\n\n### Available Namespaces\n\n```typescript\n// Node results (each result has shape { data, statusCode, headers })\n'{{results.fetch_user.data.id}}'\n'{{results.fetch_user.data.profile.name}}'\n\n// Workflow context\n'{{context.userId}}'\n'{{context.tenant.name}}'\n\n// Secrets\n'{{$secret(\"api_key\")}}'\n\n// Iterator / forEach data (in child workflows)\n'{{row.index}}'\n'{{row.data.columnName}}'\n\n// Ancestor forEach rows (in nested forEach child workflows)\n'{{rows.forEach_depts.data.name}}'\n\n// ADK session state\n'{{state.user_preferences.theme}}'\n```\n\n### JSONata Functions\n\n```typescript\n// String operations\n'{{$uppercase(results.fetch_user.data.name)}}'\n'{{$substring(results.fetch_text.data.content, 0, 100)}}'\n\n// Arithmetic\n'{{results.get_price.data.amount * 1.1}}'\n\n// Array operations\n'{{$count(results.list_items.data.items)}}'\n'{{results.list_items.data.items[status = \"active\"]}}'\n\n// Conditionals\n'{{results.check_status.data.code = 200 ? \"success\" : \"failure\"}}'\n\n// Timestamps\n'{{$now()}}'\n```\n\n### Boolean Expressions (for Conditions)\n\nUsed in `terminateWhen`, `continueTo.when`, and `pollUntil`:\n\n```typescript\n'{{results.check_status.data.state = \"done\"}}'\n'{{results.fetch_data.data.count > 10}}'\n'{{results.health_check.data.ready = true}}'\n```\n\n## Validation Utilities\n\n```typescript\nimport {\n  validateJsonataExpression,\n  validateTemplateExpression,\n  validateBooleanExpression,\n  validateNestedExpressions,\n  extractJsonataExpression,\n  extractAllExpressions,\n  hasTemplateExpressions,\n} from '@graph-compose/core';\n\n// Validate a raw JSONata expression\nvalidateJsonataExpression('results.user.data.name');\n\n// Validate a template string with {{ }} delimiters\nvalidateTemplateExpression('Hello {{results.user.data.name}}');\n\n// Validate a boolean expression for conditions\nvalidateBooleanExpression('{{results.status.data.state = \"done\"}}');\n\n// Find all expression errors in a nested object\nconst errors = validateNestedExpressions(myObject, ['nodeId']);\n\n// Check if a value contains template expressions\nif (hasTemplateExpressions(someValue)) { /* ... */ }\n\n// Extract expressions from templates\nconst exprs = extractAllExpressions('{{a}} and {{b}}'); // ['a', 'b']\n```\n\n## Constants\n\nTemporal workflow queries, signals, and task queue names:\n\n```typescript\nimport {\n  WORKFLOW_QUERIES,\n  WORKFLOW_SIGNALS,\n  ADK_QUERIES,\n  ADK_SIGNALS,\n  TASK_QUEUES,\n  WORKFLOW_NAMES,\n} from '@graph-compose/core';\n\n// HTTP workflow queries\nWORKFLOW_QUERIES.EXECUTION_STATE              // \"getExecutionState\"\nWORKFLOW_QUERIES.NODE_RESULT                  // \"getNodeResult\"\nWORKFLOW_QUERIES.NODE_STATE                   // \"getNodeState\"\nWORKFLOW_QUERIES.WAITING_CONFIRMATION_NODE    // \"getWaitingConfirmationNodeId\"\n\n// HTTP workflow signals\nWORKFLOW_SIGNALS.CONFIRM_NODE       // \"confirmNode\"\n\n// ADK workflow queries\nADK_QUERIES.GET_SESSION_EVENTS     // \"get_session_events\"\nADK_QUERIES.GET_LATEST_ORCHESTRATION_RESULT\n\n// ADK workflow signals\nADK_SIGNALS.RECEIVE_MESSAGE        // \"receive_message\"\nADK_SIGNALS.CONFIRM_ACTION         // \"confirm_action\"\nADK_SIGNALS.END_CONVERSATION       // \"end_conversation\"\n\n// Task queues\nTASK_QUEUES.adk                     // \"adk-task-queue\"\nTASK_QUEUES.http                    // \"http-worker\"\n```\n\n## Workflow State Types\n\n### HTTP Workflow State\n\n```typescript\nimport type { GraphWorkflowState, NodeResult } from '@graph-compose/core';\n\n// GraphWorkflowState\n{\n  context: Record<string, any>;           // Current global context\n  executed: string[];                      // Completed node IDs\n  results: Record<string, NodeResult>;     // Node results keyed by ID\n}\n\n// NodeResult\n{\n  data: any;                               // Response data\n  statusCode?: number;                     // HTTP status code\n  headers?: Record<string, string>;        // Response headers\n}\n```\n\n### ADK Workflow State\n\n```typescript\nimport type { AdkWorkflowState } from '@graph-compose/core';\n\n{\n  latestOrchestrationResult?: AdkOrchestrationResult;\n  conversationHistory: AdkSessionEvent[];\n  pendingConfirmations?: Record<string, AdkPendingConfirmation>;\n  isWaitingForConfirmation: boolean;\n  latestInvocationTrace?: AdkInvocationTrace;\n  isStopped?: boolean;\n  conversationEndRequested?: boolean;\n}\n```\n\n### Webhook Payloads\n\n```typescript\nimport type { WebhookPayload, NodeWebhookPayload, CompletionWebhookPayload } from '@graph-compose/core';\n\n// WebhookPayload\n{\n  workflowId: string;\n  runId: string;\n  type: \"node\" | \"completion\";\n  data: NodeWebhookPayload | CompletionWebhookPayload;\n}\n```\n\n## Exported Schemas\n\nAll Zod schemas for runtime validation:\n\n```typescript\nimport {\n  // Workflow\n  WorkflowGraphSchema,\n\n  // Node schemas\n  NodeSchema,               // Discriminated union of all node types\n  HttpNodeSchema,\n  ErrorBoundaryNodeSchema,\n  ConfirmationNodeSchema,\n  AdkNodeSchema,\n  ForEachNodeSchema,\n  EndForEachNodeSchema,\n  IteratorNodeSchema,\n  DestinationNodeSchema,\n\n  // Common schemas\n  HTTPConfigSchema,\n  ActivityConfigSchema,\n  RetryPolicySchema,\n  NodeConditionsSchema,\n  ValidationSchema,\n  ChildWorkflowConfigSchema,\n\n  // ADK schemas\n  ADKWorkflowDefinitionSchema,\n  AgentConfigSchema,\n  LlmAgentConfigSchema,\n  SequentialAgentConfigSchema,\n  ParallelAgentConfigSchema,\n  LoopAgentConfigSchema,\n  GlobalToolDefinitionSchema,\n  GlobalHttpToolDefinitionSchema,\n  GlobalAgentToolDefinitionSchema,\n\n  // Result schemas\n  NodeResultSchema,\n} from '@graph-compose/core';\n```\n\n## TypeScript Types\n\nAll types are inferred from Zod schemas:\n\n```typescript\nimport type {\n  // Workflow\n  WorkflowGraph,\n  WorkflowConfig,\n  WorkflowResults,\n\n  // Nodes\n  Node,\n  HttpNode,\n  ErrorBoundaryNode,\n  ConfirmationNode,\n  ForEachNode,\n  EndForEachNode,\n  AdkNode,\n  IteratorNode,\n  DestinationNode,\n\n  // HTTP\n  HTTPConfig,\n  JsonataParam,\n\n  // Conditions\n  NodeConditions,\n  FlowControl,\n\n  // Activity\n  ActivityConfig,\n  RetryPolicy,\n  ChildWorkflowConfig,\n\n  // ADK\n  ADKWorkflowDefinition,\n  AgentConfig,\n  LlmAgentConfig,\n  SequentialAgentConfig,\n  ParallelAgentConfig,\n  LoopAgentConfig,\n  GlobalToolDefinition,\n  GlobalHttpToolDefinition,\n  GlobalAgentToolDefinition,\n  SubAgentReference,\n\n  // State & Results\n  GraphWorkflowState,\n  NodeResult,\n  AdkWorkflowState,\n  RowInput,\n  RowsMap,\n\n  // Webhooks\n  WebhookPayload,\n} from '@graph-compose/core';\n```\n\n## Related Packages\n\n| Package | Description |\n|---------|-------------|\n| [`@graph-compose/client`](https://www.npmjs.com/package/@graph-compose/client) | Fluent TypeScript SDK for building and executing workflows on the Graph Compose platform |\n| [`@graph-compose/execution-kernel`](https://www.npmjs.com/package/@graph-compose/execution-kernel) | Lower-level execution primitives for building custom orchestrators |\n| [`@graph-compose/runtime`](https://www.npmjs.com/package/@graph-compose/runtime) | Batteries-included HTTP workflow runtime built on the execution kernel |\n\n## Requirements\n\n- Node.js 18+\n- TypeScript 5+ (recommended)\n\n## License\n\nThis project is dual-licensed:\n\n- **AGPL-3.0** for open-source use. See [LICENSE](./LICENSE) for details.\n- **Commercial License** available for organizations that need an alternative to AGPL. Contact the maintainers for details.\n","readmeFilename":"README.md"}