{"_id":"@openai/mcp-extensions","name":"@openai/mcp-extensions","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@openai/mcp-extensions","version":"0.1.0","description":"OpenAI extensions for MCP servers and apps.","type":"module","exports":{"./app":{"types":"./dist/app/index.d.ts","import":"./dist/app/index.js"},"./app/styles.css":"./styles.css","./server":{"types":"./dist/server/index.d.ts","import":"./dist/server/index.js"},"./app/transport":{"types":"./dist/app/transport.d.ts","import":"./dist/app/transport.js"}},"sideEffects":["*.css"],"dependencies":{"zod":"4.4.3","@cfworker/json-schema":"^4.1.1"},"peerDependencies":{"@modelcontextprotocol/ext-apps":"^1.7.5","@modelcontextprotocol/sdk":"^1.29.0"},"peerDependenciesMeta":{"@modelcontextprotocol/ext-apps":{"optional":true}},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/openai/mcp-extensions.git","directory":"typescript"},"engines":{"node":">=22"},"devDependencies":{"@modelcontextprotocol/ext-apps":"^1.7.5","@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"registry":"https://registry.npmjs.org/","access":"public"},"scripts":{"build":"tsc -p tsconfig.json","types":"tsc --noEmit","package:check":"publint"},"_id":"@openai/mcp-extensions@0.1.0","bugs":{"url":"https://github.com/openai/mcp-extensions/issues"},"homepage":"https://github.com/openai/mcp-extensions#readme","_integrity":"sha512-AkQ7hRS9DSUTBHgwVwd+BO6yh1y75SldqNTt8YISUnJODKD3Esg+zC2mq96FMmgzCTV7VRykkgzBzkF6W1zkdw==","_resolved":"/Users/jbeckwith/Documents/Codex/2026-09-25/work/mcp-extensions-launch-import/outputs/release-36603941964-node/node/package.tgz","_from":"file:outputs/release-36603941964-node/node/package.tgz","_nodeVersion":"25.8.1","_npmVersion":"11.19.0","dist":{"integrity":"sha512-AkQ7hRS9DSUTBHgwVwd+BO6yh1y75SldqNTt8YISUnJODKD3Esg+zC2mq96FMmgzCTV7VRykkgzBzkF6W1zkdw==","shasum":"ded1953da5e2222be8bfeb9f066e49751bf75289","tarball":"https://registry.npmjs.org/@openai/mcp-extensions/-/mcp-extensions-0.1.0.tgz","fileCount":46,"unpackedSize":187864,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDlfM/s4hc+g5zUNAmKxo7P4Wz9oE4bLRDzMMr+rMWDvAiB0Tvuhhssi9ApvnL3HYXNu4yHYjaOikVVT5jyL5ofisA=="}]},"_npmUser":{"name":"jbeckwith-oai","email":"jbeckwith@openai.com"},"directories":{},"maintainers":[{"name":"openai-publisher","email":"oai-package-publish-npm@openai.com"},{"name":"tino-openai","email":"tino@openai.com"},{"name":"dylan-hurd-openai","email":"dylan.hurd@openai.com"},{"name":"moustafa-openai","email":"moustafa@openai.com"},{"name":"tylersmith-openai","email":"tylersmith@openai.com"},{"name":"mdangelo-openai","email":"mdangelo@openai.com"},{"name":"victor-openai","email":"victor@openai.com"},{"name":"jbeckwith-oai","email":"jbeckwith@openai.com"},{"name":"wadih-openai","email":"wadih@openai.com"},{"name":"atty-openai","email":"atty@openai.com"},{"name":"tibo-openai","email":"tibo@openai.com"},{"name":"dkundel-openai","email":"dkundel@openai.com"},{"name":"mbolin-openai","email":"mbolin@openai.com"},{"name":"fouad-openai","email":"fouad@openai.com"},{"name":"easong-openai","email":"easong@openai.com"},{"name":"aibrahim-openai","email":"ahmedibrhm32@gmail.com"},{"name":"apcha-oai","email":"apcha@openai.com"},{"name":"seratch-openai","email":"seratch@openai.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-extensions_0.1.0_1790702803578_0.3988049097415405"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-29T17:26:43.323Z","0.1.0":"2026-09-29T17:26:43.786Z","modified":"2026-09-29T17:26:43.965Z"},"maintainers":[{"name":"openai-publisher","email":"oai-package-publish-npm@openai.com"},{"name":"tino-openai","email":"tino@openai.com"},{"name":"dylan-hurd-openai","email":"dylan.hurd@openai.com"},{"name":"moustafa-openai","email":"moustafa@openai.com"},{"name":"tylersmith-openai","email":"tylersmith@openai.com"},{"name":"mdangelo-openai","email":"mdangelo@openai.com"},{"name":"victor-openai","email":"victor@openai.com"},{"name":"jbeckwith-oai","email":"jbeckwith@openai.com"},{"name":"wadih-openai","email":"wadih@openai.com"},{"name":"atty-openai","email":"atty@openai.com"},{"name":"tibo-openai","email":"tibo@openai.com"},{"name":"dkundel-openai","email":"dkundel@openai.com"},{"name":"mbolin-openai","email":"mbolin@openai.com"},{"name":"fouad-openai","email":"fouad@openai.com"},{"name":"easong-openai","email":"easong@openai.com"},{"name":"aibrahim-openai","email":"ahmedibrhm32@gmail.com"},{"name":"apcha-oai","email":"apcha@openai.com"},{"name":"seratch-openai","email":"seratch@openai.com"}],"description":"OpenAI extensions for MCP servers and apps.","homepage":"https://github.com/openai/mcp-extensions#readme","repository":{"type":"git","url":"git+https://github.com/openai/mcp-extensions.git","directory":"typescript"},"bugs":{"url":"https://github.com/openai/mcp-extensions/issues"},"license":"Apache-2.0","readme":"# OpenAI MCP Extensions for TypeScript and JavaScript\n\nThis SDK provides TypeScript APIs that extend the official [@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk) and [@modelcontextprotocol/ext-apps](https://www.npmjs.com/package/@modelcontextprotocol/ext-apps) SDKs to make it easier to implement the [OpenAI MCP Extensions spec](../docs/spec.md) for TypeScript MCP Servers and MCP Apps.\n\nUse `@openai/mcp-extensions/server` for server code and `@openai/mcp-extensions/app` for app code. This SDK and README contain examples that run in MCP Apps and on MCP Servers. You can identify where a given code block should be used from its imports.\n\n## Installation\n\nInstall the SDK from npm:\n\n```sh\npnpm add @openai/mcp-extensions\n```\n\n## MCP Server Setup\n\nEnable OpenAI extensions for an MCP Server created with the MCP TypeScript SDK.\n\n```ts\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/server\";\n\nconst server = new McpServer({ name: \"my-server\", version: \"1.0.0\" });\nconst openaiExtensions = new OpenAIExtensions(server);\n```\n\n## MCP App Setup\n\nEnable OpenAI extensions for an MCP App.\n\n```ts\nimport { App } from \"@modelcontextprotocol/ext-apps\";\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst app = new App({ name: \"my-app\", version: \"1.0.0\" });\nconst openaiExtensions = new OpenAIExtensions(app);\n\napp.ontoolresult = (result) => render(result.structuredContent);\nawait app.connect();\n```\n\nRegister `app.ontoolresult` before `app.connect()` to render the initial result instead of calling the tool again, which delays rendering and causes visible flicker.\n\nOpenAI extension categories (`message`, `modelContext`, `files`, and `resources`) are set as fields on `openaiExtensions`. They are undefined until initialization completes. If a given extension is unsupported on the current host, it may remain undefined even after initialization.\n\n## App Styling\n\nMCP Apps work best when they match the look and feel of ChatGPT. To help with this, this SDK provides a stylesheet you can use to make your components feel more native.\n\nApply the host’s theme and styles when your app connects and whenever they change.\n\n```ts\nimport {\n  App,\n  applyDocumentTheme,\n  applyHostStyleVariables,\n} from \"@modelcontextprotocol/ext-apps\";\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\nimport \"@openai/mcp-extensions/app/styles.css\";\n\nconst app = new App({ name: \"my-app\", version: \"1.0.0\" });\nconst openaiExtensions = new OpenAIExtensions(app);\n\nfunction applyHostContext(context: ReturnType<App[\"getHostContext\"]>): void {\n  if (context?.theme != null) applyDocumentTheme(context.theme);\n  if (context?.styles?.variables != null) {\n    applyHostStyleVariables(context.styles.variables);\n  }\n}\n\napp.addEventListener(\"hostcontextchanged\", applyHostContext);\napp.ontoolresult = (result) => render(result.structuredContent);\nawait app.connect();\napplyHostContext(app.getHostContext());\n```\n\nStyle a card with a labeled input and button using the app stylesheet.\n\n```html\n<section class=\"card\">\n  <h2>New issue</h2>\n  <label class=\"form-label\" for=\"title\">Title</label>\n  <input class=\"form-control\" id=\"title\" placeholder=\"What needs attention?\" />\n  <button class=\"btn btn-primary\" type=\"button\">Create issue</button>\n</section>\n```\n\nSee [styles.css](styles.css) for the available styles. Use wrappers for app-specific layout to preserve the controls' appearance.\n\nChatGPT Desktop lets users choose `default` or `pointer` for interactive controls. To match that setting in your app, use the `cursor-interaction` CSS class. If the host omits its cursor preference or sends an unsupported value, the cursor defaults to `pointer`.\n\n```html\n<button class=\"cursor-interaction\" type=\"button\">Run</button>\n```\n\nBundle or inline the CSS in your app's HTML. The default iframe CSP can block external stylesheets. Without a frontend build, extract `package/styles.css` from the release tarball and inline it in your app resource.\n\nFor a complete React plugin, see [the Bits & Bolts sidebar and file viewer](../plugins/bits-and-bolts/README.md).\n\n## [UI Entrypoints](../docs/spec.md#mcp-app-entrypoints)\n\n```ts\nimport {\n  RESOURCE_MIME_TYPE,\n  registerAppResource,\n  registerAppTool,\n} from \"@modelcontextprotocol/ext-apps/server\";\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/server\";\nimport type {\n  OpenAIUiResourceMetadata,\n  OpenAIUiToolMetadata,\n} from \"@openai/mcp-extensions/server\";\n\nconst TABLE_URI = \"ui://table/viewer\";\n\nregisterAppResource(server, \"table\", TABLE_URI, {}, async () => ({\n  contents: [\n    {\n      uri: TABLE_URI,\n      mimeType: RESOURCE_MIME_TYPE,\n      text: TABLE_HTML,\n      _meta: {\n        \"openai/ui\": {\n          preferredDisplayMode: \"fullscreen\",\n          availableDisplayModes: [\"inline\", \"fullscreen\"],\n        } satisfies OpenAIUiResourceMetadata,\n      },\n    },\n  ],\n}));\n\nregisterAppTool(\n  server,\n  \"table.open\",\n  {\n    icons: [\n      {\n        src: \"https://example.com/cad-library.svg\",\n        mimeType: \"image/svg+xml\",\n        sizes: [\"any\"],\n      },\n    ],\n    _meta: {\n      ui: { resourceUri: TABLE_URI, visibility: [\"app\"] },\n      \"openai/ui\": {\n        // Include one or more entrypoints.\n        entrypoints: [\n          {\n            type: \"global\",\n            quickAction: {\n              title: \"New table\",\n              icons: [{ src: \"https://example.com/plus.svg\" }],\n              target: { type: \"tool\", name: \"create_table\", arguments: {} },\n            },\n          },\n          { type: \"file\", extensions: [\".csv\", \".tsv\"] },\n          { type: \"settings\", searchTerms: [\"tables\", \"spreadsheet\"] },\n        ],\n      } satisfies OpenAIUiToolMetadata,\n    },\n  },\n  async () => ({ content: [] }),\n);\n```\n\n## [File Extension Handlers](../docs/spec.md#file-extension-entrypoint)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\nimport { OpenAIFileEntrypointInputSchema } from \"@openai/mcp-extensions/app\";\n\nconst openaiExtensions = new OpenAIExtensions(app);\n\napp.addEventListener(\"toolinput\", async ({ arguments: args }) => {\n  const input = OpenAIFileEntrypointInputSchema.safeParse(args);\n  if (!input.success) {\n    return;\n  }\n\n  if (openaiExtensions.resources == null) {\n    return;\n  }\n  const resource = await openaiExtensions.resources.read({\n    uri: input.data.file.resourceUri,\n  });\n  const content = resource.contents[0];\n});\n\n// Register before connecting so the initial tool input is not missed.\nawait app.connect();\n```\n\n### [Resource Metadata](../docs/spec.md#resource-writes)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst resource = await openaiExtensions.resources?.read({\n  uri: resourceUri,\n});\n\nconst content = resource?.contents[0];\nif (content?.openaiMetadata) {\n  const { etag, writable } = content.openaiMetadata;\n  console.log({ etag, writable });\n}\n```\n\n### [Resource Representation](../docs/spec.md#resourcesread-representation)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst resource = await openaiExtensions.resources?.read({\n  uri: resourceUri,\n  representation: \"blob\",\n});\n\nconst content = resource?.contents[0];\nconst blob = content != null && \"blob\" in content ? content.blob : null;\n```\n\n### [Resource Subscriptions](../docs/spec.md#resource-subscriptions)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst disposeUpdateHandler = openaiExtensions.resources?.addUpdateHandler(\n  async ({ params }) => {\n    if (params.uri === resourceUri) {\n      await reloadFile(resourceUri);\n    }\n  },\n);\n\nawait openaiExtensions.resources?.subscribe({ uri: resourceUri });\n\n// Stop receiving updates when the file is no longer being viewed.\ndisposeUpdateHandler?.();\nawait openaiExtensions.resources?.unsubscribe({ uri: resourceUri });\n```\n\n### [Resource Writes](../docs/spec.md#resource-writes)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst resource = await openaiExtensions.resources?.read({\n  uri: resourceUri,\n});\nconst metadata = resource?.contents[0]?.openaiMetadata;\n\nif (metadata?.writable) {\n  const result = await openaiExtensions.resources?.write(resourceUri, {\n    text: updatedText,\n    ...(metadata.etag == null ? {} : { ifMatch: metadata.etag }),\n  });\n\n  switch (result?.outcome) {\n    case \"saved\":\n      break;\n    case \"conflict\":\n      await reloadFile(resourceUri);\n      break;\n    case \"too-large\":\n      showError(`File exceeds the ${result.maxBytes}-byte write limit.`);\n  }\n}\n```\n\n## [Structured Settings](../docs/spec.md#structured-settings)\n\n```ts\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/server\";\nimport { z } from \"zod\";\n\nimport { loadPreferences, updatePreferences } from \"./preferences.js\";\n\nconst server = new McpServer({ name: \"viewer\", version: \"1.0.0\" });\nconst extensions = new OpenAIExtensions(server);\nextensions.settings?.register({\n  fields: {\n    units: {\n      schema: z.enum([\"mm\", \"in\"]),\n      title: \"Measurement units\",\n    },\n    showGrid: {\n      schema: z.boolean(),\n      title: \"Show grid\",\n    },\n  },\n  // Optionally arrange fields into groups.\n  // Omitted properties are included in an \"Other settings\" group below all listed groups.\n  layout: [\n    {\n      kind: \"group\",\n      title: \"Display\",\n      items: [\n        { kind: \"property\", property: \"units\" },\n        { kind: \"property\", property: \"showGrid\" },\n      ],\n    },\n  ],\n  read: (extra) => loadPreferences(extra.authInfo),\n  update: (set, extra) => updatePreferences(set, extra.authInfo),\n});\n```\n\n## [Deep Links](../docs/spec.md#deep-links)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst openaiExtensions = new OpenAIExtensions(app);\n\nfunction applyDeepLink(url: string): void {\n  // Validate the app-specific route, then update the app's navigation state.\n  console.log({ url });\n}\n\nfunction handleDeepLink(): void {\n  const deepLink = openaiExtensions.deepLink.getCurrent();\n  if (deepLink === undefined) {\n    return;\n  }\n\n  applyDeepLink(deepLink.url);\n}\n\napp.addEventListener(\"hostcontextchanged\", handleDeepLink);\nawait app.connect();\nhandleDeepLink();\n```\n\n## [ui/update-model-context](../docs/spec.md#context-changed-notifications)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst openaiExtensions = new OpenAIExtensions(app);\n\nfunction syncCart(): void {\n  const current = openaiExtensions.modelContext?.getCurrent();\n  if (current !== undefined) {\n    const items = current?.structuredContent?.items;\n    restoreCart(\n      Array.isArray(items)\n        ? items.filter((item): item is string => typeof item === \"string\")\n        : [],\n    );\n  }\n}\n\napp.addEventListener(\"hostcontextchanged\", syncCart);\nawait app.connect();\nsyncCart();\n\nconst modelContext = openaiExtensions.modelContext;\nif (modelContext != null) {\n  const items = [\"Coffee\", \"Tea\"];\n  const update = await modelContext.update({\n    content: [\n      {\n        type: \"text\",\n        text: `Selected shopping cart items: ${items.join(\", \")}.`,\n      },\n    ],\n    structuredContent: { items },\n  });\n\n  console.log(update?.updateId);\n}\n```\n\n## [ui/message](../docs/spec.md#uimessage-extensions)\n\nSend app content without changing the user's existing draft.\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst openaiExtensions = new OpenAIExtensions(app);\nawait app.connect();\n\nconst message = openaiExtensions.message;\nif (message != null) {\n  await message.send({\n    role: \"user\",\n    content: [{ type: \"text\", text: \"Compare the items in my shopping cart.\" }],\n  });\n}\n```\n\n## [Opening Local Files](../docs/spec.md#opening-local-files)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst openaiExtensions = new OpenAIExtensions(app);\nawait app.connect();\n\nawait openaiExtensions.files?.open(\"/workspace/docs/index.html\");\n```\n\n## [Filesystem Access](../docs/spec.md#filesystem-access)\n\n**MCP App**\n\nRead a related file through a server tool using a path relative to the opened file.\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/app\";\n\nconst result = await app.callServerTool({\n  name: \"files.read-relative\",\n  arguments: { relativePath: \"./Callout.tsx\" },\n});\n\nif (result.isError) {\n  throw new Error(\"Unable to read the related file.\");\n}\nconst content = result.content.find((item) => item.type === \"text\");\nif (content == null) {\n  throw new Error(\"The tool did not return text.\");\n}\nconst text = content.text;\n```\n\n**MCP Server**\n\nRead files relative to an opened file while keeping access within its directory.\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/server\";\nimport { getResourcePath } from \"@openai/mcp-extensions/server\";\nimport { readFile, realpath } from \"node:fs/promises\";\nimport { dirname, isAbsolute, relative, resolve, sep } from \"node:path\";\nimport { z } from \"zod\";\n\nfunction isWithin(baseDirectory: string, candidatePath: string): boolean {\n  const pathWithinBase = relative(baseDirectory, candidatePath);\n  return (\n    pathWithinBase !== \"..\" &&\n    !pathWithinBase.startsWith(`..${sep}`) &&\n    !isAbsolute(pathWithinBase)\n  );\n}\n\nserver.registerTool(\n  \"files.read-relative\",\n  {\n    inputSchema: {\n      relativePath: z.string(),\n    },\n  },\n  async ({ relativePath }, extra) => {\n    const openedFilePath = getResourcePath(extra._meta);\n\n    if (openedFilePath == null) {\n      throw new Error(\"Missing resource path.\");\n    }\n\n    try {\n      const baseDirectory = await realpath(dirname(openedFilePath));\n      const requestedPath = resolve(baseDirectory, relativePath);\n      if (!isWithin(baseDirectory, requestedPath)) {\n        throw new Error();\n      }\n\n      const siblingPath = await realpath(requestedPath);\n      if (!isWithin(baseDirectory, siblingPath)) {\n        throw new Error();\n      }\n\n      const text = await readFile(siblingPath, \"utf8\");\n      return { content: [{ type: \"text\", text }] };\n    } catch {\n      // Do not expose the host filesystem path to the app.\n      throw new Error(\"Unable to read the requested file.\");\n    }\n  },\n);\n```\n\n## [Composer Mentions](../docs/spec.md#composer-at-mentions)\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/server\";\n\nopenaiExtensions.mentions.setHandler(async ({ query }) => ({\n  items: await searchMentions({ query }),\n}));\n```\n\n## [Form Elicitation](../docs/spec.md#openai-form-elicitation)\n\n**NOTE:** OpenAI-registered MCP servers require [MRTR for form elicitation](../docs/spec.md#openai-form-elicitation). Direct MCP connections still support legacy forms through `elicitInput`, which does not implement MRTR.\n\n### Suggested Values\n\nUsers can enter values that are not listed. The same field constraints apply to suggested and entered values.\n\n```ts\nimport type { OpenAIForm } from \"@openai/mcp-extensions/server\";\n\nconst reviewSchema = {\n  type: \"object\",\n  properties: {\n    purpose: {\n      type: \"string\",\n      minLength: 1,\n      \"x-openai-suggestions\": [{ const: \"prototype\", title: \"Prototype\" }],\n    },\n    checks: {\n      type: \"array\",\n      items: {\n        type: \"string\",\n        minLength: 1,\n        \"x-openai-suggestions\": [{ const: \"clearance\", title: \"Clearance\" }],\n      },\n    },\n  },\n} satisfies OpenAIForm;\n```\n\n### Resource Selection\n\n```ts\nimport { OpenAIExtensions } from \"@openai/mcp-extensions/server\";\n\nconst result = await openaiExtensions.elicitInput({\n  mode: \"form\",\n  message: \"Choose reference images\",\n  requestedSchema: {\n    type: \"object\",\n    properties: {\n      images: {\n        type: \"array\",\n        items: { type: \"string\", format: \"uri\" },\n        maxItems: 5,\n        default: [\"file:///images/sales.png\"],\n        \"x-openai-input\": {\n          type: \"resource\",\n          options: [\n            {\n              uri: \"file:///images/sales.png\",\n              name: \"sales.png\",\n              title: \"Sales image\",\n              _meta: {\n                \"openai/thumbnail\": { src: \"https://example.com/sales.png\" },\n                \"openai/preview\": {\n                  target: {\n                    type: \"resource_link\",\n                    uri: \"file:///images/sales.png\",\n                    name: \"sales.png\",\n                    mimeType: \"image/png\",\n                  },\n                },\n              },\n            },\n          ],\n          userOptions: { accept: [\"image/*\"] },\n        },\n      },\n    },\n    required: [\"images\"],\n  },\n});\n\nif (result.action === \"accept\") {\n  await createPresentation({ images: result.content.images });\n}\n```\n","readmeFilename":"README.md","_rev":"1-2efa4df07b1157516d4116700541be31"}