@adobe/llm-apps-runtime 0.2.0 → 0.4.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.
- package/README.md +21 -7
- package/package.json +6 -2
- package/src/analytics.js +3 -3
- package/src/index.js +5 -6
- package/src/local.js +33 -6
package/README.md
CHANGED
|
@@ -71,25 +71,39 @@ When `moduleContext` is provided, the webpack path is used. Otherwise the filesy
|
|
|
71
71
|
|
|
72
72
|
**Returns** `{ main }` — an async function compatible with Adobe I/O Runtime's action signature.
|
|
73
73
|
|
|
74
|
-
### `createLocalServer(main, port)`
|
|
74
|
+
### `createLocalServer(main, port, extraParams)`
|
|
75
75
|
|
|
76
76
|
Starts a plain Node.js HTTP server that wraps a `main(params)` function. Useful for `npm run dev:local` in consumer apps — no Adobe credentials required.
|
|
77
77
|
|
|
78
78
|
```js
|
|
79
|
-
const { createLocalServer } = require('@adobe/llm-apps-runtime')
|
|
79
|
+
const { createLocalServer, parseParamArgs } = require('@adobe/llm-apps-runtime/local')
|
|
80
80
|
const { main } = require('./dist/index.js') // your webpack bundle
|
|
81
|
-
|
|
81
|
+
const extraParams = parseParamArgs(process.argv) // --param KEY=VALUE flags
|
|
82
|
+
createLocalServer(main, process.env.PORT || 9080, extraParams)
|
|
82
83
|
```
|
|
83
84
|
|
|
84
85
|
**Parameters**
|
|
85
86
|
|
|
86
|
-
| Parameter
|
|
87
|
-
|
|
88
|
-
| `main`
|
|
89
|
-
| `port`
|
|
87
|
+
| Parameter | Type | Default | Description |
|
|
88
|
+
|---------------|----------|---------|-------------|
|
|
89
|
+
| `main` | Function | — | The `main(params)` function returned by `createMain`. |
|
|
90
|
+
| `port` | number | `9080` | Port to listen on. |
|
|
91
|
+
| `extraParams` | object | `{}` | Key-value pairs merged into every request's `params`, simulating Adobe I/O Runtime action params. |
|
|
90
92
|
|
|
91
93
|
**Returns** an [`http.Server`](https://nodejs.org/api/http.html#class-httpserver) instance.
|
|
92
94
|
|
|
95
|
+
#### Passing action params locally
|
|
96
|
+
|
|
97
|
+
In production, Adobe I/O Runtime merges action params (set via `aio app deploy --param`) into the `params` object that `main()` receives alongside the request. Locally there is no runtime, so you pass them on the command line using the same `--param KEY=VALUE` syntax:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
node server/local.js \
|
|
101
|
+
--param MY_API_URL=http://localhost:3000 \
|
|
102
|
+
--param MY_API_KEY=dev-secret
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`parseParamArgs(process.argv)` reads these flags and passes them to `createLocalServer` as `extraParams`. Every inbound request then receives them as top-level `params` fields, so any param-reading code in your action works identically to the deployed runtime.
|
|
106
|
+
|
|
93
107
|
### Action loading primitives
|
|
94
108
|
|
|
95
109
|
Exported from the package root for advanced use cases (custom loaders, integration tests):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/llm-apps-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Server runtime for Adobe LLM Apps — a platform for building AI tools and interactive widgets on Adobe I/O Runtime",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -42,5 +42,9 @@
|
|
|
42
42
|
"serverless",
|
|
43
43
|
"i/o-runtime"
|
|
44
44
|
],
|
|
45
|
-
"license": "SEE LICENSE IN LICENSE"
|
|
45
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/Adobe-AIFoundations/llm-apps-runtime.git"
|
|
49
|
+
}
|
|
46
50
|
}
|
package/src/analytics.js
CHANGED
|
@@ -13,7 +13,7 @@ governing permissions and limitations under the License.
|
|
|
13
13
|
/**
|
|
14
14
|
* Per-invocation analytics buffering + signed batch flush.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
16
|
+
* Adobe I/O Runtime freezes containers after `main()` returns, so we cannot fire-and-forget
|
|
17
17
|
* HTTP from one invocation and have it complete in the next. The wrapper buffers
|
|
18
18
|
* events in a per-invocation array, then performs a single awaited POST at
|
|
19
19
|
* end-of-request. One MCP request that triggers N tool calls = one HTTP round-trip
|
|
@@ -25,7 +25,7 @@ governing permissions and limitations under the License.
|
|
|
25
25
|
* Cost model: this code runs inside the customer's Adobe I/O Runtime namespace
|
|
26
26
|
* and consumes the customer's App Builder Pack entitlement (6M GB-s/year). The
|
|
27
27
|
* 500 ms hard timeout caps the customer's billable activation extension at
|
|
28
|
-
* ~600 ms (rounded up to the nearest 100 ms by
|
|
28
|
+
* ~600 ms (rounded up to the nearest 100 ms by Adobe I/O Runtime billing). The circuit
|
|
29
29
|
* breaker exists primarily to protect the customer's GB-s budget when ingest
|
|
30
30
|
* is slow or unhealthy — load-shedding for the customer's wallet, not just for
|
|
31
31
|
* our service.
|
|
@@ -85,7 +85,7 @@ function safeSize (value) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
/**
|
|
88
|
-
* Read analytics config from
|
|
88
|
+
* Read analytics config from Adobe I/O Runtime action params. Returns null when
|
|
89
89
|
* any required field is missing; the wrapper short-circuits to a no-op
|
|
90
90
|
* so unconfigured deploys cost zero network calls.
|
|
91
91
|
*/
|
package/src/index.js
CHANGED
|
@@ -207,8 +207,6 @@ function createMain (options = {}) {
|
|
|
207
207
|
|
|
208
208
|
logger?.info('MCP request processed by SDK')
|
|
209
209
|
|
|
210
|
-
await flushAnalyticsSafe(analyticsConfig)
|
|
211
|
-
|
|
212
210
|
return {
|
|
213
211
|
statusCode: response.status,
|
|
214
212
|
headers: {
|
|
@@ -225,10 +223,6 @@ function createMain (options = {}) {
|
|
|
225
223
|
|
|
226
224
|
try { server.close() } catch (e) { /* ignore cleanup errors */ }
|
|
227
225
|
|
|
228
|
-
// Flush whatever we managed to buffer before the failure so
|
|
229
|
-
// partial telemetry isn't lost on the error path.
|
|
230
|
-
await flushAnalyticsSafe(analyticsConfig)
|
|
231
|
-
|
|
232
226
|
return {
|
|
233
227
|
statusCode: 500,
|
|
234
228
|
headers: {
|
|
@@ -241,6 +235,11 @@ function createMain (options = {}) {
|
|
|
241
235
|
id: null
|
|
242
236
|
})
|
|
243
237
|
}
|
|
238
|
+
} finally {
|
|
239
|
+
// Flush on every exit path — success, error, or unexpected throw.
|
|
240
|
+
// In JS, finally runs before the pending return resolves, so the
|
|
241
|
+
// POST completes before the Adobe I/O Runtime container freezes.
|
|
242
|
+
await flushAnalyticsSafe(analyticsConfig)
|
|
244
243
|
}
|
|
245
244
|
}
|
|
246
245
|
|
package/src/local.js
CHANGED
|
@@ -18,21 +18,47 @@ governing permissions and limitations under the License.
|
|
|
18
18
|
*
|
|
19
19
|
* Usage in consumer app server/local.js:
|
|
20
20
|
*
|
|
21
|
-
* const { createLocalServer } = require('@adobe/llm-apps-runtime')
|
|
21
|
+
* const { createLocalServer, parseParamArgs } = require('@adobe/llm-apps-runtime/local')
|
|
22
22
|
* const { main } = require('../dist/index.js') // webpack bundle
|
|
23
|
-
*
|
|
23
|
+
* const extraParams = parseParamArgs(process.argv) // --param KEY=VALUE flags
|
|
24
|
+
* createLocalServer(main, process.env.PORT || 9080, extraParams)
|
|
24
25
|
*/
|
|
25
26
|
|
|
26
27
|
const http = require('http')
|
|
27
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Parse --param KEY=VALUE pairs from an argv array, mirroring the grammar
|
|
31
|
+
* used by `aio app deploy --param`. Returns a plain object. Entries that
|
|
32
|
+
* do not contain '=' or have an empty key are silently skipped.
|
|
33
|
+
*
|
|
34
|
+
* @param {string[]} argv process.argv (or any argv-style array)
|
|
35
|
+
* @returns {object}
|
|
36
|
+
*/
|
|
37
|
+
function parseParamArgs (argv) {
|
|
38
|
+
const out = {}
|
|
39
|
+
for (let i = 2; i < argv.length; i++) {
|
|
40
|
+
if (argv[i] === '--param' && argv[i + 1]) {
|
|
41
|
+
const eq = argv[i + 1].indexOf('=')
|
|
42
|
+
if (eq > 0) {
|
|
43
|
+
out[argv[i + 1].slice(0, eq)] = argv[i + 1].slice(eq + 1)
|
|
44
|
+
}
|
|
45
|
+
i++
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out
|
|
49
|
+
}
|
|
50
|
+
|
|
28
51
|
/**
|
|
29
52
|
* Start a local HTTP server that routes plain HTTP requests to an MCP main() function.
|
|
30
53
|
*
|
|
31
|
-
* @param {Function} main
|
|
32
|
-
* @param {number} port
|
|
54
|
+
* @param {Function} main The main(params) function returned by createMain
|
|
55
|
+
* @param {number} port Port to listen on (default 9080)
|
|
56
|
+
* @param {object} extraParams Optional action params to inject into every request,
|
|
57
|
+
* simulating Adobe I/O Runtime action params (e.g. LLMA_ANALYTICS_*).
|
|
58
|
+
* Use parseParamArgs(process.argv) to populate from --param flags.
|
|
33
59
|
* @returns {http.Server}
|
|
34
60
|
*/
|
|
35
|
-
function createLocalServer (main, port) {
|
|
61
|
+
function createLocalServer (main, port, extraParams = {}) {
|
|
36
62
|
// Use ?? (not ||) so an explicit 0 (ephemeral port, useful for tests) is honored.
|
|
37
63
|
const listenPort = port ?? 9080
|
|
38
64
|
|
|
@@ -43,6 +69,7 @@ function createLocalServer (main, port) {
|
|
|
43
69
|
const rawBody = Buffer.concat(chunks).toString('utf8')
|
|
44
70
|
|
|
45
71
|
const params = {
|
|
72
|
+
...extraParams, // simulate Adobe I/O Runtime action params
|
|
46
73
|
__ow_method: req.method.toLowerCase(),
|
|
47
74
|
__ow_path: req.url,
|
|
48
75
|
__ow_body: rawBody || undefined,
|
|
@@ -88,4 +115,4 @@ function createLocalServer (main, port) {
|
|
|
88
115
|
return server
|
|
89
116
|
}
|
|
90
117
|
|
|
91
|
-
module.exports = { createLocalServer }
|
|
118
|
+
module.exports = { createLocalServer, parseParamArgs }
|