greentic-designer 0.6.0

Greentic Designer — orchestrator that powers Adaptive Card design via the adaptive-card-mcp toolkit
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# Component-HTTP Flow Integration

Instructions and knowledge for integrating `component-http` into greentic flows (`.ygtc`). This document teaches how to combine Adaptive Card nodes with HTTP API call nodes in a single flow, enabling cards to send/receive data from external APIs.

---

## What is component-http?

A WASM component that makes HTTP requests from within a greentic flow. It runs inside the greentic-runner sandbox — the component calls the host's HTTP client (reqwest) via the `greentic:http@1.0.0` WIT interface. Components cannot open sockets directly; all network access goes through the host.

- **Component ID**: `ai.greentic.component-http`
- **OCI source**: `oci://ghcr.io/greenticai/components/component-http:latest`
- **Operations**: `request` (blocking HTTP), `stream` (SSE/NDJSON)
- **Host requirement**: `greentic:http/client@1.0.0` (enabled automatically for `messaging` flow type)

---

## Schemas

### Config (per-node, set once)

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `base_url` | string (uri) | no || Base URL for all requests (e.g., `https://api.example.com/v1`) |
| `auth_type` | string | no | `"none"` | Authentication type: `none`, `bearer`, `api_key`, `basic` |
| `auth_token` | string | no || Token/key. Prefix with `secret:` to use secret store (e.g., `secret:API_TOKEN`) |
| `timeout_ms` | number | no | `30000` | Request timeout in milliseconds |
| `api_key_header` | string | no | `"X-API-Key"` | Header name for `api_key` auth type |
| `default_headers` | object | no || Default headers added to every request (e.g., `{"Accept": "application/json"}`) |

### Input (per-invocation, from flow data)

| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `url` | string | yes || Request URL. Can be relative if `base_url` is configured (e.g., `/tickets`) |
| `method` | string | no | `"POST"` | HTTP method: `GET`, `POST`, `PUT`, `DELETE`, `PATCH` |
| `body` | any | no || Request body (JSON object or string) |
| `headers` | object | no || Additional request headers for this call |

### Output (returned to flow)

| Field | Type | Description |
|-------|------|-------------|
| `status` | number | HTTP status code (200, 404, 500, etc.) |
| `body` | any | Response body (parsed as JSON if possible, raw string otherwise) |

---

## Flow Node Syntax

### Schema v2 format (recommended, used by cards2pack)

```yaml
nodes:
  my_http_node:
    routing:
      - to: next_node
    run:
      component: repo://local/component-http
      config:
        base_url: https://api.example.com
        auth_type: bearer
        auth_token: secret:MY_TOKEN
        timeout_ms: 15000
        default_headers:
          Accept: application/json
```

### component.exec format (used in hand-written flows like weather demo)

```yaml
nodes:
  my_http_node:
    component.exec:
      component: ai.greentic.component-http
      operation: request
      input:
        url: "/api/tickets"
        method: POST
        body:
          category: "{{node.form_card.result.category}}"
          description: "{{node.form_card.result.description}}"
    routing:
      - to: next_node
```

Both formats work in greentic-runner. Use schema v2 (`run:`) for consistency with cards2pack-generated flows.

---

## Data Flow Between Nodes

Data passes between nodes using Handlebars-style template references:

| Reference | Meaning |
|-----------|---------|
| `{{in.input.metadata.KEY}}` | Flow-level input (from ingress payload) |
| `{{node.NODE_ID.result.FIELD}}` | Output from a previously executed node |
| `{{parameters.KEY}}` | Flow-level parameters |
| `{{state.KEY}}` | Flow session state |

### Example: Card form data → HTTP POST → Confirmation card

```
[create_ticket_form]  user fills category, priority, description
        ▼ node output includes form field values
[api_create_ticket]   POST /api/tickets with form data
        ▼ node output: { status: 201, body: { ticket_id: "IT-123", ... } }
[ticket_confirmation] card displays ticket_id from API response
```

In the flow:

```yaml
api_create_ticket:
  component.exec:
    component: ai.greentic.component-http
    operation: request
    input:
      url: "/api/tickets"
      method: POST
      body:
        category: "{{node.create_ticket_form.result.category}}"
        priority: "{{node.create_ticket_form.result.priority}}"
        description: "{{node.create_ticket_form.result.description}}"
  routing:
    - to: ticket_confirmation

ticket_confirmation:
  component.exec:
    component: ai.greentic.component-adaptive-card
    operation: card
    input:
      card_source: asset
      card_spec:
        asset_path: assets/cards/ticket_confirmation.json
      payload:
        ticket: "{{node.api_create_ticket.result.body}}"
  routing:
    - out: true
```

---

## Routing Patterns

### Simple: Linear

```yaml
card_a:
  routing:
    - to: http_call
http_call:
  routing:
    - to: card_b
card_b:
  routing: out
```

### Conditional: Branch based on HTTP response

```yaml
api_check_status:
  routing:
    - to: success_card
    - to: error_card
```

### Card action routing (via routeToCardId)

Card nodes use `routeToCardId` in action data to determine which node to go to next. When inserting an HTTP node between two cards, change the card's `routeToCardId` to point to the HTTP node instead of the next card.

**Before (card → card):**
```
welcome → create_ticket_step1 → create_ticket_step2 → ticket_confirmation
```

**After (card → HTTP → card):**
```
welcome → create_ticket_step1 → create_ticket_step2 → api_create_ticket → ticket_confirmation
```

---

## Complete Example: IT Helpdesk with API Integration

This example extends a static IT helpdesk card flow with real API calls.

### Flow file: `flows/it_helpdesk_portal.ygtc`

```yaml
id: it_helpdesk_portal
type: messaging
start: welcome
parameters: {}
tags: []
schema_version: 2
entrypoints:
  default: welcome

nodes:
  # ─── WELCOME MENU ───
  welcome:
    routing:
      - to: create_ticket_step1
      - to: api_fetch_tickets
      - to: call_center
    card:
      card_source: asset
      card_spec:
        asset_path: assets/cards/welcome.json
      mode: renderAndValidate
      node_id: welcome
      payload: {}
      session: {}
      state: {}
      validation_mode: warn

  # ─── CREATE TICKET: Step 1 (category, priority, description) ───
  create_ticket_step1:
    routing:
      - to: create_ticket_step2
    card:
      card_source: asset
      card_spec:
        asset_path: assets/cards/create_ticket_step1.json
      mode: renderAndValidate
      node_id: create_ticket_step1
      payload: {}
      session: {}
      state: {}
      validation_mode: warn

  # ─── CREATE TICKET: Step 2 (contact info) ───
  create_ticket_step2:
    routing:
      - to: api_create_ticket
    card:
      card_source: asset
      card_spec:
        asset_path: assets/cards/create_ticket_step2.json
      mode: renderAndValidate
      node_id: create_ticket_step2
      payload: {}
      session: {}
      state: {}
      validation_mode: warn

  # ─── HTTP: Create ticket via API ───
  api_create_ticket:
    routing:
      - to: ticket_confirmation
    component.exec:
      component: ai.greentic.component-http
      operation: request
      input:
        url: "/api/tickets"
        method: POST
        body:
          category: "{{node.create_ticket_step1.result.category}}"
          priority: "{{node.create_ticket_step1.result.priority}}"
          description: "{{node.create_ticket_step1.result.description}}"
          fullname: "{{node.create_ticket_step2.result.fullname}}"
          email: "{{node.create_ticket_step2.result.email}}"
          phone: "{{node.create_ticket_step2.result.phone}}"

  # ─── CONFIRMATION: Show created ticket (data from API) ───
  ticket_confirmation:
    routing:
      - to: api_fetch_tickets
      - to: welcome
    component.exec:
      component: ai.greentic.component-adaptive-card
      operation: card
      input:
        card_source: asset
        card_spec:
          asset_path: assets/cards/ticket_confirmation.json
        payload:
          ticket: "{{node.api_create_ticket.result.body}}"

  # ─── HTTP: Fetch user's tickets ───
  api_fetch_tickets:
    routing:
      - to: view_tickets
    component.exec:
      component: ai.greentic.component-http
      operation: request
      input:
        url: "/api/tickets"
        method: GET

  # ─── VIEW TICKETS: List tickets (data from API) ───
  view_tickets:
    routing:
      - to: api_ticket_detail
      - to: welcome
    component.exec:
      component: ai.greentic.component-adaptive-card
      operation: card
      input:
        card_source: asset
        card_spec:
          asset_path: assets/cards/view_tickets.json
        payload:
          tickets: "{{node.api_fetch_tickets.result.body}}"

  # ─── HTTP: Fetch single ticket detail ───
  api_ticket_detail:
    routing:
      - to: ticket_status
    component.exec:
      component: ai.greentic.component-http
      operation: request
      input:
        url: "/api/tickets/{{node.view_tickets.result.ticket_select}}"
        method: GET

  # ─── TICKET STATUS: Show timeline (data from API) ───
  ticket_status:
    routing:
      - to: api_fetch_tickets
      - to: welcome
    component.exec:
      component: ai.greentic.component-adaptive-card
      operation: card
      input:
        card_source: asset
        card_spec:
          asset_path: assets/cards/ticket_status.json
        payload:
          ticket: "{{node.api_ticket_detail.result.body}}"

  # ─── CALL CENTER (static card, no API needed) ───
  call_center:
    routing:
      - to: request_callback
      - to: welcome
    card:
      card_source: asset
      card_spec:
        asset_path: assets/cards/call_center.json
      mode: renderAndValidate
      node_id: call_center
      payload: {}
      session: {}
      state: {}
      validation_mode: warn

  # ─── REQUEST CALLBACK (static card) ───
  request_callback:
    routing:
      - to: callback_confirmation
    card:
      card_source: asset
      card_spec:
        asset_path: assets/cards/request_callback.json
      mode: renderAndValidate
      node_id: request_callback
      payload: {}
      session: {}
      state: {}
      validation_mode: warn

  # ─── CALLBACK CONFIRMATION (static card) ───
  callback_confirmation:
    routing:
      - to: welcome
    card:
      card_source: asset
      card_spec:
        asset_path: assets/cards/callback_confirmation.json
      mode: renderAndValidate
      node_id: callback_confirmation
      payload: {}
      session: {}
      state: {}
      validation_mode: warn
```

### Component sources in pack manifest

The pack must declare both components:

```yaml
component_sources:
  - component_id: ai.greentic.component-adaptive-card
    source: oci://ghcr.io/greenticai/components/component-adaptive-card:latest
  - component_id: ai.greentic.component-http
    source: oci://ghcr.io/greenticai/components/component-http:latest
```

### HTTP node config (set via pack wizard or setup answers)

```json
{
  "base_url": "https://helpdesk-api.example.com",
  "auth_type": "bearer",
  "auth_token": "secret:HELPDESK_API_TOKEN",
  "timeout_ms": 15000,
  "default_headers": {
    "Accept": "application/json",
    "Content-Type": "application/json"
  }
}
```

---

## When to Use component-http in a Flow

Insert an HTTP node when a card transition needs to:

| Use Case | HTTP Method | Where in Flow |
|----------|-------------|---------------|
| Submit form data to backend | POST | Between form card and confirmation card |
| Fetch list data to display | GET | Before a list/table card |
| Fetch detail for a selected item | GET | Between list card and detail card |
| Update a record | PUT/PATCH | Between edit form and result card |
| Delete a record | DELETE | Between confirm-delete card and success card |

Do NOT use component-http for:
- Card-to-card navigation that doesn't need backend data (keep static routing)
- API calls that should happen outside the flow (e.g., webhooks, scheduled jobs)

---

## Pack Requirements

To include component-http in a `.gtpack`:

1. **Component binary**: Must be bundled inline or referenced via OCI
2. **Secrets**: API tokens must be set up via wizard/setup (`secret:TOKEN_NAME` format)
3. **Two components minimum**: `component-adaptive-card` (for cards) + `component-http` (for API calls)
4. **Flow type**: Must be `messaging` (enables HTTP client in runner host)

---

## Common Patterns

### Pattern 1: Form → API → Confirmation

```
[form_card] → [api_submit] → [confirmation_card]
```

User fills form → HTTP POST sends data → confirmation shows API response.

### Pattern 2: Menu → API Fetch → List Display

```
[menu_card] → [api_fetch_list] → [list_card]
```

User clicks "View Items" → HTTP GET fetches list → card renders list from API data.

### Pattern 3: List → Select → API Detail → Detail Card

```
[list_card] → [api_fetch_detail] → [detail_card]
```

User selects item → HTTP GET fetches detail by ID → card renders full detail.

### Pattern 4: CRUD Cycle

```
[list] → [api_fetch] → [display] → [edit_form] → [api_update] → [success] → [api_fetch] → [list]
```

Full create-read-update-delete loop with API calls at each mutation point.

---

## Reference: Working Flows in Codebase

| Flow | Location | Pattern |
|------|----------|---------|
| Weather API + Card | `weather-demo-scratch/weatherapi-pack/flows/flow_get_weather.ygtc` | component.exec → adaptive-card with `{{node.X.result.Y}}` |
| component-http gtest | `components-public/artifacts/readme-gtests/07_component-http_add_to_flow/artifacts/main.ygtc` | Two HTTP nodes chained, schema v2 `run:` format |
| Cisco Live RFQ | `cisco-live-bundle/flows/main.ygtc` | cards2pack-generated multi-card flow (card-only, no HTTP) |