Sviluppo development
Questa sezione descrive la struttura del progetto del gestore, il flusso di lavoro di sviluppo locale e la configurazione di test per Adobe LLM Apps. Per il contratto del gestore e il codice di esempio, vedere Scrivere il gestore azioni.
Struttura del progetto
L’archivio collegato segue questo layout:
your-llm-app/
├── entry.js # Webpack entry — do not modify
├── actions/ # One folder per action
│ ├── search-products/
│ │ └── index.js # Handler (async function)
│ ├── get-product-details/
│ │ └── index.js
│ └── echo/
│ └── index.js
├── test/
│ ├── actions/
│ │ └── search-products.test.js
│ ├── fixtures/
│ │ └── actions.json
│ ├── html-transform.js
│ ├── jest.setup.js
│ └── server.test.js
├── server/
│ └── local.js # Local dev server (port 9080)
├── actions.json # Gitignored — local copy of UI metadata
├── app.config.yaml # Adobe I/O Runtime config
├── webpack.config.js
└── package.json
Punti chiave:
entry.jsè il punto di ingresso del webpack. Al momento della compilazione, rileva ogni fileactions/*/index.jse lo raggruppa in un singolodist/index.js. Non modificare.actions.jsonè ignorato. Scaricala dalla pagina Azioni nell’interfaccia utente per lo sviluppo locale. Per le distribuzioni, la pipeline lo scrive automaticamente dall’API.- I test sono attivi in
test/actions/, non inactions/. Webpack racchiude tutto ciò che si trova inactions/nell’artefatto distribuito. I test di co-localizzazione verrebbero inviati a Adobe I/O Runtime.
Sviluppo locale
Puoi sviluppare e testare i gestori localmente senza credenziali Adobe:
npm install
npm run dev:local
In questo modo viene creato il progetto con Webpack e viene avviato un server HTTP Node.js semplice su http://localhost:9080. Il server rileva automaticamente i file del gestore in actions/ e li registra come strumenti MCP.
Scarica actions.json
Affinché il server locale sia a conoscenza dei metadati dell’azione (nome, descrizione, schema di input), scaricare actions.json dalla pagina Azioni nell’interfaccia utente di LLM Apps e inserirlo nella directory principale dell’archivio. Senza di esso, il server individua i gestori ma li registra con metadati minimi.
È inoltre possibile copiare actions.example.json in actions.json come punto di partenza.
Test con curl
# List all registered tools
curl -sX POST "http://localhost:9080" \
-H 'content-type: application/json' \
-H 'accept: application/json;q=1.0, text/event-stream;q=0.5' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
# Call the search-products action
curl -sX POST "http://localhost:9080" \
-H 'content-type: application/json' \
-H 'accept: application/json;q=1.0, text/event-stream;q=0.5' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search-products","arguments":{"category":"bagged-coffee"}}}'
Test con MCP Inspector
npx @modelcontextprotocol/inspector
Imposta Transport Type su streamable-http e URL su http://localhost:9080.
Test
Gli unit test del gestore risiedono in test/actions/ e rispecchiano il layout actions/:
// test/actions/search-products.test.js
const handler = require('../../actions/search-products/index.js')
test('returns all products when no filter is given', async () => {
const result = await handler({})
expect(result.content[0].text).toContain('product')
expect(result.structuredContent.products.length).toBeGreaterThan(0)
})
test('filters by category', async () => {
const result = await handler({ category: 'bagged-coffee' })
expect(result.structuredContent.products.every(
(p) => p.category === 'bagged-coffee'
)).toBe(true)
})
test('filters by query', async () => {
const result = await handler({ query: 'dark-roast' })
expect(result.structuredContent.products.length).toBeGreaterThan(0)
})
test('returns empty result for unknown category', async () => {
const result = await handler({ category: 'nonexistent' })
expect(result.structuredContent.products).toHaveLength(0)
})
Esegui test con:
npm test # all tests
npx jest test/actions/search-products # one action only
Distribuzione
Non generare o distribuire manualmente. Per informazioni dettagliate sulla pipeline di distribuzione, vedere Distribuire l’app.
Il flusso di lavoro quotidiano è:
actions/<name>/index.jsnpm run dev:localgit push