@alvera-ai/platform-sdk 0.17.0 → 0.18.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 (83) hide show
  1. package/.agent/AGENTS.md +82 -144
  2. package/.agent/account_management.md +2 -2
  3. package/.agent/action_logs.md +4 -4
  4. package/.agent/ai_agents.md +28 -21
  5. package/.agent/ai_sandbox.md +49 -39
  6. package/.agent/connected_apps.md +3 -3
  7. package/.agent/cookbook/_fixtures/README.md +1 -1
  8. package/.agent/cookbook/_fixtures/{foundation → organic-marketing}/_lead_submissions_foundation_generic_table.liquid +1 -1
  9. package/.agent/cookbook/_fixtures/organic-marketing/_lead_submissions_foundation_legal_entity.liquid +80 -0
  10. package/.agent/cookbook/_fixtures/{foundation → organic-marketing}/_lead_submissions_foundation_mdm.liquid +2 -1
  11. package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_generic_table.liquid +57 -0
  12. package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_legal_entity.liquid +30 -0
  13. package/.agent/cookbook/_fixtures/payments-compliance/_compliance_screenings_mdm.liquid +44 -0
  14. package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_generic_table.liquid +57 -0
  15. package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_legal_entity.liquid +36 -0
  16. package/.agent/cookbook/_fixtures/payments-compliance/_payment_accounts_mdm.liquid +41 -0
  17. package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_generic_table.liquid +70 -0
  18. package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_legal_entity.liquid +52 -0
  19. package/.agent/cookbook/_fixtures/primary-care-feedback/_cahps_appointments_mdm.liquid +42 -0
  20. package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_generic_table.liquid +38 -0
  21. package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_legal_entity.liquid +48 -0
  22. package/.agent/cookbook/_fixtures/subscription-saas/_customers_subscription_mdm.liquid +49 -0
  23. package/.agent/cookbook/organic-marketing.md +2801 -0
  24. package/.agent/cookbook/payments-compliance.md +2180 -0
  25. package/.agent/cookbook/primary-care.md +2175 -0
  26. package/.agent/cookbook/subscription-saas.md +2403 -0
  27. package/.agent/data_activation_clients.md +65 -52
  28. package/.agent/datalakes.md +338 -171
  29. package/.agent/errors.md +3 -3
  30. package/.agent/generic_tables.md +151 -62
  31. package/.agent/interoperability_contracts.md +57 -22
  32. package/.agent/mdm.md +136 -153
  33. package/.agent/messages.md +36 -34
  34. package/.agent/mock-services.md +1 -1
  35. package/.agent/mutations.md +2 -2
  36. package/.agent/templates.md +14 -13
  37. package/.agent/tools.md +63 -21
  38. package/.agent/type_naming.md +13 -13
  39. package/.agent/workflows.md +99 -53
  40. package/README.md +2 -2
  41. package/dist/bin/platform-sdk.mjs +33 -47
  42. package/dist/bin/platform-sdk.mjs.map +1 -1
  43. package/dist/index.d.mts +565 -379
  44. package/dist/index.d.mts.map +1 -1
  45. package/dist/index.mjs +494 -59
  46. package/dist/index.mjs.map +1 -1
  47. package/package.json +4 -3
  48. package/.agent/cookbook/_fixtures/foundation/_lead_submissions_foundation_legal_entity.liquid +0 -88
  49. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_appointment.liquid +0 -47
  50. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_mdm.liquid +0 -24
  51. package/.agent/cookbook/_fixtures/healthcare/_cahps_appointments_healthcare_patient.liquid +0 -38
  52. package/.agent/cookbook/_fixtures/payments/_compliance_screenings_payments_compliance_screening.liquid +0 -59
  53. package/.agent/cookbook/_fixtures/payments/_compliance_screenings_payments_mdm.liquid +0 -36
  54. package/.agent/cookbook/_fixtures/payments/_payment_accounts_payments_mdm.liquid +0 -30
  55. package/.agent/cookbook/_fixtures/payments/_payment_accounts_payments_payment_account.liquid +0 -55
  56. package/.agent/cookbook/_fixtures/subscription/_customers_subscription_mdm.liquid +0 -20
  57. package/.agent/cookbook/_setup/foundation.md +0 -359
  58. package/.agent/cookbook/_setup/healthcare.md +0 -361
  59. package/.agent/cookbook/_setup/payments.md +0 -365
  60. package/.agent/cookbook/_setup/subscription.md +0 -364
  61. package/.agent/cookbook/action-status-updaters.md +0 -278
  62. package/.agent/cookbook/ai-agent-invoke.md +0 -279
  63. package/.agent/cookbook/appointment-review-sms-workflow.md +0 -801
  64. package/.agent/cookbook/birthday-greeting-sms-trigger.md +0 -696
  65. package/.agent/cookbook/bulk-ingest.md +0 -302
  66. package/.agent/cookbook/contact-us-triage-with-llm.md +0 -663
  67. package/.agent/cookbook/dunning-sms-for-delinquent.md +0 -659
  68. package/.agent/cookbook/generic-tables.md +0 -244
  69. package/.agent/cookbook/invite-team.md +0 -200
  70. package/.agent/cookbook/kyc-notification-on-account-activation.md +0 -661
  71. package/.agent/cookbook/marketing-campaign-send.md +0 -1044
  72. package/.agent/cookbook/paginated-restapi-poller.md +0 -383
  73. package/.agent/cookbook/rest-fetch.md +0 -273
  74. package/.agent/cookbook/sanctions-screening-with-agent-review.md +0 -773
  75. package/.agent/cookbook/score-leads-with-llm-categorization.md +0 -665
  76. package/.agent/cookbook/system-templates.md +0 -165
  77. package/.agent/cookbook/talk-to-data.md +0 -178
  78. package/.agent/cookbook/triage-prospects-by-priority.md +0 -571
  79. package/.agent/cookbook/welcome-sms-for-customers.md +0 -647
  80. /package/.agent/cookbook/_fixtures/{healthcare → primary-care-feedback}/memorandum-of-association-01.png +0 -0
  81. /package/.agent/cookbook/_fixtures/{healthcare → primary-care-feedback}/sample_two_page.pdf +0 -0
  82. /package/.agent/cookbook/_fixtures/{subscription → subscription-saas}/_customers_subscription_customer.liquid +0 -0
  83. /package/.agent/cookbook/_fixtures/{subscription → subscription-saas}/stripe_customers_batch1.csv +0 -0
@@ -38,7 +38,6 @@ const { data: created } = await api.dataActivationClients.create(
38
38
  tool_call: { tool_call_type: 'manual_upload' },
39
39
  interoperability_contract_ids: [patientContractId, appointmentContractId],
40
40
  cron_expressions: [], // omit for on-demand; e.g. ['0 7,19 * * *']
41
- loop_over: [], // 'services' | 'locations' | 'providers'
42
41
  row_filter: undefined, // Liquid pre-filter; see §2
43
42
  downstream_connection_ids: [], // DAC chaining; cycle-checked
44
43
  },
@@ -75,8 +74,9 @@ Discover it and ingest through it:
75
74
  const { data: clients } = await api.dataActivationClients.list(tenantSlug, datalakeSlug)
76
75
  // `list` returns the paged envelope { data, meta } — the DAC array is clients.data
77
76
  const seedDac = (clients.data ?? []).find(
78
- (c) => c.is_default && c.name.endsWith('customer DataActivationClient'),
77
+ (c) => c.is_default && (c.name ?? '').endsWith('customer DataActivationClient'),
79
78
  )
79
+ if (!seedDac?.slug) throw new Error('no default activation client for that table')
80
80
  // ingest is SLUG-keyed (see §6) — pass seedDac.slug, not seedDac.id
81
81
  await api.dataActivationClients.ingest(tenantSlug, datalakeSlug, seedDac.slug, { data: row })
82
82
  ```
@@ -203,7 +203,8 @@ response_extractor optional embed — TemplateConfig ({ type, body
203
203
  a Liquid template that unwraps a nested API
204
204
  envelope into the row array (e.g.
205
205
  `{{ msg.data | to_json }}`). Load-bearing for
206
- `rest_api` fetch DACs; see `rest-fetch.md` §004
206
+ `rest_api` fetch clients; see
207
+ `cookbook/subscription-saas.md` §032–035
207
208
  ```
208
209
 
209
210
  **Write-only (Request-only).** None — every caller-supplied
@@ -429,7 +430,7 @@ rows_ingested number — count of top-level rows the contract emitted
429
430
  dataset_updated number — count of dataset rows whose batch_id this run wrote
430
431
  (load-bearing: see Gotcha 7)
431
432
  output_files { object_key, mode }[] — merged ndjson archive refs, one per
432
- bucket; mode is 'regulated' | 'unregulated'
433
+ bucket; mode is 'raw' | 'tokenized' | 'redacted'
433
434
  (empty until the post-batch merge worker commits).
434
435
  NOT a string[] — each entry is an embed object;
435
436
  use /logs/:id/download to fetch a presigned URL
@@ -483,12 +484,12 @@ durable" signal — not just the presence of the log row.
483
484
  >
484
485
  > ```typescript
485
486
  > const { data: probe } = await api.datalakes.executeSql(tenantSlug, datalakeSlug, {
486
- > sql: `SELECT 1 FROM patients WHERE batch_id = '${batchId}' LIMIT 1`,
487
- > mode: 'unregulated',
487
+ > sql: `SELECT 1 FROM ${tableName} WHERE batch_id = '${batchId}' LIMIT 1`,
488
+ > mode: 'raw',
488
489
  > })
489
490
  > // `data` is an array-of-arrays (a `string` only for { format: 'csv' });
490
- > // a non-empty page proves the batch landed. Reference the unregulated
491
- > // table by its base name — `mode: 'regulated'` uses the `regulated_` prefix.
491
+ > // a non-empty page proves the batch landed. The table is named the same
492
+ > // in every lake — `mode` selects which copy answers, not which name.
492
493
  > const landed = typeof probe !== 'string' && probe.data.length > 0
493
494
  > ```
494
495
  >
@@ -507,7 +508,7 @@ default — the datalake is mandatory and explicit, mirroring
507
508
 
508
509
  ```typescript
509
510
  // (1) POST creates a user search and runs the underlying SQL
510
- // synchronously against the regulated schema. The result
511
+ // synchronously against the raw lake. The result
511
512
  // set is materialised server-side and identified by the
512
513
  // returned UUID.
513
514
  const { data: search } = await api.datasets.createUserSearch(
@@ -516,24 +517,32 @@ const { data: search } = await api.datasets.createUserSearch(
516
517
  'patient', // dataset name
517
518
  {
518
519
  search_query: `ri.value = '${externalPatientId}'` // SQL WHERE-clause fragment
519
- + ` AND rp.batch_id = '${batchId}'`,
520
+ + ` AND le.batch_id = '${batchId}'`,
520
521
  },
521
522
  )
522
523
  // search.id — UUID of the materialised result set
523
- // search.status — 'completed' on success; 'failed' surfaces error_message
524
+ // search.status — 'new' | 'in_progress' | 'completed' | 'error'.
525
+ // The failure member is 'error', NOT 'failed' — and it is
526
+ // 'error' that carries error_message. There is no 'failed'.
524
527
  // search.results_count — ALWAYS null on the POST response (see Gotcha 5)
525
528
 
526
529
  // (2) GET paginates rows from the materialised result set.
527
- // dataAccessMode selects the storage tier:
528
- // 'regulated' — raw values verbatim (PHI/PII intact)
529
- // 'unregulated' — tokenized columns return as
530
- // { redacted_data, token, type } objects;
531
- // plain columns return as their primitive type
530
+ // dataAccessMode selects which lake answers:
531
+ // 'raw' — real values verbatim
532
+ // 'tokenized' — masked columns return a stable tok_<hash>
533
+ // 'redacted' — masked columns return an unjoinable placeholder
534
+ // `search.id` is `string | undefined` on the response type, and
535
+ // `DatasetSearchOptions.userSearchId` is declared `?: string` — optional, but
536
+ // NOT `| undefined`. So an app with `exactOptionalPropertyTypes` will not
537
+ // compile the shorthand, and an app without it gets a runtime 404 that reads
538
+ // like a wrong path. Narrow it first.
539
+ if (!search.id) throw new Error(`createUserSearch returned no id (status ${search.status})`)
540
+
532
541
  const { data: page } = await api.datasets.search(
533
542
  tenantSlug,
534
543
  datalakeSlug,
535
544
  'patient',
536
- { userSearchId: search.id, dataAccessMode: 'unregulated' },
545
+ { userSearchId: search.id, dataAccessMode: 'tokenized' },
537
546
  )
538
547
  // page.data — array of rows
539
548
  // page.meta — pagination
@@ -541,50 +550,54 @@ const { data: page } = await api.datasets.search(
541
550
 
542
551
  #### SQL aliases
543
552
 
544
- `createUserSearch` accepts a WHERE-clause fragment against a
545
- fixed set of table aliases. Each dataset has a base alias for its
546
- primary regulated table, plus `ri` for the regulated_identifiers
547
- join. **The base alias is assigned by that dataset's server-side
548
- decomposed query — it is NOT derivable from the dataset name, and
549
- different datasets reuse the same letters.** Verified examples:
553
+ `createUserSearch` accepts a WHERE-clause fragment against a fixed set
554
+ of server-assigned table aliases. **The alias is assigned by the
555
+ dataset's server-side decomposed query — it is not derivable from the
556
+ dataset name**, so confirm it rather than guessing:
550
557
 
551
558
  ```
552
- patient → rp (regulated_patients) + ri
553
- appointment → ra (regulated_appointments) + ri
554
- customer → ra (regulated_customers) + ri ← 'ra', NOT 'rc'
559
+ legal_entity → le
560
+ message → m
561
+ action_log → al
562
+ document → d
563
+ beneficial_owner → bo
555
564
  ```
556
565
 
557
- `customer` is a live trap: its primary table is aliased `ra`, not
558
- `rc` (both `rest-fetch.md` §006 and `bulk-ingest.md` §008 query it as
559
- `ra.batch_id`). Don't guess the alias from the dataset name — confirm
560
- it from the dataset's green cookbook/test before writing the fragment.
561
- The `ri.value` predicate filters on external identifiers (the values
562
- your inbound rows carried); the `<base_alias>.batch_id` predicate
563
- scopes the search to one run.
566
+ GH-859 removed the per-domain datasets this list used to name —
567
+ `patient`, `appointment`, `customer` and their `regulated_*` tables
568
+ are gone, and with them the `rp` / `ra` / `rc` aliases. **A customer,
569
+ a patient or an appointment is now a generic table you declare, plus
570
+ the legal entity its rows resolve to**; there is no dataset of that
571
+ name to search. The four cookbooks all take this shape.
564
572
 
565
- #### Tokenized vs plain column shape
573
+ The `<alias>.batch_id` predicate scopes a search to one run, which is
574
+ the usual reason to reach for this surface at all.
566
575
 
567
- In `dataAccessMode: 'unregulated'`, tokenized columns surface
568
- as objects, NOT primitives:
576
+ #### What a masked column looks like coming back
569
577
 
570
- ```typescript
571
- {
572
- redacted_data: '*****', // server-redacted preview
573
- token: 'tk_...', // stable opaque token
574
- type: 'string' // original column's logical type — one of:
575
- | 'text' // 'string' / 'text': free-form text content
576
- | 'email' // 'email': RFC 5322 email
577
- | 'phone' // 'phone': E.164 / display phone number
578
- | 'date' // 'date': ISO 8601 date
579
- | 'image', // 'image': image file reference
580
- }
578
+ **Every column comes back as a plain value of its own type, in every
579
+ mode.** A masked column is a string; it is not wrapped in an object.
580
+
581
+ Measured on a live three-lake tenant, the same `first_name` read three
582
+ ways through `datasets.search`:
583
+
584
+ ```
585
+ raw "Teodoro"
586
+ tokenized "tok_def1e9dd0d0d276ea8e39f885790f5ad"
587
+ redacted "xxxx-oro"
581
588
  ```
582
589
 
583
- Plain columns (non-tokenized) surface as the same primitive
584
- the regulated schema stores. A consumer code path that
585
- unconditionally treats every field as a string will crash on
586
- tokenized columns — type-check `typeof row.field === 'object'`
587
- first.
590
+ An older version of this guide described tokenized columns arriving as
591
+ `{ redacted_data, token, type }` objects and told consumers to branch on
592
+ `typeof row.field === 'object'`. That branch can never be taken. If you
593
+ are carrying such a guard, it is dead code — and worse, the `else` arm
594
+ it guards is the one doing all the work.
595
+
596
+ The two masked forms differ in what they are *for*. `tok_<hash>` is
597
+ stable, so the same input yields the same token and a machine can join
598
+ on it across tables without ever resolving it. `xxxx-<tail>` is
599
+ deliberately unjoinable — a placeholder for a person glancing at a
600
+ screen. Pick the mode by which of those two readers you are serving.
588
601
 
589
602
  ## 7. Gotchas
590
603