@elevasis/sdk 1.51.0 → 1.52.1
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.
- package/dist/{chunk-HIVK54X6.js → chunk-T6DTAP2U.js} +121 -18
- package/dist/{chunk-NNRXVYNC.js → chunk-XC57JNMA.js} +79 -19
- package/dist/cli.cjs +151 -19
- package/dist/index.d.ts +248 -1
- package/dist/index.js +1 -1
- package/dist/test-utils/index.d.ts +13 -2
- package/dist/test-utils/index.js +16 -3
- package/dist/worker/index.d.ts +1 -1
- package/dist/worker/index.js +2 -2
- package/package.json +2 -2
- package/reference/_navigation.md +4 -5
- package/reference/_reference-manifest.json +0 -14
- package/reference/packages/ui/src/hooks/README.md +22 -23
- package/reference/rules/content.md +4 -1
- package/reference/rules/frontend.md +2 -2
- package/reference/rules/organization-os.md +1 -1
- package/reference/rules/ui.md +18 -16
- package/reference/rules/vibe-intents.md +28 -6
- package/reference/rules/vibe.md +3 -2
- package/reference/scaffold/operations/propagation-pipeline.md +33 -19
- package/reference/scaffold/operations/scaffold-maintenance.md +1 -1
- package/reference/scaffold/recipes/customize-crm-actions.md +1 -1
- package/reference/scaffold/recipes/extend-content.md +262 -14
- package/reference/scaffold/recipes/extend-crm.md +4 -2
- package/reference/scaffold/recipes/extend-lead-gen.md +34 -5
- package/reference/scaffold/ui/customization.md +5 -5
- package/reference/scaffold/ui/recipes.md +11 -15
- package/reference/sdk/platform-tools/adapters-integration.mdx +2 -1
- package/reference/sdk/platform-tools/adapters-platform.mdx +1 -1
- package/reference/sdk/platform-tools/index.mdx +7 -7
- package/reference/sdk/resources/index.mdx +8 -8
- package/reference/ui/exports.mdx +0 -1
|
@@ -51,23 +51,30 @@ A pipeline's step catalog is named `content:catalog/{pipelineId}-steps` and refe
|
|
|
51
51
|
| Add content nav or a content route | `CONTENT_ITEMS`, `ContentSidebar`, `ContentSidebarMiddle` | Same manifest/sidebar composition pattern as CRM and lead-gen. |
|
|
52
52
|
| Give producers a style guide or voice constraints | The generating workflow's own prompt | Content has no rules-document tier. Put the instructions where the model reads them. |
|
|
53
53
|
| Track where a piece was published | `createDistribution` / `updateDistribution` | One distribution row per platform per item. |
|
|
54
|
+
| Actually post an item to a platform | Section 6 — a publish panel of yours, over a prepared distribution row | Publishing is operating, so it is your screen. Instagram has a published workflow; do not copy it. |
|
|
54
55
|
| Pick source material for a new item | `createSourceAsset` / `getSourceAsset` / `listSourceAssets` / `updateSourceAsset` | Raw material a producer works from -- an uploaded episode, a transcript, a reference file. |
|
|
55
56
|
| Operate the pipeline from outside a browser | `elevasis-sdk content:*` | Read-only plus one write (`content:review`). Not how a workflow produces content -- see the boundary below. |
|
|
56
57
|
| Add a new persisted content column or table | Platform/API migration work, not just scaffold work | DB, core schemas/types, API service/handlers, hooks, docs, and scaffold contracts move together. |
|
|
57
58
|
|
|
58
59
|
## Published Content Surfaces
|
|
59
60
|
|
|
60
|
-
| Surface | Import from
|
|
61
|
-
| ---------------------------------------------------------------------------------------------------------------------- |
|
|
62
|
-
| `contentManifest`, `CONTENT_ITEMS`, `ContentSidebar`, `ContentSidebarMiddle`, `MyReviewQueuePanel` | `@elevasis/ui/features/content`
|
|
63
|
-
| `ContentOverviewPage`, `ContentItemsPage`, `ContentItemReviewPage`, `ContentPipelinesPage`, `ContentPipelineBoardPage` | `@elevasis/ui/features/content`
|
|
64
|
-
| `ContentDistributionsPage`, `ContentDistributionDetailPage` | `@elevasis/ui/features/content`
|
|
65
|
-
| `ContentReviewCard`, `ReviewActionBar`, `PayloadBody`, `AlternatesPanel`, `ProcessingStateStrip` | `@elevasis/ui/features/content`
|
|
66
|
-
| `useContentConfig`, `resolveContentStepResource` | `@elevasis/ui/features/content`
|
|
67
|
-
| `useContentItems`, `useContentItem`, `useContentItemAttempts`, `useUpdateContentItem`, `useReviewContentItem` | `@elevasis/ui/hooks`
|
|
68
|
-
| `useContentDistributions`, `useContentDistribution`, `useUpdateContentDistribution` | `@elevasis/ui/hooks`
|
|
69
|
-
| `useContentPipelineSummary` | `@elevasis/ui/hooks`
|
|
70
|
-
| `
|
|
61
|
+
| Surface | Import from | Use for |
|
|
62
|
+
| ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------------ |
|
|
63
|
+
| `contentManifest`, `CONTENT_ITEMS`, `ContentSidebar`, `ContentSidebarMiddle`, `MyReviewQueuePanel` | `@elevasis/ui/features/content` | Feature registration and sidebar composition |
|
|
64
|
+
| `ContentOverviewPage`, `ContentItemsPage`, `ContentItemReviewPage`, `ContentPipelinesPage`, `ContentPipelineBoardPage` | `@elevasis/ui/features/content` | Shared pages you can route to or wrap |
|
|
65
|
+
| `ContentDistributionsPage`, `ContentDistributionDetailPage` | `@elevasis/ui/features/content` | Distribution surfaces |
|
|
66
|
+
| `ContentReviewCard`, `ReviewActionBar`, `PayloadBody`, `AlternatesPanel`, `ProcessingStateStrip` | `@elevasis/ui/features/content` | Review UI primitives for a custom review screen |
|
|
67
|
+
| `useContentConfig`, `resolveContentStepResource` | `@elevasis/ui/features/content` | Read the resolved pipeline/step catalogs from OM |
|
|
68
|
+
| `useContentItems`, `useContentItem`, `useContentItemAttempts`, `useUpdateContentItem`, `useReviewContentItem` | `@elevasis/ui/hooks` | Item data access and review mutations |
|
|
69
|
+
| `useContentDistributions`, `useContentDistribution`, `useUpdateContentDistribution` | `@elevasis/ui/hooks` | Distribution data access |
|
|
70
|
+
| `useContentPipelineSummary` | `@elevasis/ui/hooks` | Pipeline roll-ups |
|
|
71
|
+
| `ContentWorkspaceShell`, `ContentAnalysisStepPanel`, `ContentStepPanelMap`, `ContentWorkspaceState` | `@elevasis/ui/features/content` | The workspace frame and its panel contract |
|
|
72
|
+
| `useExecuteAsync`, `useExecution`, `isExecutionInFlight`, `TERMINAL_EXECUTION_STATUSES` | `@elevasis/ui/hooks` | Start a publishing workflow and watch it finish |
|
|
73
|
+
| `useCreateContentDistribution`, `useUpdateContentDistribution` | `@elevasis/ui/hooks` | Prepare and record a post |
|
|
74
|
+
| `content` | `@elevasis/sdk/worker` | Workflow-side content adapter |
|
|
75
|
+
| `createPublishInstagramWorkflow`, `createInstagramAdapter` | `@elevasis/sdk/worker` | Post to Instagram from a workflow |
|
|
76
|
+
| `createMockInstagram` | `@elevasis/sdk/test-utils` | Test a publish pipeline without a real account |
|
|
77
|
+
| `defineContentPipeline`, `defineContentSystem` | `@elevasis/core/organization-model` | Declare a pipeline and derive the System block |
|
|
71
78
|
|
|
72
79
|
Read the generated contracts before changing typed boundaries:
|
|
73
80
|
|
|
@@ -341,8 +348,8 @@ Everything you need to build a combined create-and-review screen is already expo
|
|
|
341
348
|
`resolveContentStepResource`.
|
|
342
349
|
|
|
343
350
|
**`Workspace` is a fixed platform label and is not vocabulary-driven.** Rename the page, not the
|
|
344
|
-
section. (The section was called `Create` before 2026-08-15. `createItems`
|
|
345
|
-
deprecated alias
|
|
351
|
+
section. (The section was called `Create` before 2026-08-15. The `createItems` prop was renamed to
|
|
352
|
+
`workspaceItems`; the deprecated alias has since been removed, so `workspaceItems` is the only name.)
|
|
346
353
|
|
|
347
354
|
### Point the shared pages at your Workspace
|
|
348
355
|
|
|
@@ -418,13 +425,254 @@ rendering "Pipelines" here, and nothing fails to tell you.
|
|
|
418
425
|
Replace `contentManifest` with `customContentManifest` in the local `SYSTEM_MANIFESTS` array and add
|
|
419
426
|
the matching route under `ui/src/routes/content/`.
|
|
420
427
|
|
|
421
|
-
## 6.
|
|
428
|
+
## 6. Send It Out
|
|
429
|
+
|
|
430
|
+
Sections 1 through 5 get an item made and reviewed. This one covers the last step of a pipeline
|
|
431
|
+
that publishes: turning a finished item into a post on a platform.
|
|
432
|
+
|
|
433
|
+
Publishing is **operating**, so by the section 5 contract it is yours: a panel on your workspace,
|
|
434
|
+
not a shared page. The shared distribution pages display what went out and never write. What the
|
|
435
|
+
platform gives you is the distribution row, a way to start a workflow and watch it, and — for
|
|
436
|
+
Instagram — the publishing workflow itself.
|
|
437
|
+
|
|
438
|
+
### A panel is registered against a step key
|
|
439
|
+
|
|
440
|
+
`ContentWorkspaceShell` walks the pipeline from the deployed model and renders whichever panel
|
|
441
|
+
your map names for the active step. The map is keyed by **step key**, not by any convention on the
|
|
442
|
+
component:
|
|
443
|
+
|
|
444
|
+
```tsx
|
|
445
|
+
import { ContentAnalysisStepPanel, ContentWorkspaceShell } from '@elevasis/ui/features/content'
|
|
446
|
+
import type { ContentStepPanelMap } from '@elevasis/ui/features/content'
|
|
447
|
+
|
|
448
|
+
interface PostDraft {
|
|
449
|
+
platform: string | null
|
|
450
|
+
publishExecutionId: string | null
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const panels: ContentStepPanelMap<PostDraft> = {
|
|
454
|
+
analysis: ContentAnalysisStepPanel,
|
|
455
|
+
caption: CaptionStepPanel,
|
|
456
|
+
publish: PublishStepPanel
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export function WritePostPage() {
|
|
460
|
+
return (
|
|
461
|
+
<ContentWorkspaceShell
|
|
462
|
+
panels={panels}
|
|
463
|
+
initialDraft={{ platform: null, publishExecutionId: null }}
|
|
464
|
+
title="Write a Post"
|
|
465
|
+
/>
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
Every panel is called with the same `ContentWorkspaceState<TDraft>` — the item, its body, the
|
|
471
|
+
distribution row, `refetchDistributions`, step navigation, and your own `draft`. Anything matching
|
|
472
|
+
that signature is a panel. A step key with no entry in the map is reported rather than rendering
|
|
473
|
+
nothing, which is the reason the map is explicit instead of derived from the key.
|
|
474
|
+
|
|
475
|
+
`ContentAnalysisStepPanel` is the one step panel published today, because it needs an item id and
|
|
476
|
+
nothing else. A publish panel is not shippable the same way: it reaches a credential, a status
|
|
477
|
+
vocabulary, and a workflow id, all of which are yours to choose.
|
|
478
|
+
|
|
479
|
+
### Prepare the distribution row before posting
|
|
480
|
+
|
|
481
|
+
A distribution is one row per platform per item, and it is what the publishing workflow reads. It
|
|
482
|
+
must exist, and carry its media, **before** anything goes out:
|
|
483
|
+
|
|
484
|
+
```tsx
|
|
485
|
+
const createDistribution = useCreateContentDistribution()
|
|
486
|
+
|
|
487
|
+
await createDistribution.mutateAsync({
|
|
488
|
+
contentItemId: item.id,
|
|
489
|
+
platform,
|
|
490
|
+
format: 'carousel',
|
|
491
|
+
status: 'pending',
|
|
492
|
+
// The caption as it will go out. The row is the record of the post, not a pointer at an
|
|
493
|
+
// item whose body may be edited afterwards.
|
|
494
|
+
adaptedBody: body.trim().length > 0 ? body : null,
|
|
495
|
+
mediaUrls: renderedEntries
|
|
496
|
+
})
|
|
497
|
+
refetchDistributions()
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
The row freezing what goes out is the point: re-cropping an image after the fact must not quietly
|
|
501
|
+
change what the record says was posted. The corollary is that a row prepared before the caption was
|
|
502
|
+
written holds a stale caption — write the current body onto it at post time, while `publishedAt` is
|
|
503
|
+
still null and nothing has gone out yet.
|
|
504
|
+
|
|
505
|
+
### Reaching a publishing workflow
|
|
506
|
+
|
|
507
|
+
Start it async and watch it. Staging a carousel is one upload per image plus polling until the
|
|
508
|
+
platform reports each container finished, which is far longer than a request a page can hold open:
|
|
509
|
+
|
|
510
|
+
```tsx
|
|
511
|
+
const startPublish = useExecuteAsync()
|
|
512
|
+
const publishExecution = useExecution(publishWorkflowId, draft.publishExecutionId ?? '')
|
|
513
|
+
|
|
514
|
+
const started = await startPublish.mutateAsync({
|
|
515
|
+
resourceId: publishWorkflowId,
|
|
516
|
+
resourceType: 'workflow',
|
|
517
|
+
input: { distributionId: distribution.id }
|
|
518
|
+
})
|
|
519
|
+
setDraft({ publishExecutionId: started.executionId })
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
**Name the workflow; do not ask the model which one it is.** `resolveContentStepResource` returns
|
|
523
|
+
the first resource whose ontology claims the step's action, which is a coin flip once more than one
|
|
524
|
+
does. A workflow id is a decision your app makes — pass it as a prop or read it from your own
|
|
525
|
+
config.
|
|
526
|
+
|
|
527
|
+
**Use `isExecutionInFlight` for "is it still going", not `status === 'running'`.** `warning` is a
|
|
528
|
+
terminal status the platform picks for a run that succeeded while emitting warn-level logs, so a
|
|
529
|
+
`running` test treats a finished run as still in flight and a `completed`-only test never notices
|
|
530
|
+
it finished. Both are exported from `@elevasis/ui/hooks`:
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
import { isExecutionInFlight, TERMINAL_EXECUTION_STATUSES } from '@elevasis/ui/hooks'
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
`useExecution` already polls on that predicate, so a panel needs no poll of its own. One browser
|
|
537
|
+
caveat when you go to verify it: React Query pauses `refetchInterval` while `document.hidden`, so a
|
|
538
|
+
backgrounded tab measures zero requests against correct code.
|
|
539
|
+
|
|
540
|
+
### Instagram: use the published workflow, do not copy it
|
|
541
|
+
|
|
542
|
+
`createPublishInstagramWorkflow` takes a credential name and returns a registered workflow. That is
|
|
543
|
+
the whole of what is project-specific about posting to Instagram:
|
|
544
|
+
|
|
545
|
+
<!-- doc-snippet:skip: illustrative excerpt -- a project-local registration module -->
|
|
546
|
+
|
|
547
|
+
```ts
|
|
548
|
+
import { createPublishInstagramWorkflow } from '@elevasis/sdk/worker'
|
|
549
|
+
|
|
550
|
+
export const publishInstagramWorkflow = createPublishInstagramWorkflow({
|
|
551
|
+
credentialName: 'acme-instagram',
|
|
552
|
+
resourceId: 'cnt-publish-instagram-workflow'
|
|
553
|
+
})
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
The credential holds `{ accessToken, igUserId }` — the account id rides along with the token, so no
|
|
557
|
+
caller carries it. Given a `distributionId` the workflow signs each image, builds the containers,
|
|
558
|
+
publishes, and writes the returned post id and permalink back onto the same row. It does not move
|
|
559
|
+
the item's status: which status means "finished" is resolved against your own model by the surface
|
|
560
|
+
that owns the item, and deciding it twice is two answers that can disagree.
|
|
561
|
+
|
|
562
|
+
**It refuses rather than repairs, and that is why it is not yours to copy.** Three checks run before
|
|
563
|
+
anything reaches Instagram, each guarding an action that cannot be taken back:
|
|
564
|
+
|
|
565
|
+
| Refusal | Why it is a refusal |
|
|
566
|
+
| ---------------------------------------- | --------------------------------------------------------------------------- |
|
|
567
|
+
| the row's `platform` is not `instagram` | posting a row prepared for somewhere else posts the wrong thing |
|
|
568
|
+
| the row already carries `platformPostId` | only a real publish writes that field, so posting again duplicates the post |
|
|
569
|
+
| the row already carries `publishedAt` | someone recorded this as posted; posting now would post it twice |
|
|
570
|
+
| the row has no `mediaUrls` | there is nothing to post — render first |
|
|
571
|
+
|
|
572
|
+
To post again, create a new distribution. Nothing clears these.
|
|
573
|
+
|
|
574
|
+
A failed execution therefore generally means **nothing was posted**, and its own error message is
|
|
575
|
+
more specific than anything a panel could write — show `execution.error` rather than a generic line.
|
|
576
|
+
|
|
577
|
+
### Posting by hand
|
|
578
|
+
|
|
579
|
+
Not every platform has a workflow behind it, and the manual path needs no credential at all.
|
|
580
|
+
Record it on the same row:
|
|
581
|
+
|
|
582
|
+
```tsx
|
|
583
|
+
await updateDistribution.mutateAsync({
|
|
584
|
+
distributionId: distribution.id,
|
|
585
|
+
updates: {
|
|
586
|
+
status: 'published',
|
|
587
|
+
publishMethod: 'manual',
|
|
588
|
+
publishedAt: new Date().toISOString(),
|
|
589
|
+
...(isUsableUrl ? { platformUrl: typedUrl } : {})
|
|
590
|
+
}
|
|
591
|
+
})
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
`publishedAt` set with no `platformPostId` is the manual shape — do not invent an id no platform
|
|
595
|
+
returned. When you later ask how a post went out, test against `'manual'` rather than against an
|
|
596
|
+
API value: a publishing workflow writes the platform it posted through (`'instagram-api'`), so
|
|
597
|
+
"was this done by hand" is the question with one stable answer.
|
|
598
|
+
|
|
599
|
+
### Testing a publish pipeline
|
|
600
|
+
|
|
601
|
+
Mock the integration; do not point a test at a real account. `createMockInstagram` covers all eight
|
|
602
|
+
adapter methods:
|
|
603
|
+
|
|
604
|
+
<!-- doc-snippet:skip: illustrative excerpt -- vitest usage inside a project's own suite -->
|
|
605
|
+
|
|
606
|
+
```ts
|
|
607
|
+
import { createMockInstagram } from '@elevasis/sdk/test-utils'
|
|
608
|
+
|
|
609
|
+
const instagram = createMockInstagram('acme-instagram', {
|
|
610
|
+
// A publish sequence polls until the container reports FINISHED. Un-overridden, it never does.
|
|
611
|
+
getContainerStatus: ({ containerId }) => ({ containerId, statusCode: 'FINISHED', status: 'Finished' }),
|
|
612
|
+
publishContainer: { mediaId: 'media-1' }
|
|
613
|
+
})
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
## 7. Mark the System API-Ready
|
|
422
617
|
|
|
423
618
|
`content.apiInterface.lifecycle` goes `active` only when the System's scoped resources, `content:object/item`, and the pipeline/step/status catalogs are all in place. Two failure modes are worth knowing before you flip it:
|
|
424
619
|
|
|
425
620
|
- An **empty** `apiInterface.resourceIds` array throws rather than opting out. Omitting the whole `apiInterface` block is the opt-out; a `resourceIds: []` stub is the anomaly.
|
|
426
621
|
- Readiness is derived from a **deployed** snapshot. A model edit that has not been redeployed produces a stale-snapshot 503 that looks like a code bug. Redeploy before debugging.
|
|
427
622
|
|
|
623
|
+
### Or derive the whole block with `defineContentSystem`
|
|
624
|
+
|
|
625
|
+
`defineContentPipeline` (section 1) removes the per-pipeline duplication. What is left is the
|
|
626
|
+
surrounding boilerplate every content adopter writes identically: the `apiInterface` block, its
|
|
627
|
+
`readinessContract`, the `content:object/item` object type, and the status catalog. `defineContentSystem`
|
|
628
|
+
takes the pipelines and derives all four.
|
|
629
|
+
|
|
630
|
+
<!-- doc-snippet:skip: illustrative excerpt -- references project-local pipeline declarations -->
|
|
631
|
+
|
|
632
|
+
```ts
|
|
633
|
+
import { defineContentPipeline, defineContentSystem } from '@elevasis/core/organization-model'
|
|
634
|
+
|
|
635
|
+
const linkedInPost = defineContentPipeline({
|
|
636
|
+
systemPath: 'content',
|
|
637
|
+
id: 'linkedin-post',
|
|
638
|
+
label: 'LinkedIn Post',
|
|
639
|
+
workspaceRoute: '/content/write',
|
|
640
|
+
steps: [{ key: 'draft', actor: 'agent', review: 'required', resource: saveContentBatch }]
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
export const contentSystem = defineContentSystem({
|
|
644
|
+
systemPath: 'content',
|
|
645
|
+
resourceIds: ['save-content-batch', 'publish-linkedin'],
|
|
646
|
+
pipelines: [linkedInPost],
|
|
647
|
+
item: { label: 'Post', description: 'One LinkedIn post, from idea to distribution.' },
|
|
648
|
+
statuses: [
|
|
649
|
+
{ key: 'draft', label: 'Written', order: 10, semanticClass: 'active' },
|
|
650
|
+
{ key: 'posted', label: 'Posted', order: 20, semanticClass: 'completed' }
|
|
651
|
+
]
|
|
652
|
+
})
|
|
653
|
+
|
|
654
|
+
// Inside the content System:
|
|
655
|
+
// apiInterface: contentSystem.apiInterface
|
|
656
|
+
// ontology: { ...contentSystem.objectTypes, ...contentSystem.catalogTypes, ...yourOwn }
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
It emits `apiInterface` (with `readinessProfile: 'content.api'` and a `readinessContract` listing
|
|
660
|
+
the pipeline, every step catalog, and the status catalog), `objectTypes` carrying
|
|
661
|
+
`content:object/item`, and `catalogTypes` carrying the pipeline, step, and status catalogs. Your own
|
|
662
|
+
object types, action types, and per-adopter catalogs — pillar, platform, source-asset kind — stay
|
|
663
|
+
hand-authored alongside them.
|
|
664
|
+
|
|
665
|
+
**The contract is unchanged; only the boilerplate is gone.** Content is validated against a
|
|
666
|
+
declared `readinessContract` rather than a platform validator, and that is deliberate: a CRM
|
|
667
|
+
pipeline is a CRM pipeline, so platform code can hardcode what to check, while a content pipeline is
|
|
668
|
+
whatever its adopter declares. Making it built-in would hardcode one step catalog for every project.
|
|
669
|
+
`defineContentSystem` writes the contract for you; it does not remove it.
|
|
670
|
+
|
|
671
|
+
**`lifecycle` defaults to `'active'`, so calling this helper is itself the decision to serve the
|
|
672
|
+
API.** Pass `lifecycle: 'draft'` while the pipelines are declared but not yet served. The opt-out
|
|
673
|
+
above — omitting `apiInterface` entirely — means not calling `defineContentSystem` for that block at
|
|
674
|
+
all; there is no way to call it and get no marker.
|
|
675
|
+
|
|
428
676
|
## Verify
|
|
429
677
|
|
|
430
678
|
Run the checks for the surfaces you touched:
|
|
@@ -67,7 +67,7 @@ Deal list and detail responses include a server-derived `priority` object. Use `
|
|
|
67
67
|
For a simple nav addition, extend `CRM_ITEMS` and override the CRM system manifest:
|
|
68
68
|
|
|
69
69
|
```tsx
|
|
70
|
-
// ui/src/
|
|
70
|
+
// ui/src/config/shell.tsx
|
|
71
71
|
import { crmManifest, CRM_ITEMS, CrmSidebar, CrmSidebarMiddle } from '@elevasis/ui/features/crm'
|
|
72
72
|
import type { SystemModule } from '@elevasis/ui/provider'
|
|
73
73
|
import type { NavItem } from '@elevasis/ui/layout'
|
|
@@ -90,7 +90,9 @@ export const customCrmManifest: SystemModule = {
|
|
|
90
90
|
}
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
Then replace `crmManifest` with `customCrmManifest` in the
|
|
93
|
+
Then replace `crmManifest` with `customCrmManifest` in the `SYSTEM_MANIFESTS` array — which is declared in this same file, `ui/src/config/shell.tsx` — and add the matching route under `ui/src/routes/crm/`.
|
|
94
|
+
|
|
95
|
+
**Do this in `shell.tsx`, not in `ui/src/routes/__root.tsx`.** `__root.tsx` imports `SYSTEM_MANIFESTS` from `@/config/shell` and filters it through `selectDeclaredSystems`; it does not declare the array. It is also `replace`-category with a `replace-all` strategy, so anything you write into it is overwritten outright on the next sync -- not preserved, not merged, not flagged. `shell.tsx` is the seam that exists for exactly this edit.
|
|
94
96
|
|
|
95
97
|
For structural changes, compose `CrmSidebarTop`, `SubshellNavList`, `SubshellSidebarSection`, `MyTasksPanel`, and `QuickCreateActions`. The full sidebar decision tree lives in `operations/node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md`.
|
|
96
98
|
|
|
@@ -73,7 +73,7 @@ Look for the **Lead Gen Platform Primitives** section. It includes list shapes,
|
|
|
73
73
|
For a simple nav addition, extend `LEAD_GEN_ITEMS` and override the lead-gen system manifest:
|
|
74
74
|
|
|
75
75
|
```tsx
|
|
76
|
-
// ui/src/
|
|
76
|
+
// ui/src/config/shell.tsx
|
|
77
77
|
import { leadGenManifest, LEAD_GEN_ITEMS, LeadGenSidebar, LeadGenSidebarMiddle } from '@elevasis/ui/features/lead-gen'
|
|
78
78
|
import type { SystemModule } from '@elevasis/ui/provider'
|
|
79
79
|
import type { NavItem } from '@elevasis/ui/layout'
|
|
@@ -96,7 +96,9 @@ export const customLeadGenManifest: SystemModule = {
|
|
|
96
96
|
}
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
Then replace `leadGenManifest` with `customLeadGenManifest` in the
|
|
99
|
+
Then replace `leadGenManifest` with `customLeadGenManifest` in the `SYSTEM_MANIFESTS` array — which is declared in this same file, `ui/src/config/shell.tsx` — and add the matching route under `ui/src/routes/lead-gen/`.
|
|
100
|
+
|
|
101
|
+
**Do this in `shell.tsx`, not in `ui/src/routes/__root.tsx`.** `__root.tsx` imports `SYSTEM_MANIFESTS` from `@/config/shell` and filters it through `selectDeclaredSystems`; it does not declare the array. It is also `replace`-category with a `replace-all` strategy, so anything you write into it is overwritten outright on the next sync -- not preserved, not merged, not flagged. `shell.tsx` is the seam that exists for exactly this edit.
|
|
100
102
|
|
|
101
103
|
For structural changes, compose `LeadGenSidebarTop`, `SubshellNavList`, and `SubshellSidebarSection`. The full sidebar decision tree lives in `operations/node_modules/@elevasis/sdk/reference/scaffold/ui/customization.md`.
|
|
102
104
|
|
|
@@ -185,14 +187,18 @@ const App = createElevasisApp({
|
|
|
185
187
|
```
|
|
186
188
|
|
|
187
189
|
```tsx
|
|
188
|
-
// ui/src/routes/__root.tsx
|
|
190
|
+
// ui/src/routes/__root.tsx (sync-managed — shown for reference, not for editing)
|
|
189
191
|
import { ElevasisAuthenticatedShell } from '@elevasis/ui/app'
|
|
190
192
|
import { canonicalOrganizationModel } from '@core/config/organization-model'
|
|
193
|
+
import { selectDeclaredSystems } from '@elevasis/ui/provider'
|
|
194
|
+
import { SYSTEM_MANIFESTS } from '@/config/shell'
|
|
195
|
+
|
|
196
|
+
const DECLARED_SYSTEM_MANIFESTS = selectDeclaredSystems(SYSTEM_MANIFESTS, canonicalOrganizationModel)
|
|
191
197
|
|
|
192
|
-
|
|
198
|
+
function RootLayoutComponent() {
|
|
193
199
|
return (
|
|
194
200
|
<ElevasisAuthenticatedShell
|
|
195
|
-
systems={
|
|
201
|
+
systems={DECLARED_SYSTEM_MANIFESTS}
|
|
196
202
|
organizationModel={canonicalOrganizationModel}
|
|
197
203
|
// other shell config...
|
|
198
204
|
/>
|
|
@@ -264,6 +270,7 @@ const listActions: ListBuilderRegistry = [
|
|
|
264
270
|
}
|
|
265
271
|
]
|
|
266
272
|
|
|
273
|
+
// Declared in ui/src/config/shell.tsx and imported here.
|
|
267
274
|
const SYSTEM_MANIFESTS = [
|
|
268
275
|
leadGenManifest,
|
|
269
276
|
// Add any other shared/local system manifests here.
|
|
@@ -493,6 +500,28 @@ export const organizationModel = {
|
|
|
493
500
|
}
|
|
494
501
|
```
|
|
495
502
|
|
|
503
|
+
### Which authoring shape to use
|
|
504
|
+
|
|
505
|
+
Two shapes exist and the readiness profile decides which one you get.
|
|
506
|
+
|
|
507
|
+
**Adopting one of the platform's catalogued profiles** — `SYSTEM_INTERFACE_PROFILES` holds four: `sales.lead-gen.api`, `sales.crm.api`, and `sales.lead-gen.crm-handoff`, which are the three built-in-validated ones, plus `content.api`, which is contract-validated. All four go through the helper — use the `defineSystemApiInterface` helper from `@elevasis/core/organization-model`, not a hand-written literal. It is what `pnpm elevasis-sdk om:emit-api-interface` generates, so the helper keeps your hand-authored System and your scaffolded one the same shape:
|
|
508
|
+
|
|
509
|
+
<!-- doc-snippet:skip: illustrative excerpt, not a standalone compilable file -->
|
|
510
|
+
|
|
511
|
+
```ts
|
|
512
|
+
import { defineSystemApiInterface } from '@elevasis/core/organization-model'
|
|
513
|
+
|
|
514
|
+
export const prospectingApiInterface = defineSystemApiInterface({
|
|
515
|
+
systemPath: 'sales.lead-gen',
|
|
516
|
+
readinessProfile: 'sales.lead-gen.api',
|
|
517
|
+
resourceIds: ['acme-list-build-workflow', 'acme-list-export-workflow']
|
|
518
|
+
})
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
The helper throws at declaration time on the failure modes the literal lets through silently — most importantly an **empty `resourceIds`**, which otherwise computes as ready and then 503s every request. That is why `resourceIds` is typed `[string, ...string[]]`. **"No scoped resources" means omit the `apiInterface` block entirely**, never hand-write one with an empty list.
|
|
522
|
+
|
|
523
|
+
**Declaring a custom `readinessProfile`**, as the `acme.prospecting.api` block above does, the helper is not available to you: it validates `readinessProfile` against `SYSTEM_INTERFACE_PROFILES` — a platform-owned catalog in `@elevasis/core` — and throws on anything outside it. A custom profile therefore stays a hand-written literal, and its `readinessContract` is mandatory for the reason given above. Do not add your id to `SYSTEM_INTERFACE_PROFILES`; that is platform source, not tenant source.
|
|
524
|
+
|
|
496
525
|
`readinessContract.requiredObjects` and `requiredCatalogs` are arrays of ontology IDs owned by this system. The platform validates that each declared object type exists in the OM and that each declared catalog type has at least one entry. `requiredCatalogs` must declare at least one entry — an empty contract asserts nothing and is rejected.
|
|
497
526
|
|
|
498
527
|
Built-in profile ids (`sales.lead-gen.api`, etc.) derive their requirements from platform code. **A `readinessContract` declared alongside a built-in profile is ignored outright — not merely unnecessary.** The readiness engine branches on the profile: a registered built-in runs its own validator, and the authored contract is read only on the `else` branch, so anything you declare next to a built-in profile validates nothing and silently drifts from what the platform actually enforces. Real projects have shipped full contracts this way believing they were enforced.
|
|
@@ -28,10 +28,10 @@ There is one pattern for customizing a system's sidebar or pages: set `sidebar`
|
|
|
28
28
|
|
|
29
29
|
Extend CRM's nav by spreading `CRM_ITEMS` and appending a Reports entry. Pass the extended array to `CrmSidebarMiddle`.
|
|
30
30
|
|
|
31
|
-
Wire the override in `ui/src/routes/__root.tsx
|
|
31
|
+
Wire the override in `ui/src/config/shell.tsx`, the customization seam that owns the manifest list. `ui/src/routes/__root.tsx` imports `SYSTEM_MANIFESTS` from there and filters it through `selectDeclaredSystems` before mounting, so a manifest whose System the org model does not declare is dropped automatically.
|
|
32
32
|
|
|
33
33
|
```tsx
|
|
34
|
-
// ui/src/
|
|
34
|
+
// ui/src/config/shell.tsx (excerpt -- add after existing imports)
|
|
35
35
|
|
|
36
36
|
import { crmManifest, CrmSidebar, CrmSidebarMiddle, CRM_ITEMS } from '@elevasis/ui/features/crm'
|
|
37
37
|
import { IconFileText } from '@tabler/icons-react'
|
|
@@ -58,13 +58,13 @@ Then swap `crmManifest` for `customCrmManifest` in the `SYSTEM_MANIFESTS` array:
|
|
|
58
58
|
|
|
59
59
|
```tsx
|
|
60
60
|
// In the SYSTEM_MANIFESTS array (same file)
|
|
61
|
-
const SYSTEM_MANIFESTS: SystemModule[] = [
|
|
61
|
+
export const SYSTEM_MANIFESTS: SystemModule[] = [
|
|
62
62
|
leadGenManifest,
|
|
63
63
|
customCrmManifest, // <-- replaces crmManifest
|
|
64
64
|
deliveryManifest,
|
|
65
65
|
operationsManifest,
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
submittedRequestsManifest,
|
|
67
|
+
knowledgeManifest
|
|
68
68
|
]
|
|
69
69
|
```
|
|
70
70
|
|
|
@@ -15,7 +15,7 @@ Create `ui/src/routes/my-system.index.tsx`:
|
|
|
15
15
|
```tsx
|
|
16
16
|
import { createFileRoute } from '@tanstack/react-router'
|
|
17
17
|
import { ProtectedRoute } from '@/features/auth'
|
|
18
|
-
import {
|
|
18
|
+
import { AppPageLayout } from '@elevasis/ui/layout'
|
|
19
19
|
import { MySystemPage } from '@/features/my-system/components/MySystemPage'
|
|
20
20
|
|
|
21
21
|
export const Route = createFileRoute('/my-system/')({
|
|
@@ -25,18 +25,18 @@ export const Route = createFileRoute('/my-system/')({
|
|
|
25
25
|
function MySystemRouteComponent() {
|
|
26
26
|
return (
|
|
27
27
|
<ProtectedRoute>
|
|
28
|
-
<
|
|
29
|
-
<
|
|
30
|
-
|
|
31
|
-
<MySystemPage />
|
|
32
|
-
</PageContainer>
|
|
33
|
-
</AppShellContentContainer>
|
|
34
|
-
</AppTopbarAdjusterWrapper>
|
|
28
|
+
<AppPageLayout>
|
|
29
|
+
<MySystemPage />
|
|
30
|
+
</AppPageLayout>
|
|
35
31
|
</ProtectedRoute>
|
|
36
32
|
)
|
|
37
33
|
}
|
|
38
34
|
```
|
|
39
35
|
|
|
36
|
+
`AppPageLayout` is the standard route shell — topbar offset, the shell's padded content region, then the page container. It replaced the hand-written three-component nesting of `AppTopbarAdjusterWrapper` / `AppShellContentContainer` / `PageContainer`; do not write that nesting yourself. Pass `contained={false}` for a page that manages its own width (the monitoring dashboards do, since their charts run full-bleed) — that prop is the escape hatch, not a re-nest.
|
|
37
|
+
|
|
38
|
+
For a page that sits inside a **subshell sidebar**, use `SubshellPageLayout` from the same subpath instead. The two are mutually exclusive: `AppPageLayout` pushes the whole main region down, while the subshell applies the topbar offset to the scrolling right side only so the sidebar starts at the top. Nesting one in the other double-pads the page and breaks the `height: 100%` chain, so the inner scroll never engages. A subshell page that must run full-bleed renders `SubshellContentContainer` directly — there is deliberately no `contained` prop on `SubshellPageLayout`.
|
|
39
|
+
|
|
40
40
|
Add the sidebar entry as a system node in `core/config/organization-model.ts`:
|
|
41
41
|
|
|
42
42
|
`systems` is an id-keyed record, not an array, and `order` is required on every entry:
|
|
@@ -68,13 +68,9 @@ function MySystemRouteComponent() {
|
|
|
68
68
|
return (
|
|
69
69
|
<ProtectedRoute>
|
|
70
70
|
<AccessGuard accessKey="my-system">
|
|
71
|
-
<
|
|
72
|
-
<
|
|
73
|
-
|
|
74
|
-
<MySystemPage />
|
|
75
|
-
</PageContainer>
|
|
76
|
-
</AppShellContentContainer>
|
|
77
|
-
</AppTopbarAdjusterWrapper>
|
|
71
|
+
<AppPageLayout>
|
|
72
|
+
<MySystemPage />
|
|
73
|
+
</AppPageLayout>
|
|
78
74
|
</AccessGuard>
|
|
79
75
|
</ProtectedRoute>
|
|
80
76
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Integration Adapters"
|
|
3
|
-
description: "Auto-generated table of all
|
|
3
|
+
description: "Auto-generated table of all 14 integration (credential-bound) adapters exported from @elevasis/sdk/worker. Each row's methods are read from that adapter's METHODS array; the adapter set is the INTEGRATION_EXPORTS list in the generator, checked against the adapter directory on every run."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
{/* @generated by .claude/_gen/sync-sdk-adapters.ts — DO NOT EDIT */}
|
|
@@ -16,6 +16,7 @@ Integration adapters use a factory pattern. Call `create*Adapter(credential)` wi
|
|
|
16
16
|
| Dropbox | `createDropboxAdapter(credential)` | `uploadFile`, `createFolder`, `listFolder`, `getMetadata`, `getTemporaryLink`, `createSharedLink`, `download`, `getThumbnail`, `getThumbnailBatch` | Dropbox — upload files and create folders. |
|
|
17
17
|
| Gmail | `createGmailAdapter(credential)` | `sendEmail` | Gmail — send emails via a bound Gmail credential. |
|
|
18
18
|
| GoogleSheets | `createGoogleSheetsAdapter(credential)` | `readSheet`, `writeSheet`, `appendRows`, `clearRange`, `getSpreadsheetMetadata`, `batchUpdate`, `getHeaders`, `getLastRow`, `getRowByValue`, `updateRowByValue`, `upsertRow`, `filterRows`, `deleteRowByValue` | Google Sheets — read, write, append, filter, and manage spreadsheet data. |
|
|
19
|
+
| Instagram | `createInstagramAdapter(credential)` | `createMediaContainer`, `createCarouselContainer`, `publishContainer`, `getContainerStatus`, `getMediaPermalink`, `getPublishingLimit`, `getMediaInsights`, `refreshToken` | Instagram — Content Publishing container flow (create, poll, publish, permalink) plus media insights. |
|
|
19
20
|
| Instantly | `createInstantlyAdapter(credential)` | `sendReply`, `removeFromSubsequence`, `getEmails`, `updateInterestStatus`, `addToCampaign`, `listCampaigns`, `getCampaign`, `updateCampaign`, `pauseCampaign`, `activateCampaign`, `getCampaignAnalytics`, `getStepAnalytics`, `bulkAddLeads`, `getAccountHealth`, `createInboxTest`, `createCampaign`, `getDailyCampaignAnalytics`, `listLeads`, `bulkDeleteLeads`, `deleteCampaign`, `patchLead` | Instantly — manage email outreach campaigns, leads, analytics, and inbox health. |
|
|
20
21
|
| MillionVerifier | `createMillionVerifierAdapter(credential)` | `verifyEmail`, `checkCredits` | MillionVerifier — verify email deliverability and check account credits. |
|
|
21
22
|
| Anymailfinder | `createAnymailfinderAdapter(credential)` | `findCompanyEmail`, `findPersonEmail`, `findDecisionMakerEmail`, `verifyEmail` | Anymailfinder — find and verify company and person email addresses. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Platform Adapters"
|
|
3
|
-
description: "Auto-generated table of all 14 platform (singleton, no credential) adapters exported from @elevasis/sdk/worker
|
|
3
|
+
description: "Auto-generated table of all 14 platform (singleton, no credential) adapters exported from @elevasis/sdk/worker. Each row's methods are read from that adapter's METHODS array; the adapter set is the PLATFORM_EXPORTS list in the generator, checked against the adapter directory on every run."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
{/* @generated by .claude/_gen/sync-sdk-adapters.ts — DO NOT EDIT */}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Platform Tools
|
|
3
|
-
description: Access
|
|
3
|
+
description: Access 28 adapters (14 integration + 14 platform) from your SDK workflows -- typed adapters, credential security model, and working code examples
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Your SDK workflows have access to
|
|
6
|
+
Your SDK workflows have access to 28 adapters (14 integration + 14 platform) -- Gmail, Stripe, Google Sheets, PDF generation, human-in-the-loop approvals, storage, scheduling, and more. Credentials are managed server-side and never appear in your code.
|
|
7
7
|
|
|
8
8
|
**Typed adapters** are the recommended way to call tools. They provide full TypeScript autocomplete, compile-time method checking, and eliminate boilerplate. Use `platform.call()` only for tools that don't have an adapter yet.
|
|
9
9
|
|
|
@@ -43,7 +43,7 @@ Both patterns return a Promise that resolves with the tool result or rejects wit
|
|
|
43
43
|
|
|
44
44
|
## Integration Adapters
|
|
45
45
|
|
|
46
|
-
The SDK ships
|
|
46
|
+
The SDK ships 14 integration adapters (credential-bound factory functions) covering third-party APIs -- Attio, Apify, ClickUp, Dropbox, Gmail, Google Sheets, Instagram, Instantly, MillionVerifier, Anymailfinder, Tomba, Resend, SignatureAPI, and Stripe. Pass the credential name once at adapter creation. Supabase is covered separately under [Database Access](#database-access) below.
|
|
47
47
|
|
|
48
48
|
For the full per-adapter method tables, credential shapes, and code examples, see [Integration Adapters](adapters-integration.mdx) -- generated from the adapter source so it never drifts.
|
|
49
49
|
|
|
@@ -130,9 +130,9 @@ Credentials are created in the command center UI: navigate to Credentials -> Add
|
|
|
130
130
|
|
|
131
131
|
## Platform Services
|
|
132
132
|
|
|
133
|
-
The SDK ships
|
|
133
|
+
The SDK ships 14 platform service singletons available without a `credential` field -- imported directly from `@elevasis/sdk/worker`: `scheduler`, `llm`, `storage`, `notifications`, `acqDb`, `projects`, `crm`, `list`, `pdf`, `approval`, `execution`, `email`, `artifacts`, and `content`. The platform injects context server-side, so no credential is passed.
|
|
134
134
|
|
|
135
|
-
For the full per-service method tables (including the `acqDb`
|
|
135
|
+
For the full per-service method tables (including the `acqDb` 60-method surface), see [Platform Adapters](adapters-platform.mdx) -- generated from the adapter source.
|
|
136
136
|
|
|
137
137
|
## LLM Tool
|
|
138
138
|
|
|
@@ -195,8 +195,8 @@ const qualified = await platform.call({
|
|
|
195
195
|
|
|
196
196
|
## Documentation
|
|
197
197
|
|
|
198
|
-
- [Integration Adapters](adapters-integration.mdx) - All
|
|
199
|
-
- [Platform Adapters](adapters-platform.mdx) - All
|
|
198
|
+
- [Integration Adapters](adapters-integration.mdx) - All 14 integration adapters with method tables and code examples
|
|
199
|
+
- [Platform Adapters](adapters-platform.mdx) - All 14 platform service adapters with method tables and code examples
|
|
200
200
|
- [Adapter Type Safety](type-safety.mdx) - Required fields, discriminated unions, and intentionally loose adapter types
|
|
201
201
|
|
|
202
202
|
---
|
|
@@ -325,14 +325,14 @@ const myAgent: AgentDefinition = {
|
|
|
325
325
|
|
|
326
326
|
### config (agent-specific fields)
|
|
327
327
|
|
|
328
|
-
| Field | Type | Description
|
|
329
|
-
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
330
|
-
| `kind` | `'orchestrator' | 'specialist' | 'utility' | 'platform'` | Required. What role this agent plays — not enforced at runtime today, but tenant-authored and validated at deploy against your OM resource descriptor's own `kind`.
|
|
331
|
-
| `systemPrompt` | `string` | Required. The agent's base system prompt.
|
|
332
|
-
| `constraints` | `{ maxIterations?, timeout?, maxSessionMemoryKeys?, maxMemoryTokens? }` (optional) | Iteration budget, execution timeout in ms, and session-memory limits.
|
|
333
|
-
| `sessionCapable` | `boolean` (optional) | Opt in to multi-turn sessions. Defaults to `false` — the shape used in the example above, which completes and returns `contract.outputSchema` in a single turn.
|
|
334
|
-
| `securityLevel` | `'standard' | 'hardened' | 'none'` (optional) | Prompt-hardening tier. Auto-derived from `sessionCapable` when omitted (`true` → `'hardened'`, `false` → `'standard'`).
|
|
335
|
-
| `memoryPreferences` | `string` (optional) | Guidance injected into the system prompt when session memory management is enabled.
|
|
328
|
+
| Field | Type | Description |
|
|
329
|
+
| ------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
330
|
+
| `kind` | `'orchestrator' | 'specialist' | 'utility' | 'platform'` | Required. What role this agent plays — not enforced at runtime today, but tenant-authored and validated at deploy against your OM resource descriptor's own `kind`. |
|
|
331
|
+
| `systemPrompt` | `string` | Required. The agent's base system prompt. |
|
|
332
|
+
| `constraints` | `{ maxIterations?, timeout?, maxSessionMemoryKeys?, maxMemoryTokens? }` (optional) | Iteration budget, execution timeout in ms, and session-memory limits. |
|
|
333
|
+
| `sessionCapable` | `boolean` (optional) | Opt in to multi-turn sessions. Defaults to `false` — the shape used in the example above, which completes and returns `contract.outputSchema` in a single turn. |
|
|
334
|
+
| `securityLevel` | `'standard' | 'hardened' | 'none'` (optional) | Prompt-hardening tier. Auto-derived from `sessionCapable` when omitted (`true` → `'hardened'`, `false` → `'standard'`). `'none'` disables prompt hardening. It is a deliberate explicit opt-in, valid even for a session-capable agent when that agent's surface has no untrusted-input boundary to defend. |
|
|
335
|
+
| `memoryPreferences` | `string` (optional) | Guidance injected into the system prompt when session memory management is enabled. |
|
|
336
336
|
|
|
337
337
|
### contract (agent)
|
|
338
338
|
|
package/reference/ui/exports.mdx
CHANGED
|
@@ -56,7 +56,6 @@ description: "Auto-generated catalog of all published @elevasis/ui subpath expor
|
|
|
56
56
|
| `@elevasis/ui/provider/ElevasisServiceContext` | Elevasis Service Context | Provider | Standalone service context and provider that supplies apiRequest, organizationId, and isReady to child components. |
|
|
57
57
|
| `@elevasis/ui/hooks/delivery` | Hooks Delivery | Hooks | Published delivery hooks for projects, milestones, tasks, and notes. |
|
|
58
58
|
| `@elevasis/ui/hooks/user-notes` | Hooks User Notes | Hooks | Published user-notes query and mutation hooks used by shared Notes surfaces. |
|
|
59
|
-
| `@elevasis/ui/hooks/operations/command-view/utils/transformCommandViewData` | Transform Command View Data | Hooks | Utility that transforms backend CommandViewData arrays into a unified frontend CommandViewGraph with nodes and edges. |
|
|
60
59
|
| `@elevasis/ui/test-utils` | Test Utils | Testing | Published rendering helpers, auth mocks, MSW handlers, and test provider utilities. |
|
|
61
60
|
| `@elevasis/ui/test-utils/setup` | Test Utils Setup | Testing | Vitest setup file for UI consumers using browser mocks and MSW. |
|
|
62
61
|
| `@elevasis/ui/test-utils/setup-integration` | Test Utils Integration Setup | Testing | Vitest setup file for integration tests that avoid MSW and use real network boundaries. |
|