@agimon-ai/po-computer-use 0.0.0-alpha.106 → 0.0.0-alpha.108
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/dist/{extensionService-BS2Lz9R8.cjs → extensionService-BB08HbHP.cjs} +72 -5
- package/dist/extensionService-BB08HbHP.cjs.map +1 -0
- package/dist/{extensionService-DGTnZr5E.mjs → extensionService-D8bAAsIN.mjs} +72 -5
- package/dist/extensionService-D8bAAsIN.mjs.map +1 -0
- package/dist/extensions/server.cjs +15 -3
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.mjs +15 -3
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +12 -10
- package/src/prompts/codemode-how-to-computer-use/SKILL.md +8 -0
- package/dist/extensionService-BS2Lz9R8.cjs.map +0 -1
- package/dist/extensionService-DGTnZr5E.mjs.map +0 -1
|
@@ -26,6 +26,7 @@ let node_child_process = require("node:child_process");
|
|
|
26
26
|
let node_fs_promises = require("node:fs/promises");
|
|
27
27
|
let node_module = require("node:module");
|
|
28
28
|
let node_crypto = require("node:crypto");
|
|
29
|
+
let _agimon_ai_po_core_inputTemplate = require("@agimon-ai/po-core/inputTemplate");
|
|
29
30
|
let _agimon_ai_po_core_packageApi = require("@agimon-ai/po-core/packageApi");
|
|
30
31
|
//#region src/constants/computerUse.ts
|
|
31
32
|
const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]
|
|
@@ -479,6 +480,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
479
480
|
closed = false;
|
|
480
481
|
desktop;
|
|
481
482
|
beforeActivate;
|
|
483
|
+
profileRuntime;
|
|
484
|
+
nativeTarget;
|
|
485
|
+
resolvingInput = false;
|
|
486
|
+
inputController;
|
|
487
|
+
sensitiveInput = false;
|
|
482
488
|
listeners = /* @__PURE__ */ new Set();
|
|
483
489
|
unsubscribeDesktop;
|
|
484
490
|
static DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -490,7 +496,9 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
490
496
|
this.requestTimeoutMs = options.requestTimeoutMs ?? ComputerUseRequestBroker.DEFAULT_REQUEST_TIMEOUT_MS;
|
|
491
497
|
this.desktop = options.desktop;
|
|
492
498
|
this.beforeActivate = options.beforeActivate;
|
|
499
|
+
this.profileRuntime = options.profileRuntime;
|
|
493
500
|
this.unsubscribeDesktop = options.desktop?.subscribe(() => {
|
|
501
|
+
this.inputController?.abort();
|
|
494
502
|
clearTimeout(this.expiryTimer);
|
|
495
503
|
if (!options.desktop?.available) {
|
|
496
504
|
this.rejectPending("Desktop disconnected.");
|
|
@@ -548,10 +556,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
548
556
|
act: async (action, signal) => {
|
|
549
557
|
requireDesktop();
|
|
550
558
|
if (!semanticAction(action)) throw new Error("A valid semantic action is required.");
|
|
551
|
-
return result(await this.
|
|
559
|
+
return result(await this.performAction(action, signal));
|
|
552
560
|
},
|
|
553
561
|
stop: async (signal) => {
|
|
554
562
|
signal?.throwIfAborted();
|
|
563
|
+
this.inputController?.abort();
|
|
555
564
|
if (this.phase !== "inactive" && this.phase !== "failed") {
|
|
556
565
|
this.phase = "stopping";
|
|
557
566
|
this.rejectPending("Computer use was stopped.");
|
|
@@ -624,7 +633,58 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
624
633
|
}
|
|
625
634
|
this.rejectPending(message);
|
|
626
635
|
}
|
|
636
|
+
async performAction(action, requestSignal) {
|
|
637
|
+
if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
|
|
638
|
+
if (action.kind !== "set_value" || !(0, _agimon_ai_po_core_inputTemplate.hasInputTemplate)(action.value)) return this.enqueue("act", action, requestSignal);
|
|
639
|
+
this.resolvingInput = true;
|
|
640
|
+
try {
|
|
641
|
+
if (this.phase !== "active" || this.pending || !this.grantId) throw new Error();
|
|
642
|
+
const parts = (0, _agimon_ai_po_core_inputTemplate.parseInputTemplate)(action.value);
|
|
643
|
+
const profile = this.profileRuntime?.();
|
|
644
|
+
if (!profile) throw new Error();
|
|
645
|
+
const snapshot = profile.readSelection();
|
|
646
|
+
const generation = snapshot.generation;
|
|
647
|
+
const grantId = this.grantId;
|
|
648
|
+
const target = this.nativeTarget;
|
|
649
|
+
const usesSecret = parts.some((part) => part.kind === "secret");
|
|
650
|
+
if (usesSecret && (!target || target.scope === "desktop" || typeof target.bundleId !== "string")) throw new Error();
|
|
651
|
+
const controller = new AbortController();
|
|
652
|
+
this.inputController = controller;
|
|
653
|
+
const signal = AbortSignal.any([
|
|
654
|
+
snapshot.signal,
|
|
655
|
+
controller.signal,
|
|
656
|
+
...requestSignal ? [requestSignal] : []
|
|
657
|
+
]);
|
|
658
|
+
const value = await (0, _agimon_ai_po_core_inputTemplate.renderInputTemplate)(parts, {
|
|
659
|
+
readEnv: (name) => snapshot.env && Object.hasOwn(snapshot.env, name) ? snapshot.env[name] : void 0,
|
|
660
|
+
resolveSecret: (name) => profile.resolveInputSecret(name, {
|
|
661
|
+
surface: "computer",
|
|
662
|
+
target: target.bundleId,
|
|
663
|
+
signal
|
|
664
|
+
}),
|
|
665
|
+
onResolved: () => {
|
|
666
|
+
this.sensitiveInput = true;
|
|
667
|
+
},
|
|
668
|
+
signal
|
|
669
|
+
});
|
|
670
|
+
signal.throwIfAborted();
|
|
671
|
+
if (this.closed || this.phase !== "active" || this.grantId !== grantId || this.nativeTarget !== target || this.profileRuntime?.() !== profile || profile.readSelection().generation !== generation) throw new Error();
|
|
672
|
+
this.resolvingInput = false;
|
|
673
|
+
return await this.enqueue("act", {
|
|
674
|
+
...action,
|
|
675
|
+
value,
|
|
676
|
+
...usesSecret ? { sensitiveBundleId: target.bundleId } : {}
|
|
677
|
+
}, signal);
|
|
678
|
+
} catch {
|
|
679
|
+
return jsonError("Computer input template failed.", 400);
|
|
680
|
+
} finally {
|
|
681
|
+
this.inputController = void 0;
|
|
682
|
+
this.resolvingInput = false;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
627
685
|
async enqueue(operation, payload, signal) {
|
|
686
|
+
if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
|
|
687
|
+
if (operation === "observe" && this.sensitiveInput) return jsonError("Observations are sealed after sensitive input.", 409);
|
|
628
688
|
if (this.phase !== "active" || this.grantId === void 0) return jsonError("Computer use is not active.", 409);
|
|
629
689
|
if (this.pending !== void 0) return jsonError("Another computer-use request is live.", 409);
|
|
630
690
|
if (signal?.aborted === true) return jsonError("The computer-use request was cancelled.", 499);
|
|
@@ -653,9 +713,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
653
713
|
});
|
|
654
714
|
this.changed();
|
|
655
715
|
try {
|
|
656
|
-
|
|
716
|
+
const value = await completion;
|
|
717
|
+
return Response.json(this.sensitiveInput ? { applied: true } : value);
|
|
657
718
|
} catch (error) {
|
|
658
|
-
return jsonError(error instanceof Error ? error.message : String(error), 502);
|
|
719
|
+
return jsonError(this.sensitiveInput ? "Sensitive computer input failed." : error instanceof Error ? error.message : String(error), 502);
|
|
659
720
|
}
|
|
660
721
|
}
|
|
661
722
|
async fetch(request) {
|
|
@@ -691,9 +752,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
691
752
|
if (request.method === "POST" && path === routes.agentAction.path) {
|
|
692
753
|
const action = await body(request);
|
|
693
754
|
if (!semanticAction(action)) return jsonError("A valid semantic action is required.", 400);
|
|
694
|
-
return this.
|
|
755
|
+
return this.performAction(action, request.signal);
|
|
695
756
|
}
|
|
696
757
|
if (request.method === "POST" && path === routes.agentStop.path) {
|
|
758
|
+
this.inputController?.abort();
|
|
697
759
|
if (this.phase !== "active") return jsonError("Computer use is not active.", 409);
|
|
698
760
|
this.phase = "stopping";
|
|
699
761
|
this.rejectPending("The computer-use request was stopped.");
|
|
@@ -726,6 +788,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
726
788
|
return Response.json(this.state());
|
|
727
789
|
}
|
|
728
790
|
if (request.method === "POST" && path === routes.hubStop.path) {
|
|
791
|
+
this.inputController?.abort();
|
|
729
792
|
const input = await body(request);
|
|
730
793
|
if (this.phase === "activating") {
|
|
731
794
|
if (typeof input.error === "string") {
|
|
@@ -739,6 +802,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
739
802
|
const host = record(input.host);
|
|
740
803
|
if (typeof host?.grantId !== "string" || !Number.isFinite(host.expiresAt) || host.expiresAt <= Date.now()) return jsonError("Desktop did not issue a complete grant.", 502);
|
|
741
804
|
const selectedTarget = record(host.target);
|
|
805
|
+
this.nativeTarget = selectedTarget === void 0 ? void 0 : Object.freeze({ ...selectedTarget });
|
|
742
806
|
if (this.activation !== void 0 && selectedTarget !== void 0) this.activation = Object.freeze({
|
|
743
807
|
...this.activation,
|
|
744
808
|
target: Object.freeze({ ...selectedTarget })
|
|
@@ -751,6 +815,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
751
815
|
this.expiryTimer = setTimeout(() => {
|
|
752
816
|
if (this.closed || this.phase !== "active") return;
|
|
753
817
|
this.phase = "stopping";
|
|
818
|
+
this.inputController?.abort();
|
|
754
819
|
this.rejectPending("The computer-use grant expired.");
|
|
755
820
|
this.changed();
|
|
756
821
|
}, Math.max(0, this.expiresAt - Date.now()));
|
|
@@ -763,6 +828,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
763
828
|
this.grantId = void 0;
|
|
764
829
|
this.expiresAt = void 0;
|
|
765
830
|
this.activation = void 0;
|
|
831
|
+
this.nativeTarget = void 0;
|
|
766
832
|
this.artifact = artifactView(input.artifact) ?? this.artifact;
|
|
767
833
|
}
|
|
768
834
|
this.changed();
|
|
@@ -773,6 +839,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
773
839
|
close() {
|
|
774
840
|
if (this.closed) return;
|
|
775
841
|
this.closed = true;
|
|
842
|
+
this.inputController?.abort();
|
|
776
843
|
clearTimeout(this.expiryTimer);
|
|
777
844
|
this.unsubscribeDesktop?.();
|
|
778
845
|
this.listeners.clear();
|
|
@@ -1144,4 +1211,4 @@ Object.defineProperty(exports, "routes", {
|
|
|
1144
1211
|
}
|
|
1145
1212
|
});
|
|
1146
1213
|
|
|
1147
|
-
//# sourceMappingURL=extensionService-
|
|
1214
|
+
//# sourceMappingURL=extensionService-BB08HbHP.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensionService-BB08HbHP.cjs","names":["poApiCallerFrom","randomUUID","hasInputTemplate","parseInputTemplate","renderInputTemplate","realpath","path","createRequire","spawn"],"sources":["../src/constants/computerUse.ts","../src/services/computerScriptWorker/index.ts","../src/types/computerUseApi.ts","../src/types/desktopPermissions.ts","../src/types/apiRoutes.ts","../src/services/computerUseApi/index.ts","../src/services/computerScriptRunner/index.ts","../src/services/extensionService/index.ts"],"sourcesContent":["export const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]\nUse computer_state before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer_state. Use computer_action for one semantic press, focus, set_value, or scroll at a time. Use computer_exec only for a trusted, explicitly allowed local TypeScript script. Never infer coordinates, inspect another application, bypass secure elements, or retry an uncertain outcome. Stop computer use when the task is complete.`;\nexport const COMMAND_NAME = 'computer-use';\nexport const COMMAND_DESCRIPTION = 'Inspect or manage the session computer use mode';\n\nexport const COMPUTER_USE_TOOL_NAMES = ['computer_state', 'computer_action', 'computer_exec'] as const;\n/** The session artifact storage service and the folder computer-use evidence lands in. */\nexport const COMPUTER_USE_ARTIFACTS_SERVICE = 'po/artifacts';\nexport const COMPUTER_USE_ARTIFACT_DIRECTORY = 'computer-use';\n/** The host recording store's own bounds: its largest recording and its range size. */\nexport const COMPUTER_USE_RECORDING_MAX_BYTES = 128 * 1024 * 1024;\nexport const COMPUTER_USE_RECORDING_CHUNK_BYTES = 1024 * 1024;\nexport const COMPUTER_USE_CODEMODE_GUIDANCE =\n '[COMPUTER USE ACTIVE]\\nUse computer.state() in exec before acting and after any action that may change the interface. Use only element refs and snapshot ids returned by computer.state(). Never infer coordinates or bypass secure elements. Call computer.stop() when the task is complete. Load codemode-how-to-computer-use for details.';\n","/** Source for an isolated child process. Restricted modules execute in QuickJS, not in Node's realm. */\nexport const COMPUTER_SCRIPT_WORKER_SOURCE = String.raw`\nimport { readFileSync, realpathSync, statSync } from 'node:fs';\nimport path from 'node:path';\nimport { stripTypeScriptTypes } from 'node:module';\nimport { pathToFileURL } from 'node:url';\n\nlet nextRequestId = 0;\nlet started = false;\nconst pending = new Map();\nconst controller = new AbortController();\nprocess.once('SIGTERM', () => controller.abort());\nconst send = (message) => {\n if (process.connected) process.send(message, () => {});\n};\nconst call = (operation, payload) => new Promise((resolve, reject) => {\n if (controller.signal.aborted) return reject(new Error('Computer script was cancelled.'));\n if (pending.size >= 64) return reject(new Error('Too many outstanding program operations.'));\n const id = String(++nextRequestId);\n pending.set(id, { resolve, reject });\n send({ type: 'program', id, operation, payload });\n});\n\nasync function restricted(message) {\n const { getQuickJS } = await import(pathToFileURL(message.quickjsPath).href);\n const QuickJS = await getQuickJS();\n const runtime = QuickJS.newRuntime();\n runtime.setMemoryLimit(32 * 1024 * 1024);\n runtime.setMaxStackSize(512 * 1024);\n const deadline = Date.now() + message.timeoutMs;\n runtime.setInterruptHandler(() => controller.signal.aborted || Date.now() >= deadline);\n const { realpath } = await import('node:fs/promises');\n const root = await realpath(message.scriptRoot);\n const sources = new Map();\n let sourceBytes = 0;\n let moduleFailure;\n // sync: QuickJS invokes module normalization and loading synchronously and cannot await filesystem reads.\n const modulePath = (candidate) => {\n const filename = realpathSync(candidate);\n const relative = path.relative(root, filename);\n if (relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative)) {\n throw new Error('Computer helper escapes the admitted script root.');\n }\n if (!/\\.(ts|js|mjs)$/.test(filename)) throw new Error('Computer helpers must be JavaScript or erasable TypeScript.');\n return filename;\n };\n const entry = modulePath(message.scriptPath);\n runtime.setModuleLoader((filename) => {\n // Preserve a rejected normalization even if the engine subsequently asks to load an empty name.\n if (moduleFailure) throw moduleFailure;\n if (sources.has(filename)) return sources.get(filename);\n if (sources.size >= 32 || statSync(filename).size > 256 * 1024) throw new Error('Computer script module limit exceeded.');\n const source = readFileSync(filename, 'utf8');\n sourceBytes += Buffer.byteLength(source);\n if (sourceBytes > 512 * 1024) throw new Error('Computer script source limit exceeded.');\n const compiled = filename.endsWith('.ts') ? stripTypeScriptTypes(source, { mode: 'strip' }) : source;\n sources.set(filename, compiled);\n return compiled;\n }, (base, name) => {\n try {\n if (name === '__entry__') return entry;\n if (!name.startsWith('./') && !name.startsWith('../')) {\n throw new Error('Restricted computer functions cannot import host or package modules.');\n }\n return modulePath(path.resolve(path.dirname(base), name));\n } catch (error) {\n moduleFailure = error;\n throw error;\n }\n });\n const vm = runtime.newContext();\n let disposed = false;\n const deferreds = new Set();\n const pump = () => {\n if (disposed) return;\n const jobs = runtime.executePendingJobs();\n if (jobs.error) {\n const detail = vm.dump(jobs.error);\n jobs.error.dispose();\n throw new Error(detail?.message ?? String(detail));\n }\n };\n const set = (name, value) => {\n vm.setProp(vm.global, name, value);\n value.dispose();\n };\n set('__input', vm.newString(JSON.stringify(message.input)));\n set('__aborted', vm.newFunction('__aborted', () => controller.signal.aborted ? vm.true : vm.false));\n set('__log', vm.newFunction('__log', (level, text) => {\n send({ type: 'log', level: vm.getString(level), message: vm.getString(text) });\n }));\n set('__call', vm.newFunction('__call', (operationHandle, payloadHandle) => {\n const operation = vm.getString(operationHandle);\n const serialized = vm.getString(payloadHandle);\n if (serialized.length > message.maxOutputBytes) throw new Error('Computer action exceeds the size limit.');\n if (operation !== 'observe' && operation !== 'act') throw new Error('Unsupported program operation.');\n const deferred = vm.newPromise();\n deferreds.add(deferred);\n call(operation, JSON.parse(serialized)).then((value) => {\n if (disposed) return;\n const handle = vm.newString(JSON.stringify(value));\n deferred.resolve(handle);\n handle.dispose();\n }, (error) => {\n if (disposed) return;\n const handle = vm.newError(error.message);\n deferred.reject(handle);\n handle.dispose();\n }).then(() => {\n if (disposed) return;\n deferred.dispose();\n deferreds.delete(deferred);\n pump();\n }).catch((error) => send({ type: 'failed', error: error.message }));\n return deferred.handle.dup();\n }));\n let evaluation;\n try {\n evaluation = vm.unwrapResult(vm.evalCode(\n 'import { run } from \"__entry__\";\\n' +\n 'const invoke = __call; const log = __log; const isAborted = __aborted;\\n' +\n 'const program = Object.freeze({\\n' +\n ' observe: async (options = {}) => JSON.parse(await invoke(\"observe\", JSON.stringify(options))),\\n' +\n ' act: async (action) => JSON.parse(await invoke(\"act\", JSON.stringify(action)))\\n' +\n '});\\n' +\n 'const logger = Object.freeze(Object.fromEntries([\"debug\",\"info\",\"warn\",\"error\"].map(level => [level, value => log(level, String(value))])));\\n' +\n 'const signal = Object.freeze({ get aborted() { return isAborted(); }, throwIfAborted() { if (isAborted()) throw new Error(\"Computer script was cancelled.\"); } });\\n' +\n 'const result = await run({ context: { program }, input: JSON.parse(__input), logger, signal });\\n' +\n 'globalThis.__result = result === undefined ? undefined : JSON.stringify(result);',\n path.join(root, '__computer_entry__.mjs'), { type: 'module' },\n ));\n const completion = vm.resolvePromise(evaluation);\n pump();\n const completed = vm.unwrapResult(await completion);\n completed.dispose();\n const result = vm.getProp(vm.global, '__result');\n const resultJson = vm.dump(result);\n result.dispose();\n return resultJson;\n } finally {\n disposed = true;\n for (const deferred of deferreds) deferred.dispose();\n evaluation?.dispose();\n vm.dispose();\n runtime.dispose();\n }\n}\n\nprocess.on('message', async (message) => {\n if (message?.type === 'response') {\n const request = pending.get(message.id);\n if (!request) return;\n pending.delete(message.id);\n if (message.error) request.reject(new Error(message.error));\n else request.resolve(message.value);\n return;\n }\n if (message?.type !== 'start' || started) return;\n started = true;\n try {\n let resultJson;\n if (message.trusted) {\n const loaded = await import(pathToFileURL(message.scriptPath).href);\n if (typeof loaded.run !== 'function') throw new Error('Computer script must export a named run function.');\n const program = {\n observe: (options = {}) => call('observe', options),\n act: (action) => call('act', action),\n };\n const logger = Object.fromEntries(['debug','info','warn','error'].map(level => [level, value => {\n send({ type: 'log', level, message: String(value) });\n }]));\n const result = await loaded.run({ context: { program }, input: message.input, logger, signal: controller.signal });\n resultJson = result === undefined ? undefined : JSON.stringify(result);\n } else {\n resultJson = await restricted(message);\n }\n if (typeof resultJson === 'string' && Buffer.byteLength(resultJson) > message.maxOutputBytes) {\n throw new Error('Computer script result exceeded the size limit.');\n }\n send({ type: 'complete', resultJson });\n } catch (error) {\n send({ type: 'failed', error: String(error?.message ?? error).slice(0, 1024) });\n }\n});\n`;\n","import type { PoApiCaller } from '@agimon-ai/po-core/packageApi';\n\nexport const API_BASE_PATH = 'computer-use';\nexport const computerUseChannelType = 'computer_use_state';\nexport const COMPUTER_USE_MODE_ID = 'computer-use';\nexport const COMPUTER_USE_STATUS_KEY = 'po-computer-use';\nexport const COMPUTER_USE_MODE_STATUS_KEY = 'po-computer-use-mode';\nexport const COMPUTER_USE_MAX_DURATION_MS = 1_800 * 1_000;\nexport const COMPUTER_USE_DEFAULT_DURATION_MS = 300 * 1_000;\n/** The session lengths a person can pick when granting control, up to the maximum. */\nexport const COMPUTER_USE_DURATION_CHOICES_MS = [\n COMPUTER_USE_DEFAULT_DURATION_MS,\n 900_000,\n COMPUTER_USE_MAX_DURATION_MS,\n] as const;\nexport const COMPUTER_USE_CONFIRMATION_WINDOW_MS = 2 * 60 * 1_000;\n\n/**\n * Every path this API answers on, below its mount.\n *\n * The typed route table in `./apiRoutes` is built from this, the dispatcher\n * reads that table, and the hub channel addresses the broker with these same\n * strings, so a route cannot move on one side alone.\n */\nexport const COMPUTER_USE_ROUTES = {\n activate: '/activate',\n artifact: '/artifact',\n agentState: '/agent/state',\n agentObserve: '/agent/observe',\n agentAction: '/agent/action',\n agentStop: '/agent/stop',\n hubState: '/hub/state',\n hubActivation: '/hub/activation',\n hubAuthorization: '/hub/authorization',\n hubNext: '/hub/next',\n hubComplete: '/hub/complete',\n hubStop: '/hub/stop',\n} as const;\n\nexport const COMPUTER_USE_WAKE_LIMIT = 1_000_000;\n\nexport interface ComputerUseArtifactView {\n readonly artifactId: string;\n readonly status: 'ready' | 'failed';\n readonly sizeBytes?: number;\n readonly downloadUrl?: string;\n readonly previewUrl?: string;\n readonly actionCount?: number;\n readonly completedAt?: string;\n readonly failure?: { readonly code: string; readonly message: string };\n}\n\nexport interface ComputerUseSessionView {\n readonly sessionId: string;\n readonly revision: number;\n readonly wake: number;\n readonly phase: 'inactive' | 'awaiting_confirmation' | 'activating' | 'active' | 'stopping' | 'failed';\n readonly requestId?: string;\n readonly target?: Record<string, unknown>;\n readonly durationMs?: number;\n readonly expiresAt?: number;\n readonly failure?: { readonly code: string; readonly message: string };\n readonly artifact?: ComputerUseArtifactView;\n}\n\nexport interface ComputerUseActivationRequest {\n readonly requestId: string;\n readonly target?: Record<string, unknown>;\n readonly durationSeconds: number;\n readonly createdAt: number;\n readonly confirmationExpiresAt: number;\n /** Set by the session broker only after the person approves the in-app dialog. */\n readonly confirmedAt?: number;\n readonly caller: PoApiCaller;\n}\n\nexport interface ComputerUseBrokerRequest {\n readonly id: string;\n readonly operation: 'observe' | 'act';\n readonly payload?: unknown;\n readonly grantId: string;\n readonly sequence?: number;\n}\n\nexport interface ComputerUseChannelPayload {\n readonly state: ComputerUseSessionView;\n readonly targets: readonly Record<string, unknown>[];\n readonly busy?: true;\n}\n\nexport type ComputerUseBrowserCommand = { readonly action: 'status' | 'targets' | 'stop' | 'artifacts' };\n","/** The mount's only path: GET reads the permission states, POST asks macOS for one. */\nexport const DESKTOP_PERMISSIONS_PATH = '/';\n\n/** The macOS privacy permissions Desktop reports, in the order the settings page shows them. */\nexport const DESKTOP_PERMISSIONS = [\n 'accessibility',\n 'screen-recording',\n 'microphone',\n 'automation',\n 'full-disk-access',\n] as const;\nexport type DesktopPermission = (typeof DESKTOP_PERMISSIONS)[number];\n\n/** `per-app` is Automation: macOS asks once for each app Po controls and reports no overall state. */\nexport type DesktopPermissionState = 'granted' | 'denied' | 'not-determined' | 'per-app';\nexport type DesktopPermissionStates = Record<DesktopPermission, DesktopPermissionState>;\n\nexport interface DesktopPermissionRequest {\n readonly permission: DesktopPermission;\n}\n\nexport function isDesktopPermission(value: unknown): value is DesktopPermission {\n return typeof value === 'string' && (DESKTOP_PERMISSIONS as readonly string[]).includes(value);\n}\n","import type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport {\n COMPUTER_USE_ROUTES,\n type ComputerUseActivationRequest,\n type ComputerUseBrokerRequest,\n type ComputerUseSessionView,\n} from './computerUseApi';\nimport { DESKTOP_PERMISSIONS_PATH, type DesktopPermissionStates } from './desktopPermissions';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path: the build reads both off\n * `src/extensions/workspaces/sessions/(backend)/api/computer-use/`, so the\n * mount is stated once, by the folder that creates it.\n *\n * The paths come from `COMPUTER_USE_ROUTES` rather than being written out\n * again. That table already addressed the broker from the hub channel and from\n * the broker's own dispatcher, and a second copy here is exactly the\n * disagreement this file exists to prevent. The dispatcher now reads this\n * table, so the page, the broker and the hub all resolve one set of strings.\n *\n * Activation, status, cancellation and recording reads are reachable from a browser. The `/agent/` and `/hub/` routes\n * each demand a host-issued bearer token and answer 404 without one; they are\n * declared here because they are this API's surface, not because a page calls\n * them.\n */\nconst routes = {\n artifact: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.artifact,\n query: ['artifactId', 'offset'],\n raw: true,\n },\n activationState: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.activate,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n cancelActivation: {\n method: 'DELETE',\n path: COMPUTER_USE_ROUTES.activate,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n activate: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.activate,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n agentState: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.agentState,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n /** Answers whatever the admitted Desktop provider returned, which is runtime-defined JSON. */\n agentObserve: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.agentObserve,\n response: undefined as unknown as ApiResponseOf<unknown>,\n },\n agentAction: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.agentAction,\n response: undefined as unknown as ApiResponseOf<unknown>,\n },\n agentStop: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.agentStop,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n hubState: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubState,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n /** Null until a reader has confirmed one; reading it moves the session to `activating`. */\n hubActivation: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubActivation,\n response: undefined as unknown as ApiResponseOf<ComputerUseActivationRequest | null>,\n },\n hubAuthorization: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubAuthorization,\n response: undefined as unknown as ApiResponseOf<{ readonly grantId: string; readonly expiresAt?: number } | null>,\n },\n hubNext: {\n method: 'GET',\n path: COMPUTER_USE_ROUTES.hubNext,\n response: undefined as unknown as ApiResponseOf<ComputerUseBrokerRequest | null>,\n },\n hubComplete: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.hubComplete,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n hubStop: {\n method: 'POST',\n path: COMPUTER_USE_ROUTES.hubStop,\n response: undefined as unknown as ApiResponseOf<ComputerUseSessionView>,\n },\n /** Desktop's macOS permission states, served by the hub's `desktop-permissions` mount. */\n desktopPermissions: {\n method: 'GET',\n path: DESKTOP_PERMISSIONS_PATH,\n response: undefined as unknown as ApiResponseOf<DesktopPermissionStates>,\n },\n /** Asks macOS for the body's permission on the Mac running Desktop; answers the states after. */\n requestDesktopPermission: {\n method: 'POST',\n path: DESKTOP_PERMISSIONS_PATH,\n response: undefined as unknown as ApiResponseOf<DesktopPermissionStates>,\n },\n} as const satisfies ApiRoutes;\n\nexport default routes;\n","import { randomUUID } from 'node:crypto';\n\nimport type { PoComputerUseSessionAccess, PoDirectEventBus } from '@agimon-ai/po-core/hubChannel';\nimport { hasInputTemplate, parseInputTemplate, renderInputTemplate } from '@agimon-ai/po-core/inputTemplate';\nimport { poApiCallerFrom, type PoApi, type PoApiContext, type PoApiHandler } from '@agimon-ai/po-core/packageApi';\n\nimport routes from '../../types/apiRoutes';\nimport type { ComputerUseAction, ComputerUseObservation, ComputerUseObservationOptions } from '../../types/computerUse';\nimport {\n API_BASE_PATH,\n computerUseChannelType,\n COMPUTER_USE_CONFIRMATION_WINDOW_MS,\n COMPUTER_USE_MAX_DURATION_MS,\n COMPUTER_USE_WAKE_LIMIT,\n type ComputerUseActivationRequest,\n type ComputerUseArtifactView,\n type ComputerUseBrokerRequest,\n type ComputerUseSessionView,\n} from '../../types/computerUseApi';\nimport type { ComputerUseSessionClient } from '../sessionApiClient';\n\ninterface PendingRequest {\n readonly request: ComputerUseBrokerRequest;\n readonly dispose: () => void;\n resolve(value: unknown): void;\n reject(error: Error): void;\n}\n\nfunction jsonError(message: string, status: number): Response {\n return Response.json({ error: message }, { status });\n}\n\nfunction record(value: unknown): Record<string, unknown> | undefined {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nasync function body(request: Request): Promise<Record<string, unknown>> {\n try {\n return record(await request.json()) ?? {};\n } catch {\n return {};\n }\n}\n\nfunction semanticAction(value: Record<string, unknown>): boolean {\n const allowed = (keys: readonly string[]) => Object.keys(value).every((key) => keys.includes(key));\n if (value.kind === 'launch') return typeof value.app === 'string' && value.app.length > 0 && allowed(['kind', 'app']);\n const base =\n typeof value.snapshotId === 'string' &&\n value.snapshotId.length > 0 &&\n typeof value.elementRef === 'string' &&\n value.elementRef.length > 0;\n if (!base) return false;\n if (value.kind === 'press' || value.kind === 'focus') return allowed(['kind', 'snapshotId', 'elementRef']);\n if (value.kind === 'set_value')\n return typeof value.value === 'string' && allowed(['kind', 'snapshotId', 'elementRef', 'value']);\n if (value.kind === 'scroll')\n return (\n ['up', 'down', 'left', 'right'].includes(value.direction as string) &&\n (value.amount === 'line' || value.amount === 'page') &&\n allowed(['kind', 'snapshotId', 'elementRef', 'direction', 'amount'])\n );\n if (value.kind === 'perform')\n return (\n typeof value.action === 'string' &&\n /^AX[A-Za-z]{1,62}$/u.test(value.action) &&\n allowed(['kind', 'snapshotId', 'elementRef', 'action'])\n );\n return false;\n}\n\n/** Throws on anything but the documented observation options, so every caller shares one check. */\nexport function observationOptions(value: unknown): ComputerUseObservationOptions {\n const options = record(value);\n if (options === undefined) throw new TypeError('Observation options must be an object.');\n for (const [key, entry] of Object.entries(options)) {\n const valid =\n key === 'includeScreenshot'\n ? typeof entry === 'boolean'\n : key === 'root' || key === 'label' || key === 'role'\n ? typeof entry === 'string' && entry.length > 0 && entry.length <= 256\n : key === 'offset'\n ? Number.isInteger(entry) && (entry as number) >= 0 && (entry as number) <= 2_000\n : key === 'limit' && Number.isInteger(entry) && (entry as number) >= 1 && (entry as number) <= 500;\n if (!valid) throw new TypeError(`Invalid observation option \"${key}\".`);\n }\n return options as ComputerUseObservationOptions;\n}\nfunction artifactView(value: unknown): ComputerUseArtifactView | undefined {\n const input = record(value);\n if (typeof input?.artifactId !== 'string' || (input.status !== 'ready' && input.status !== 'failed'))\n return undefined;\n const safeUrl = (candidate: unknown) =>\n typeof candidate === 'string' && candidate.startsWith('/api/') ? candidate : undefined;\n const downloadUrl = safeUrl(input.downloadUrl);\n const previewUrl = safeUrl(input.previewUrl);\n const artifactFailure = record(input.failure);\n const safeFailure =\n typeof artifactFailure?.code === 'string' && typeof artifactFailure.message === 'string'\n ? { code: artifactFailure.code.slice(0, 128), message: artifactFailure.message.slice(0, 512) }\n : undefined;\n return {\n artifactId: input.artifactId,\n status: input.status,\n ...(typeof input.sizeBytes === 'number' && Number.isSafeInteger(input.sizeBytes) && input.sizeBytes > 0\n ? { sizeBytes: input.sizeBytes }\n : {}),\n ...(downloadUrl === undefined ? {} : { downloadUrl }),\n ...(previewUrl === undefined ? {} : { previewUrl }),\n ...(typeof input.actionCount === 'number' ? { actionCount: input.actionCount } : {}),\n ...(typeof input.completedAt === 'string' ? { completedAt: input.completedAt } : {}),\n ...(safeFailure === undefined ? {} : { failure: safeFailure }),\n };\n}\n\nexport interface ComputerInputProfile {\n readSelection(): {\n readonly env?: Readonly<Record<string, string>>;\n readonly generation: number;\n readonly signal: AbortSignal;\n };\n resolveInputSecret(name: string, request: { surface: string; target: string; signal?: AbortSignal }): Promise<string>;\n}\n\nexport interface ComputerUseApiOptions {\n readonly sessionId?: string;\n readonly internalToken?: string;\n readonly hubToken?: string;\n readonly directEvents: PoDirectEventBus;\n readonly requestTimeoutMs?: number;\n readonly desktop?: PoComputerUseSessionAccess;\n readonly beforeActivate?: () => Promise<void>;\n readonly profileRuntime?: () => ComputerInputProfile | undefined;\n}\n\nexport class ComputerUseRequestBroker implements PoApiHandler {\n private readonly sessionId: string;\n private readonly internalToken?: string;\n private readonly hubToken?: string;\n private readonly directEvents: PoDirectEventBus;\n private readonly requestTimeoutMs: number;\n private revision = 0;\n private wake = 0;\n private phase: ComputerUseSessionView['phase'] = 'inactive';\n private activation?: ComputerUseActivationRequest;\n private grantId?: string;\n private expiresAt?: number;\n private actionSequence = 0;\n private expiryTimer?: ReturnType<typeof setTimeout>;\n private failure?: ComputerUseSessionView['failure'];\n private artifact?: ComputerUseArtifactView;\n private pending?: PendingRequest;\n private closed = false;\n private readonly desktop?: PoComputerUseSessionAccess;\n private readonly beforeActivate?: () => Promise<void>;\n private readonly profileRuntime?: () => ComputerInputProfile | undefined;\n private nativeTarget?: Record<string, unknown>;\n private resolvingInput = false;\n private inputController?: AbortController;\n private sensitiveInput = false;\n private readonly listeners = new Set<(state: ComputerUseSessionView) => void>();\n private readonly unsubscribeDesktop?: () => void;\n\n private static readonly DEFAULT_REQUEST_TIMEOUT_MS = 30_000;\n public constructor(options: ComputerUseApiOptions) {\n this.sessionId = options.sessionId ?? 'unknown';\n this.internalToken = options.internalToken;\n this.hubToken = options.hubToken;\n this.directEvents = options.directEvents;\n this.requestTimeoutMs = options.requestTimeoutMs ?? ComputerUseRequestBroker.DEFAULT_REQUEST_TIMEOUT_MS;\n this.desktop = options.desktop;\n this.beforeActivate = options.beforeActivate;\n this.profileRuntime = options.profileRuntime;\n this.unsubscribeDesktop = options.desktop?.subscribe(() => {\n this.inputController?.abort();\n clearTimeout(this.expiryTimer);\n if (!options.desktop?.available) {\n this.rejectPending('Desktop disconnected.');\n this.phase = 'failed';\n this.grantId = undefined;\n this.failure = { code: 'desktop_unavailable', message: 'Desktop disconnected.' };\n } else if (this.phase !== 'inactive' && this.phase !== 'failed') {\n this.phase = 'stopping';\n this.rejectPending('Control was stopped by Desktop.');\n }\n this.changed();\n });\n }\n\n public state(): ComputerUseSessionView {\n return Object.freeze({\n sessionId: this.sessionId,\n revision: this.revision,\n wake: this.wake,\n phase: this.phase,\n ...(this.activation === undefined\n ? {}\n : {\n requestId: this.activation.requestId,\n target: this.activation.target,\n durationMs: this.activation.durationSeconds * 1_000,\n }),\n ...(this.expiresAt === undefined ? {} : { expiresAt: this.expiresAt }),\n ...(this.failure === undefined ? {} : { failure: this.failure }),\n ...(this.artifact === undefined ? {} : { artifact: this.artifact }),\n });\n }\n\n /** Tools and the API share this broker. No socket, credential discovery, or second state store. */\n public sessionClient(): ComputerUseSessionClient {\n const result = async <T>(response: Response): Promise<T> => {\n const value = (await response.json()) as T & { error?: string };\n if (!response.ok) throw new Error(value.error ?? `Computer-use request failed (${response.status}).`);\n return value;\n };\n const requireDesktop = (): void => {\n if (this.closed || !this.desktop?.available || this.desktop.enabled === false)\n throw new Error('Desktop computer use is unavailable.');\n };\n return {\n state: async () => this.state(),\n subscribeStatus: (listener) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n },\n observe: async (signal, options = {}) => {\n requireDesktop();\n return result<ComputerUseObservation>(await this.enqueue('observe', observationOptions(options), signal));\n },\n act: async (action: ComputerUseAction, signal) => {\n requireDesktop();\n if (!semanticAction(action as unknown as Record<string, unknown>))\n throw new Error('A valid semantic action is required.');\n return result(await this.performAction(action, signal));\n },\n stop: async (signal) => {\n signal?.throwIfAborted();\n this.inputController?.abort();\n if (this.phase !== 'inactive' && this.phase !== 'failed') {\n this.phase = 'stopping';\n this.rejectPending('Computer use was stopped.');\n this.changed();\n }\n return this.state();\n },\n };\n }\n private changed(): void {\n this.revision += 1;\n this.wake = (this.wake + 1) % COMPUTER_USE_WAKE_LIMIT;\n const state = this.state();\n for (const listener of this.listeners) listener(state);\n this.directEvents.publish(computerUseChannelType, this.sessionId, state);\n }\n\n private authorized(request: Request, token: string | undefined): boolean {\n return token !== undefined && request.headers.get('authorization') === `Bearer ${token}`;\n }\n\n private async requestActivation(request: Request): Promise<Response> {\n if (\n !this.desktop?.available ||\n !(this.desktop.authorizeActivation?.(request.headers) ?? this.desktop.authorize(request.headers))\n )\n return jsonError('Not found.', 404);\n if (this.desktop.enabled === false) return jsonError('Enable computer use in global Desktop settings first.', 409);\n // Caller stamps are admitted by the host only after native proof or sealed paired authentication.\n const stamped = poApiCallerFrom(request.headers);\n const caller = stamped?.locality === 'remote' ? stamped : ({ locality: 'local', stepUp: 'not-required' } as const);\n if (this.phase !== 'inactive' && this.phase !== 'failed') return jsonError('Computer use is already busy.', 409);\n const input = await body(request);\n if (input.confirmed !== true) return jsonError('Approve computer control in the in-app dialog first.', 400);\n const target = record(input.target);\n const durationMs = input.durationMs;\n const desktopTarget = target?.scope === 'desktop' && Object.keys(target).length === 1;\n if (\n target === undefined ||\n (!desktopTarget && (typeof target.windowId !== 'string' || typeof target.bundleId !== 'string'))\n )\n return jsonError('An explicit application window or whole-desktop target is required.', 400);\n if (\n typeof durationMs !== 'number' ||\n !Number.isInteger(durationMs) ||\n durationMs < 1_000 ||\n durationMs > COMPUTER_USE_MAX_DURATION_MS\n )\n return jsonError('The requested duration is invalid.', 400);\n try {\n this.desktop.claim(request.headers);\n await this.beforeActivate?.();\n } catch (error) {\n return jsonError(error instanceof Error ? error.message : String(error), 409);\n }\n if (this.closed || !this.desktop.available || (this.phase !== 'inactive' && this.phase !== 'failed')) {\n return jsonError('Computer use is unavailable or already busy.', 409);\n }\n const createdAt = Date.now();\n this.activation = Object.freeze({\n requestId: randomUUID(),\n target: Object.freeze({ ...target }),\n durationSeconds: durationMs / 1_000,\n createdAt,\n confirmationExpiresAt: createdAt + COMPUTER_USE_CONFIRMATION_WINDOW_MS,\n confirmedAt: createdAt,\n caller: Object.freeze({ ...caller }),\n });\n this.phase = 'awaiting_confirmation';\n this.failure = undefined;\n this.artifact = undefined;\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n\n private rejectPending(message: string): void {\n const pending = this.pending;\n if (pending === undefined) return;\n this.pending = undefined;\n pending.dispose();\n pending.reject(new Error(message));\n }\n\n private stopAfterUncertainRequest(message: string): void {\n if (this.phase === 'active') {\n this.phase = 'stopping';\n this.changed();\n }\n this.rejectPending(message);\n }\n\n private async performAction(action: ComputerUseAction, requestSignal?: AbortSignal): Promise<Response> {\n if (this.resolvingInput) return jsonError('Another computer-use request is live.', 409);\n if (action.kind !== 'set_value' || !hasInputTemplate(action.value))\n return this.enqueue('act', action, requestSignal);\n this.resolvingInput = true;\n try {\n if (this.phase !== 'active' || this.pending || !this.grantId) throw new Error();\n const parts = parseInputTemplate(action.value);\n const profile = this.profileRuntime?.();\n if (!profile) throw new Error();\n const snapshot = profile.readSelection();\n const generation = snapshot.generation;\n const grantId = this.grantId;\n const target = this.nativeTarget;\n const usesSecret = parts.some((part) => part.kind === 'secret');\n if (usesSecret && (!target || target.scope === 'desktop' || typeof target.bundleId !== 'string'))\n throw new Error();\n const controller = new AbortController();\n this.inputController = controller;\n const signal = AbortSignal.any([snapshot.signal, controller.signal, ...(requestSignal ? [requestSignal] : [])]);\n // ponytail: resolved secrets seal observations for this session. A future native redaction boundary may safely reopen them.\n const value = await renderInputTemplate(parts, {\n readEnv: (name) => (snapshot.env && Object.hasOwn(snapshot.env, name) ? snapshot.env[name] : undefined),\n resolveSecret: (name) =>\n profile.resolveInputSecret(name, { surface: 'computer', target: target!.bundleId as string, signal }),\n onResolved: () => {\n this.sensitiveInput = true;\n },\n signal,\n });\n signal.throwIfAborted();\n if (\n this.closed ||\n this.phase !== 'active' ||\n this.grantId !== grantId ||\n this.nativeTarget !== target ||\n this.profileRuntime?.() !== profile ||\n profile.readSelection().generation !== generation\n )\n throw new Error();\n this.resolvingInput = false;\n return await this.enqueue(\n 'act',\n { ...action, value, ...(usesSecret ? { sensitiveBundleId: target!.bundleId } : {}) },\n signal,\n );\n } catch {\n return jsonError('Computer input template failed.', 400);\n } finally {\n this.inputController = undefined;\n this.resolvingInput = false;\n }\n }\n\n private async enqueue(\n operation: ComputerUseBrokerRequest['operation'],\n payload?: unknown,\n signal?: AbortSignal,\n ): Promise<Response> {\n if (this.resolvingInput) return jsonError('Another computer-use request is live.', 409);\n if (operation === 'observe' && this.sensitiveInput)\n return jsonError('Observations are sealed after sensitive input.', 409);\n if (this.phase !== 'active' || this.grantId === undefined) return jsonError('Computer use is not active.', 409);\n if (this.pending !== undefined) return jsonError('Another computer-use request is live.', 409);\n if (signal?.aborted === true) return jsonError('The computer-use request was cancelled.', 499);\n const sequence = operation === 'act' ? ++this.actionSequence : undefined;\n const request: ComputerUseBrokerRequest = {\n id: randomUUID(),\n operation,\n grantId: this.grantId,\n ...(sequence === undefined ? {} : { sequence }),\n ...(payload === undefined ? {} : { payload }),\n };\n const completion = new Promise<unknown>((resolve, reject) => {\n const onAbort = () => this.stopAfterUncertainRequest('The computer-use request was cancelled.');\n const timer = setTimeout(\n () => this.stopAfterUncertainRequest('The computer-use request timed out.'),\n this.requestTimeoutMs,\n );\n timer.unref?.();\n signal?.addEventListener('abort', onAbort, { once: true });\n this.pending = {\n request,\n resolve,\n reject,\n dispose: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n },\n };\n });\n this.changed();\n try {\n const value = await completion;\n return Response.json(this.sensitiveInput ? { applied: true } : value);\n } catch (error) {\n return jsonError(\n this.sensitiveInput\n ? 'Sensitive computer input failed.'\n : error instanceof Error\n ? error.message\n : String(error),\n 502,\n );\n }\n }\n\n public async fetch(request: Request): Promise<Response> {\n if (this.closed) return jsonError('Computer-use broker is closed.', 503);\n const url = new URL(request.url);\n const path = url.pathname;\n if (request.method === 'GET' && path === routes.artifact.path) {\n if (\n !(this.desktop?.authorizeRecording?.(request.headers) ?? this.desktop?.authorize(request.headers)) ||\n !this.desktop?.fetchRecording\n )\n return jsonError('Not found.', 404);\n const artifactId = url.searchParams.get('artifactId') ?? '';\n const offsetText = url.searchParams.get('offset') ?? '';\n const offset = Number(offsetText);\n if (!/^[0-9]+$/u.test(offsetText) || !Number.isSafeInteger(offset) || offset < 0 || offset > 128 * 1024 * 1024)\n return jsonError('Invalid recording offset.', 400);\n return this.desktop.fetchRecording(artifactId, `bytes=${offset}-${offset + 1024 * 1024 - 1}`);\n }\n if (path === routes.activate.path && request.method === 'GET') {\n if (\n !this.desktop?.authorizePending?.(request.headers) &&\n !(this.desktop?.authorizeRecording?.(request.headers) ?? this.desktop?.authorize(request.headers))\n )\n return jsonError('Not found.', 404);\n return Response.json(this.state());\n }\n if (path === routes.activate.path && request.method === 'DELETE') {\n if (!this.desktop?.authorizePending?.(request.headers)) return jsonError('Not found.', 404);\n if (this.phase !== 'awaiting_confirmation' && this.phase !== 'activating')\n return jsonError('No activation is pending.', 409);\n this.phase = 'stopping';\n this.rejectPending('The activation was cancelled.');\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n if (request.method === 'POST' && path === routes.activate.path) return this.requestActivation(request);\n const agent = path.startsWith('/agent/');\n const hub = path.startsWith('/hub/');\n if ((agent && !this.authorized(request, this.internalToken)) || (hub && !this.authorized(request, this.hubToken)))\n return jsonError('Not found.', 404);\n\n if (request.method === 'GET' && (path === routes.agentState.path || path === routes.hubState.path))\n return Response.json(this.state());\n if (request.method === 'POST' && path === routes.agentObserve.path)\n return this.enqueue('observe', undefined, request.signal);\n if (request.method === 'POST' && path === routes.agentAction.path) {\n const action = await body(request);\n if (!semanticAction(action)) return jsonError('A valid semantic action is required.', 400);\n return this.performAction(action as unknown as ComputerUseAction, request.signal);\n }\n if (request.method === 'POST' && path === routes.agentStop.path) {\n this.inputController?.abort();\n if (this.phase !== 'active') return jsonError('Computer use is not active.', 409);\n this.phase = 'stopping';\n this.rejectPending('The computer-use request was stopped.');\n this.changed();\n return Response.json(this.state(), { status: 202 });\n }\n if (request.method === 'GET' && path === routes.hubActivation.path) {\n if (this.activation?.confirmedAt === undefined || this.phase !== 'awaiting_confirmation')\n return Response.json(null);\n this.phase = 'activating';\n this.changed();\n return Response.json(this.activation);\n }\n if (request.method === 'GET' && path === routes.hubAuthorization.path)\n return Response.json(this.grantId === undefined ? null : { grantId: this.grantId, expiresAt: this.expiresAt });\n if (request.method === 'GET' && path === routes.hubNext.path) return Response.json(this.pending?.request ?? null);\n if (request.method === 'POST' && path === routes.hubComplete.path) {\n const input = await body(request);\n const id = typeof input.id === 'string' ? input.id : undefined;\n if (this.pending === undefined || this.pending.request.id !== id) return jsonError('The request is stale.', 409);\n const pending = this.pending;\n this.pending = undefined;\n pending.dispose();\n if (typeof input.error === 'string') {\n this.phase = 'stopping';\n pending.reject(new Error(input.error));\n } else pending.resolve(input.result);\n this.changed();\n return Response.json(this.state());\n }\n if (request.method === 'POST' && path === routes.hubStop.path) {\n this.inputController?.abort();\n const input = await body(request);\n if (this.phase === 'activating') {\n if (typeof input.error === 'string') {\n this.phase = 'failed';\n this.failure = { code: 'desktop_unavailable', message: input.error.slice(0, 512) };\n this.activation = undefined;\n } else {\n const host = record(input.host);\n if (\n typeof host?.grantId !== 'string' ||\n !Number.isFinite(host.expiresAt) ||\n (host.expiresAt as number) <= Date.now()\n )\n return jsonError('Desktop did not issue a complete grant.', 502);\n const selectedTarget = record(host.target);\n this.nativeTarget = selectedTarget === undefined ? undefined : Object.freeze({ ...selectedTarget });\n if (this.activation !== undefined && selectedTarget !== undefined)\n this.activation = Object.freeze({ ...this.activation, target: Object.freeze({ ...selectedTarget }) });\n this.grantId = host.grantId;\n this.expiresAt = host.expiresAt as number;\n this.actionSequence = 0;\n this.phase = 'active';\n clearTimeout(this.expiryTimer);\n this.expiryTimer = setTimeout(\n () => {\n if (this.closed || this.phase !== 'active') return;\n this.phase = 'stopping';\n this.inputController?.abort();\n this.rejectPending('The computer-use grant expired.');\n this.changed();\n },\n Math.max(0, this.expiresAt - Date.now()),\n );\n this.expiryTimer.unref?.();\n }\n } else {\n clearTimeout(this.expiryTimer);\n this.rejectPending('The computer-use session stopped.');\n this.phase = 'inactive';\n this.grantId = undefined;\n this.expiresAt = undefined;\n this.activation = undefined;\n this.nativeTarget = undefined;\n this.artifact = artifactView(input.artifact) ?? this.artifact;\n }\n this.changed();\n return Response.json(this.state());\n }\n return jsonError('Not found.', 404);\n }\n\n public close(): void {\n if (this.closed) return;\n this.closed = true;\n this.inputController?.abort();\n clearTimeout(this.expiryTimer);\n this.unsubscribeDesktop?.();\n this.listeners.clear();\n this.rejectPending('Computer-use broker closed.');\n this.grantId = undefined;\n this.expiresAt = undefined;\n }\n}\n\nexport function createComputerUseApi(options: ComputerUseApiOptions): ComputerUseRequestBroker {\n return new ComputerUseRequestBroker(options);\n}\n\nexport const api: PoApi = {\n basePath: API_BASE_PATH,\n start(context: PoApiContext): PoApiHandler {\n if (context.directEvents === undefined) throw new Error('Computer-use API requires the session direct event bus.');\n return createComputerUseApi({\n ...(context.sessionId === undefined ? {} : { sessionId: context.sessionId }),\n ...(context.internalToken === undefined ? {} : { internalToken: context.internalToken }),\n ...(context.hubToken === undefined ? {} : { hubToken: context.hubToken }),\n directEvents: context.directEvents,\n desktop: context.computerUse,\n });\n },\n};\n","import { spawn } from 'node:child_process';\nimport { realpath } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport type {\n ComputerScriptExecutionOptions,\n ComputerScriptExecutionResult,\n ComputerScriptRunnerOptions,\n} from '../../types/computerScript';\nimport type {\n ComputerUseAction,\n ComputerUseObservation,\n ComputerUseObservationOptions,\n ComputerUseSessionClient,\n} from '../../types/computerUse';\nimport { COMPUTER_SCRIPT_WORKER_SOURCE } from '../computerScriptWorker';\nimport { observationOptions } from '../computerUseApi';\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst DEFAULT_MAX_OUTPUT_BYTES = 256 * 1024;\nconst MAX_IMAGE_BYTES = 6 * 1024 * 1024;\nconst MAX_PENDING_OPERATIONS = 64;\n\nexport class ComputerScriptExecutionError extends Error {\n constructor(\n message: string,\n readonly completedActions: number,\n readonly outcomeUncertain: boolean,\n ) {\n super(message);\n this.name = 'ComputerScriptExecutionError';\n }\n}\n\ninterface WorkerMessage {\n readonly type?: unknown;\n readonly id?: unknown;\n readonly operation?: unknown;\n readonly payload?: unknown;\n readonly level?: unknown;\n readonly message?: unknown;\n readonly resultJson?: unknown;\n readonly error?: unknown;\n}\n\nexport class ComputerScriptRunner {\n private readonly client: ComputerUseSessionClient;\n private readonly allowedScriptPaths: readonly string[];\n private readonly scriptRoot?: string;\n private readonly timeoutMs: number;\n private readonly maxOutputBytes: number;\n\n constructor(options: ComputerScriptRunnerOptions) {\n this.client = options.client;\n this.allowedScriptPaths = options.allowedScriptPaths;\n this.scriptRoot = options.scriptRoot;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;\n }\n\n async execute(\n scriptPath: string,\n input: unknown,\n signal?: AbortSignal,\n options: ComputerScriptExecutionOptions = {},\n cwd?: string,\n ): Promise<ComputerScriptExecutionResult> {\n signal?.throwIfAborted();\n const resolvedPath = await realpath(path.resolve(this.scriptRoot ?? cwd ?? process.cwd(), scriptPath));\n const allowedPaths = await Promise.all(\n this.allowedScriptPaths.map(async (candidate) => realpath(candidate).catch(() => '')),\n );\n const trusted = options.trusted === true;\n if ((trusted || this.scriptRoot === undefined) && !allowedPaths.includes(resolvedPath)) {\n throw new Error('Computer script path is not explicitly allowed.');\n }\n if (!/\\.(ts|js|mjs)$/u.test(resolvedPath))\n throw new Error('Computer scripts must be JavaScript or erasable TypeScript files.');\n const root = await realpath(this.scriptRoot ?? path.dirname(resolvedPath));\n const relative = path.relative(root, resolvedPath);\n if (!trusted && (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) {\n throw new Error('Computer script escapes the admitted script root.');\n }\n const serializedInput = JSON.stringify(input);\n if (serializedInput === undefined) throw new Error('Computer script input must be JSON serializable.');\n if (Buffer.byteLength(serializedInput) > this.maxOutputBytes)\n throw new Error('Computer script input exceeds the size limit.');\n const quickjsPath = trusted ? undefined : createRequire(import.meta.url).resolve('quickjs-emscripten');\n signal?.throwIfAborted();\n const started = performance.now();\n\n return new Promise((resolve, reject) => {\n const child = spawn(process.execPath, ['--input-type=module', '--eval', COMPUTER_SCRIPT_WORKER_SOURCE], {\n stdio: ['ignore', 'pipe', 'pipe', 'ipc'],\n // Preserve Electron's Node mode, but no host credentials, for restricted workers.\n env: trusted ? process.env : { ELECTRON_RUN_AS_NODE: '1' },\n });\n const controller = new AbortController();\n const logs: string[] = [];\n let outputBytes = 0;\n let completedActions = 0;\n let observations = 0;\n let actionInFlight = false;\n let settled = false;\n let completing = false;\n let outstanding = 0;\n let operation: Promise<void> = Promise.resolve();\n const finish = (error?: Error, value?: ComputerScriptExecutionResult): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timeout);\n signal?.removeEventListener('abort', onAbort);\n controller.abort();\n child.kill('SIGTERM');\n const killTimer = setTimeout(() => child.kill('SIGKILL'), 250);\n killTimer.unref();\n if (error) reject(new ComputerScriptExecutionError(error.message, completedActions, actionInFlight));\n else resolve(value!);\n };\n const addOutput = (value: string): boolean => {\n outputBytes += Buffer.byteLength(value);\n if (outputBytes <= this.maxOutputBytes) return true;\n finish(new Error('Computer script output exceeded the size limit.'));\n return false;\n };\n const send = (value: object): void => {\n if (settled || !child.connected) return;\n child.send(value, (error) => {\n if (error && !settled) finish(error);\n });\n };\n const onAbort = (): void => finish(new Error('Computer script execution was cancelled.'));\n const timeout = setTimeout(() => finish(new Error('Computer script execution timed out.')), this.timeoutMs);\n timeout.unref();\n signal?.addEventListener('abort', onAbort, { once: true });\n if (signal?.aborted) return onAbort();\n child.stdout?.on('data', (chunk: Buffer) => addOutput(chunk.toString('utf8')));\n child.stderr?.on('data', (chunk: Buffer) => addOutput(chunk.toString('utf8')));\n child.on('error', (error) => finish(error));\n child.on('exit', (code, exitSignal) => {\n if (!settled)\n finish(new Error(`Computer script worker exited before completion (${exitSignal ?? code ?? 'unknown'}).`));\n });\n\n const observe = async (options: ComputerUseObservationOptions): Promise<ComputerUseObservation> => {\n const includeScreenshot = options.includeScreenshot === true;\n const value = await this.client.observe(controller.signal, { ...options, includeScreenshot });\n observations += 1;\n const { screenshot, ...semantic } = value;\n if (Buffer.byteLength(JSON.stringify(semantic)) > this.maxOutputBytes)\n throw new Error('Computer observation exceeds the size limit.');\n if (includeScreenshot && screenshot) {\n if (screenshot.mimeType !== 'image/png' || screenshot.data.length > Math.ceil(MAX_IMAGE_BYTES / 3) * 4) {\n throw new Error('Computer screenshot exceeds the image limit.');\n }\n return { ...semantic, screenshot };\n }\n return semantic;\n };\n\n child.on('message', (raw: WorkerMessage) => {\n if (settled) return;\n if (!raw || typeof raw !== 'object' || Buffer.byteLength(JSON.stringify(raw)) > this.maxOutputBytes + 4096) {\n finish(new Error('Computer worker message exceeds the size limit.'));\n return;\n }\n if (raw.type === 'log' && typeof raw.message === 'string') {\n const line = `[${String(raw.level)}] ${raw.message}`;\n if (addOutput(line)) logs.push(line);\n return;\n }\n if (raw.type === 'program') {\n if (\n completing ||\n typeof raw.id !== 'string' ||\n raw.id.length > 128 ||\n (raw.operation !== 'observe' && raw.operation !== 'act') ||\n outstanding >= MAX_PENDING_OPERATIONS\n ) {\n finish(new Error('Invalid or excessive computer program operations.'));\n return;\n }\n outstanding += 1;\n operation = operation\n .then(async () => {\n if (settled || controller.signal.aborted) return;\n try {\n let value: unknown;\n if (raw.operation === 'observe') {\n value = await observe(observationOptions(raw.payload));\n } else {\n actionInFlight = true;\n value = await this.client.act(raw.payload as ComputerUseAction, controller.signal);\n completedActions += 1;\n actionInFlight = false;\n }\n send({ type: 'response', id: raw.id, value });\n } catch (error) {\n // An action can have taken effect before its transport failed. Never run the remaining chain.\n if (actionInFlight) finish(error instanceof Error ? error : new Error(String(error)));\n else\n send({ type: 'response', id: raw.id, error: error instanceof Error ? error.message : String(error) });\n } finally {\n outstanding -= 1;\n }\n })\n .catch((error: unknown) => finish(error instanceof Error ? error : new Error(String(error))));\n return;\n }\n if (raw.type === 'failed' && typeof raw.error === 'string') {\n finish(new Error(raw.error));\n return;\n }\n if (raw.type === 'complete') {\n if (completing) {\n finish(new Error('Computer worker completed twice.'));\n return;\n }\n completing = true;\n operation = operation\n .then(async () => {\n if (settled) return;\n const resultJson = raw.resultJson;\n if (resultJson !== undefined && typeof resultJson !== 'string')\n throw new Error('Computer script returned an invalid result.');\n if (typeof resultJson === 'string' && !addOutput(resultJson)) return;\n const observation = await observe({ includeScreenshot: options.includeScreenshot === true });\n if (settled || !addOutput(JSON.stringify({ ...observation, screenshot: undefined }))) return;\n finish(undefined, {\n ...(typeof resultJson === 'string' ? { result: JSON.parse(resultJson) as unknown } : {}),\n observation,\n logs,\n metrics: {\n actions: completedActions,\n observations,\n durationMs: Math.round(performance.now() - started),\n outputBytes,\n },\n });\n })\n .catch((error: unknown) => finish(error instanceof Error ? error : new Error(String(error))));\n }\n });\n send({\n type: 'start',\n scriptPath: resolvedPath,\n scriptRoot: root,\n input: JSON.parse(serializedInput) as unknown,\n trusted,\n quickjsPath,\n timeoutMs: this.timeoutMs,\n maxOutputBytes: this.maxOutputBytes,\n });\n });\n }\n}\n","import type { ComputerUseExtensionResult, ComputerUseExtensionService } from '../../types/extension';\nimport type { ComputerUseSessionClient } from '../sessionApiClient';\n\nexport class DefaultComputerUseExtensionService implements ComputerUseExtensionService {\n public constructor(private readonly client?: ComputerUseSessionClient) {}\n\n public async execute(): Promise<ComputerUseExtensionResult> {\n if (this.client === undefined) return { message: 'Computer use requires a Po Desktop session.', level: 'error' };\n const state = await this.client.state();\n return { message: `Computer use is ${state.phase.replaceAll('_', ' ')}.`, level: 'info' };\n }\n}\n"],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { realpath } from "node:fs/promises";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
|
+
import { hasInputTemplate, parseInputTemplate, renderInputTemplate } from "@agimon-ai/po-core/inputTemplate";
|
|
6
7
|
import { poApiCallerFrom } from "@agimon-ai/po-core/packageApi";
|
|
7
8
|
//#region src/constants/computerUse.ts
|
|
8
9
|
const COMPUTER_USE_GUIDANCE = `[COMPUTER USE ACTIVE]
|
|
@@ -456,6 +457,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
456
457
|
closed = false;
|
|
457
458
|
desktop;
|
|
458
459
|
beforeActivate;
|
|
460
|
+
profileRuntime;
|
|
461
|
+
nativeTarget;
|
|
462
|
+
resolvingInput = false;
|
|
463
|
+
inputController;
|
|
464
|
+
sensitiveInput = false;
|
|
459
465
|
listeners = /* @__PURE__ */ new Set();
|
|
460
466
|
unsubscribeDesktop;
|
|
461
467
|
static DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -467,7 +473,9 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
467
473
|
this.requestTimeoutMs = options.requestTimeoutMs ?? ComputerUseRequestBroker.DEFAULT_REQUEST_TIMEOUT_MS;
|
|
468
474
|
this.desktop = options.desktop;
|
|
469
475
|
this.beforeActivate = options.beforeActivate;
|
|
476
|
+
this.profileRuntime = options.profileRuntime;
|
|
470
477
|
this.unsubscribeDesktop = options.desktop?.subscribe(() => {
|
|
478
|
+
this.inputController?.abort();
|
|
471
479
|
clearTimeout(this.expiryTimer);
|
|
472
480
|
if (!options.desktop?.available) {
|
|
473
481
|
this.rejectPending("Desktop disconnected.");
|
|
@@ -525,10 +533,11 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
525
533
|
act: async (action, signal) => {
|
|
526
534
|
requireDesktop();
|
|
527
535
|
if (!semanticAction(action)) throw new Error("A valid semantic action is required.");
|
|
528
|
-
return result(await this.
|
|
536
|
+
return result(await this.performAction(action, signal));
|
|
529
537
|
},
|
|
530
538
|
stop: async (signal) => {
|
|
531
539
|
signal?.throwIfAborted();
|
|
540
|
+
this.inputController?.abort();
|
|
532
541
|
if (this.phase !== "inactive" && this.phase !== "failed") {
|
|
533
542
|
this.phase = "stopping";
|
|
534
543
|
this.rejectPending("Computer use was stopped.");
|
|
@@ -601,7 +610,58 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
601
610
|
}
|
|
602
611
|
this.rejectPending(message);
|
|
603
612
|
}
|
|
613
|
+
async performAction(action, requestSignal) {
|
|
614
|
+
if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
|
|
615
|
+
if (action.kind !== "set_value" || !hasInputTemplate(action.value)) return this.enqueue("act", action, requestSignal);
|
|
616
|
+
this.resolvingInput = true;
|
|
617
|
+
try {
|
|
618
|
+
if (this.phase !== "active" || this.pending || !this.grantId) throw new Error();
|
|
619
|
+
const parts = parseInputTemplate(action.value);
|
|
620
|
+
const profile = this.profileRuntime?.();
|
|
621
|
+
if (!profile) throw new Error();
|
|
622
|
+
const snapshot = profile.readSelection();
|
|
623
|
+
const generation = snapshot.generation;
|
|
624
|
+
const grantId = this.grantId;
|
|
625
|
+
const target = this.nativeTarget;
|
|
626
|
+
const usesSecret = parts.some((part) => part.kind === "secret");
|
|
627
|
+
if (usesSecret && (!target || target.scope === "desktop" || typeof target.bundleId !== "string")) throw new Error();
|
|
628
|
+
const controller = new AbortController();
|
|
629
|
+
this.inputController = controller;
|
|
630
|
+
const signal = AbortSignal.any([
|
|
631
|
+
snapshot.signal,
|
|
632
|
+
controller.signal,
|
|
633
|
+
...requestSignal ? [requestSignal] : []
|
|
634
|
+
]);
|
|
635
|
+
const value = await renderInputTemplate(parts, {
|
|
636
|
+
readEnv: (name) => snapshot.env && Object.hasOwn(snapshot.env, name) ? snapshot.env[name] : void 0,
|
|
637
|
+
resolveSecret: (name) => profile.resolveInputSecret(name, {
|
|
638
|
+
surface: "computer",
|
|
639
|
+
target: target.bundleId,
|
|
640
|
+
signal
|
|
641
|
+
}),
|
|
642
|
+
onResolved: () => {
|
|
643
|
+
this.sensitiveInput = true;
|
|
644
|
+
},
|
|
645
|
+
signal
|
|
646
|
+
});
|
|
647
|
+
signal.throwIfAborted();
|
|
648
|
+
if (this.closed || this.phase !== "active" || this.grantId !== grantId || this.nativeTarget !== target || this.profileRuntime?.() !== profile || profile.readSelection().generation !== generation) throw new Error();
|
|
649
|
+
this.resolvingInput = false;
|
|
650
|
+
return await this.enqueue("act", {
|
|
651
|
+
...action,
|
|
652
|
+
value,
|
|
653
|
+
...usesSecret ? { sensitiveBundleId: target.bundleId } : {}
|
|
654
|
+
}, signal);
|
|
655
|
+
} catch {
|
|
656
|
+
return jsonError("Computer input template failed.", 400);
|
|
657
|
+
} finally {
|
|
658
|
+
this.inputController = void 0;
|
|
659
|
+
this.resolvingInput = false;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
604
662
|
async enqueue(operation, payload, signal) {
|
|
663
|
+
if (this.resolvingInput) return jsonError("Another computer-use request is live.", 409);
|
|
664
|
+
if (operation === "observe" && this.sensitiveInput) return jsonError("Observations are sealed after sensitive input.", 409);
|
|
605
665
|
if (this.phase !== "active" || this.grantId === void 0) return jsonError("Computer use is not active.", 409);
|
|
606
666
|
if (this.pending !== void 0) return jsonError("Another computer-use request is live.", 409);
|
|
607
667
|
if (signal?.aborted === true) return jsonError("The computer-use request was cancelled.", 499);
|
|
@@ -630,9 +690,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
630
690
|
});
|
|
631
691
|
this.changed();
|
|
632
692
|
try {
|
|
633
|
-
|
|
693
|
+
const value = await completion;
|
|
694
|
+
return Response.json(this.sensitiveInput ? { applied: true } : value);
|
|
634
695
|
} catch (error) {
|
|
635
|
-
return jsonError(error instanceof Error ? error.message : String(error), 502);
|
|
696
|
+
return jsonError(this.sensitiveInput ? "Sensitive computer input failed." : error instanceof Error ? error.message : String(error), 502);
|
|
636
697
|
}
|
|
637
698
|
}
|
|
638
699
|
async fetch(request) {
|
|
@@ -668,9 +729,10 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
668
729
|
if (request.method === "POST" && path === routes.agentAction.path) {
|
|
669
730
|
const action = await body(request);
|
|
670
731
|
if (!semanticAction(action)) return jsonError("A valid semantic action is required.", 400);
|
|
671
|
-
return this.
|
|
732
|
+
return this.performAction(action, request.signal);
|
|
672
733
|
}
|
|
673
734
|
if (request.method === "POST" && path === routes.agentStop.path) {
|
|
735
|
+
this.inputController?.abort();
|
|
674
736
|
if (this.phase !== "active") return jsonError("Computer use is not active.", 409);
|
|
675
737
|
this.phase = "stopping";
|
|
676
738
|
this.rejectPending("The computer-use request was stopped.");
|
|
@@ -703,6 +765,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
703
765
|
return Response.json(this.state());
|
|
704
766
|
}
|
|
705
767
|
if (request.method === "POST" && path === routes.hubStop.path) {
|
|
768
|
+
this.inputController?.abort();
|
|
706
769
|
const input = await body(request);
|
|
707
770
|
if (this.phase === "activating") {
|
|
708
771
|
if (typeof input.error === "string") {
|
|
@@ -716,6 +779,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
716
779
|
const host = record(input.host);
|
|
717
780
|
if (typeof host?.grantId !== "string" || !Number.isFinite(host.expiresAt) || host.expiresAt <= Date.now()) return jsonError("Desktop did not issue a complete grant.", 502);
|
|
718
781
|
const selectedTarget = record(host.target);
|
|
782
|
+
this.nativeTarget = selectedTarget === void 0 ? void 0 : Object.freeze({ ...selectedTarget });
|
|
719
783
|
if (this.activation !== void 0 && selectedTarget !== void 0) this.activation = Object.freeze({
|
|
720
784
|
...this.activation,
|
|
721
785
|
target: Object.freeze({ ...selectedTarget })
|
|
@@ -728,6 +792,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
728
792
|
this.expiryTimer = setTimeout(() => {
|
|
729
793
|
if (this.closed || this.phase !== "active") return;
|
|
730
794
|
this.phase = "stopping";
|
|
795
|
+
this.inputController?.abort();
|
|
731
796
|
this.rejectPending("The computer-use grant expired.");
|
|
732
797
|
this.changed();
|
|
733
798
|
}, Math.max(0, this.expiresAt - Date.now()));
|
|
@@ -740,6 +805,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
740
805
|
this.grantId = void 0;
|
|
741
806
|
this.expiresAt = void 0;
|
|
742
807
|
this.activation = void 0;
|
|
808
|
+
this.nativeTarget = void 0;
|
|
743
809
|
this.artifact = artifactView(input.artifact) ?? this.artifact;
|
|
744
810
|
}
|
|
745
811
|
this.changed();
|
|
@@ -750,6 +816,7 @@ var ComputerUseRequestBroker = class ComputerUseRequestBroker {
|
|
|
750
816
|
close() {
|
|
751
817
|
if (this.closed) return;
|
|
752
818
|
this.closed = true;
|
|
819
|
+
this.inputController?.abort();
|
|
753
820
|
clearTimeout(this.expiryTimer);
|
|
754
821
|
this.unsubscribeDesktop?.();
|
|
755
822
|
this.listeners.clear();
|
|
@@ -996,4 +1063,4 @@ var DefaultComputerUseExtensionService = class {
|
|
|
996
1063
|
//#endregion
|
|
997
1064
|
export { COMPUTER_USE_GUIDANCE as _, routes as a, COMPUTER_USE_TOOL_NAMES as b, COMPUTER_USE_MODE_ID as c, computerUseChannelType as d, COMMAND_DESCRIPTION as f, COMPUTER_USE_CODEMODE_GUIDANCE as g, COMPUTER_USE_ARTIFACT_DIRECTORY as h, createComputerUseApi as i, COMPUTER_USE_ROUTES as l, COMPUTER_USE_ARTIFACTS_SERVICE as m, ComputerScriptExecutionError as n, isDesktopPermission as o, COMMAND_NAME as p, ComputerScriptRunner as r, API_BASE_PATH as s, DefaultComputerUseExtensionService as t, COMPUTER_USE_STATUS_KEY as u, COMPUTER_USE_RECORDING_CHUNK_BYTES as v, COMPUTER_USE_RECORDING_MAX_BYTES as y };
|
|
998
1065
|
|
|
999
|
-
//# sourceMappingURL=extensionService-
|
|
1066
|
+
//# sourceMappingURL=extensionService-D8bAAsIN.mjs.map
|