Configurazione del widget (EDS)

IMPORTANT
Adobe LLM Apps è attualmente in Beta.
Le funzioni, i flussi di lavoro e l’interfaccia utente mostrati qui non rappresentano necessariamente lo stato finale del prodotto. Per partecipare al Beta, invia un’e-mail a llm-apps-beta@adobe.com.

Questa guida spiega come creare un widget EDS end-to-end: dalla configurazione dell’azione nell’interfaccia utente LLM Apps alla configurazione del progetto EDS, alla scrittura del codice di blocco che esegue il rendering dei dati all’interno della piattaforma LLM. Per una panoramica di alto livello, vedi Concetti di base.

Il SDK LLM Apps

Tutto inizia con il pacchetto @adobe/llmapps-sdk npm. SDK è la libreria JavaScript che alimenta il canale di comunicazione bidirezionale tra il widget e l’host LLM.

Il SDK invia anche aem-embed.js, il punto di ingresso specifico per EDS che collega SDK alla pipeline di blocchi EDS standard. Quando npm install @adobe/llmapps-sdk, uno script di post-installazione copia automaticamente due file nel progetto:

scripts/
└── llm-apps/
    ├── aem-embed.js     ← EDS widget entry point, ships with the SDK
    └── llmapps-sdk.js   ← core SDK, loaded internally by aem-embed.js

Nei progetti EDS, non utilizzi mai SDK direttamente nel codice di blocco. aem-embed.js crea e gestisce la connessione SDK e passa un’istanza LLMApp completamente connessa al blocco come argomento bridge in decorate(block, bridge). L’API SDK completa è disponibile su bridge. Non è necessaria alcuna importazione.

Se si sta creando un widget senza EDS (un bundler standard o un progetto TypeScript), è possibile utilizzare direttamente SDK:

import { LLMApp } from '@adobe/llmapps-sdk';

const app = new LLMApp({ appInfo: { name: 'MyWidget', version: '1.0.0' } });
await app.connect();

const { structuredContent } = await app.toolResult;

Come si combina tutto

Quando l’IA chiama l’azione e il gestore restituisce structuredContent, la piattaforma LLM esegue il rendering di un widget interattivo nella conversazione. Tre fattori rendono possibile il funzionamento congiunto:

Interfaccia utente LLM Apps: quando crei un’azione, immetti un URL script e un URL widget nella scheda Metadati widget. L’URL dello script punta a aem-embed.js, il file che viene fornito con SDK e risiede nell’archivio EDS in scripts/llm-apps/aem-embed.js. Indica alla piattaforma LLM quale script caricare quando viene richiamata l’azione.

aem-embed.js — la piattaforma LLM carica questo script in una superficie di widget in modalità sandbox. aem-embed.js è un elemento HTML personalizzato (<aem-embed>) che funge da punto di ingresso compatibile con EDS per il widget. Esegue l’handshake con l’host LLM utilizzando SDK, sopprime la normale pipeline della pagina EDS (senza intestazione/piè di pagina), recupera il contenuto della pagina EDS dall’URL del widget, esegue la pipeline del blocco EDS e distribuisce un oggetto bridge attivo alla funzione decorate() di ciascun blocco.

Codice blocco: si scrive un blocco EDS standard che esporta una funzione decorate(block, bridge). bridge è l’istanza di SDK connessa. Fornisce il risultato strutturato dell’azione e consente di inviare nuovamente messaggi alla conversazione.

Aggiungi a un progetto EDS esistente

Se disponi già di un progetto EDS, sono disponibili solo due passaggi prima di poter iniziare a scrivere blocchi.

  1. Installa @adobe/llmapps-sdk. Lo script di post-installazione copia aem-embed.js e llmapps-sdk.js in scripts/llm-apps/:

    code language-bash
    npm install @adobe/llmapps-sdk
    
  2. Configura le intestazioni CORS in modo che la piattaforma LLM possa caricare le pagine widget e gli script tra origini diverse. Vedi Configurare le intestazioni CORS di seguito.

Quindi crea il blocco seguendo il contratto decorate(block, bridge), crea la pagina del widget e immetti gli URL nella finestra di dialogo Crea azione.

Imposta un nuovo progetto EDS

Creare l’archivio

  1. Crea un nuovo archivio GitHub basato sul modello AEM boilerplate.

  2. Aggiungi l’app GitHub di sincronizzazione codice AEM all’archivio.

  3. Installare AEM CLI per lo sviluppo locale: npm install -g @adobe/aem-cli.

  4. Installa @adobe/llmapps-sdk. Lo script di post-installazione copia aem-embed.js e llmapps-sdk.js in scripts/llm-apps/:

    code language-bash
    npm install @adobe/llmapps-sdk
    

Per una guida completa sui progetti EDS, consulta l’esercitazione per sviluppatori di AEM e l’anatomia del progetto.

Una volta configurato, il sito EDS sarà disponibile all’indirizzo:

  • Anteprima: https://main--<repo>--<owner>.aem.page/
  • Live: https://main--<repo>--<owner>.aem.live/

Struttura dell’archivio

my-brand-eds/
├── scripts/
│   ├── llm-apps/
│   │   ├── aem-embed.js           # Widget entry point — copied by post-install
│   │   └── llmapps-sdk.js         # Core SDK — copied by post-install
│   ├── aem.js                     # AEM core library
│   └── scripts.js                 # Site-level decoration and loading
├── blocks/
│   └── search-products/           # One folder per widget block
│       ├── search-products.js
│       └── search-products.css
├── styles/
│   └── styles.css
├── head.html
└── package.json

Configurare le intestazioni CORS

Le pagine dei widget EDS vengono caricate all’interno di una superficie di widget in modalità sandbox dalla piattaforma LLM. Il sito EDS deve restituire access-control-allow-origin intestazioni corrette in modo che l’host possa recuperare il contenuto del widget da un’origine all’altra.

Le intestazioni vengono configurate tramite il pannello di amministrazione di AEM in admin.hlx.page utilizzando il servizio di configurazione. Aggiungi intestazioni di risposta personalizzate per i percorsi in cui risiedono le pagine dei widget e gli script di SDK:

{
  "/<your-widget-pages-path>/**": [
    { "key": "access-control-allow-origin", "value": "*" }
  ],
  "/scripts/**": [
    { "key": "access-control-allow-origin", "value": "*" }
  ]
}
NOTE
L'utilizzo di * come valore di origine è accettabile per il contenuto del widget pubblico nel dominio .aem.live. Se il sito contiene contenuto protetto, limita l’origine a domini specifici.

Creare la pagina del widget

Creare una pagina nello strumento di creazione EDS e aggiungervi il blocco. L’URL della pagina diventa l’URL widget configurato nell’azione, ovvero l’unica connessione tra l’azione e il blocco. Non esiste alcun requisito di denominazione tra il blocco e il nome dell’azione.

Authoring EDS - blocco aggiunto alla pagina widget

Immetti gli URL nella finestra di dialogo Crea azione

Dopo aver configurato l’archivio EDS, vai a URL modello → metadati widget durante la creazione dell’azione:

URL script — punta a aem-embed.js nell’archivio EDS. Questo è lo stesso valore per ogni azione nello stesso progetto EDS:

https://main--<repo>--<owner>.aem.live/scripts/llm-apps/aem-embed.js

URL widget: URL della pagina EDS creata per questo widget. Univoco per azione:

https://main--<repo>--<owner>.aem.live/<path-to-your-widget-page>

La piattaforma LLM carica aem-embed.js dall’URL dello script. aem-embed.js recupera quindi .plain.html dall’URL del widget per ottenere il contenuto del blocco.

Flusso di dati

Percorso completo dal gestore a un widget di cui è stato eseguito il rendering:

  1. Il gestore azioni restituisce structuredContent:
// actions/search-products/index.js
return {
  structuredContent: {
    products: [
      { id: 'COF-001', name: 'Single Origin Ethiopian Coffee', price: '$18', rating: 4.7 },
      { id: 'COF-002', name: 'Colombia Huila Natural', price: '$22', rating: 4.5 },
    ],
    total: 2,
    category: 'coffee'
  }
};
  1. La piattaforma LLM apre una superficie di widget e carica aem-embed.js dall’URL dello script.

  2. aem-embed.js si connette all’host tramite SDK, recupera .plain.html dall’URL del widget, esegue la pipeline del blocco EDS e chiama decorate(block, bridge) sul blocco.

  3. Il blocco legge i dati da bridge.toolResult ed esegue il rendering dell’interfaccia utente.

  4. L’interazione utente attiva bridge.sendMessage(...) o bridge.callTool(...), inviando un follow-up alla conversazione.

Il contratto decorate(block, bridge)

Ogni blocco di widget EDS deve esportare una funzione decorate predefinita. Questa è la firma di blocco EDS standard, estesa con un secondo argomento, bridge connesso, che è un’istanza SDK LLMApp con l’API completa disponibile:

export default async function decorate(block, bridge) {
  // ...
}

bridge è presente solo quando viene eseguito all’interno della superficie del widget della piattaforma LLM. Proteggi sempre le chiamate bridge in modo che il blocco venga riprodotto anche quando viene visualizzata in anteprima direttamente in un browser o nel server di sviluppo locale.

Rendering dei dati dal risultato dell’azione

bridge.toolResult è una promessa che risolve con il risultato completo restituito dal gestore, incluso structuredContent.

const SAMPLE_PRODUCTS = [
  { id: 'COF-001', name: 'Single Origin Ethiopian Coffee', price: '$18', rating: 4.7 },
];

export default async function decorate(block, bridge) {
  let products = SAMPLE_PRODUCTS;

  if (bridge) {
    const result = await bridge.toolResult;
    products = result?.structuredContent?.products ?? [];
  }

  block.innerHTML = products.map(p => `
    <div class="product-card">
      <h3>${p.name}</h3>
      <p class="price">${p.price}</p>
      <button data-id="${p.id}">Tell me more</button>
    </div>
  `).join('');
}

Applicazione del tema host

Chiamare bridge.applyHostStyles() all’inizio di decorate per inserire nel widget le variabili e i font CSS dell’host (tema chiaro/scuro, tipografia). In questo modo il widget rimane visivamente coerente con l’interfaccia utente della piattaforma LLM circostante.

export default async function decorate(block, bridge) {
  if (bridge) {
    bridge.applyHostStyles();
  }
  // ...
}

Per reagire alle modifiche del tema in fase di runtime (ad esempio, quando l’utente passa dalla modalità chiara alla modalità scura):

if (bridge) {
  bridge.onContextChange(ctx => {
    block.dataset.theme = ctx.theme; // 'light' | 'dark'
  });
}

Invio di un messaggio di completamento

bridge.sendMessage(text) inserisce un messaggio utente nella conversazione. Questo è il modo principale in cui un widget attiva un’ulteriore interazione di intelligenza artificiale, ad esempio quando un utente fa clic su una scheda del prodotto per richiedere i dettagli.

block.querySelectorAll('button[data-id]').forEach(btn => {
  btn.addEventListener('click', () => {
    bridge.sendMessage(`Show me details for product ${btn.dataset.id}`);
  });
});

Chiamata diretta di un’altra azione

bridge.callTool(name, args) richiama un’altra azione dall’interno del widget senza passare attraverso un messaggio utente. Utile per caricare dati correlati su richiesta.

btn.addEventListener('click', async () => {
  const result = await bridge.callTool('get-product-details', { id: product.id });
  renderDetails(result.structuredContent);
});

Ridimensionamento automatico del widget

La piattaforma LLM ridimensiona il widget in base a ciò che viene riportato. Utilizza bridge.autoResize(element) per mantenere sincronizzata l’altezza del widget man mano che il contenuto cambia, usa un ResizeObserver internamente. Chiamalo dopo il rendering iniziale:

export default async function decorate(block, bridge) {
  // ... render content ...

  if (bridge) {
    bridge.autoResize(block);
  }
}

In alternativa, puoi segnalare manualmente una dimensione fissa:

bridge.reportSize(block.offsetWidth, block.offsetHeight);

Modalità Anteprima e sviluppo locale

Quando si visualizza in anteprima una pagina EDS direttamente in un browser o sul server di sviluppo locale, bridge è undefined. Utilizza il pattern di fallback dei dati di esempio mostrato qui sopra in modo che il blocco venga eseguito immediatamente senza un gestore live.

Per avviare un server di sviluppo locale:

npm install -g @adobe/aem-cli
aem up

Verrà aperto http://localhost:3000, in cui è possibile passare alle pagine del widget e visualizzare i blocchi di rendering con dati di esempio. Le modifiche apportate al blocco JS e CSS vengono applicate immediatamente.

Passaggi successivi

recommendation-more-help
llm-apps-help-main-toc