{"record":{"id":"ec672499a679a8ae","repo":"paperclipai/paperclip","slug":"acpx-runtime-does-not-expose-extension-requests","errorCode":null,"errorMessage":"ACPX runtime does not expose extension requests","messagePattern":"ACPX runtime does not expose extension requests","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/acpx/codex-runtime-adapter.ts","lineNumber":1106,"sourceCode":"      return await persistedRuntimeStatus(sessionStore, handle, identity);\n    },\n    goalCapability() {\n      return goalState.capability === null\n        ? null\n        : structuredClone(goalState.capability);\n    },\n    goalSnapshot() {\n      return goalState.snapshot === null\n        ? null\n        : structuredClone(goalState.snapshot);\n    },\n    async controlGoal(action, objective) {\n      const capability = goalState.capability;\n      if (!capability || !capability.actions.includes(action)) {\n        throw new Error(`ACPX session goal action ${action} is unavailable`);\n      }\n      if (!runtime.requestExtension) {\n        throw new Error(\"ACPX runtime does not expose extension requests\");\n      }\n      const revisionBeforeControl = goalState.revision;\n      await runtime.requestExtension({\n        handle,\n        method: capability.controlMethod,\n        params: {\n          sessionId: identity.agentSessionId,\n          action,\n          ...(action === \"set\" ? { objective } : {}),\n        },\n        sessionMode: \"persistent\",\n      });\n      const shouldRepairMissingSetSnapshot =\n        action === \"set\" &&\n        Boolean(objective?.trim()) &&\n        goalState.snapshot === null;\n      const shouldRepairStaleClearSnapshot =\n        action === \"clear\" && goalState.snapshot !== null;","sourceCodeStart":1088,"sourceCodeEnd":1124,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/acpx/codex-runtime-adapter.ts#L1088-L1124","documentation":"After the goal action passes the capability check, controlGoal() requires runtime.requestExtension to forward the control method to the ACPX runtime. When the runtime object lacks a requestExtension function (the pinned runtime interface does not implement the extension-request surface), the adapter throws this error. It signals an adapter/runtime version incompatibility rather than a user input problem: the negotiated capability exists but there is no transport to exercise it.","triggerScenarios":"port.controlGoal(action, objective) invoked with a valid capability whose runtime instance was created without a requestExtension implementation (runtime.requestExtension is undefined).","commonSituations":"Running against an older ACPX/Codex runtime build that predates extension requests; a test stub or mock runtime implementing startTurn but omitting requestExtension; partial interface drift after upgrading the adapter without the runtime library.","solutions":["Upgrade the ACPX runtime package so the pinned runtime exposes requestExtension.","Verify the runtime object used to build the port is the real runtime, not a stub missing requestExtension.","Guard callers: skip goal control when requestExtension is unavailable, mirroring how setModel is conditionally exposed (see runtime.setConfigOption check).","Align adapter and runtime versions so capability negotiation and the extension transport are both present."],"exampleFix":"// before\nconst port = createPort(runtimeWithoutExtensions);\nawait port.controlGoal(\"set\", { text: \"do it\" }); // throws\n// after\nif (typeof runtime.requestExtension !== \"function\") {\n  throw new Error(\"upgrade ACPX runtime: goal control needs requestExtension\");\n}\nawait port.controlGoal(\"set\", { text: \"do it\" });","handlingStrategy":"type-guard","validationCode":"if (typeof runtime.requestExtension !== \"function\") {\n  throw new Error(\"runtime lacks extension request support; upgrade ACPX runtime\");\n}","typeGuard":"function supportsExtensionRequests(runtime) {\n  return typeof runtime?.requestExtension === \"function\";\n}","tryCatchPattern":"try {\n  await port.controlGoal(action, objective);\n} catch (e) {\n  if (e.message === \"ACPX runtime does not expose extension requests\") {\n    logRuntimeIncompatibility();\n    fallbackToLocalGoalTracking();\n  } else throw e;\n}","preventionTips":["Pin adapter and ACPX runtime versions together and test goal control on upgrade.","Use supportsExtensionRequests() as a feature gate, like the existing runtime.setConfigOption check for setModel.","In tests, make runtime mocks implement the full AcpxRuntime interface."],"tags":["runtime-incompatibility","missing-method","acpx","version-mismatch"],"backgroundTag":"method-not-implemented","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}