xcomponent-ai 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/EVENT-ACCUMULATION-GUIDE.md +505 -0
  2. package/EXTERNAL-API.md +719 -0
  3. package/LLM-GUIDE.md +575 -0
  4. package/QUICKSTART.md +1 -1
  5. package/SCALABILITY.md +455 -0
  6. package/dist/cli.js +170 -63
  7. package/dist/cli.js.map +1 -1
  8. package/dist/component-registry.d.ts +35 -4
  9. package/dist/component-registry.d.ts.map +1 -1
  10. package/dist/component-registry.js +194 -9
  11. package/dist/component-registry.js.map +1 -1
  12. package/dist/external-broker-api.d.ts +205 -0
  13. package/dist/external-broker-api.d.ts.map +1 -0
  14. package/dist/external-broker-api.js +222 -0
  15. package/dist/external-broker-api.js.map +1 -0
  16. package/dist/fsm-runtime.d.ts +47 -17
  17. package/dist/fsm-runtime.d.ts.map +1 -1
  18. package/dist/fsm-runtime.js +333 -136
  19. package/dist/fsm-runtime.js.map +1 -1
  20. package/dist/index.d.ts +4 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +11 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/mermaid-generator.d.ts.map +1 -1
  25. package/dist/mermaid-generator.js +1 -17
  26. package/dist/mermaid-generator.js.map +1 -1
  27. package/dist/message-broker.d.ts +116 -0
  28. package/dist/message-broker.d.ts.map +1 -0
  29. package/dist/message-broker.js +225 -0
  30. package/dist/message-broker.js.map +1 -0
  31. package/dist/types.d.ts +92 -19
  32. package/dist/types.d.ts.map +1 -1
  33. package/examples/advanced-patterns-demo.yaml +339 -0
  34. package/examples/cross-component-demo.yaml +68 -0
  35. package/examples/distributed-demo/README.md +234 -0
  36. package/examples/distributed-demo/order.yaml +71 -0
  37. package/examples/distributed-demo/payment.yaml +60 -0
  38. package/examples/event-accumulation-demo.yaml +172 -0
  39. package/examples/explicit-transitions-demo.yaml +236 -0
  40. package/examples/payment-receiver.yaml +56 -0
  41. package/package.json +8 -1
  42. package/public/dashboard.html +647 -110
@@ -0,0 +1,234 @@
1
+ # Distributed Multi-Process Demo
2
+
3
+ This demo shows how to run xcomponent-ai components in **separate processes** communicating via **Redis Pub/Sub**.
4
+
5
+ ## Architecture
6
+
7
+ ```
8
+ ┌─────────────────────┐ Redis ┌─────────────────────┐
9
+ │ Process 1 │ Pub/Sub │ Process 2 │
10
+ │ │ │ │
11
+ │ OrderComponent │──────────────────────▶│ PaymentComponent │
12
+ │ Port: 3001 │ PROCESS event │ Port: 3002 │
13
+ │ │ │ │
14
+ │ Order FSM │ │ Payment FSM │
15
+ │ - Created │ │ - Pending │
16
+ │ - Validated ───────┼───────────────────────┼──▶ Processing │
17
+ │ - Completed │ │ - Completed │
18
+ └─────────────────────┘ └─────────────────────┘
19
+ ```
20
+
21
+ **How it works:**
22
+ 1. Process 1 (OrderComponent) runs on port 3001
23
+ 2. Process 2 (PaymentComponent) runs on port 3002
24
+ 3. When Order transitions to "Validated", it publishes a message to Redis
25
+ 4. PaymentComponent receives the message via Redis and triggers the transition
26
+
27
+ ## Prerequisites
28
+
29
+ 1. **Install Redis:**
30
+ ```bash
31
+ # macOS
32
+ brew install redis
33
+ brew services start redis
34
+
35
+ # Ubuntu/Debian
36
+ sudo apt-get install redis-server
37
+ sudo systemctl start redis
38
+
39
+ # Docker
40
+ docker run -d -p 6379:6379 redis:7-alpine
41
+ ```
42
+
43
+ 2. **Verify Redis is running:**
44
+ ```bash
45
+ redis-cli ping
46
+ # Should return: PONG
47
+ ```
48
+
49
+ 3. **Install xcomponent-ai with Redis support:**
50
+ ```bash
51
+ npm install -g xcomponent-ai redis
52
+ ```
53
+
54
+ ## Running the Demo
55
+
56
+ ### Step 1: Start Process 1 (OrderComponent)
57
+
58
+ In **Terminal 1:**
59
+ ```bash
60
+ xcomponent-ai serve examples/distributed-demo/order.yaml \
61
+ --port 3001 \
62
+ --broker redis://localhost:6379
63
+ ```
64
+
65
+ Expected output:
66
+ ```
67
+ 📡 Mode: Distributed (broker: redis://localhost:6379)
68
+ 🚀 xcomponent-ai Runtime Started
69
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
70
+
71
+ 📦 Component: OrderComponent
72
+ Machines:
73
+ - Order (3 states, 3 transitions)
74
+
75
+ 🌐 API Server: http://localhost:3001
76
+ 📊 Dashboard: http://localhost:3001/dashboard.html
77
+ ```
78
+
79
+ ### Step 2: Start Process 2 (PaymentComponent)
80
+
81
+ In **Terminal 2:**
82
+ ```bash
83
+ xcomponent-ai serve examples/distributed-demo/payment.yaml \
84
+ --port 3002 \
85
+ --broker redis://localhost:6379
86
+ ```
87
+
88
+ Expected output:
89
+ ```
90
+ 📡 Mode: Distributed (broker: redis://localhost:6379)
91
+ 🚀 xcomponent-ai Runtime Started
92
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
93
+
94
+ 📦 Component: PaymentComponent
95
+ Machines:
96
+ - Payment (4 states, 3 transitions)
97
+
98
+ 🌐 API Server: http://localhost:3002
99
+ 📊 Dashboard: http://localhost:3002/dashboard.html
100
+ ```
101
+
102
+ ### Step 3: Test Cross-Process Communication
103
+
104
+ In **Terminal 3:**
105
+
106
+ 1. **Create a Payment instance in Process 2:**
107
+ ```bash
108
+ curl -X POST http://localhost:3002/api/components/PaymentComponent/instances \
109
+ -H "Content-Type: application/json" \
110
+ -d '{
111
+ "machineName": "Payment",
112
+ "context": {
113
+ "orderId": "ORD-001",
114
+ "amount": 1000,
115
+ "customerId": "CUST-001"
116
+ }
117
+ }'
118
+ ```
119
+
120
+ Note the `instanceId` returned (e.g., `abc-123-def-456`).
121
+
122
+ 2. **Create an Order instance in Process 1:**
123
+ ```bash
124
+ curl -X POST http://localhost:3001/api/components/OrderComponent/instances \
125
+ -H "Content-Type: application/json" \
126
+ -d '{
127
+ "machineName": "Order",
128
+ "context": {
129
+ "orderId": "ORD-001",
130
+ "amount": 1000,
131
+ "customerId": "CUST-001"
132
+ }
133
+ }'
134
+ ```
135
+
136
+ Note the `instanceId` returned (e.g., `xyz-789-uvw-012`).
137
+
138
+ 3. **Trigger VALIDATE on Order (Process 1):**
139
+ ```bash
140
+ ORDER_ID="xyz-789-uvw-012" # Replace with actual ID from step 2
141
+
142
+ curl -X POST http://localhost:3001/api/instances/$ORDER_ID/events \
143
+ -H "Content-Type: application/json" \
144
+ -d '{
145
+ "type": "VALIDATE"
146
+ }'
147
+ ```
148
+
149
+ 4. **Verify Payment transitioned in Process 2:**
150
+ ```bash
151
+ PAYMENT_ID="abc-123-def-456" # Replace with actual ID from step 1
152
+
153
+ curl http://localhost:3002/api/instances/$PAYMENT_ID
154
+ ```
155
+
156
+ You should see the Payment instance now in `Processing` state!
157
+
158
+ ### Step 4: Observe Cross-Process Communication
159
+
160
+ **In Terminal 1 (OrderComponent):**
161
+ You'll see:
162
+ ```
163
+ [2:34:01 PM] [OrderComponent] xyz-789-uvw-012: Created → Validated (event: VALIDATE)
164
+ ```
165
+
166
+ **In Terminal 2 (PaymentComponent):**
167
+ You'll see:
168
+ ```
169
+ [2:34:01 PM] [PaymentComponent] abc-123-def-456: Pending → Processing (event: PROCESS)
170
+ ```
171
+
172
+ **Magic!** The Order in Process 1 triggered the Payment in Process 2 via Redis Pub/Sub! 🎉
173
+
174
+ ## Viewing Dashboards
175
+
176
+ Open in your browser:
177
+ - **Process 1 Dashboard:** http://localhost:3001/dashboard.html
178
+ - **Process 2 Dashboard:** http://localhost:3002/dashboard.html
179
+
180
+ You can see real-time state transitions in both processes independently.
181
+
182
+ ## Scaling Up
183
+
184
+ You can run **multiple instances** of each process for load balancing:
185
+
186
+ ```bash
187
+ # 2 instances of OrderComponent
188
+ xcomponent-ai serve order.yaml --port 3001 --broker redis://localhost:6379 &
189
+ xcomponent-ai serve order.yaml --port 3011 --broker redis://localhost:6379 &
190
+
191
+ # 3 instances of PaymentComponent
192
+ xcomponent-ai serve payment.yaml --port 3002 --broker redis://localhost:6379 &
193
+ xcomponent-ai serve payment.yaml --port 3012 --broker redis://localhost:6379 &
194
+ xcomponent-ai serve payment.yaml --port 3022 --broker redis://localhost:6379 &
195
+
196
+ # Add nginx load balancer in front
197
+ ```
198
+
199
+ All instances subscribe to the same Redis channels, enabling **horizontal scaling**.
200
+
201
+ ## Environment Variable
202
+
203
+ Instead of `--broker` flag, you can use:
204
+
205
+ ```bash
206
+ export XCOMPONENT_BROKER_URL=redis://localhost:6379
207
+
208
+ xcomponent-ai serve order.yaml --port 3001
209
+ xcomponent-ai serve payment.yaml --port 3002
210
+ ```
211
+
212
+ ## Production Deployment
213
+
214
+ For production, use:
215
+ - **Redis Cluster** for high availability
216
+ - **Redis Sentinel** for automatic failover
217
+ - **Kubernetes** for orchestration
218
+ - **Load balancer** (nginx, HAProxy) for API endpoints
219
+
220
+ See [SCALABILITY.md](../../SCALABILITY.md) for detailed production patterns.
221
+
222
+ ## Switching Back to In-Memory
223
+
224
+ To run both components in a **single process** (in-memory mode):
225
+
226
+ ```bash
227
+ xcomponent-ai serve \
228
+ examples/distributed-demo/order.yaml \
229
+ examples/distributed-demo/payment.yaml \
230
+ --port 3000
231
+ # No --broker flag = in-memory mode by default
232
+ ```
233
+
234
+ **Zero code changes!** Just configuration. 🚀
@@ -0,0 +1,71 @@
1
+ # Order Component - Process 1
2
+ # This component runs in its own process and communicates with PaymentComponent via Redis
3
+
4
+ name: OrderComponent
5
+ version: 1.0.0
6
+ metadata:
7
+ description: Order management system (distributed process 1)
8
+
9
+ stateMachines:
10
+ - name: Order
11
+ initialState: Created
12
+ contextSchema:
13
+ orderId:
14
+ type: text
15
+ label: Order ID
16
+ required: true
17
+ placeholder: ORD-001
18
+ amount:
19
+ type: number
20
+ label: Total Amount
21
+ required: true
22
+ min: 1
23
+ customerId:
24
+ type: text
25
+ label: Customer ID
26
+ required: true
27
+ placeholder: CUST-001
28
+
29
+ states:
30
+ - name: Created
31
+ type: entry
32
+ description: Order created and awaiting validation
33
+
34
+ - name: Validated
35
+ type: regular
36
+ description: Order validated, payment triggered via Redis
37
+ # DISTRIBUTED CROSS-COMPONENT: Trigger payment in PaymentComponent (different process!)
38
+ cascadingRules:
39
+ - targetComponent: PaymentComponent
40
+ targetMachine: Payment
41
+ targetState: Pending
42
+ event: PROCESS
43
+ payload:
44
+ orderId: "{{orderId}}"
45
+ amount: "{{amount}}"
46
+ customerId: "{{customerId}}"
47
+
48
+ - name: Completed
49
+ type: final
50
+ description: Order completed successfully
51
+
52
+ - name: Cancelled
53
+ type: error
54
+ description: Order cancelled
55
+
56
+ transitions:
57
+ - from: Created
58
+ to: Validated
59
+ event: VALIDATE
60
+ type: triggerable
61
+ description: Validate order and trigger payment
62
+
63
+ - from: Validated
64
+ to: Completed
65
+ event: COMPLETE
66
+ type: triggerable
67
+
68
+ - from: Created
69
+ to: Cancelled
70
+ event: CANCEL
71
+ type: triggerable
@@ -0,0 +1,60 @@
1
+ # Payment Component - Process 2
2
+ # This component runs in a SEPARATE process and receives events from OrderComponent via Redis
3
+
4
+ name: PaymentComponent
5
+ version: 1.0.0
6
+ metadata:
7
+ description: Payment processing system (distributed process 2)
8
+
9
+ stateMachines:
10
+ - name: Payment
11
+ initialState: Pending
12
+ contextSchema:
13
+ orderId:
14
+ type: text
15
+ label: Order ID
16
+ required: true
17
+ amount:
18
+ type: number
19
+ label: Amount
20
+ required: true
21
+ customerId:
22
+ type: text
23
+ label: Customer ID
24
+ required: true
25
+
26
+ states:
27
+ - name: Pending
28
+ type: entry
29
+ description: Payment awaiting processing (receives PROCESS from OrderComponent)
30
+
31
+ - name: Processing
32
+ type: regular
33
+ description: Payment being processed
34
+
35
+ - name: Completed
36
+ type: final
37
+ description: Payment completed successfully
38
+
39
+ - name: Failed
40
+ type: error
41
+ description: Payment failed
42
+
43
+ transitions:
44
+ - from: Pending
45
+ to: Processing
46
+ event: PROCESS
47
+ type: triggerable
48
+ description: Start payment processing (triggered by OrderComponent via Redis)
49
+
50
+ - from: Processing
51
+ to: Completed
52
+ event: CONFIRM
53
+ type: triggerable
54
+ description: Confirm payment success
55
+
56
+ - from: Processing
57
+ to: Failed
58
+ event: FAIL
59
+ type: triggerable
60
+ description: Mark payment as failed
@@ -0,0 +1,172 @@
1
+ # Event Accumulation Demo
2
+ # Shows how to accumulate multiple events and use EXPLICIT CONTROL for transitions
3
+ #
4
+ # Use Case: Trading Order that receives multiple execution notifications
5
+ # and transitions to "Fully Executed" only when all quantity is executed
6
+ #
7
+ # Key Pattern: sender.sendToSelf() for explicit transition control
8
+
9
+ name: TradingComponent
10
+ version: 1.0.0
11
+ metadata:
12
+ description: Trading order with partial executions and explicit control
13
+
14
+ # Define triggered methods that accumulate data and EXPLICITLY control transitions
15
+ triggeredMethods:
16
+ # Accumulates execution data and EXPLICITLY decides when to transition
17
+ accumulateExecution: |
18
+ async function(event, context, sender) {
19
+ // Initialize if first execution
20
+ if (!context.executedQuantity) {
21
+ context.executedQuantity = 0;
22
+ }
23
+ if (!context.executions) {
24
+ context.executions = [];
25
+ }
26
+
27
+ // Add executed quantity from event
28
+ const executedQty = event.payload.quantity || 0;
29
+ context.executedQuantity += executedQty;
30
+
31
+ // Track individual executions for audit
32
+ context.executions.push({
33
+ quantity: executedQty,
34
+ price: event.payload.price,
35
+ timestamp: event.timestamp,
36
+ executionId: event.payload.executionId
37
+ });
38
+
39
+ console.log(`Accumulated: ${context.executedQuantity}/${context.totalQuantity}`);
40
+
41
+ // EXPLICIT CONTROL: Decide when to transition to FullyExecuted
42
+ if (context.executedQuantity >= context.totalQuantity) {
43
+ console.log(`Order ${context.orderId} is now fully executed!`);
44
+ // Send event to self to trigger transition to FullyExecuted
45
+ await sender.sendToSelf({
46
+ type: 'FULLY_EXECUTED',
47
+ payload: {
48
+ totalExecuted: context.executedQuantity,
49
+ executionCount: context.executions.length,
50
+ averagePrice: context.executions.reduce((sum, e) => sum + e.price, 0) / context.executions.length
51
+ },
52
+ timestamp: Date.now()
53
+ });
54
+ }
55
+ }
56
+
57
+ # Handle completion
58
+ handleCompletion: |
59
+ async function(event, context, sender) {
60
+ console.log(`Order ${context.orderId} completed!`);
61
+ console.log(` Total executed: ${event.payload.totalExecuted}`);
62
+ console.log(` Executions: ${event.payload.executionCount}`);
63
+ console.log(` Average price: ${event.payload.averagePrice}`);
64
+
65
+ context.completedAt = Date.now();
66
+ context.stats = event.payload;
67
+ }
68
+
69
+ stateMachines:
70
+ - name: TradingOrder
71
+ initialState: Created
72
+
73
+ contextSchema:
74
+ orderId:
75
+ type: text
76
+ label: Order ID
77
+ required: true
78
+ symbol:
79
+ type: text
80
+ label: Symbol (e.g., AAPL)
81
+ required: true
82
+ totalQuantity:
83
+ type: number
84
+ label: Total Quantity to Execute
85
+ required: true
86
+ min: 1
87
+ side:
88
+ type: select
89
+ label: Side
90
+ options:
91
+ - BUY
92
+ - SELL
93
+ required: true
94
+
95
+ states:
96
+ - name: Created
97
+ type: entry
98
+ description: Order created, waiting for market submission
99
+
100
+ - name: Submitted
101
+ type: regular
102
+ description: Order submitted to market
103
+
104
+ - name: PartiallyExecuted
105
+ type: regular
106
+ description: Order partially executed, waiting for more fills
107
+
108
+ - name: FullyExecuted
109
+ type: regular
110
+ description: Order fully executed
111
+
112
+ - name: Completed
113
+ type: final
114
+ description: Order completed (settlement done)
115
+
116
+ - name: Cancelled
117
+ type: error
118
+ description: Order cancelled
119
+
120
+ transitions:
121
+ # Submit order to market
122
+ - from: Created
123
+ to: Submitted
124
+ event: SUBMIT
125
+ type: triggerable
126
+
127
+ # First execution notification (Submitted → PartiallyExecuted)
128
+ - from: Submitted
129
+ to: PartiallyExecuted
130
+ event: EXECUTION_NOTIFICATION
131
+ type: triggerable
132
+ triggeredMethod: accumulateExecution
133
+
134
+ # SELF-LOOP: Subsequent execution notifications (PartiallyExecuted → PartiallyExecuted)
135
+ # Triggered method decides when to send FULLY_EXECUTED event
136
+ - from: PartiallyExecuted
137
+ to: PartiallyExecuted
138
+ event: EXECUTION_NOTIFICATION
139
+ type: triggerable
140
+ triggeredMethod: accumulateExecution
141
+
142
+ # EXPLICIT TRANSITION: Triggered by sender.sendToSelf() in accumulateExecution
143
+ # No guards! The business logic is in the triggered method
144
+ - from: PartiallyExecuted
145
+ to: FullyExecuted
146
+ event: FULLY_EXECUTED
147
+ type: triggerable
148
+ triggeredMethod: handleCompletion
149
+
150
+ # Also handle direct full execution from Submitted (single large fill)
151
+ - from: Submitted
152
+ to: FullyExecuted
153
+ event: FULLY_EXECUTED
154
+ type: triggerable
155
+ triggeredMethod: handleCompletion
156
+
157
+ # Settlement
158
+ - from: FullyExecuted
159
+ to: Completed
160
+ event: SETTLE
161
+ type: triggerable
162
+
163
+ # Cancellation
164
+ - from: Submitted
165
+ to: Cancelled
166
+ event: CANCEL
167
+ type: triggerable
168
+
169
+ - from: PartiallyExecuted
170
+ to: Cancelled
171
+ event: CANCEL
172
+ type: triggerable